Merge pull request #4991 from leoetlino/config-loaders
New config loaders
This commit is contained in:
commit
dc42f7fb28
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,7 @@ enum LOG_TYPE
|
|||
COMMANDPROCESSOR,
|
||||
COMMON,
|
||||
CONSOLE,
|
||||
CORE,
|
||||
DISCIO,
|
||||
DSPHLE,
|
||||
DSPLLE,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue