mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-16 04:09:39 +00:00
Some pieces of code are calling IsRunning because there's some particular action that only makes sense when emulation is running, for instance showing the state of the emulated CPU. IsRunning is appropriate to use for this. Then there are pieces of code that are calling IsRunning because there's some particular thing they must avoid doing e.g. when the CPU thread is running or IOS is running. IsRunning isn't quite appropriate for this. Such code should also be checking for the states Starting and Stopping. Keep in mind that: * When the state is Starting, the state can asynchronously change to Running at any time. * When we try to stop the core, the state gets set to Stopping before we take any action to actually stop things. This commit adds a new method Core::IsUninitialized, and changes all callers of IsRunning and GetState that look to me like they should be changed.
230 lines
7.2 KiB
C++
230 lines
7.2 KiB
C++
// Copyright 2016 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#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/MainSettings.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"
|
|
#include "Core/System.h"
|
|
|
|
namespace ConfigLoaders
|
|
{
|
|
void SaveToSYSCONF(Config::LayerType layer, std::function<bool(const Config::Location&)> predicate)
|
|
{
|
|
if (!Core::IsUninitialized(Core::System::GetInstance()))
|
|
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);
|
|
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::DualShockUDPClient, F_DUALSHOCKUDPCLIENTCONFIG_IDX},
|
|
{Config::System::FreeLook, F_FREELOOKCONFIG_IDX},
|
|
{Config::System::Achievements, F_RETROACHIEVEMENTSCONFIG_IDX},
|
|
// Config::System::Session should not be added to this list
|
|
};
|
|
|
|
// INI layer configuration loader
|
|
class BaseConfigLayerLoader final : public Config::ConfigLayerLoader
|
|
{
|
|
public:
|
|
BaseConfigLayerLoader() : ConfigLayerLoader(Config::LayerType::Base) {}
|
|
void Load(Config::Layer* layer) override
|
|
{
|
|
// List of settings that under no circumstances should be loaded from the global config INI.
|
|
static const auto s_setting_disallowed = {
|
|
&Config::MAIN_MEMORY_CARD_SIZE.GetLocation(),
|
|
};
|
|
|
|
LoadFromSYSCONF(layer);
|
|
for (const auto& system : system_to_ini)
|
|
{
|
|
Common::IniFile ini;
|
|
ini.Load(File::GetUserPath(system.second));
|
|
const auto& system_sections = ini.GetSections();
|
|
|
|
for (const auto& section : system_sections)
|
|
{
|
|
const std::string section_name = section.GetName();
|
|
const auto& section_map = section.GetValues();
|
|
|
|
for (const auto& value : section_map)
|
|
{
|
|
const Config::Location location{system.first, section_name, value.first};
|
|
const bool load_disallowed =
|
|
std::any_of(begin(s_setting_disallowed), end(s_setting_disallowed),
|
|
[&location](const Config::Location* l) { return *l == location; });
|
|
if (load_disallowed)
|
|
continue;
|
|
|
|
layer->Set(location, value.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Save(Config::Layer* layer) override
|
|
{
|
|
SaveToSYSCONF(layer->GetLayer());
|
|
|
|
std::map<Config::System, Common::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;
|
|
|
|
if (location.system == Config::System::Session)
|
|
continue;
|
|
|
|
if (location.system == Config::System::GameSettingsOnly)
|
|
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)
|
|
{
|
|
auto* 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::IsUninitialized(Core::System::GetInstance()))
|
|
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
|