GameConfigLoader: Implement missing Save function

This commit is contained in:
Léo Lam 2017-02-15 16:14:06 +01:00
parent 4761afe179
commit fa98d07f7a

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm>
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/Config/Config.h" #include "Common/Config/Config.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
@ -30,12 +32,21 @@ static std::vector<std::string> GetGameIniFilenames(const std::string& id, u16 r
return filenames; return filenames;
} }
static std::tuple<Config::System, std::string, std::string> struct ConfigLocation
MapINIToRealLocation(const std::string& section, const std::string& key)
{ {
static std::map<std::pair<std::string, std::string>, Config::System system;
std::tuple<Config::System, std::string, std::string>> std::string section;
ini_to_location = { std::string key;
bool operator==(const ConfigLocation& other) const
{
return std::tie(system, section, key) == std::tie(other.system, other.section, other.key);
}
bool operator!=(const ConfigLocation& other) const { return !operator==(other); }
};
static std::map<std::pair<std::string, std::string>, ConfigLocation> ini_to_location = {
// Core // Core
{{"Core", "CPUThread"}, {Config::System::Main, "Core", "CPUThread"}}, {{"Core", "CPUThread"}, {Config::System::Main, "Core", "CPUThread"}},
{{"Core", "SkipIdle"}, {Config::System::Main, "Core", "SkipIdle"}}, {{"Core", "SkipIdle"}, {Config::System::Main, "Core", "SkipIdle"}},
@ -99,19 +110,14 @@ MapINIToRealLocation(const std::string& section, const std::string& key)
{{"Controls", "PadProfile2"}, {Config::System::GCPad, "Controls", "PadProfile2"}}, {{"Controls", "PadProfile2"}, {Config::System::GCPad, "Controls", "PadProfile2"}},
{{"Controls", "PadProfile3"}, {Config::System::GCPad, "Controls", "PadProfile3"}}, {{"Controls", "PadProfile3"}, {Config::System::GCPad, "Controls", "PadProfile3"}},
{{"Controls", "PadProfile4"}, {Config::System::GCPad, "Controls", "PadProfile4"}}, {{"Controls", "PadProfile4"}, {Config::System::GCPad, "Controls", "PadProfile4"}},
{{"Controls", "WiimoteProfile1"}, {{"Controls", "WiimoteProfile1"}, {Config::System::WiiPad, "Controls", "WiimoteProfile1"}},
{Config::System::WiiPad, "Controls", "WiimoteProfile1"}}, {{"Controls", "WiimoteProfile2"}, {Config::System::WiiPad, "Controls", "WiimoteProfile2"}},
{{"Controls", "WiimoteProfile2"}, {{"Controls", "WiimoteProfile3"}, {Config::System::WiiPad, "Controls", "WiimoteProfile3"}},
{Config::System::WiiPad, "Controls", "WiimoteProfile2"}}, {{"Controls", "WiimoteProfile4"}, {Config::System::WiiPad, "Controls", "WiimoteProfile4"}},
{{"Controls", "WiimoteProfile3"},
{Config::System::WiiPad, "Controls", "WiimoteProfile3"}},
{{"Controls", "WiimoteProfile4"},
{Config::System::WiiPad, "Controls", "WiimoteProfile4"}},
// Video // Video
{{"Video_Hardware", "VSync"}, {Config::System::GFX, "Hardware", "VSync"}}, {{"Video_Hardware", "VSync"}, {Config::System::GFX, "Hardware", "VSync"}},
{{"Video_Settings", "wideScreenHack"}, {{"Video_Settings", "wideScreenHack"}, {Config::System::GFX, "Settings", "wideScreenHack"}},
{Config::System::GFX, "Settings", "wideScreenHack"}},
{{"Video_Settings", "AspectRatio"}, {Config::System::GFX, "Settings", "AspectRatio"}}, {{"Video_Settings", "AspectRatio"}, {Config::System::GFX, "Settings", "AspectRatio"}},
{{"Video_Settings", "Crop"}, {Config::System::GFX, "Settings", "Crop"}}, {{"Video_Settings", "Crop"}, {Config::System::GFX, "Settings", "Crop"}},
{{"Video_Settings", "UseXFB"}, {Config::System::GFX, "Settings", "UseXFB"}}, {{"Video_Settings", "UseXFB"}, {Config::System::GFX, "Settings", "UseXFB"}},
@ -125,8 +131,7 @@ MapINIToRealLocation(const std::string& section, const std::string& key)
{Config::System::GFX, "Settings", "CacheHiresTextures"}}, {Config::System::GFX, "Settings", "CacheHiresTextures"}},
{{"Video_Settings", "EnablePixelLighting"}, {{"Video_Settings", "EnablePixelLighting"},
{Config::System::GFX, "Settings", "EnablePixelLighting"}}, {Config::System::GFX, "Settings", "EnablePixelLighting"}},
{{"Video_Settings", "ForcedSlowDepth"}, {{"Video_Settings", "ForcedSlowDepth"}, {Config::System::GFX, "Settings", "ForcedSlowDepth"}},
{Config::System::GFX, "Settings", "ForcedSlowDepth"}},
{{"Video_Settings", "MSAA"}, {Config::System::GFX, "Settings", "MSAA"}}, {{"Video_Settings", "MSAA"}, {Config::System::GFX, "Settings", "MSAA"}},
{{"Video_Settings", "SSAA"}, {Config::System::GFX, "Settings", "SSAA"}}, {{"Video_Settings", "SSAA"}, {Config::System::GFX, "Settings", "SSAA"}},
{{"Video_Settings", "EFBScale"}, {Config::System::GFX, "Settings", "EFBScale"}}, {{"Video_Settings", "EFBScale"}, {Config::System::GFX, "Settings", "EFBScale"}},
@ -140,16 +145,14 @@ MapINIToRealLocation(const std::string& section, const std::string& key)
{Config::System::GFX, "Enhancements", "PostProcessingShader"}}, {Config::System::GFX, "Enhancements", "PostProcessingShader"}},
{{"Video_Stereoscopy", "StereoMode"}, {Config::System::GFX, "Stereoscopy", "StereoMode"}}, {{"Video_Stereoscopy", "StereoMode"}, {Config::System::GFX, "Stereoscopy", "StereoMode"}},
{{"Video_Stereoscopy", "StereoDepth"}, {{"Video_Stereoscopy", "StereoDepth"}, {Config::System::GFX, "Stereoscopy", "StereoDepth"}},
{Config::System::GFX, "Stereoscopy", "StereoDepth"}},
{{"Video_Stereoscopy", "StereoSwapEyes"}, {{"Video_Stereoscopy", "StereoSwapEyes"},
{Config::System::GFX, "Stereoscopy", "StereoSwapEyes"}}, {Config::System::GFX, "Stereoscopy", "StereoSwapEyes"}},
{{"Video_Hacks", "EFBAccessEnable"}, {Config::System::GFX, "Hacks", "EFBAccessEnable"}}, {{"Video_Hacks", "EFBAccessEnable"}, {Config::System::GFX, "Hacks", "EFBAccessEnable"}},
{{"Video_Hacks", "BBoxEnable"}, {Config::System::GFX, "Hacks", "BBoxEnable"}}, {{"Video_Hacks", "BBoxEnable"}, {Config::System::GFX, "Hacks", "BBoxEnable"}},
{{"Video_Hacks", "ForceProgressive"}, {Config::System::GFX, "Hacks", "ForceProgressive"}}, {{"Video_Hacks", "ForceProgressive"}, {Config::System::GFX, "Hacks", "ForceProgressive"}},
{{"Video_Hacks", "EFBToTextureEnable"}, {{"Video_Hacks", "EFBToTextureEnable"}, {Config::System::GFX, "Hacks", "EFBToTextureEnable"}},
{Config::System::GFX, "Hacks", "EFBToTextureEnable"}},
{{"Video_Hacks", "EFBScaledCopy"}, {Config::System::GFX, "Hacks", "EFBScaledCopy"}}, {{"Video_Hacks", "EFBScaledCopy"}, {Config::System::GFX, "Hacks", "EFBScaledCopy"}},
{{"Video_Hacks", "EFBEmulateFormatChanges"}, {{"Video_Hacks", "EFBEmulateFormatChanges"},
{Config::System::GFX, "Hacks", "EFBEmulateFormatChanges"}}, {Config::System::GFX, "Hacks", "EFBEmulateFormatChanges"}},
@ -174,16 +177,18 @@ MapINIToRealLocation(const std::string& section, const std::string& key)
{{"EmuState", "EmulationStateId"}, {Config::System::UI, "EmuState", "EmulationStateId"}}, {{"EmuState", "EmulationStateId"}, {Config::System::UI, "EmuState", "EmulationStateId"}},
{{"EmuState", "EmulationIssues"}, {Config::System::UI, "EmuState", "EmulationIssues"}}, {{"EmuState", "EmulationIssues"}, {Config::System::UI, "EmuState", "EmulationIssues"}},
{{"EmuState", "Title"}, {Config::System::UI, "EmuState", "Title"}}, {{"EmuState", "Title"}, {Config::System::UI, "EmuState", "Title"}},
}; };
auto it = ini_to_location.find(std::make_pair(section, key)); static ConfigLocation MapINIToRealLocation(const std::string& section, const std::string& key)
{
auto it = ini_to_location.find({section, key});
if (it == ini_to_location.end()) if (it == ini_to_location.end())
{ {
// Try again, but this time with an empty key // Try again, but this time with an empty key
// Certain sections like 'Speedhacks' has keys that are variable // Certain sections like 'Speedhacks' has keys that are variable
it = ini_to_location.find(std::make_pair(section, "")); it = ini_to_location.find({section, ""});
if (it != ini_to_location.end()) if (it != ini_to_location.end())
return std::make_tuple(std::get<0>(it->second), std::get<1>(it->second), key); return it->second;
// Attempt to load it as a configuration option // Attempt to load it as a configuration option
// It will be in the format of '<System>.<Section>' // It will be in the format of '<System>.<Section>'
@ -197,13 +202,34 @@ MapINIToRealLocation(const std::string& section, const std::string& key)
fail |= buffer.fail(); fail |= buffer.fail();
if (!fail) if (!fail)
return std::make_tuple(Config::GetSystemFromName(system_str), config_section, key); return {Config::GetSystemFromName(system_str), config_section, key};
WARN_LOG(COMMON, "Unknown game INI option in section %s: %s", section.c_str(), key.c_str()); WARN_LOG(COMMON, "Unknown game INI option in section %s: %s", section.c_str(), key.c_str());
return std::make_tuple(Config::System::Main, "", ""); return {Config::System::Main, "", ""};
} }
return ini_to_location[std::make_pair(section, key)]; return ini_to_location[{section, key}];
}
static std::pair<std::string, std::string> GetINILocationFromConfig(const ConfigLocation& location)
{
auto it = std::find_if(ini_to_location.begin(), ini_to_location.end(),
[&](const auto& entry) { return entry.second == location; });
if (it != ini_to_location.end())
return it->first;
// Try again, but this time with an empty key
// Certain sections like 'Speedhacks' have keys that are variable
it = std::find_if(ini_to_location.begin(), ini_to_location.end(), [&](const auto& entry) {
return std::tie(entry.second.system, entry.second.key) ==
std::tie(location.system, location.key);
});
if (it != ini_to_location.end())
return it->first;
WARN_LOG(COMMON, "Unknown option: %s.%s", location.section.c_str(), location.key.c_str());
return {"", ""};
} }
// INI Game layer configuration loader // INI Game layer configuration loader
@ -243,14 +269,13 @@ public:
if (chunk.size()) if (chunk.size())
{ {
std::tuple<Config::System, std::string, std::string> mapped_config = const auto mapped_config = MapINIToRealLocation(section_name, "");
MapINIToRealLocation(section_name, "");
if (std::get<1>(mapped_config).empty() && std::get<2>(mapped_config).empty()) if (mapped_config.section.empty() && mapped_config.key.empty())
continue; continue;
auto* config_section = config_layer->GetOrCreateSection(std::get<0>(mapped_config), auto* config_section =
std::get<1>(mapped_config)); config_layer->GetOrCreateSection(mapped_config.system, mapped_config.section);
config_section->SetLines(chunk); config_section->SetLines(chunk);
} }
} }
@ -260,16 +285,14 @@ public:
for (auto& value : section_map) for (auto& value : section_map)
{ {
std::tuple<Config::System, std::string, std::string> mapped_config = const auto mapped_config = MapINIToRealLocation(section_name, value.first);
MapINIToRealLocation(section_name, value.first);
if (std::get<1>(mapped_config).empty() && std::get<2>(mapped_config).empty()) if (mapped_config.section.empty() && mapped_config.key.empty())
continue; continue;
auto* config_section = config_layer->GetOrCreateSection(std::get<0>(mapped_config), auto* config_section =
std::get<1>(mapped_config)); config_layer->GetOrCreateSection(mapped_config.system, mapped_config.section);
config_section->Set(mapped_config.key, value.second);
config_section->Set(std::get<2>(mapped_config), value.second);
} }
} }
@ -330,12 +353,54 @@ public:
} }
} }
void Save(Config::Layer* config_layer) override {} void Save(Config::Layer* config_layer) override;
private: private:
const std::string m_id; const std::string m_id;
const u16 m_revision; const u16 m_revision;
}; };
void INIGameConfigLayerLoader::Save(Config::Layer* config_layer)
{
if (config_layer->GetLayer() != Config::LayerType::LocalGame)
return;
IniFile ini;
for (const std::string& file_name : GetGameIniFilenames(m_id, m_revision))
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + file_name, true);
for (const auto& system : config_layer->GetLayerMap())
{
for (const auto& section : system.second)
{
for (const auto& value : section.GetValues())
{
const auto ini_location =
GetINILocationFromConfig({system.first, section.GetName(), value.first});
if (ini_location.first.empty() && ini_location.second.empty())
continue;
IniFile::Section* ini_section = ini.GetOrCreateSection(ini_location.first);
ini_section->Set(ini_location.second, value.second);
}
}
}
// Try to save to the revision specific INI first, if it exists.
const std::string gameini_with_rev =
File::GetUserPath(D_GAMESETTINGS_IDX) + m_id + StringFromFormat("r%d", m_revision) + ".ini";
if (File::Exists(gameini_with_rev))
{
ini.Save(gameini_with_rev);
return;
}
// Otherwise, save to the game INI. We don't try any INI broader than that because it will
// likely cause issues with cheat codes and game patches.
const std::string gameini = File::GetUserPath(D_GAMESETTINGS_IDX) + m_id + ".ini";
ini.Save(gameini);
}
// Loader generation // Loader generation
std::unique_ptr<Config::ConfigLayerLoader> GenerateGlobalGameConfigLoader(const std::string& id, std::unique_ptr<Config::ConfigLayerLoader> GenerateGlobalGameConfigLoader(const std::string& id,
u16 revision) u16 revision)