@@ -8,10 +8,47 @@

#include "Common/Config/Config.h"
#include "Common/Config/Layer.h"
#include "Common/Config/Section.h"

namespace Config
{
namespace detail
{
std::string ValueToString(u16 value)
{
return StringFromFormat("0x%04x", value);
}

std::string ValueToString(u32 value)
{
return StringFromFormat("0x%08x", value);
}

std::string ValueToString(float value)
{
return StringFromFormat("%#.9g", value);
}

std::string ValueToString(double value)
{
return StringFromFormat("%#.17g", value);
}

std::string ValueToString(int value)
{
return std::to_string(value);
}

std::string ValueToString(bool value)
{
return StringFromBool(value);
}

std::string ValueToString(const std::string& value)
{
return value;
}
}

ConfigLayerLoader::ConfigLayerLoader(LayerType layer) : m_layer(layer)
{
}
@@ -38,64 +75,56 @@ Layer::~Layer()
Save();
}

bool Layer::Exists(System system, const std::string& section_name, const std::string& key)
bool Layer::Exists(const ConfigLocation& location) const
{
Section* section = GetSection(system, section_name);
if (!section)
return false;
return section->Exists(key);
const auto iter = m_map.find(location);
return iter != m_map.end() && iter->second.has_value();
}

bool Layer::DeleteKey(System system, const std::string& section_name, const std::string& key)
bool Layer::DeleteKey(const ConfigLocation& location)
{
Section* section = GetSection(system, section_name);
if (!section)
return false;
return section->Delete(key);
m_is_dirty = true;
bool had_value = m_map[location].has_value();
m_map[location].reset();
return had_value;
}

Section* Layer::GetSection(System system, const std::string& section_name)
void Layer::DeleteAllKeys()
{
for (auto& section : m_sections[system])
if (!strcasecmp(section->m_name.c_str(), section_name.c_str()))
return section.get();
return nullptr;
m_is_dirty = true;
for (auto& pair : m_map)
{
pair.second.reset();
}
}

Section* Layer::GetOrCreateSection(System system, const std::string& section_name)
Section Layer::GetSection(System system, const std::string& section)
{
Section* section = GetSection(system, section_name);
if (!section)
{
if (m_layer == LayerType::Meta)
{
m_sections[system].emplace_back(
std::make_unique<RecursiveSection>(m_layer, system, section_name));
}
else
{
m_sections[system].emplace_back(std::make_unique<Section>(m_layer, system, section_name));
}
section = m_sections[system].back().get();
}
return section;
return Section{m_map.lower_bound(ConfigLocation{system, section, ""}),
m_map.lower_bound(ConfigLocation{system, section + '\001', ""})};
}

ConstSection Layer::GetSection(System system, const std::string& section) const
{
return ConstSection{m_map.lower_bound(ConfigLocation{system, section, ""}),
m_map.lower_bound(ConfigLocation{system, section + '\001', ""})};
}

void Layer::Load()
{
if (m_loader)
m_loader->Load(this);
ClearDirty();
m_is_dirty = false;
InvokeConfigChangedCallbacks();
}

void Layer::Save()
{
if (!m_loader || !IsDirty())
if (!m_loader || !m_is_dirty)
return;

m_loader->Save(this);
ClearDirty();
m_is_dirty = false;
InvokeConfigChangedCallbacks();
}

@@ -106,44 +135,6 @@ LayerType Layer::GetLayer() const

const LayerMap& Layer::GetLayerMap() const
{
return m_sections;
}

bool Layer::IsDirty() const
{
return std::any_of(m_sections.begin(), m_sections.end(), [](const auto& system) {
return std::any_of(system.second.begin(), system.second.end(),
[](const auto& section) { return section->IsDirty(); });
});
}

void Layer::ClearDirty()
{
std::for_each(m_sections.begin(), m_sections.end(), [](auto& system) {
std::for_each(system.second.begin(), system.second.end(),
[](auto& section) { section->ClearDirty(); });
});
}

RecursiveLayer::RecursiveLayer() : Layer(LayerType::Meta)
{
}

Section* RecursiveLayer::GetSection(System system, const std::string& section_name)
{
// Always queries backwards recursively, so it doesn't matter if it exists or not on this layer
return GetOrCreateSection(system, section_name);
}

Section* RecursiveLayer::GetOrCreateSection(System system, const std::string& section_name)
{
Section* section = Layer::GetSection(system, section_name);
if (!section)
{
m_sections[system].emplace_back(
std::make_unique<RecursiveSection>(m_layer, system, section_name));
section = m_sections[system].back().get();
}
return section;
return m_map;
}
}
@@ -6,18 +6,47 @@

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "Common/Config/ConfigInfo.h"
#include "Common/Config/Enums.h"
#include "Common/Config/Section.h"
#include "Common/StringUtil.h"

namespace Config
{
namespace detail
{
std::string ValueToString(u16 value);
std::string ValueToString(u32 value);
std::string ValueToString(float value);
std::string ValueToString(double value);
std::string ValueToString(int value);
std::string ValueToString(bool value);
std::string ValueToString(const std::string& value);

template <typename T>
std::optional<T> TryParse(const std::string& str_value)
{
T value;
if (!::TryParse(str_value, &value))
return std::nullopt;
return value;
}

template <>
inline std::optional<std::string> TryParse(const std::string& str_value)
{
return str_value;
}
}

template <typename T>
struct ConfigInfo;

using LayerMap = std::map<System, std::vector<std::unique_ptr<Section>>>;
class Layer;
using LayerMap = std::map<ConfigLocation, std::optional<std::string>>;

class ConfigLayerLoader
{
@@ -33,6 +62,30 @@ class ConfigLayerLoader
const LayerType m_layer;
};

class Section
{
public:
using iterator = LayerMap::iterator;
Section(iterator begin_, iterator end_) : m_begin(begin_), m_end(end_) {}
iterator begin() const { return m_begin; }
iterator end() const { return m_end; }
private:
iterator m_begin;
iterator m_end;
};

class ConstSection
{
public:
using iterator = LayerMap::const_iterator;
ConstSection(iterator begin_, iterator end_) : m_begin(begin_), m_end(end_) {}
iterator begin() const { return m_begin; }
iterator end() const { return m_end; }
private:
iterator m_begin;
iterator m_end;
};

class Layer
{
public:
@@ -41,34 +94,45 @@ class Layer
virtual ~Layer();

// Convenience functions
bool Exists(System system, const std::string& section_name, const std::string& key);
bool DeleteKey(System system, const std::string& section_name, const std::string& key);
bool Exists(const ConfigLocation& location) const;
bool DeleteKey(const ConfigLocation& location);
void DeleteAllKeys();

template <typename T>
bool GetIfExists(System system, const std::string& section_name, const std::string& key, T* value)
T Get(const ConfigInfo<T>& config_info)
{
if (Exists(system, section_name, key))
return GetOrCreateSection(system, section_name)->Get(key, value);

return false;
return Get<T>(config_info.location).value_or(config_info.default_value);
}

virtual Section* GetSection(System system, const std::string& section_name);
virtual Section* GetOrCreateSection(System system, const std::string& section_name);

template <typename T>
T Get(const ConfigInfo<T>& config_info)
std::optional<T> Get(const ConfigLocation& location)
{
return GetOrCreateSection(config_info.location.system, config_info.location.section)
->template Get<T>(config_info.location.key, config_info.default_value);
const std::optional<std::string>& str_value = m_map[location];
if (!str_value)
return std::nullopt;
return detail::TryParse<T>(*str_value);
}

template <typename T>
void Set(const ConfigInfo<T>& config_info, const T& value)
{
GetOrCreateSection(config_info.location.system, config_info.location.section)
->Set(config_info.location.key, value);
Set<T>(config_info.location, value);
}

template <typename T>
void Set(const ConfigLocation& location, const T& value)
{
const std::string new_value = detail::ValueToString(value);
std::optional<std::string>& current_value = m_map[location];
if (current_value == new_value)
return;
m_is_dirty = true;
current_value = new_value;
}

Section GetSection(System system, const std::string& section);
ConstSection GetSection(System system, const std::string& section) const;

// Explicit load and save of layers
void Load();
void Save();
@@ -77,19 +141,9 @@ class Layer
const LayerMap& GetLayerMap() const;

protected:
bool IsDirty() const;
void ClearDirty();

LayerMap m_sections;
bool m_is_dirty = false;
LayerMap m_map;
const LayerType m_layer;
std::unique_ptr<ConfigLayerLoader> m_loader;
};

class RecursiveLayer final : public Layer
{
public:
RecursiveLayer();
Section* GetSection(System system, const std::string& section_name) override;
Section* GetOrCreateSection(System system, const std::string& section_name) override;
};
}

