Merge pull request #4991 from leoetlino/config-loaders

New config loaders
This commit is contained in:
Anthony 2017-03-09 16:56:14 +00:00 committed by GitHub
commit dc42f7fb28
16 changed files with 902 additions and 29 deletions

View File

@ -256,6 +256,37 @@ bool IniFile::Section::Delete(const std::string& key)
return true;
}
void IniFile::Section::SetLines(const std::vector<std::string>& lines)
{
m_lines = lines;
}
bool IniFile::Section::GetLines(std::vector<std::string>* lines, const bool remove_comments) const
{
for (std::string line : m_lines)
{
line = StripSpaces(line);
if (remove_comments)
{
size_t commentPos = line.find('#');
if (commentPos == 0)
{
continue;
}
if (commentPos != std::string::npos)
{
line = StripSpaces(line.substr(0, commentPos));
}
}
lines->push_back(line);
}
return true;
}
// IniFile
const IniFile::Section* IniFile::GetSection(const std::string& sectionName) const
@ -312,7 +343,7 @@ bool IniFile::Exists(const std::string& sectionName, const std::string& key) con
void IniFile::SetLines(const std::string& sectionName, const std::vector<std::string>& lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines = lines;
section->SetLines(lines);
}
bool IniFile::DeleteKey(const std::string& sectionName, const std::string& key)
@ -345,28 +376,7 @@ bool IniFile::GetLines(const std::string& sectionName, std::vector<std::string>*
if (!section)
return false;
for (std::string line : section->lines)
{
line = StripSpaces(line);
if (remove_comments)
{
size_t commentPos = line.find('#');
if (commentPos == 0)
{
continue;
}
if (commentPos != std::string::npos)
{
line = StripSpaces(line.substr(0, commentPos));
}
}
lines->push_back(line);
}
return true;
return section->GetLines(lines, remove_comments);
}
void IniFile::SortSections()
@ -439,7 +449,7 @@ bool IniFile::Load(const std::string& filename, bool keep_current_data)
// INI is a hack anyway.
if ((key == "" && value == "") ||
(line.size() >= 1 && (line[0] == '$' || line[0] == '+' || line[0] == '*')))
current_section->lines.push_back(line);
current_section->m_lines.push_back(line);
else
current_section->Set(key, value);
}
@ -464,12 +474,12 @@ bool IniFile::Save(const std::string& filename)
for (const Section& section : sections)
{
if (section.keys_order.size() != 0 || section.lines.size() != 0)
if (section.keys_order.size() != 0 || section.m_lines.size() != 0)
out << "[" << section.name << "]" << std::endl;
if (section.keys_order.size() == 0)
{
for (const std::string& s : section.lines)
for (const std::string& s : section.m_lines)
out << s << std::endl;
}
else

View File

@ -66,18 +66,22 @@ public:
bool Get(const std::string& key, double* value, double defaultValue = 0.0) const;
bool Get(const std::string& key, std::vector<std::string>* values) const;
void SetLines(const std::vector<std::string>& lines);
bool GetLines(std::vector<std::string>* lines, const bool remove_comments = true) const;
bool operator<(const Section& other) const { return name < other.name; }
using SectionMap = std::map<std::string, std::string, CaseInsensitiveStringCompare>;
const std::string& GetName() const { return name; }
const SectionMap& GetValues() const { return values; }
bool HasLines() const { return !m_lines.empty(); }
protected:
std::string name;
std::vector<std::string> keys_order;
SectionMap values;
std::vector<std::string> lines;
std::vector<std::string> m_lines;
};
/**

View File

@ -15,6 +15,7 @@ enum LOG_TYPE
COMMANDPROCESSOR,
COMMON,
CONSOLE,
CORE,
DISCIO,
DSPHLE,
DSPLLE,

View File

@ -49,6 +49,7 @@ LogManager::LogManager()
m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc");
m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console");
m_Log[LogTypes::CORE] = new LogContainer("CORE", "Core");
m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO");
m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE");
m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE");

View File

@ -24,6 +24,10 @@ set(SRCS
Boot/Boot_ELF.cpp
Boot/Boot_WiiWAD.cpp
Boot/ElfReader.cpp
ConfigLoaders/BaseConfigLoader.cpp
ConfigLoaders/GameConfigLoader.cpp
ConfigLoaders/MovieConfigLoader.cpp
ConfigLoaders/NetPlayConfigLoader.cpp
Debugger/Debugger_SymbolMap.cpp
Debugger/Dump.cpp
Debugger/PPCDebugInterface.cpp

View File

@ -0,0 +1,95 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstring>
#include <list>
#include <map>
#include <string>
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/Logging/Log.h"
#include "Core/ConfigLoaders/BaseConfigLoader.h"
namespace ConfigLoaders
{
const std::map<Config::System, int> system_to_ini = {
{Config::System::Main, F_DOLPHINCONFIG_IDX},
{Config::System::GCPad, F_GCPADCONFIG_IDX},
{Config::System::WiiPad, F_WIIPADCONFIG_IDX},
{Config::System::GCKeyboard, F_GCKEYBOARDCONFIG_IDX},
{Config::System::GFX, F_GFXCONFIG_IDX},
{Config::System::Logger, F_LOGGERCONFIG_IDX},
{Config::System::Debugger, F_DEBUGGERCONFIG_IDX},
{Config::System::UI, F_UICONFIG_IDX},
};
// INI layer configuration loader
class INIBaseConfigLayerLoader final : public Config::ConfigLayerLoader
{
public:
INIBaseConfigLayerLoader() : ConfigLayerLoader(Config::LayerType::Base) {}
void Load(Config::Layer* config_layer) override
{
for (const auto& system : system_to_ini)
{
IniFile ini;
ini.Load(File::GetUserPath(system.second));
const std::list<IniFile::Section>& system_sections = ini.GetSections();
for (const auto& section : system_sections)
{
const std::string section_name = section.GetName();
Config::Section* config_section =
config_layer->GetOrCreateSection(system.first, section_name);
const IniFile::Section::SectionMap& section_map = section.GetValues();
for (const auto& value : section_map)
config_section->Set(value.first, value.second);
}
}
}
void Save(Config::Layer* config_layer) override
{
const Config::LayerMap& sections = config_layer->GetLayerMap();
for (const auto& system : sections)
{
auto mapping = system_to_ini.find(system.first);
if (mapping == system_to_ini.end())
{
ERROR_LOG(COMMON, "Config can't map system '%s' to an INI file!",
Config::GetSystemName(system.first).c_str());
continue;
}
IniFile ini;
ini.Load(File::GetUserPath(mapping->second));
for (const auto& section : system.second)
{
const std::string section_name = section.GetName();
const Config::SectionValueMap& section_values = section.GetValues();
IniFile::Section* ini_section = ini.GetOrCreateSection(section_name);
for (const auto& value : section_values)
ini_section->Set(value.first, value.second);
}
ini.Save(File::GetUserPath(mapping->second));
}
}
};
// Loader generation
std::unique_ptr<Config::ConfigLayerLoader> GenerateBaseConfigLoader()
{
return std::make_unique<INIBaseConfigLayerLoader>();
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
namespace Config
{
class ConfigLayerLoader;
}
namespace ConfigLoaders
{
std::unique_ptr<Config::ConfigLayerLoader> GenerateBaseConfigLoader();
}

View File

@ -0,0 +1,434 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#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"
namespace ConfigLoaders
{
// Returns all possible filenames in ascending order of priority
static std::vector<std::string> GetGameIniFilenames(const std::string& id, u16 revision)
{
std::vector<std::string> 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;
}
struct ConfigLocation
{
Config::System system;
std::string section;
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", "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"}},
};
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())
{
// Try again, but this time with an empty key
// Certain sections like 'Speedhacks' has keys that are variable
it = ini_to_location.find({section, ""});
if (it != ini_to_location.end())
return it->second;
// Attempt to load it as a configuration option
// It will be in the format of '<System>.<Section>'
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 {Config::GetSystemFromName(system_str), config_section, key};
WARN_LOG(CORE, "Unknown game INI option in section %s: %s", section.c_str(), key.c_str());
return {Config::System::Main, "", ""};
}
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(),
[&location](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(), [&location](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(CORE, "Unknown option: %s.%s", location.section.c_str(), location.key.c_str());
return {"", ""};
}
// INI Game layer configuration loader
class INIGameConfigLayerLoader final : 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<IniFile::Section>& system_sections = ini.GetSections();
for (const auto& section : system_sections)
{
LoadFromSystemSection(config_layer, section);
}
LoadControllerConfig(config_layer);
}
void Save(Config::Layer* config_layer) override;
private:
void LoadControllerConfig(Config::Layer* config_layer) const
{
// Game INIs can have controller profiles embedded in to them
static const std::array<char, 4> nums = {{'1', '2', '3', '4'}};
if (m_id == "00000000")
return;
const std::array<std::tuple<std::string, std::string, Config::System>, 2> profile_info = {{
std::make_tuple("Pad", "GCPad", Config::System::GCPad),
std::make_tuple("Wiimote", "Wiimote", Config::System::WiiPad),
}};
for (const 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 (const char num : nums)
{
bool use_profile = false;
std::string profile;
if (control_section->Exists(type + "Profile" + num))
{
if (control_section->Get(type + "Profile" + num, &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 (const auto& value : section_map)
{
Config::Section* section = config_layer->GetOrCreateSection(
std::get<2>(use_data), std::get<1>(use_data) + num);
section->Set(value.first, value.second);
}
}
}
}
}
void LoadFromSystemSection(Config::Layer* config_layer, const IniFile::Section& section) const
{
const std::string section_name = section.GetName();
if (section.HasLines())
{
// Trash INI File chunks
std::vector<std::string> chunk;
section.GetLines(&chunk, true);
if (chunk.size())
{
const auto mapped_config = MapINIToRealLocation(section_name, "");
if (mapped_config.section.empty() && mapped_config.key.empty())
return;
auto* config_section =
config_layer->GetOrCreateSection(mapped_config.system, mapped_config.section);
config_section->SetLines(chunk);
}
}
// Regular key,value pairs
const IniFile::Section::SectionMap& section_map = section.GetValues();
for (const auto& value : section_map)
{
const auto mapped_config = MapINIToRealLocation(section_name, value.first);
if (mapped_config.section.empty() && mapped_config.key.empty())
continue;
auto* config_section =
config_layer->GetOrCreateSection(mapped_config.system, mapped_config.section);
config_section->Set(mapped_config.key, value.second);
}
}
const std::string m_id;
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
std::unique_ptr<Config::ConfigLayerLoader> GenerateGlobalGameConfigLoader(const std::string& id,
u16 revision)
{
return std::make_unique<INIGameConfigLayerLoader>(id, revision, true);
}
std::unique_ptr<Config::ConfigLayerLoader> GenerateLocalGameConfigLoader(const std::string& id,
u16 revision)
{
return std::make_unique<INIGameConfigLayerLoader>(id, revision, false);
}
}

View File

@ -0,0 +1,23 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <cstring>
#include <memory>
#include "Common/CommonTypes.h"
namespace Config
{
class ConfigLayerLoader;
}
namespace ConfigLoaders
{
std::unique_ptr<Config::ConfigLayerLoader> GenerateGlobalGameConfigLoader(const std::string& id,
u16 revision);
std::unique_ptr<Config::ConfigLayerLoader> GenerateLocalGameConfigLoader(const std::string& id,
u16 revision);
}

View File

@ -0,0 +1,86 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstring>
#include <string>
#include "Common/CommonFuncs.h"
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigLoaders/MovieConfigLoader.h"
#include "Core/Movie.h"
namespace ConfigLoaders
{
// TODO: Future project, let this support all the configuration options.
// This will require a large break to the DTM format
void MovieConfigLayerLoader::Load(Config::Layer* config_layer)
{
Config::Section* core = config_layer->GetOrCreateSection(Config::System::Main, "Core");
Config::Section* display = config_layer->GetOrCreateSection(Config::System::Main, "Display");
Config::Section* video_settings = Config::GetOrCreateSection(Config::System::GFX, "Settings");
Config::Section* video_hacks = Config::GetOrCreateSection(Config::System::GFX, "Hacks");
core->Set("SkipIdle", m_header->bSkipIdle);
core->Set("CPUThread", m_header->bDualCore);
core->Set("DSPHLE", m_header->bDSPHLE);
core->Set("FastDiscSpeed", m_header->bFastDiscSpeed);
core->Set("CPUCore", m_header->CPUCore);
core->Set("SyncGPU", m_header->bSyncGPU);
core->Set("GFXBackend", std::string(reinterpret_cast<char*>(m_header->videoBackend)));
display->Set("ProgressiveScan", m_header->bProgressive);
display->Set("PAL60", m_header->bPAL60);
video_settings->Set("UseXFB", m_header->bUseXFB);
video_settings->Set("UseRealXFB", m_header->bUseRealXFB);
video_hacks->Set("EFBAccessEnable", m_header->bEFBAccessEnable);
video_hacks->Set("EFBToTextureEnable", m_header->bSkipEFBCopyToRam);
video_hacks->Set("EFBEmulateFormatChanges", m_header->bEFBEmulateFormatChanges);
}
void MovieConfigLayerLoader::Save(Config::Layer* config_layer)
{
Config::Section* core = config_layer->GetOrCreateSection(Config::System::Main, "Core");
Config::Section* display = config_layer->GetOrCreateSection(Config::System::Main, "Display");
Config::Section* video_settings = Config::GetOrCreateSection(Config::System::GFX, "Settings");
Config::Section* video_hacks = Config::GetOrCreateSection(Config::System::GFX, "Hacks");
std::string video_backend;
u32 cpu_core;
core->Get("SkipIdle", &m_header->bSkipIdle);
core->Get("CPUThread", &m_header->bDualCore);
core->Get("DSPHLE", &m_header->bDSPHLE);
core->Get("FastDiscSpeed", &m_header->bFastDiscSpeed);
core->Get("CPUCore", &cpu_core);
core->Get("SyncGPU", &m_header->bSyncGPU);
core->Get("GFXBackend", &video_backend);
display->Get("ProgressiveScan", &m_header->bProgressive);
display->Get("PAL60", &m_header->bPAL60);
video_settings->Get("UseXFB", &m_header->bUseXFB);
video_settings->Get("UseRealXFB", &m_header->bUseRealXFB);
video_hacks->Get("EFBAccessEnable", &m_header->bEFBAccessEnable);
video_hacks->Get("EFBToTextureEnable", &m_header->bSkipEFBCopyToRam);
video_hacks->Get("EFBEmulateFormatChanges", &m_header->bEFBEmulateFormatChanges);
// This never used the regular config
m_header->bEFBCopyEnable = true;
m_header->bEFBCopyCacheEnable = false;
m_header->CPUCore = cpu_core;
strncpy(reinterpret_cast<char*>(m_header->videoBackend), video_backend.c_str(),
ArraySize(m_header->videoBackend));
}
// Loader generation
std::unique_ptr<Config::ConfigLayerLoader> GenerateMovieConfigLoader(Movie::DTMHeader* header)
{
return std::make_unique<MovieConfigLayerLoader>(header);
}
}

View File

@ -0,0 +1,35 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include "Common/Config/Config.h"
namespace Movie
{
struct DTMHeader;
}
namespace ConfigLoaders
{
class MovieConfigLayerLoader final : public Config::ConfigLayerLoader
{
public:
explicit MovieConfigLayerLoader(Movie::DTMHeader* header)
: ConfigLayerLoader(Config::LayerType::Movie), m_header(header)
{
}
void Load(Config::Layer* config_layer) override;
void Save(Config::Layer* config_layer) override;
void ChangeDTMHeader(Movie::DTMHeader* header) { m_header = header; }
private:
Movie::DTMHeader* m_header;
};
std::unique_ptr<Config::ConfigLayerLoader> GenerateMovieConfigLoader(Movie::DTMHeader* header);
}

View File

@ -0,0 +1,61 @@
// 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 "Core/ConfigLoaders/NetPlayConfigLoader.h"
#include "Core/NetPlayProto.h"
namespace ConfigLoaders
{
class NetPlayConfigLayerLoader final : public Config::ConfigLayerLoader
{
public:
explicit NetPlayConfigLayerLoader(const NetSettings& settings)
: ConfigLayerLoader(Config::LayerType::Netplay), m_settings(settings)
{
}
void Load(Config::Layer* config_layer) override
{
Config::Section* core = config_layer->GetOrCreateSection(Config::System::Main, "Core");
Config::Section* dsp = config_layer->GetOrCreateSection(Config::System::Main, "DSP");
Config::Section* display = config_layer->GetOrCreateSection(Config::System::Main, "Display");
core->Set("CPUThread", m_settings.m_CPUthread);
core->Set("CPUCore", m_settings.m_CPUcore);
core->Set("SelectedLanguage", m_settings.m_SelectedLanguage);
core->Set("OverrideGCLang", m_settings.m_OverrideGCLanguage);
core->Set("DSPHLE", m_settings.m_DSPHLE);
core->Set("OverclockEnable", m_settings.m_OCEnable);
core->Set("Overclock", m_settings.m_OCFactor);
core->Set("SlotA", m_settings.m_EXIDevice[0]);
core->Set("SlotB", m_settings.m_EXIDevice[1]);
core->Set("EnableSaving", m_settings.m_WriteToMemcard);
dsp->Set("EnableJIT", m_settings.m_DSPEnableJIT);
display->Set("ProgressiveScan", m_settings.m_ProgressiveScan);
display->Set("PAL60", m_settings.m_PAL60);
}
void Save(Config::Layer* config_layer) override
{
// Do Nothing
}
private:
const NetSettings m_settings;
};
// Loader generation
std::unique_ptr<Config::ConfigLayerLoader> GenerateNetPlayConfigLoader(const NetSettings& settings)
{
return std::make_unique<NetPlayConfigLayerLoader>(settings);
}
}

View File

@ -0,0 +1,19 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
struct NetSettings;
namespace Config
{
class ConfigLayerLoader;
}
namespace ConfigLoaders
{
std::unique_ptr<Config::ConfigLayerLoader> GenerateNetPlayConfigLoader(const NetSettings& settings);
}

View File

@ -220,6 +220,10 @@
<ClCompile Include="Movie.cpp" />
<ClCompile Include="NetPlayClient.cpp" />
<ClCompile Include="NetPlayServer.cpp" />
<ClCompile Include="ConfigLoaders\BaseConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\GameConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\MovieConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\NetPlayConfigLoader.cpp" />
<ClCompile Include="PatchEngine.cpp" />
<ClCompile Include="PowerPC\BreakPoints.cpp" />
<ClCompile Include="PowerPC\CachedInterpreter\CachedInterpreter.cpp" />
@ -461,6 +465,10 @@
<ClInclude Include="NetPlayClient.h" />
<ClInclude Include="NetPlayProto.h" />
<ClInclude Include="NetPlayServer.h" />
<ClInclude Include="ConfigLoaders\BaseConfigLoader.h" />
<ClInclude Include="ConfigLoaders\GameConfigLoader.h" />
<ClInclude Include="ConfigLoaders\MovieConfigLoader.h" />
<ClInclude Include="ConfigLoaders\NetPlayConfigLoader.h" />
<ClInclude Include="PatchEngine.h" />
<ClInclude Include="PowerPC\BreakPoints.h" />
<ClInclude Include="PowerPC\CPUCoreBase.h" />

View File

@ -170,6 +170,10 @@
<ClCompile Include="NetPlayClient.cpp" />
<ClCompile Include="NetPlayServer.cpp" />
<ClCompile Include="PatchEngine.cpp" />
<ClCompile Include="ConfigLoaders\BaseConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\GameConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\MovieConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\NetPlayConfigLoader.cpp" />
<ClCompile Include="State.cpp" />
<ClCompile Include="WiiRoot.cpp" />
<ClCompile Include="ActionReplay.cpp">
@ -860,6 +864,10 @@
<ClInclude Include="NetPlayProto.h" />
<ClInclude Include="NetPlayServer.h" />
<ClInclude Include="PatchEngine.h" />
<ClInclude Include="ConfigLoaders\BaseConfigLoader.h" />
<ClInclude Include="ConfigLoaders\GameConfigLoader.h" />
<ClInclude Include="ConfigLoaders\MovieConfigLoader.h" />
<ClInclude Include="ConfigLoaders\NetPlayConfigLoader.h" />
<ClInclude Include="State.h" />
<ClInclude Include="WiiRoot.h" />
<ClInclude Include="ActionReplay.h">

View File

@ -2,13 +2,65 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <list>
#include <sstream>
#include <string>
#include <tuple>
#include <OptionParser.h>
#include "Common/Common.h"
#include "Common/Config/Config.h"
#include "UICommon/CommandLineParse.h"
namespace CommandLineParse
{
class CommandLineConfigLayerLoader final : public Config::ConfigLayerLoader
{
public:
CommandLineConfigLayerLoader(const std::list<std::string>& args, const std::string& video_backend,
const std::string& audio_backend)
: ConfigLayerLoader(Config::LayerType::CommandLine)
{
if (video_backend.size())
m_values.emplace_back(std::make_tuple("Dolphin", "Core", "GFXBackend", video_backend));
if (audio_backend.size())
m_values.emplace_back(
std::make_tuple("Dolphin", "Core", "DSPHLE", audio_backend == "HLE" ? "True" : "False"));
// Arguments are in the format of <System>.<Section>.<Key>=Value
for (const auto& arg : args)
{
std::istringstream buffer(arg);
std::string system, section, key, value;
std::getline(buffer, system, '.');
std::getline(buffer, section, '.');
std::getline(buffer, key, '=');
std::getline(buffer, value, '=');
m_values.emplace_back(std::make_tuple(system, section, key, value));
}
}
void Load(Config::Layer* config_layer) override
{
for (auto& value : m_values)
{
Config::Section* section = config_layer->GetOrCreateSection(
Config::GetSystemFromName(std::get<0>(value)), std::get<1>(value));
section->Set(std::get<2>(value), std::get<3>(value));
}
}
void Save(Config::Layer* config_layer) override
{
// Save Nothing
}
private:
std::list<std::tuple<std::string, std::string, std::string, std::string>> m_values;
};
std::unique_ptr<optparse::OptionParser> CreateParser(ParserOptions options)
{
auto parser = std::make_unique<optparse::OptionParser>();
@ -23,6 +75,11 @@ std::unique_ptr<optparse::OptionParser> CreateParser(ParserOptions options)
.metavar("<file>")
.type("string")
.help("Load the specified file");
parser->add_option("-C", "--config")
.action("append")
.metavar("<System>.<Section>.<Key>=<Value>")
.type("string")
.help("Set a configuration option");
if (options == ParserOptions::IncludeGUIOptions)
{
@ -32,7 +89,8 @@ std::unique_ptr<optparse::OptionParser> CreateParser(ParserOptions options)
parser->add_option("-c", "--confirm").action("store_true").help("Set Confirm on Stop");
}
// XXX: These two are setting configuration options
parser->set_defaults("video_backend", "");
parser->set_defaults("audio_emulation", "");
parser->add_option("-v", "--video_backend").action("store").help("Specify a video backend");
parser->add_option("-a", "--audio_emulation")
.choices({"HLE", "LLE"})
@ -43,6 +101,15 @@ std::unique_ptr<optparse::OptionParser> CreateParser(ParserOptions options)
optparse::Values& ParseArguments(optparse::OptionParser* parser, int argc, char** argv)
{
return parser->parse_args(argc, argv);
optparse::Values& options = parser->parse_args(argc, argv);
const std::list<std::string>& config_args = options.all("config");
if (config_args.size())
{
Config::AddLayer(std::make_unique<CommandLineConfigLayerLoader>(
config_args, static_cast<const char*>(options.get("video_backend")),
static_cast<const char*>(options.get("audio_emulation"))));
}
return options;
}
}