414 lines
9.7 KiB
C++
414 lines
9.7 KiB
C++
#pragma once
|
|
|
|
#include "RE/B/BSFixedString.h"
|
|
#include "RE/B/BSSimpleList.h"
|
|
#include "RE/B/BSTBTree.h"
|
|
#include "RE/M/MemoryManager.h"
|
|
|
|
namespace RE
|
|
{
|
|
union SETTING_VALUE
|
|
{
|
|
std::int8_t c;
|
|
bool b;
|
|
float f;
|
|
std::uint8_t h;
|
|
std::int32_t i;
|
|
char* s;
|
|
std::uint32_t u;
|
|
std::uint32_t r;
|
|
std::uint32_t a;
|
|
};
|
|
|
|
class __declspec(novtable) Setting
|
|
{
|
|
public:
|
|
static constexpr auto RTTI{ RTTI::Setting };
|
|
static constexpr auto VTABLE{ VTABLE::Setting };
|
|
|
|
enum class SETTING_TYPE
|
|
{
|
|
kBinary, // b
|
|
kChar, // c
|
|
kUChar, // h
|
|
kInt, // i
|
|
kUInt, // u
|
|
kFloat, // f
|
|
kString, // s/S
|
|
kRGB, // r
|
|
kRGBA, // a
|
|
kNone
|
|
};
|
|
|
|
Setting(const char* a_key, char a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.c = a_value;
|
|
}
|
|
|
|
Setting(const char* a_key, bool a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.b = a_value;
|
|
}
|
|
|
|
Setting(const char* a_key, float a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.f = a_value;
|
|
}
|
|
|
|
Setting(const char* a_key, std::uint8_t a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.h = a_value;
|
|
}
|
|
|
|
Setting(const char* a_key, std::int32_t a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.i = a_value;
|
|
}
|
|
|
|
Setting(const char* a_key, const char* a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.s = _strdup(a_value);
|
|
}
|
|
|
|
Setting(const char* a_key, std::uint32_t a_value)
|
|
{
|
|
_key = a_key;
|
|
_value.u = a_value;
|
|
}
|
|
|
|
virtual ~Setting() // 00
|
|
{
|
|
if (_key && _key[0] == 'S') {
|
|
free(const_cast<char*>(_key));
|
|
_key = nullptr;
|
|
}
|
|
}
|
|
|
|
// add
|
|
[[nodiscard]] virtual bool IsPrefSetting() { return false; } // 01
|
|
|
|
F4_HEAP_REDEFINE_NEW(Setting);
|
|
|
|
[[nodiscard]] bool GetBinary() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kBinary);
|
|
return _value.b;
|
|
}
|
|
|
|
[[nodiscard]] char GetChar() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kChar);
|
|
return _value.c;
|
|
}
|
|
|
|
[[nodiscard]] float GetFloat() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kFloat);
|
|
return _value.f;
|
|
}
|
|
|
|
[[nodiscard]] std::int32_t GetInt() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kInt);
|
|
return _value.i;
|
|
}
|
|
|
|
[[nodiscard]] std::string_view GetKey() const noexcept { return _key ? _key : ""sv; }
|
|
|
|
[[nodiscard]] std::span<const std::uint8_t, 3> GetRGB() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kRGB);
|
|
return std::span<const std::uint8_t, 3>{
|
|
reinterpret_cast<const std::uint8_t(&)[3]>(*std::addressof(_value.r))
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] std::span<const std::uint8_t, 4> GetRGBA() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kRGBA);
|
|
return std::span<const std::uint8_t, 4>{
|
|
reinterpret_cast<const std::uint8_t(&)[4]>(*std::addressof(_value.a))
|
|
};
|
|
}
|
|
|
|
[[nodiscard]] std::string_view GetString() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kString);
|
|
return _value.s ? _value.s : ""sv;
|
|
}
|
|
|
|
[[nodiscard]] SETTING_TYPE GetType() const noexcept
|
|
{
|
|
if (_key) {
|
|
switch (_key[0]) {
|
|
case 'b':
|
|
return SETTING_TYPE::kBinary;
|
|
case 'c':
|
|
return SETTING_TYPE::kChar;
|
|
case 'h':
|
|
return SETTING_TYPE::kUChar;
|
|
case 'i':
|
|
return SETTING_TYPE::kInt;
|
|
case 'u':
|
|
return SETTING_TYPE::kUInt;
|
|
case 'f':
|
|
return SETTING_TYPE::kFloat;
|
|
case 's':
|
|
case 'S':
|
|
return SETTING_TYPE::kString;
|
|
case 'r':
|
|
return SETTING_TYPE::kRGB;
|
|
case 'a':
|
|
return SETTING_TYPE::kRGBA;
|
|
default:
|
|
return SETTING_TYPE::kNone;
|
|
}
|
|
} else {
|
|
return SETTING_TYPE::kNone;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] std::uint8_t GetUChar() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kUChar);
|
|
return _value.h;
|
|
}
|
|
|
|
[[nodiscard]] std::uint32_t GetUInt() const noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kUInt);
|
|
return _value.u;
|
|
}
|
|
|
|
void SetBinary(bool a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kBinary);
|
|
_value.b = a_value;
|
|
}
|
|
|
|
void SetChar(char a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kChar);
|
|
_value.c = a_value;
|
|
}
|
|
|
|
void SetFloat(float a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kFloat);
|
|
_value.f = a_value;
|
|
}
|
|
|
|
void SetInt(std::int32_t a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kInt);
|
|
_value.i = a_value;
|
|
}
|
|
|
|
void SetRGB(std::span<const std::uint8_t, 3> a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kRGB);
|
|
std::copy(
|
|
a_value.begin(),
|
|
a_value.end(),
|
|
std::addressof(_value.r));
|
|
}
|
|
|
|
void SetRGBA(std::span<const std::uint8_t, 4> a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kRGBA);
|
|
std::copy(
|
|
a_value.begin(),
|
|
a_value.end(),
|
|
std::addressof(_value.r));
|
|
}
|
|
|
|
void SetString(char* a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kString);
|
|
_value.s = a_value;
|
|
}
|
|
|
|
void SetUChar(std::uint8_t a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kUChar);
|
|
_value.h = a_value;
|
|
}
|
|
|
|
void SetUInt(std::uint32_t a_value) noexcept
|
|
{
|
|
assert(GetType() == SETTING_TYPE::kUInt);
|
|
_value.u = a_value;
|
|
}
|
|
|
|
private:
|
|
// members
|
|
SETTING_VALUE _value; // 08
|
|
const char* _key; // 10
|
|
};
|
|
static_assert(sizeof(Setting) == 0x18);
|
|
|
|
template <class T>
|
|
class __declspec(novtable) SettingT :
|
|
public Setting // 00
|
|
{
|
|
public:
|
|
};
|
|
|
|
class GameSettingCollection;
|
|
class INIPrefSettingCollection;
|
|
class INISettingCollection;
|
|
class LipSynchroSettingCollection;
|
|
class RegSettingCollection;
|
|
|
|
extern template class SettingT<GameSettingCollection>;
|
|
extern template class SettingT<INIPrefSettingCollection>;
|
|
extern template class SettingT<INISettingCollection>;
|
|
extern template class SettingT<LipSynchroSettingCollection>;
|
|
extern template class SettingT<RegSettingCollection>;
|
|
|
|
template <class T>
|
|
class __declspec(novtable) SettingCollection
|
|
{
|
|
public:
|
|
virtual ~SettingCollection() = default; // 00
|
|
|
|
// add
|
|
virtual void Add(T* a_setting) = 0; // 01
|
|
virtual void Remove(T* a_setting) = 0; // 02
|
|
virtual bool WriteSetting(T& a_setting) = 0; // 03
|
|
virtual bool ReadSetting(T& a_setting) = 0; // 04
|
|
virtual bool Open([[maybe_unused]] bool a_write) { return false; } // 05
|
|
virtual bool Close() { return true; } // 06
|
|
virtual bool ReadSettingsFromProfile() { return false; } // 07
|
|
virtual bool WriteSettings() { return handle != nullptr; } // 08
|
|
virtual bool ReadSettings() { return handle != nullptr; } // 09
|
|
|
|
// members
|
|
char settingFile[260]; // 008
|
|
void* handle; // 110
|
|
};
|
|
|
|
extern template class SettingCollection<Setting>;
|
|
|
|
template <class T>
|
|
class __declspec(novtable) SettingCollectionList :
|
|
public SettingCollection<T>
|
|
{
|
|
public:
|
|
// members
|
|
BSSimpleList<T*> settings; // 118
|
|
};
|
|
|
|
extern template class SettingCollectionList<Setting>;
|
|
|
|
class __declspec(novtable) INISettingCollection :
|
|
public SettingCollectionList<Setting> // 000
|
|
{
|
|
public:
|
|
static constexpr auto RTTI{ RTTI::INISettingCollection };
|
|
static constexpr auto VTABLE{ VTABLE::INISettingCollection };
|
|
|
|
[[nodiscard]] static INISettingCollection* GetSingleton()
|
|
{
|
|
static REL::Relocation<INISettingCollection**> singleton{ ID::Setting::INISettingCollection::Singleton };
|
|
return *singleton;
|
|
}
|
|
|
|
[[nodiscard]] Setting* GetSetting(std::string_view a_name)
|
|
{
|
|
for (auto& setting : settings) {
|
|
if (setting->GetKey() == a_name) {
|
|
return setting;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
static_assert(sizeof(INISettingCollection) == 0x128);
|
|
|
|
class __declspec(novtable) INIPrefSettingCollection :
|
|
public INISettingCollection // 000
|
|
{
|
|
public:
|
|
static constexpr auto RTTI{ RTTI::INIPrefSettingCollection };
|
|
static constexpr auto VTABLE{ VTABLE::INIPrefSettingCollection };
|
|
|
|
[[nodiscard]] static INIPrefSettingCollection* GetSingleton()
|
|
{
|
|
static REL::Relocation<INIPrefSettingCollection**> singleton{ ID::Setting::INIPrefSettingCollection::Singleton };
|
|
return *singleton;
|
|
}
|
|
};
|
|
static_assert(sizeof(INIPrefSettingCollection) == 0x128);
|
|
|
|
namespace detail
|
|
{
|
|
class SettingCollectionMapCompare
|
|
{
|
|
public:
|
|
[[nodiscard]] bool operator()(const RE::BSFixedString& a_lhs, const RE::BSFixedString& a_rhs) const noexcept
|
|
{
|
|
return a_lhs.c_str() < a_rhs.c_str();
|
|
}
|
|
};
|
|
}
|
|
|
|
template <class T>
|
|
class __declspec(novtable) SettingCollectionMap :
|
|
public SettingCollection<T> // 000
|
|
{
|
|
public:
|
|
// members
|
|
BSTBTree<BSFixedString, T*, detail::SettingCollectionMapCompare> settings; // 118
|
|
};
|
|
|
|
extern template class SettingCollectionMap<Setting>;
|
|
|
|
class __declspec(novtable) GameSettingCollection :
|
|
public SettingCollectionMap<Setting> // 000
|
|
{
|
|
public:
|
|
static constexpr auto RTTI{ RTTI::GameSettingCollection };
|
|
static constexpr auto VTABLE{ VTABLE::GameSettingCollection };
|
|
|
|
static void InitCollection()
|
|
{
|
|
using func_t = decltype(&GameSettingCollection::InitCollection);
|
|
static REL::Relocation<func_t> func{ ID::Setting::GameSettingCollection::InitCollection };
|
|
return func();
|
|
}
|
|
|
|
[[nodiscard]] static GameSettingCollection* GetSingleton()
|
|
{
|
|
static REL::Relocation<GameSettingCollection**> singleton{ ID::Setting::GameSettingCollection::Singleton };
|
|
return *singleton;
|
|
}
|
|
|
|
[[nodiscard]] Setting* GetSetting(std::string_view a_name)
|
|
{
|
|
auto it = settings.find(a_name);
|
|
return it != settings.end() ? it->second : nullptr;
|
|
}
|
|
};
|
|
static_assert(sizeof(GameSettingCollection) == 0x138);
|
|
|
|
inline Setting* GetINISetting(std::string_view a_name)
|
|
{
|
|
Setting* setting = nullptr;
|
|
|
|
auto iniPrefs = INIPrefSettingCollection::GetSingleton();
|
|
setting = iniPrefs ? iniPrefs->GetSetting(a_name) : nullptr;
|
|
if (!setting) {
|
|
auto ini = INISettingCollection::GetSingleton();
|
|
setting = ini ? ini->GetSetting(a_name) : nullptr;
|
|
}
|
|
return setting;
|
|
}
|
|
}
|