This file was deleted.

This file was deleted.

@@ -376,7 +376,7 @@ bool BootCore(std::unique_ptr<BootParameters> boot)

// Ensure any new settings are written to the SYSCONF
if (StartUp.bWii)
ConfigLoaders::SaveToSYSCONF(Config::GetLayer(Config::LayerType::Meta));
ConfigLoaders::SaveToSYSCONF(Config::LayerType::Meta);

const bool load_ipl = !StartUp.bWii && !StartUp.bHLE_BS2 &&
std::holds_alternative<BootParameters::Disc>(boot->parameters);
@@ -61,6 +61,7 @@ ConfigInfo<bool> GetInfoForSimulateKonga(u32 channel)
}

const ConfigInfo<bool> MAIN_WII_SD_CARD{{System::Main, "Core", "WiiSDCard"}, false};
const ConfigInfo<bool> MAIN_WII_SD_CARD_WRITABLE{{System::Main, "Core", "WiiSDCardWritable"}, true};
const ConfigInfo<bool> MAIN_WII_KEYBOARD{{System::Main, "Core", "WiiKeyboard"}, false};
const ConfigInfo<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING{
{System::Main, "Core", "WiimoteContinuousScanning"}, false};
@@ -40,6 +40,7 @@ ConfigInfo<u32> GetInfoForSIDevice(u32 channel);
ConfigInfo<bool> GetInfoForAdapterRumble(u32 channel);
ConfigInfo<bool> GetInfoForSimulateKonga(u32 channel);
extern const ConfigInfo<bool> MAIN_WII_SD_CARD;
extern const ConfigInfo<bool> MAIN_WII_SD_CARD_WRITABLE;
extern const ConfigInfo<bool> MAIN_WII_KEYBOARD;
extern const ConfigInfo<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING;
extern const ConfigInfo<bool> MAIN_WIIMOTE_ENABLE_SPEAKER;
@@ -26,7 +26,7 @@

namespace ConfigLoaders
{
void SaveToSYSCONF(Config::Layer* layer)
void SaveToSYSCONF(Config::LayerType layer)
{
if (Core::IsRunning())
return;
@@ -40,9 +40,9 @@ void SaveToSYSCONF(Config::Layer* layer)
const std::string key = info.location.section + "." + info.location.key;

if (setting.type == SysConf::Entry::Type::Long)
sysconf.SetData<u32>(key, setting.type, layer->Get(info));
sysconf.SetData<u32>(key, setting.type, Config::Get(layer, info));
else if (setting.type == SysConf::Entry::Type::Byte)
sysconf.SetData<u8>(key, setting.type, static_cast<u8>(layer->Get(info)));
sysconf.SetData<u8>(key, setting.type, static_cast<u8>(Config::Get(layer, info)));
},
setting.config_info);
}
@@ -77,9 +77,9 @@ class BaseConfigLayerLoader final : public Config::ConfigLayerLoader
{
public:
BaseConfigLayerLoader() : ConfigLayerLoader(Config::LayerType::Base) {}
void Load(Config::Layer* config_layer) override
void Load(Config::Layer* layer) override
{
LoadFromSYSCONF(config_layer);
LoadFromSYSCONF(layer);
for (const auto& system : system_to_ini)
{
IniFile ini;
@@ -89,55 +89,62 @@ class BaseConfigLayerLoader final : public Config::ConfigLayerLoader
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);
{
const Config::ConfigLocation location{system.first, section_name, value.first};
layer->Set(location, value.second);
}
}
}
}

