mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-08 05:33:31 +01:00
![JosJuice](/assets/img/avatar_default.png)
Whether the custom RTC setting is enabled shouldn't in itself affect determinism (as long as the actual RTC value is properly synced). Alters the logic added in 4b2906c. I'm not entirely certain that this is correct, but the current code doesn't really make sense to me... If we need to force the RTC bias to 0 when custom RTC is enabled, why don't we need to do it when custom RTC is disabled? The code for getting the host system's current time doesn't contain any special handling for the guest's RTC bias as far as I can tell.
222 lines
6.9 KiB
C++
222 lines
6.9 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 <functional>
|
|
#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, std::function<bool(const Config::Location&)> predicate)
|
|
{
|
|
if (Core::IsRunning())
|
|
return;
|
|
|
|
IOS::HLE::Kernel ios;
|
|
SysConf sysconf{ios.GetFS()};
|
|
|
|
for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS)
|
|
{
|
|
std::visit(
|
|
[&](auto* info) {
|
|
if (predicate && !predicate(info->GetLocation()))
|
|
return;
|
|
|
|
const std::string key = info->GetLocation().section + "." + info->GetLocation().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);
|
|
}
|
|
|
|
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_FMT(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},
|
|
{Config::System::FreeLook, F_FREELOOKCONFIG_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::Location 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::Location& 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_FMT(COMMON, "Config can't map system '{}' to an INI file!",
|
|
Config::GetSystemName(location.system));
|
|
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 Config::Location location = info->GetLocation();
|
|
const std::string key = location.section + "." + location.key;
|
|
if (setting.type == SysConf::Entry::Type::Long)
|
|
{
|
|
layer->Set(location, sysconf.GetData<u32>(key, info->GetDefaultValue()));
|
|
}
|
|
else if (setting.type == SysConf::Entry::Type::Byte)
|
|
{
|
|
layer->Set(location, sysconf.GetData<u8>(key, info->GetDefaultValue()));
|
|
}
|
|
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->GetDefaultValue();
|
|
SysConf::Entry* entry = sysconf.GetEntry(key);
|
|
if (entry)
|
|
{
|
|
std::memcpy(&value, entry->bytes.data(),
|
|
std::min(entry->bytes.size(), sizeof(u32)));
|
|
}
|
|
layer->Set(location, value);
|
|
}
|
|
},
|
|
setting.config_info);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Loader generation
|
|
std::unique_ptr<Config::ConfigLayerLoader> GenerateBaseConfigLoader()
|
|
{
|
|
return std::make_unique<BaseConfigLayerLoader>();
|
|
}
|
|
} // namespace ConfigLoaders
|