217 lines
6.7 KiB
C++
217 lines
6.7 KiB
C++
// Copyright 2016 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "Core/ConfigLoaders/BaseConfigLoader.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <variant>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/Config/Config.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/IniFile.h"
|
|
#include "Common/Logging/Log.h"
|
|
|
|
#include "Core/Config/SYSCONFSettings.h"
|
|
#include "Core/ConfigLoaders/IsSettingSaveable.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/IOS/IOS.h"
|
|
#include "Core/IOS/USB/Bluetooth/BTBase.h"
|
|
#include "Core/SysConf.h"
|
|
|
|
namespace ConfigLoaders
|
|
{
|
|
void SaveToSYSCONF(Config::LayerType layer)
|
|
{
|
|
if (Core::IsRunning())
|
|
return;
|
|
|
|
IOS::HLE::Kernel ios;
|
|
SysConf sysconf{ios.GetFS()};
|
|
|
|
for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS)
|
|
{
|
|
std::visit(
|
|
[layer, &setting, &sysconf](auto& info) {
|
|
const std::string key = info.location.section + "." + info.location.key;
|
|
|
|
if (setting.type == SysConf::Entry::Type::Long)
|
|
{
|
|
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>(Config::Get(layer, info)));
|
|
}
|
|
else if (setting.type == SysConf::Entry::Type::BigArray)
|
|
{
|
|
// Somewhat hacky support for IPL.SADR. The setting only stores the
|
|
// first 4 bytes even thought the SYSCONF entry is much bigger.
|
|
SysConf::Entry* entry = sysconf.GetOrAddEntry(key, setting.type);
|
|
if (entry->bytes.size() < 0x1007 + 1)
|
|
entry->bytes.resize(0x1007 + 1);
|
|
*reinterpret_cast<u32*>(entry->bytes.data()) = Config::Get(layer, info);
|
|
}
|
|
},
|
|
setting.config_info);
|
|
}
|
|
|
|
if (SConfig::GetInstance().bEnableCustomRTC)
|
|
sysconf.SetData<u32>("IPL.CB", SysConf::Entry::Type::Long, 0);
|
|
|
|
// Disable WiiConnect24's standby mode. If it is enabled, it prevents us from receiving
|
|
// shutdown commands in the State Transition Manager (STM).
|
|
// TODO: remove this if and once Dolphin supports WC24 standby mode.
|
|
SysConf::Entry* idle_entry = sysconf.GetOrAddEntry("IPL.IDL", SysConf::Entry::Type::SmallArray);
|
|
if (idle_entry->bytes.empty())
|
|
idle_entry->bytes = std::vector<u8>(2);
|
|
else
|
|
idle_entry->bytes[0] = 0;
|
|
NOTICE_LOG(CORE, "Disabling WC24 'standby' (shutdown to idle) to avoid hanging on shutdown");
|
|
|
|
IOS::HLE::RestoreBTInfoSection(&sysconf);
|
|
sysconf.Save();
|
|
}
|
|
|
|
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::DualShockUDPClient, F_DUALSHOCKUDPCLIENTCONFIG_IDX},
|
|
};
|
|
|
|
// INI layer configuration loader
|
|
class BaseConfigLayerLoader final : public Config::ConfigLayerLoader
|
|
{
|
|
public:
|
|
BaseConfigLayerLoader() : ConfigLayerLoader(Config::LayerType::Base) {}
|
|
void Load(Config::Layer* layer) override
|
|
{
|
|
LoadFromSYSCONF(layer);
|
|
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();
|
|
const IniFile::Section::SectionMap& section_map = section.GetValues();
|
|
|
|
for (const auto& value : section_map)
|
|
{
|
|
const Config::ConfigLocation location{system.first, section_name, value.first};
|
|
layer->Set(location, value.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Save(Config::Layer* layer) override
|
|
{
|
|
SaveToSYSCONF(layer->GetLayer());
|
|
|
|
std::map<Config::System, IniFile> inis;
|
|
|
|
for (const auto& system : system_to_ini)
|
|
{
|
|
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 ini = inis.find(location.system);
|
|
if (ini == inis.end())
|
|
{
|
|
ERROR_LOG(COMMON, "Config can't map system '%s' to an INI file!",
|
|
Config::GetSystemName(location.system).c_str());
|
|
continue;
|
|
}
|
|
|
|
if (!IsSettingSaveable(location))
|
|
continue;
|
|
|
|
if (value)
|
|
{
|
|
IniFile::Section* ini_section = ini->second.GetOrCreateSection(location.section);
|
|
ini_section->Set(location.key, *value);
|
|
}
|
|
else
|
|
{
|
|
ini->second.DeleteKey(location.section, location.key);
|
|
}
|
|
}
|
|
|
|
for (const auto& system : system_to_ini)
|
|
{
|
|
inis[system.first].Save(File::GetUserPath(system.second));
|
|
}
|
|
}
|
|
|
|
private:
|
|
void LoadFromSYSCONF(Config::Layer* layer)
|
|
{
|
|
if (Core::IsRunning())
|
|
return;
|
|
|
|
IOS::HLE::Kernel ios;
|
|
SysConf sysconf{ios.GetFS()};
|
|
for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS)
|
|
{
|
|
std::visit(
|
|
[&](auto& info) {
|
|
const std::string key = info.location.section + "." + info.location.key;
|
|
if (setting.type == SysConf::Entry::Type::Long)
|
|
{
|
|
layer->Set(info.location, sysconf.GetData<u32>(key, info.default_value));
|
|
}
|
|
else if (setting.type == SysConf::Entry::Type::Byte)
|
|
{
|
|
layer->Set(info.location, sysconf.GetData<u8>(key, info.default_value));
|
|
}
|
|
else if (setting.type == SysConf::Entry::Type::BigArray)
|
|
{
|
|
// Somewhat hacky support for IPL.SADR. The setting only stores the
|
|
// first 4 bytes even thought the SYSCONF entry is much bigger.
|
|
u32 value = info.default_value;
|
|
SysConf::Entry* entry = sysconf.GetEntry(key);
|
|
if (entry)
|
|
{
|
|
std::memcpy(&value, entry->bytes.data(),
|
|
std::min(entry->bytes.size(), sizeof(u32)));
|
|
}
|
|
layer->Set(info.location, value);
|
|
}
|
|
},
|
|
setting.config_info);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Loader generation
|
|
std::unique_ptr<Config::ConfigLayerLoader> GenerateBaseConfigLoader()
|
|
{
|
|
return std::make_unique<BaseConfigLayerLoader>();
|
|
}
|
|
} // namespace ConfigLoaders
|