void Save(Config::Layer* config_layer) override
void Save(Config::Layer* layer) override
{
const Config::LayerMap& sections = config_layer->GetLayerMap();
for (const auto& system : sections)
SaveToSYSCONF(layer->GetLayer());

std::map<Config::System, IniFile> inis;

for (const auto& system : system_to_ini)
{
if (system.first == Config::System::SYSCONF)
{
SaveToSYSCONF(config_layer);
inis[system.first].Load(File::GetUserPath(system.second));
}

for (const auto& config : layer->GetLayerMap())
{
const Config::ConfigLocation& location = config.first;
const std::optional<std::string>& value = config.second;

// Done by SaveToSYSCONF
if (location.system == Config::System::SYSCONF)
continue;
}

auto mapping = system_to_ini.find(system.first);
if (mapping == system_to_ini.end())
auto ini = inis.find(location.system);
if (ini == inis.end())
{
ERROR_LOG(COMMON, "Config can't map system '%s' to an INI file!",
Config::GetSystemName(system.first).c_str());
Config::GetSystemName(location.system).c_str());
continue;
}

IniFile ini;
ini.Load(File::GetUserPath(mapping->second));
if (!IsSettingSaveable(location))
continue;

for (const auto& section : system.second)
if (value)
{
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)
{
if (!IsSettingSaveable({system.first, section->GetName(), value.first}))
continue;

ini_section->Set(value.first, value.second);
}
IniFile::Section* ini_section = ini->second.GetOrCreateSection(location.section);
ini_section->Set(location.key, *value);
}
else
{
ini->second.DeleteKey(location.section, location.key);
}
}

ini.Save(File::GetUserPath(mapping->second));
for (const auto& system : system_to_ini)
{
inis[system.first].Save(File::GetUserPath(system.second));
}
}

@@ -153,13 +160,10 @@ class BaseConfigLayerLoader final : public Config::ConfigLayerLoader
std::visit(
[&](auto& info) {
const std::string key = info.location.section + "." + info.location.key;
auto* section =
layer->GetOrCreateSection(Config::System::SYSCONF, info.location.section);

if (setting.type == SysConf::Entry::Type::Long)
section->Set(info.location.key, sysconf.GetData<u32>(key, info.default_value));
layer->Set(info.location, sysconf.GetData<u32>(key, info.default_value));
else if (setting.type == SysConf::Entry::Type::Byte)
section->Set(info.location.key, sysconf.GetData<u8>(key, info.default_value));
layer->Set(info.location, sysconf.GetData<u8>(key, info.default_value));
},
setting.config_info);
}
@@ -9,11 +9,11 @@
namespace Config
{
class ConfigLayerLoader;
class Layer;
enum class LayerType;
}

namespace ConfigLoaders
{
void SaveToSYSCONF(Config::Layer* layer);
void SaveToSYSCONF(Config::LayerType layer);
std::unique_ptr<Config::ConfigLayerLoader> GenerateBaseConfigLoader();
}
@@ -199,10 +199,10 @@ class INIGameConfigLayerLoader final : public Config::ConfigLayerLoader
{
}

