From 9dbb6f9022df4f8bb11f6a06add53d9e9b3f10a4 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 27 Jan 2016 18:09:15 -0600 Subject: [PATCH] Game configuration loader --- .../Core/ConfigLoaders/GameConfigLoader.cpp | 343 ++++++++++++++++++ .../Core/ConfigLoaders/GameConfigLoader.h | 14 + 2 files changed, 357 insertions(+) create mode 100644 Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp create mode 100644 Source/Core/Core/ConfigLoaders/GameConfigLoader.h diff --git a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp new file mode 100644 index 0000000000..f9f7b2d3bb --- /dev/null +++ b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp @@ -0,0 +1,343 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Common/CommonPaths.h" +#include "Common/Config/Config.h" +#include "Common/FileUtil.h" +#include "Common/IniFile.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/StringUtil.h" + +#include "Core/ConfigLoaders/GameConfigLoader.h" + +// Returns all possible filenames in ascending order of priority +static std::vector GetGameIniFilenames(const std::string& id, u16 revision) +{ + std::vector filenames; + + // INIs that match all regions + if (id.size() >= 4) + filenames.push_back(id.substr(0, 3) + ".ini"); + + // Regular INIs + filenames.push_back(id + ".ini"); + + // INIs with specific revisions + filenames.push_back(id + StringFromFormat("r%d", revision) + ".ini"); + + return filenames; +} + +static std::tuple +MapINIToRealLocation(const std::string& section, const std::string& key) +{ + static std::map, + std::tuple> + ini_to_location = { + // Core + {{"Core", "CPUThread"}, {Config::System::Main, "Core", "CPUThread"}}, + {{"Core", "SkipIdle"}, {Config::System::Main, "Core", "SkipIdle"}}, + {{"Core", "SyncOnSkipIdle"}, {Config::System::Main, "Core", "SyncOnSkipIdle"}}, + {{"Core", "FPRF"}, {Config::System::Main, "Core", "FPRF"}}, + {{"Core", "AccurateNaNs"}, {Config::System::Main, "Core", "AccurateNaNs"}}, + {{"Core", "MMU"}, {Config::System::Main, "Core", "MMU"}}, + {{"Core", "DCBZ"}, {Config::System::Main, "Core", "DCBZ"}}, + {{"Core", "SyncGPU"}, {Config::System::Main, "Core", "SyncGPU"}}, + {{"Core", "FastDiscSpeed"}, {Config::System::Main, "Core", "FastDiscSpeed"}}, + {{"Core", "DSPHLE"}, {Config::System::Main, "Core", "DSPHLE"}}, + {{"Core", "GFXBackend"}, {Config::System::Main, "Core", "GFXBackend"}}, + {{"Core", "CPUCore"}, {Config::System::Main, "Core", "CPUCore"}}, + {{"Core", "HLE_BS2"}, {Config::System::Main, "Core", "HLE_BS2"}}, + {{"Core", "EmulationSpeed"}, {Config::System::Main, "Core", "EmulationSpeed"}}, + {{"Core", "GPUDeterminismMode"}, {Config::System::Main, "Core", "GPUDeterminismMode"}}, + {{"Core", "ProgressiveScan"}, {Config::System::Main, "Display", "ProgressiveScan"}}, + {{"Core", "PAL60"}, {Config::System::Main, "Display", "PAL60"}}, + + // Action Replay cheats + {{"ActionReplay_Enabled", ""}, {Config::System::Main, "ActionReplay_Enabled", ""}}, + {{"ActionReplay", ""}, {Config::System::Main, "ActionReplay", ""}}, + + // Gecko cheats + {{"Gecko_Enabled", ""}, {Config::System::Main, "Gecko_Enabled", ""}}, + {{"Gecko", ""}, {Config::System::Main, "Gecko", ""}}, + + // OnLoad cheats + {{"OnLoad", ""}, {Config::System::Main, "OnLoad", ""}}, + + // OnFrame cheats + {{"OnFrame_Enabled", ""}, {Config::System::Main, "OnFrame_Enabled", ""}}, + {{"OnFrame", ""}, {Config::System::Main, "OnFrame", ""}}, + + // Speedhacks + {{"Speedhacks", ""}, {Config::System::Main, "Speedhacks", ""}}, + + // Debugger values + {{"Watches", ""}, {Config::System::Debugger, "Watches", ""}}, + {{"BreakPoints", ""}, {Config::System::Debugger, "BreakPoints", ""}}, + {{"MemoryChecks", ""}, {Config::System::Debugger, "MemoryChecks", ""}}, + + // DSP + {{"DSP", "Volume"}, {Config::System::Main, "DSP", "Volume"}}, + {{"DSP", "EnableJIT"}, {Config::System::Main, "DSP", "EnableJIT"}}, + {{"DSP", "Backend"}, {Config::System::Main, "DSP", "Backend"}}, + + // Controls + {{"Controls", "PadType0"}, {Config::System::GCPad, "Core", "SIDevice0"}}, + {{"Controls", "PadType1"}, {Config::System::GCPad, "Core", "SIDevice1"}}, + {{"Controls", "PadType2"}, {Config::System::GCPad, "Core", "SIDevice2"}}, + {{"Controls", "PadType3"}, {Config::System::GCPad, "Core", "SIDevice3"}}, + {{"Controls", "WiimoteSource0"}, {Config::System::WiiPad, "Wiimote1", "Source"}}, + {{"Controls", "WiimoteSource1"}, {Config::System::WiiPad, "Wiimote2", "Source"}}, + {{"Controls", "WiimoteSource2"}, {Config::System::WiiPad, "Wiimote3", "Source"}}, + {{"Controls", "WiimoteSource3"}, {Config::System::WiiPad, "Wiimote4", "Source"}}, + {{"Controls", "WiimoteSourceBB"}, {Config::System::WiiPad, "BalanceBoard", "Source"}}, + + // Controller profiles + {{"Controls", "PadProfile1"}, {Config::System::GCPad, "Controls", "PadProfile1"}}, + {{"Controls", "PadProfile2"}, {Config::System::GCPad, "Controls", "PadProfile2"}}, + {{"Controls", "PadProfile3"}, {Config::System::GCPad, "Controls", "PadProfile3"}}, + {{"Controls", "PadProfile4"}, {Config::System::GCPad, "Controls", "PadProfile4"}}, + {{"Controls", "WiimoteProfile1"}, + {Config::System::WiiPad, "Controls", "WiimoteProfile1"}}, + {{"Controls", "WiimoteProfile2"}, + {Config::System::WiiPad, "Controls", "WiimoteProfile2"}}, + {{"Controls", "WiimoteProfile3"}, + {Config::System::WiiPad, "Controls", "WiimoteProfile3"}}, + {{"Controls", "WiimoteProfile4"}, + {Config::System::WiiPad, "Controls", "WiimoteProfile4"}}, + + // Video + {{"Video_Hardware", "VSync"}, {Config::System::GFX, "Hardware", "VSync"}}, + {{"Video_Settings", "wideScreenHack"}, + {Config::System::GFX, "Settings", "wideScreenHack"}}, + {{"Video_Settings", "AspectRatio"}, {Config::System::GFX, "Settings", "AspectRatio"}}, + {{"Video_Settings", "Crop"}, {Config::System::GFX, "Settings", "Crop"}}, + {{"Video_Settings", "UseXFB"}, {Config::System::GFX, "Settings", "UseXFB"}}, + {{"Video_Settings", "UseRealXFB"}, {Config::System::GFX, "Settings", "UseRealXFB"}}, + {{"Video_Settings", "SafeTextureCacheColorSamples"}, + {Config::System::GFX, "Settings", "SafeTextureCacheColorSamples"}}, + {{"Video_Settings", "HiresTextures"}, {Config::System::GFX, "Settings", "HiresTextures"}}, + {{"Video_Settings", "ConvertHiresTextures"}, + {Config::System::GFX, "Settings", "ConvertHiresTextures"}}, + {{"Video_Settings", "CacheHiresTextures"}, + {Config::System::GFX, "Settings", "CacheHiresTextures"}}, + {{"Video_Settings", "EnablePixelLighting"}, + {Config::System::GFX, "Settings", "EnablePixelLighting"}}, + {{"Video_Settings", "ForcedSlowDepth"}, + {Config::System::GFX, "Settings", "ForcedSlowDepth"}}, + {{"Video_Settings", "MSAA"}, {Config::System::GFX, "Settings", "MSAA"}}, + {{"Video_Settings", "SSAA"}, {Config::System::GFX, "Settings", "SSAA"}}, + {{"Video_Settings", "EFBScale"}, {Config::System::GFX, "Settings", "EFBScale"}}, + {{"Video_Settings", "DisableFog"}, {Config::System::GFX, "Settings", "DisableFog"}}, + + {{"Video_Enhancements", "ForceFiltering"}, + {Config::System::GFX, "Enhancements", "ForceFiltering"}}, + {{"Video_Enhancements", "MaxAnisotropy"}, + {Config::System::GFX, "Enhancements", "MaxAnisotropy"}}, + {{"Video_Enhancements", "PostProcessingShader"}, + {Config::System::GFX, "Enhancements", "PostProcessingShader"}}, + + {{"Video_Stereoscopy", "StereoMode"}, {Config::System::GFX, "Stereoscopy", "StereoMode"}}, + {{"Video_Stereoscopy", "StereoDepth"}, + {Config::System::GFX, "Stereoscopy", "StereoDepth"}}, + {{"Video_Stereoscopy", "StereoSwapEyes"}, + {Config::System::GFX, "Stereoscopy", "StereoSwapEyes"}}, + + {{"Video_Hacks", "EFBAccessEnable"}, {Config::System::GFX, "Hacks", "EFBAccessEnable"}}, + {{"Video_Hacks", "BBoxEnable"}, {Config::System::GFX, "Hacks", "BBoxEnable"}}, + {{"Video_Hacks", "ForceProgressive"}, {Config::System::GFX, "Hacks", "ForceProgressive"}}, + {{"Video_Hacks", "EFBToTextureEnable"}, + {Config::System::GFX, "Hacks", "EFBToTextureEnable"}}, + {{"Video_Hacks", "EFBScaledCopy"}, {Config::System::GFX, "Hacks", "EFBScaledCopy"}}, + {{"Video_Hacks", "EFBEmulateFormatChanges"}, + {Config::System::GFX, "Hacks", "EFBEmulateFormatChanges"}}, + + // GameINI specific video settings + {{"Video", "ProjectionHack"}, {Config::System::GFX, "Video", "ProjectionHack"}}, + {{"Video", "PH_SZNear"}, {Config::System::GFX, "Video", "PH_SZNear"}}, + {{"Video", "PH_SZFar"}, {Config::System::GFX, "Video", "PH_SZFar"}}, + {{"Video", "PH_ZNear"}, {Config::System::GFX, "Video", "PH_ZNear"}}, + {{"Video", "PH_ZFar"}, {Config::System::GFX, "Video", "PH_ZFar"}}, + {{"Video", "PH_ExtraParam"}, {Config::System::GFX, "Video", "PH_ExtraParam"}}, + {{"Video", "PerfQueriesEnable"}, {Config::System::GFX, "Video", "PerfQueriesEnable"}}, + + {{"Video_Stereoscopy", "StereoConvergence"}, + {Config::System::GFX, "Stereoscopy", "StereoConvergence"}}, + {{"Video_Stereoscopy", "StereoEFBMonoDepth"}, + {Config::System::GFX, "Stereoscopy", "StereoEFBMonoDepth"}}, + {{"Video_Stereoscopy", "StereoDepthPercentage"}, + {Config::System::GFX, "Stereoscopy", "StereoDepthPercentage"}}, + + // UI + {{"EmuState", "EmulationStateId"}, {Config::System::UI, "EmuState", "EmulationStateId"}}, + {{"EmuState", "EmulationIssues"}, {Config::System::UI, "EmuState", "EmulationIssues"}}, + {{"EmuState", "Title"}, {Config::System::UI, "EmuState", "Title"}}, + }; + + auto it = ini_to_location.find(std::make_pair(section, key)); + if (it == ini_to_location.end()) + { + // Try again, but this time with an empty key + // Certain sections like 'Speedhacks' has keys that are variable + it = ini_to_location.find(std::make_pair(section, "")); + if (it != ini_to_location.end()) + return std::make_tuple(std::get<0>(it->second), std::get<1>(it->second), key); + + // Attempt to load it as a configuration option + // It will be in the format of '.
' + std::istringstream buffer(section); + std::string system_str, config_section; + + bool fail = false; + std::getline(buffer, system_str, '.'); + fail |= buffer.fail(); + std::getline(buffer, config_section, '.'); + fail |= buffer.fail(); + + if (!fail) + return std::make_tuple(Config::GetSystemFromName(system_str), config_section, key); + + ERROR_LOG(COMMON, "Couldn't load game INI option %s-%s properly!\n", section.c_str(), + key.c_str()); + return std::make_tuple(Config::System::Main, "FAIL!", key); + } + + return ini_to_location[std::make_pair(section, key)]; +} + +// INI Game layer configuration loader +class INIGameConfigLayerLoader : public Config::ConfigLayerLoader +{ +public: + INIGameConfigLayerLoader(const std::string& id, u16 revision, bool global) + : ConfigLayerLoader(global ? Config::LayerType::GlobalGame : Config::LayerType::LocalGame), + m_id(id), m_revision(revision) + { + } + + void Load(Config::Layer* config_layer) override + { + IniFile ini; + if (config_layer->GetLayer() == Config::LayerType::GlobalGame) + { + for (const std::string& filename : GetGameIniFilenames(m_id, m_revision)) + ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); + } + else + { + for (const std::string& filename : GetGameIniFilenames(m_id, m_revision)) + ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); + } + + const std::list& system_sections = ini.GetSections(); + + for (auto section : system_sections) + { + const std::string section_name = section.GetName(); + if (section.HasLines()) + { + // Trash INI File chunks + std::vector chunk; + section.GetLines(&chunk, true); + + if (chunk.size()) + { + std::tuple mapped_config = + MapINIToRealLocation(section_name, ""); + auto* config_section = config_layer->GetOrCreateSection(std::get<0>(mapped_config), + std::get<1>(mapped_config)); + config_section->SetLines(chunk); + } + } + + // Regular key,value pairs + const IniFile::Section::SectionMap& section_map = section.GetValues(); + + for (auto& value : section_map) + { + std::tuple mapped_config = + MapINIToRealLocation(section_name, value.first); + auto* config_section = config_layer->GetOrCreateSection(std::get<0>(mapped_config), + std::get<1>(mapped_config)); + + config_section->Set(std::get<2>(mapped_config), value.second); + } + } + + // Game INIs can have controller profiles embedded in to them + std::string num[] = {"1", "2", "3", "4"}; + + if (m_id != "00000000") + { + std::tuple profile_info[] = { + std::make_tuple("Pad", "GCPad", Config::System::GCPad), + std::make_tuple("Wiimote", "Wiimote", Config::System::WiiPad), + }; + + for (auto& use_data : profile_info) + { + std::string type = std::get<0>(use_data); + std::string path = "Profiles/" + std::get<1>(use_data) + "/"; + + Config::Section* control_section = + config_layer->GetOrCreateSection(std::get<2>(use_data), "Controls"); + + for (int i = 0; i < 4; i++) + { + bool use_profile = false; + std::string profile; + if (control_section->Exists(type + "Profile" + num[i])) + { + if (control_section->Get(type + "Profile" + num[i], &profile)) + { + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + path + profile + ".ini")) + { + use_profile = true; + } + else + { + // TODO: PanicAlert shouldn't be used for this. + PanicAlertT("Selected controller profile does not exist"); + } + } + } + + if (use_profile) + { + IniFile profile_ini; + profile_ini.Load(File::GetUserPath(D_CONFIG_IDX) + path + profile + ".ini"); + + const IniFile::Section* ini_section = profile_ini.GetOrCreateSection("Profile"); + const IniFile::Section::SectionMap& section_map = ini_section->GetValues(); + for (auto& value : section_map) + { + Config::Section* section = config_layer->GetOrCreateSection( + std::get<2>(use_data), std::get<1>(use_data) + num[i]); + section->Set(value.first, value.second); + } + } + } + } + } + } + + void Save(Config::Layer* config_layer) override {} +private: + const std::string m_id; + const u16 m_revision; +}; + +// Loader generation +std::unique_ptr GenerateGlobalGameConfigLoader(const std::string& id, + u16 revision) +{ + return std::make_unique(id, revision, true); +} + +std::unique_ptr GenerateLocalGameConfigLoader(const std::string& id, + u16 revision) +{ + return std::make_unique(id, revision, false); +} diff --git a/Source/Core/Core/ConfigLoaders/GameConfigLoader.h b/Source/Core/Core/ConfigLoaders/GameConfigLoader.h new file mode 100644 index 0000000000..55c807cecb --- /dev/null +++ b/Source/Core/Core/ConfigLoaders/GameConfigLoader.h @@ -0,0 +1,14 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "Common/Config/Config.h" + +std::unique_ptr GenerateGlobalGameConfigLoader(const std::string& id, + u16 revision); +std::unique_ptr GenerateLocalGameConfigLoader(const std::string& id, + u16 revision);