IniReader: Remove ini file from cache when it's changed by SetString

- Had to reorganize some code to make this work. Changed how some singletons are created to guarantee destructor calls in correct order (IniReader is constructed first and destructed last, after every other module).
This commit is contained in:
phobos2077
2023-06-17 23:33:37 +02:00
parent 1e4bbaedbd
commit cec091bda2
13 changed files with 99 additions and 86 deletions
-2
View File
@@ -35,8 +35,6 @@ static constexpr char* IniModeKey = "ConsoleWindow";
static constexpr char* IniPositionKey = "ConsoleWindowData";
static constexpr char* IniCodePageKey = "ConsoleCodePage";
ConsoleWindow ConsoleWindow::_instance;
bool ConsoleWindow::tryGetWindow(HWND* wnd) {
*wnd = GetConsoleWindow();
if (!*wnd) {
+4 -3
View File
@@ -31,7 +31,10 @@ public:
DISPLAY_MSG = 8,
};
static ConsoleWindow& instance() { return _instance; }
static ConsoleWindow& instance() {
static ConsoleWindow instance;
return instance;
}
ConsoleWindow() {}
~ConsoleWindow();
@@ -44,8 +47,6 @@ public:
void write(const char* message, Source source);
private:
static ConsoleWindow _instance;
int _mode = 0;
Source _lastSource;
+53 -44
View File
@@ -27,29 +27,44 @@
namespace sfall
{
DWORD IniReader::modifiedIni;
static const char* ddrawIni = ".\\ddraw.ini";
static char ini[65] = ".\\";
static std::unordered_map<std::string, std::unique_ptr<Config>> iniCache;
IniReader& IniReader::instance() {
static IniReader instance;
return instance;
}
Config* IniReader::GetIniConfig(const char* iniFile) {
IniReader::IniReader() {
}
Config* IniReader::getIniConfig(const char* iniFile) {
std::string pathStr(iniFile);
auto cacheHit = iniCache.find(pathStr);
if (cacheHit != iniCache.end()) {
auto cacheHit = IniReader::instance()._iniCache.find(pathStr);
if (cacheHit != _iniCache.end()) {
return cacheHit->second.get();
}
auto config = std::make_unique<Config>();
if (!config->read(iniFile, false)) {
iniCache.emplace(std::move(pathStr), nullptr);
_iniCache.emplace(std::move(pathStr), nullptr);
return nullptr;
}
return iniCache.emplace(std::move(pathStr), std::move(config)).first->second.get();
return _iniCache.emplace(std::move(pathStr), std::move(config)).first->second.get();
}
const char* IniReader::getConfigFile() {
return _ini;
}
void IniReader::setDefaultConfigFile() {
std::strcpy(&_ini[2], &ddrawIni[2]);
}
void IniReader::setConfigFile(const char* iniFile) {
strcat_s(_ini, iniFile);
}
static int getInt(const char* section, const char* setting, int defaultValue, const char* iniFile) {
auto config = IniReader::GetIniConfig(iniFile);
auto config = IniReader::instance().getIniConfig(iniFile);
int value;
if (config == nullptr || !config->getInt(section, setting, value)) {
value = defaultValue;
@@ -58,7 +73,7 @@ static int getInt(const char* section, const char* setting, int defaultValue, co
}
static size_t getString(const char* section, const char* setting, const char* defaultValue, char* buf, size_t bufSize, const char* iniFile) {
auto config = IniReader::GetIniConfig(iniFile);
auto config = IniReader::instance().getIniConfig(iniFile);
const std::string* value;
if (config == nullptr || !config->getString(section, setting, value)) {
strncpy_s(buf, bufSize, defaultValue, bufSize - 1);
@@ -70,7 +85,7 @@ static size_t getString(const char* section, const char* setting, const char* de
}
static std::string getString(const char* section, const char* setting, const char* defaultValue, size_t bufSize, const char* iniFile) {
auto config = IniReader::GetIniConfig(iniFile);
auto config = IniReader::instance().getIniConfig(iniFile);
const std::string* value;
if (config == nullptr || !config->getString(section, setting, value)) {
return std::string(defaultValue);
@@ -78,28 +93,32 @@ static std::string getString(const char* section, const char* setting, const cha
return *value;
}
static std::vector<std::string> getList(const char* section, const char* setting, const char* defaultValue, size_t bufSize, char delimiter, const char* iniFile) {
auto list = split(getString(section, setting, defaultValue, bufSize, iniFile), delimiter);
std::transform(list.cbegin(), list.cend(), list.begin(), (std::string (*)(const std::string&))trim);
return list;
int IniReader::setString(const char* section, const char* setting, const char* value, const char* iniFile) {
_iniCache.erase(iniFile); // remove file from cache so it returns updated value on the next read
return WritePrivateProfileStringA(section, setting, value, iniFile);
}
void IniReader::clearCache() {
_iniCache.clear();
}
void IniReader::init() {
_modifiedIni = IniReader::GetConfigInt("Main", "ModifiedIni", 0);
LoadGameHook::OnGameReset() += [this] { clearCache(); };
}
static int setInt(const char* section, const char* setting, int value, const char* iniFile) {
char buf[33];
_itoa_s(value, buf, 33, 10);
return WritePrivateProfileStringA(section, setting, buf, iniFile);
return IniReader::instance().setString(section, setting, buf, iniFile);
}
const char* IniReader::GetConfigFile() {
return ini;
}
void IniReader::SetDefaultConfigFile() {
std::strcpy(&ini[2], &ddrawIni[2]);
}
void IniReader::SetConfigFile(const char* iniFile) {
strcat_s(ini, iniFile);
static std::vector<std::string> getList(const char* section, const char* setting, const char* defaultValue, size_t bufSize, char delimiter, const char* iniFile) {
auto list = split(getString(section, setting, defaultValue, bufSize, iniFile), delimiter);
std::transform(list.cbegin(), list.cend(), list.begin(), (std::string (*)(const std::string&))trim);
return list;
}
int IniReader::GetIntDefaultConfig(const char* section, const char* setting, int defaultValue) {
@@ -115,19 +134,19 @@ std::vector<std::string> IniReader::GetListDefaultConfig(const char* section, co
}
int IniReader::GetConfigInt(const char* section, const char* setting, int defaultValue) {
return getInt(section, setting, defaultValue, ini);
return getInt(section, setting, defaultValue, instance()._ini);
}
std::string IniReader::GetConfigString(const char* section, const char* setting, const char* defaultValue, size_t bufSize) {
return trim(getString(section, setting, defaultValue, bufSize, ini));
return trim(getString(section, setting, defaultValue, bufSize, instance()._ini));
}
size_t IniReader::GetConfigString(const char* section, const char* setting, const char* defaultValue, char* buf, size_t bufSize) {
return getString(section, setting, defaultValue, buf, bufSize, ini);
return getString(section, setting, defaultValue, buf, bufSize, instance()._ini);
}
std::vector<std::string> IniReader::GetConfigList(const char* section, const char* setting, const char* defaultValue, size_t bufSize) {
return getList(section, setting, defaultValue, bufSize, ',', ini);
return getList(section, setting, defaultValue, bufSize, ',', instance()._ini);
}
int IniReader::GetInt(const char* section, const char* setting, int defaultValue, const char* iniFile) {
@@ -147,11 +166,11 @@ std::vector<std::string> IniReader::GetList(const char* section, const char* set
}
int IniReader::SetConfigInt(const char* section, const char* setting, int value) {
return setInt(section, setting, value, ini);
return setInt(section, setting, value, instance()._ini);
}
int IniReader::SetConfigString(const char* section, const char* setting, const char* value) {
return WritePrivateProfileStringA(section, setting, value, ini);
return instance().setString(section, setting, value, instance()._ini);
}
int IniReader::SetDefaultConfigInt(const char* section, const char* setting, int value) {
@@ -159,17 +178,7 @@ int IniReader::SetDefaultConfigInt(const char* section, const char* setting, int
}
int IniReader::SetDefaultConfigString(const char* section, const char* setting, const char* value) {
return WritePrivateProfileStringA(section, setting, value, ddrawIni);
}
void OnGameReset() {
iniCache.clear();
}
void IniReader::init() {
modifiedIni = IniReader::GetConfigInt("Main", "ModifiedIni", 0);
LoadGameHook::OnGameReset() += OnGameReset;
return instance().setString(section, setting, value, ddrawIni);
}
}
+27 -11
View File
@@ -24,17 +24,7 @@ class Config;
class IniReader {
public:
static void init();
static DWORD modifiedIni;
static const char* GetConfigFile();
static void SetDefaultConfigFile();
static void SetConfigFile(const char* iniFile);
// Gets a Config from an INI file at given path, relative to game root folder.
// Config is loaded once per given path when requested and only unloaded on game reset (returning to main menu).
static Config* GetIniConfig(const char* iniFile);
static IniReader& instance();
// Gets the integer value from the default config (i.e. ddraw.ini)
static int GetIntDefaultConfig(const char* section, const char* setting, int defaultValue);
@@ -75,6 +65,32 @@ public:
static int SetDefaultConfigInt(const char* section, const char* setting, int value);
static int SetDefaultConfigString(const char* section, const char* setting, const char* value);
void init();
void clearCache();
DWORD modifiedIni() { return _modifiedIni; }
const char* getConfigFile();
void setDefaultConfigFile();
void setConfigFile(const char* iniFile);
// Gets a Config from an INI file at given path, relative to game root folder.
// Config is loaded once per given path when requested and only unloaded on game reset (returning to main menu).
Config* getIniConfig(const char* iniFile);
// Sets the string value in a given INI file
int setString(const char* section, const char* setting, const char* value, const char* iniFile);
private:
DWORD _modifiedIni;
char _ini[65]{ ".\\" };
std::unordered_map<std::string, std::unique_ptr<Config>> _iniCache;
IniReader();
IniReader(IniReader const&) = delete;
void operator=(IniReader const&) = delete;
};
}
-6
View File
@@ -5,8 +5,6 @@
namespace sfall
{
ModuleManager ModuleManager::_instance;
ModuleManager::ModuleManager() {
}
@@ -23,8 +21,4 @@ void ModuleManager::initAll() {
}
}
ModuleManager& ModuleManager::instance() {
return _instance;
}
}
+6 -5
View File
@@ -23,16 +23,17 @@ public:
_modules.emplace_back(new T());
}
static ModuleManager& instance();
static ModuleManager& instance() {
static ModuleManager instance;
return instance;
}
private:
// disallow copy constructor and copy assignment because we're dealing with unique_ptr's here
ModuleManager(const ModuleManager&);
void operator = (const ModuleManager&) {}
ModuleManager(const ModuleManager&) = delete;
void operator = (const ModuleManager&) = delete;
std::vector<std::unique_ptr<Module>> _modules;
static ModuleManager _instance;
};
}
-1
View File
@@ -57,7 +57,6 @@ class Message : public Module {
public:
const char* name() { return "Message"; }
void init();
//void exit() override;
static const char* GameLanguage();
-1
View File
@@ -27,7 +27,6 @@ class MetaruleExtender : public Module {
public:
const char* name() { return "MetaruleExtender"; }
void init();
//void exit() override;
};
-1
View File
@@ -27,7 +27,6 @@ class Movies : public Module {
public:
const char* name() { return "Movies"; }
void init();
//void exit() override;
static bool DirectShowMovies();
};
-1
View File
@@ -28,7 +28,6 @@ class ScriptShaders : public Module {
public:
const char* name() { return "ScriptShaders"; }
void init();
//void exit() override;
static size_t Count();
@@ -34,7 +34,7 @@ static std::unordered_map<std::string, DWORD> ConfigArrayCache;
static std::unordered_map<std::string, DWORD> ConfigArrayCacheDat;
static bool IsSpecialIni(const char* str, const char* end) {
const char* pos = strfind(str, &IniReader::GetConfigFile()[2]); // TODO test
const char* pos = strfind(str, &IniReader::instance().getConfigFile()[2]); // TODO test
if (pos && pos < end) return true;
pos = strfind(str, "f2_res.ini");
if (pos && pos < end) return true;
@@ -102,7 +102,7 @@ void op_get_ini_string(OpcodeContext& ctx) {
}
void op_modified_ini(OpcodeContext& ctx) {
ctx.setReturn(IniReader::modifiedIni);
ctx.setReturn(IniReader::instance().modifiedIni());
}
void mf_set_ini_setting(OpcodeContext& ctx) {
@@ -119,7 +119,7 @@ void mf_set_ini_setting(OpcodeContext& ctx) {
char section[33], file[128];
int result = ParseIniSetting(ctx.arg(0).strValue(), key, section, file);
if (result > 0) {
result = WritePrivateProfileStringA(section, key, saveValue, file);
result = IniReader::instance().setString(section, key, saveValue, file);
}
switch (result) {
@@ -156,7 +156,7 @@ static std::string GetIniFilePathFromArg(const ScriptValue& arg) {
}
void mf_get_ini_sections(OpcodeContext& ctx) {
Config* config = IniReader::GetIniConfig(GetIniFilePathFromArg(ctx.arg(0)).c_str());
Config* config = IniReader::instance().getIniConfig(GetIniFilePathFromArg(ctx.arg(0)).c_str());
if (config == nullptr) {
ctx.setReturn(CreateTempArray(0, 0));
return;
@@ -183,7 +183,7 @@ void mf_get_ini_section(OpcodeContext& ctx) {
int arrayId = CreateTempArray(-1, 0); // associative
ctx.setReturn(arrayId);
Config* config = IniReader::GetIniConfig(GetIniFilePathFromArg(ctx.arg(0)).c_str());
Config* config = IniReader::instance().getIniConfig(GetIniFilePathFromArg(ctx.arg(0)).c_str());
if (config == nullptr) return; // ini file not found
const auto& data = config->data();
@@ -224,7 +224,7 @@ void mf_get_ini_config(OpcodeContext& ctx) {
}
else {
// Request config from IniReader (to take advantage of it's cache).
config = IniReader::GetIniConfig(filePath.c_str());
config = IniReader::instance().getIniConfig(filePath.c_str());
if (config == nullptr) {
ctx.printOpcodeError("Could not read config file: %s", filePath.c_str());
ctx.setReturn(0);
-1
View File
@@ -27,7 +27,6 @@ class Unarmed : public Module {
public:
const char* name() { return "Unarmed"; }
void init();
//void exit() override;
static long GetHitAPCost(fo::AttackType hit);
static long GetDamage(fo::AttackType hit, long &minOut, long &maxOut);
+3 -4
View File
@@ -214,6 +214,7 @@ static HMODULE SfallInit() {
if (!CRC(filepath)) return 0;
IniReader::instance().init();
LoggingInit();
ConsoleWindow::instance().init();
@@ -263,7 +264,7 @@ static HMODULE SfallInit() {
HANDLE h = CreateFileA(overrideIni.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
IniReader::SetConfigFile(overrideIni.c_str());
IniReader::instance().setConfigFile(overrideIni.c_str());
} else {
MessageBoxA(0, "You gave a command line argument to Fallout, but the configuration ini file was not found.\n"
"Using default ddraw.ini instead.", "Warning", MB_TASKMODAL | MB_ICONWARNING);
@@ -271,12 +272,10 @@ static HMODULE SfallInit() {
}
} else {
defaultIni:
IniReader::SetDefaultConfigFile();
IniReader::instance().setDefaultConfigFile();
}
//std::srand(GetTickCount());
IniReader::init();
if (IniReader::GetConfigString("Misc", "ConfigFile", "", falloutConfigName, 65)) {
dlogr("Applying config file patch.", DL_INIT);
SafeWriteBatch<DWORD>((DWORD)&falloutConfigName, {0x444BA5, 0x444BCA});