void Load(Config::Layer* config_layer) override
void Load(Config::Layer* layer) override
{
IniFile ini;
if (config_layer->GetLayer() == Config::LayerType::GlobalGame)
if (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);
@@ -217,16 +217,16 @@ class INIGameConfigLayerLoader final : public Config::ConfigLayerLoader

for (const auto& section : system_sections)
{
LoadFromSystemSection(config_layer, section);
LoadFromSystemSection(layer, section);
}

LoadControllerConfig(config_layer);
LoadControllerConfig(layer);
}

void Save(Config::Layer* config_layer) override;
void Save(Config::Layer* layer) override;

private:
void LoadControllerConfig(Config::Layer* config_layer) const
void LoadControllerConfig(Config::Layer* layer) const
{
// Game INIs can have controller profiles embedded in to them
static const std::array<char, 4> nums = {{'1', '2', '3', '4'}};
@@ -244,115 +244,89 @@ class INIGameConfigLayerLoader final : public Config::ConfigLayerLoader
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");
const auto control_section = [&](std::string key) {
return Config::ConfigLocation{std::get<2>(use_data), "Controls", key};
};

for (const char num : nums)
{
bool use_profile = false;
std::string profile;
if (control_section->Exists(type + "Profile" + num))
if (auto profile = layer->Get<std::string>(control_section(type + "Profile" + num)))
{
if (control_section->Get(type + "Profile" + num, &profile))
std::string ini_path = File::GetUserPath(D_CONFIG_IDX) + path + *profile + ".ini";
if (!File::Exists(ini_path))
{
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");
}
// TODO: PanicAlert shouldn't be used for this.
PanicAlertT("Selected controller profile does not exist");
continue;
}
}

if (use_profile)
{
IniFile profile_ini;
profile_ini.Load(File::GetUserPath(D_CONFIG_IDX) + path + profile + ".ini");
profile_ini.Load(ini_path);

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);
Config::ConfigLocation location{std::get<2>(use_data), std::get<1>(use_data) + num,
value.first};
layer->Set(location, value.second);
}
}
}
}
}

void LoadFromSystemSection(Config::Layer* config_layer, const IniFile::Section& section) const
void LoadFromSystemSection(Config::Layer* 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);
const auto location = MapINIToRealLocation(section_name, value.first);

if (mapped_config.section.empty() && mapped_config.key.empty())
if (location.section.empty() && location.key.empty())
continue;

auto* config_section =
config_layer->GetOrCreateSection(mapped_config.system, mapped_config.section);
config_section->Set(mapped_config.key, value.second);
layer->Set(location, value.second);
}
}

const std::string m_id;
const u16 m_revision;
};

