dolphin/Source/Core/Common/Config/Layer.h
JosJuice 5978550b2f Android: Fix in-game settings changes not getting saved
EmulationActivity has an instance of Settings. If you go to
SettingsActivity from EmulationActivity and change some settings,
the changes get saved to disk, but EmulationActivity's Settings
instance still contains the old settings in its map of all
settings (assuming the EmulationActivity was not killed by the
system to save memory). Then, once you're done playing your
game and exit EmulationActivity, EmulationActivity calls
Settings.saveSettings. This call to saveSettings first overwrites
the entire INI file with its map of all settings (which is
outdated) in order to save any legacy settings that have changed
(which they haven't, since the GUI doesn't let you change legacy
settings while a game is running). Then, it asks the new config
system to write the most up-to-date values available for non-legacy
settings, which should make all the settings be up-to-date again.
The problem here is that the new config system would skip writing
to disk if no settings changes had been made since the last time
we asked it to write to disk (i.e. since SettingsActivity exited).

NB: Calling Settings.loadSettings in EmulationActivity.onResume
is not a working solution. I assume this is because
SettingsActivity saves its settings in onStop and not onPause.
2021-01-18 15:27:16 +01:00

160 lines
3.6 KiB
C++

// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <vector>
#include "Common/Config/ConfigInfo.h"
#include "Common/Config/Enums.h"
#include "Common/StringUtil.h"
namespace Config
{
namespace detail
{
template <typename T, std::enable_if_t<!std::is_enum<T>::value>* = nullptr>
std::optional<T> TryParse(const std::string& str_value)
{
T value;
if (!::TryParse(str_value, &value))
return std::nullopt;
return value;
}
template <typename T, std::enable_if_t<std::is_enum<T>::value>* = nullptr>
std::optional<T> TryParse(const std::string& str_value)
{
const auto result = TryParse<std::underlying_type_t<T>>(str_value);
if (result)
return static_cast<T>(*result);
return {};
}
template <>
inline std::optional<std::string> TryParse(const std::string& str_value)
{
return str_value;
}
} // namespace detail
template <typename T>
class Info;
class Layer;
using LayerMap = std::map<Location, std::optional<std::string>>;
class ConfigLayerLoader
{
public:
explicit ConfigLayerLoader(LayerType layer);
virtual ~ConfigLayerLoader();
virtual void Load(Layer* config_layer) = 0;
virtual void Save(Layer* config_layer) = 0;
LayerType GetLayer() const;
private:
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:
explicit Layer(LayerType layer);
explicit Layer(std::unique_ptr<ConfigLayerLoader> loader);
virtual ~Layer();
// Convenience functions
bool Exists(const Location& location) const;
bool DeleteKey(const Location& location);
void DeleteAllKeys();
template <typename T>
T Get(const Info<T>& config_info) const
{
return Get<T>(config_info.GetLocation()).value_or(config_info.GetDefaultValue());
}
template <typename T>
std::optional<T> Get(const Location& location) const
{
const auto iter = m_map.find(location);
if (iter == m_map.end() || !iter->second.has_value())
return std::nullopt;
return detail::TryParse<T>(*iter->second);
}
template <typename T>
void Set(const Info<T>& config_info, const std::common_type_t<T>& value)
{
Set(config_info.GetLocation(), value);
}
template <typename T>
void Set(const Location& location, const T& value)
{
Set(location, ValueToString(value));
}
void Set(const Location& location, std::string new_value)
{
const auto iter = m_map.find(location);
if (iter != m_map.end() && iter->second == new_value)
return;
m_is_dirty = true;
m_map.insert_or_assign(location, std::move(new_value));
}
void MarkAsDirty() { m_is_dirty = true; }
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();
LayerType GetLayer() const;
const LayerMap& GetLayerMap() const;
protected:
bool m_is_dirty = false;
LayerMap m_map;
const LayerType m_layer;
std::unique_ptr<ConfigLayerLoader> m_loader;
};
} // namespace Config