void INIGameConfigLayerLoader::Save(Config::Layer* config_layer)
void INIGameConfigLayerLoader::Save(Config::Layer* layer)
{
if (config_layer->GetLayer() != Config::LayerType::LocalGame)
if (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& config : layer->GetLayerMap())
{
for (const auto& section : system.second)
{
for (const auto& value : section->GetValues())
{
if (!IsSettingSaveable({system.first, section->GetName(), value.first}))
continue;
const Config::ConfigLocation& location = config.first;
const std::optional<std::string>& value = config.second;

const auto ini_location =
GetINILocationFromConfig({system.first, section->GetName(), value.first});
if (ini_location.first.empty() && ini_location.second.empty())
continue;
if (!IsSettingSaveable(location))
continue;

IniFile::Section* ini_section = ini.GetOrCreateSection(ini_location.first);
ini_section->Set(ini_location.second, value.second);
}
const auto ini_location = GetINILocationFromConfig(location);
if (ini_location.first.empty() && ini_location.second.empty())
continue;

if (value)
{
IniFile::Section* ini_section = ini.GetOrCreateSection(ini_location.first);
ini_section->Set(ini_location.second, *value);
}
else
{
ini.DeleteKey(ini_location.first, ini_location.second);
}
}

@@ -46,27 +46,27 @@ static void LoadFromDTM(Config::Layer* config_layer, Movie::DTMHeader* dtm)
config_layer->Set(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, dtm->bEFBEmulateFormatChanges);
}

void SaveToDTM(Config::Layer* config_layer, Movie::DTMHeader* dtm)
void SaveToDTM(Movie::DTMHeader* dtm)
{
dtm->bDualCore = config_layer->Get(Config::MAIN_CPU_THREAD);
dtm->bDSPHLE = config_layer->Get(Config::MAIN_DSP_HLE);
dtm->bFastDiscSpeed = config_layer->Get(Config::MAIN_FAST_DISC_SPEED);
dtm->CPUCore = config_layer->Get(Config::MAIN_CPU_CORE);
dtm->bSyncGPU = config_layer->Get(Config::MAIN_SYNC_GPU);
const std::string video_backend = config_layer->Get(Config::MAIN_GFX_BACKEND);
dtm->bDualCore = Config::Get(Config::MAIN_CPU_THREAD);
dtm->bDSPHLE = Config::Get(Config::MAIN_DSP_HLE);
dtm->bFastDiscSpeed = Config::Get(Config::MAIN_FAST_DISC_SPEED);
dtm->CPUCore = Config::Get(Config::MAIN_CPU_CORE);
dtm->bSyncGPU = Config::Get(Config::MAIN_SYNC_GPU);
const std::string video_backend = Config::Get(Config::MAIN_GFX_BACKEND);

dtm->bProgressive = config_layer->Get(Config::SYSCONF_PROGRESSIVE_SCAN);
dtm->bPAL60 = config_layer->Get(Config::SYSCONF_PAL60);
dtm->bProgressive = Config::Get(Config::SYSCONF_PROGRESSIVE_SCAN);
dtm->bPAL60 = Config::Get(Config::SYSCONF_PAL60);
if (dtm->bWii)
dtm->language = config_layer->Get(Config::SYSCONF_LANGUAGE);
dtm->language = Config::Get(Config::SYSCONF_LANGUAGE);
else
dtm->language = config_layer->Get(Config::MAIN_GC_LANGUAGE);
dtm->language = Config::Get(Config::MAIN_GC_LANGUAGE);

dtm->bUseXFB = config_layer->Get(Config::GFX_USE_XFB);
dtm->bUseRealXFB = config_layer->Get(Config::GFX_USE_REAL_XFB);
dtm->bEFBAccessEnable = config_layer->Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
dtm->bSkipEFBCopyToRam = config_layer->Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
dtm->bEFBEmulateFormatChanges = config_layer->Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES);
dtm->bUseXFB = Config::Get(Config::GFX_USE_XFB);
dtm->bUseRealXFB = Config::Get(Config::GFX_USE_REAL_XFB);
dtm->bEFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
dtm->bSkipEFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
dtm->bEFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES);

// This never used the regular config
dtm->bSkipIdle = true;
@@ -30,6 +30,6 @@ class MovieConfigLayerLoader final : public Config::ConfigLayerLoader
Movie::DTMHeader* m_header;
};

void SaveToDTM(Config::Layer* layer, Movie::DTMHeader* header);
void SaveToDTM(Movie::DTMHeader* header);
std::unique_ptr<Config::ConfigLayerLoader> GenerateMovieConfigLoader(Movie::DTMHeader* header);
}
@@ -7,6 +7,7 @@
#include <memory>

#include "Common/Config/Config.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/NetPlayProto.h"

@@ -20,29 +21,26 @@ class NetPlayConfigLayerLoader final : public Config::ConfigLayerLoader
{
}

void Load(Config::Layer* config_layer) override
void Load(Config::Layer* layer) override
{
Config::Section* core = config_layer->GetOrCreateSection(Config::System::Main, "Core");
Config::Section* dsp = config_layer->GetOrCreateSection(Config::System::Main, "DSP");

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);

config_layer->Set(Config::SYSCONF_PROGRESSIVE_SCAN, m_settings.m_ProgressiveScan);
config_layer->Set(Config::SYSCONF_PAL60, m_settings.m_PAL60);
layer->Set(Config::MAIN_CPU_THREAD, m_settings.m_CPUthread);
layer->Set(Config::MAIN_CPU_CORE, m_settings.m_CPUcore);
layer->Set(Config::MAIN_GC_LANGUAGE, m_settings.m_SelectedLanguage);
layer->Set(Config::MAIN_OVERRIDE_GC_LANGUAGE, m_settings.m_OverrideGCLanguage);
layer->Set(Config::MAIN_DSP_HLE, m_settings.m_DSPHLE);
layer->Set(Config::MAIN_OVERCLOCK_ENABLE, m_settings.m_OCEnable);
layer->Set(Config::MAIN_OVERCLOCK, m_settings.m_OCFactor);
layer->Set(Config::MAIN_SLOT_A, static_cast<int>(m_settings.m_EXIDevice[0]));
layer->Set(Config::MAIN_SLOT_B, static_cast<int>(m_settings.m_EXIDevice[1]));
layer->Set(Config::MAIN_WII_SD_CARD_WRITABLE, m_settings.m_WriteToMemcard);

layer->Set(Config::MAIN_DSP_JIT, m_settings.m_DSPEnableJIT);

layer->Set(Config::SYSCONF_PROGRESSIVE_SCAN, m_settings.m_ProgressiveScan);
layer->Set(Config::SYSCONF_PAL60, m_settings.m_PAL60);
}

void Save(Config::Layer* config_layer) override
void Save(Config::Layer* layer) override
{
// Do Nothing
}
@@ -1306,7 +1306,7 @@ void SaveRecording(const std::string& filename)
header.recordingStartTime = s_recordingStartTime;

header.bSaveConfig = true;
ConfigLoaders::SaveToDTM(Config::GetLayer(Config::LayerType::Meta), &header);
ConfigLoaders::SaveToDTM(&header);
header.memcards = s_memcards;
header.bClearSave = s_bClearSave;
header.bNetPlay = s_bNetPlay;
@@ -10,7 +10,9 @@
#include <OptionParser.h>

#include "Common/Config/Config.h"
#include "Common/StringUtil.h"
#include "Common/Version.h"
#include "Core/Config/MainSettings.h"
#include "UICommon/CommandLineParse.h"

namespace CommandLineParse
@@ -23,42 +25,41 @@ class CommandLineConfigLayerLoader final : public Config::ConfigLayerLoader
: ConfigLayerLoader(Config::LayerType::CommandLine)
{
if (video_backend.size())
m_values.emplace_back(std::make_tuple("Dolphin", "Core", "GFXBackend", video_backend));
m_values.emplace_back(std::make_tuple(Config::MAIN_GFX_BACKEND.location, video_backend));

if (audio_backend.size())
m_values.emplace_back(
std::make_tuple("Dolphin", "Core", "DSPHLE", audio_backend == "HLE" ? "True" : "False"));
std::make_tuple(Config::MAIN_DSP_HLE.location, StringFromBool(audio_backend == "HLE")));

// 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::string system_str, section, key, value;
std::getline(buffer, system_str, '.');
std::getline(buffer, section, '.');
std::getline(buffer, key, '=');
std::getline(buffer, value, '=');
m_values.emplace_back(std::make_tuple(system, section, key, value));
Config::System system = Config::GetSystemFromName(system_str);
m_values.emplace_back(std::make_tuple(Config::ConfigLocation{system, section, key}, value));
}
}

void Load(Config::Layer* config_layer) override
void Load(Config::Layer* 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));
layer->Set(std::get<0>(value), std::get<1>(value));
}
}

void Save(Config::Layer* config_layer) override
void Save(Config::Layer* layer) override
{
// Save Nothing
}

private:
std::list<std::tuple<std::string, std::string, std::string, std::string>> m_values;
std::list<std::tuple<Config::ConfigLocation, std::string>> m_values;
};

std::unique_ptr<optparse::OptionParser> CreateParser(ParserOptions options)