diff --git a/ZHMModSDK/Include/Glacier/ZString.h b/ZHMModSDK/Include/Glacier/ZString.h index e9bfb7a6..9c98ef88 100644 --- a/ZHMModSDK/Include/Glacier/ZString.h +++ b/ZHMModSDK/Include/Glacier/ZString.h @@ -23,6 +23,10 @@ class ZString m_nLength = static_cast(str.size()) | 0x80000000; } + ZString(const std::string& str) { + Allocate(str.c_str(), str.size()); + } + ZString(const char* str) : m_pChars(str) { diff --git a/ZHMModSDK/Include/IModSDK.h b/ZHMModSDK/Include/IModSDK.h index e217277d..43468a0f 100644 --- a/ZHMModSDK/Include/IModSDK.h +++ b/ZHMModSDK/Include/IModSDK.h @@ -73,6 +73,124 @@ class IModSDK virtual bool PatchCode(const char* p_Pattern, const char* p_Mask, void* p_NewCode, size_t p_CodeSize, ptrdiff_t p_Offset) = 0; virtual void ImGuiGameRenderTarget(ZRenderDestination* p_RT, const ImVec2& p_Size = { 0, 0 }) = 0; + + /** + * Set a plugin setting value for the given name. + * @param p_Plugin The plugin to set the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + virtual void SetPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, const ZString& p_Value) = 0; + + /** + * Set a plugin setting integer value for the given name. + * @param p_Plugin The plugin to set the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + virtual void SetPluginSettingInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, int64 p_Value) = 0; + + /** + * Set a plugin setting unsigned integer value for the given name. + * @param p_Plugin The plugin to set the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + virtual void SetPluginSettingUInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, uint64 p_Value) = 0; + + /** + * Set a plugin setting double value for the given name. + * @param p_Plugin The plugin to set the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + virtual void SetPluginSettingDouble(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, double p_Value) = 0; + + /** + * Set a plugin setting boolean value for the given name. + * @param p_Plugin The plugin to set the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + virtual void SetPluginSettingBool(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, bool p_Value) = 0; + + /** + * Get a plugin setting string value for the given name. + * @param p_Plugin The plugin to get the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist. + * @return The value of the setting, or the default value if the setting does not exist. + */ + virtual ZString GetPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, const ZString& p_DefaultValue) = 0; + + /** + * Get a plugin setting integer value for the given name. + * @param p_Plugin The plugin to get the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not an integer. + * @return The value of the setting, or the default value if the setting does not exist or is not an integer. + */ + virtual int64 GetPluginSettingInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, int64 p_DefaultValue) = 0; + + /** + * Get a plugin setting unsigned integer value for the given name. + * @param p_Plugin The plugin to get the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not an unsigned integer. + * @return The value of the setting, or the default value if the setting does not exist or is not an unsigned integer. + */ + virtual uint64 GetPluginSettingUInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, uint64 p_DefaultValue) = 0; + + /** + * Get a plugin setting double value for the given name. + * @param p_Plugin The plugin to get the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not a double. + * @return The value of the setting, or the default value if the setting does not exist or is not a double. + */ + virtual double GetPluginSettingDouble(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, double p_DefaultValue) = 0; + + /** + * Get a plugin setting boolean value for the given name. + * @param p_Plugin The plugin to get the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not a boolean. + * @return The value of the setting, or the default value if the setting does not exist or is not a boolean. + */ + virtual bool GetPluginSettingBool(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, bool p_DefaultValue) = 0; + + /** + * Check if a plugin setting with the given name exists. + * @param p_Plugin The plugin to check the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @return True if the setting exists, false otherwise. + */ + virtual bool HasPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name) = 0; + + /** + * Remove a plugin setting with the given name. + * @param p_Plugin The plugin to remove the setting for. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + */ + virtual void RemovePluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name) = 0; + + /** + * Reload the settings for the given plugin. + * @param p_Plugin The plugin to reload the settings for. + */ + virtual void ReloadPluginSettings(IPluginInterface* p_Plugin) = 0; }; /** diff --git a/ZHMModSDK/Include/IPluginInterface.h b/ZHMModSDK/Include/IPluginInterface.h index babd7ac7..12aa874b 100644 --- a/ZHMModSDK/Include/IPluginInterface.h +++ b/ZHMModSDK/Include/IPluginInterface.h @@ -27,6 +27,138 @@ class IPluginInterface virtual void OnDrawUI(bool p_HasFocus) {} virtual void OnDraw3D(IRenderer* p_Renderer) {} virtual void OnDrawMenu() {} + +public: + /** + * Set a setting string value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + void SetSetting(const ZString& p_Section, const ZString& p_Name, const ZString& p_Value) { + SDK()->SetPluginSetting(this, p_Section, p_Name, p_Value); + } + + /** + * Set a setting integer value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + void SetSettingInt(const ZString& p_Section, const ZString& p_Name, int64 p_Value) { + SDK()->SetPluginSettingInt(this, p_Section, p_Name, p_Value); + } + + /** + * Set a setting unsigned integer value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + void SetSettingUInt(const ZString& p_Section, const ZString& p_Name, uint64 p_Value) { + SDK()->SetPluginSettingUInt(this, p_Section, p_Name, p_Value); + } + + /** + * Set a setting double value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + void SetSettingDouble(const ZString& p_Section, const ZString& p_Name, double p_Value) { + SDK()->SetPluginSettingDouble(this, p_Section, p_Name, p_Value); + } + + /** + * Set a setting boolean value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_Value The value of the setting. + */ + void SetSettingBool(const ZString& p_Section, const ZString& p_Name, bool p_Value) { + SDK()->SetPluginSettingBool(this, p_Section, p_Name, p_Value); + } + + /** + * Get a setting string value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist. + * @return The value of the setting, or the default value if the setting does not exist. + */ + ZString GetSetting(const ZString& p_Section, const ZString& p_Name, const ZString& p_DefaultValue) { + return SDK()->GetPluginSetting(this, p_Section, p_Name, p_DefaultValue); + } + + /** + * Get a setting integer value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not an integer. + * @return The value of the setting, or the default value if the setting does not exist or is not an integer. + */ + int64 GetSettingInt(const ZString& p_Section, const ZString& p_Name, int64 p_DefaultValue) { + return SDK()->GetPluginSettingInt(this, p_Section, p_Name, p_DefaultValue); + } + + /** + * Get a setting unsigned integer value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not an unsigned integer. + * @return The value of the setting, or the default value if the setting does not exist or is not an unsigned integer. + */ + uint64 GetSettingUInt(const ZString& p_Section, const ZString& p_Name, uint64 p_DefaultValue) { + return SDK()->GetPluginSettingUInt(this, p_Section, p_Name, p_DefaultValue); + } + + /** + * Get a setting double value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not a double. + * @return The value of the setting, or the default value if the setting does not exist or is not a double. + */ + double GetSettingDouble(const ZString& p_Section, const ZString& p_Name, double p_DefaultValue) { + return SDK()->GetPluginSettingDouble(this, p_Section, p_Name, p_DefaultValue); + } + + /** + * Get a setting boolean value for the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @param p_DefaultValue The default value to return if the setting does not exist or is not a boolean. + * @return The value of the setting, or the default value if the setting does not exist or is not a boolean. + */ + bool GetSettingBool(const ZString& p_Section, const ZString& p_Name, bool p_DefaultValue) { + return SDK()->GetPluginSettingBool(this, p_Section, p_Name, p_DefaultValue); + } + + /** + * Check if a setting with the given name exists. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + * @return True if the setting exists, false otherwise. + */ + bool HasSetting(const ZString& p_Section, const ZString& p_Name) { + return SDK()->HasPluginSetting(this, p_Section, p_Name); + } + + /** + * Remove a setting with the given name. + * @param p_Section The section of the setting in the INI file. + * @param p_Name The name of the setting. + */ + void RemoveSetting(const ZString& p_Section, const ZString& p_Name) { + SDK()->RemovePluginSetting(this, p_Section, p_Name); + } + + /** + * Reload the settings for the current plugin. + */ + void ReloadSettings() { + SDK()->ReloadPluginSettings(this); + } friend class ModSDK; }; diff --git a/ZHMModSDK/Src/Glacier/ZString.cpp b/ZHMModSDK/Src/Glacier/ZString.cpp index a78c9e68..446bb014 100644 --- a/ZHMModSDK/Src/Glacier/ZString.cpp +++ b/ZHMModSDK/Src/Glacier/ZString.cpp @@ -14,6 +14,7 @@ ZString::~ZString() void ZString::Allocate(const char* str, size_t size) { m_nLength = static_cast(size); - m_pChars = reinterpret_cast((*Globals::MemoryManager)->m_pNormalAllocator->Allocate(size)); + m_pChars = reinterpret_cast((*Globals::MemoryManager)->m_pNormalAllocator->Allocate(size + 1)); memcpy(const_cast(m_pChars), str, size); + const_cast(m_pChars)[size] = '\0'; } diff --git a/ZHMModSDK/Src/ModLoader.cpp b/ZHMModSDK/Src/ModLoader.cpp index 7e981a1f..b0278f16 100644 --- a/ZHMModSDK/Src/ModLoader.cpp +++ b/ZHMModSDK/Src/ModLoader.cpp @@ -202,69 +202,68 @@ void ModLoader::LoadAllMods() void ModLoader::LoadMod(const std::string& p_Name, bool p_LiveLoad) { - std::unique_lock s_Lock(m_Mutex); + const std::string s_Name = Util::StringUtils::ToLowerCase(p_Name); + IPluginInterface* s_PluginInterface; - const std::string s_Name = Util::StringUtils::ToLowerCase(p_Name); + { + std::unique_lock s_Lock(m_Mutex); - if (m_LoadedMods.contains(s_Name)) - { - Logger::Warn("A mod with the same name ({}) is already loaded. Skipping.", p_Name); - return; - } + if (m_LoadedMods.contains(s_Name)) { + Logger::Warn("A mod with the same name ({}) is already loaded. Skipping.", p_Name); + return; + } - char s_ExePathStr[MAX_PATH]; - auto s_PathSize = GetModuleFileNameA(nullptr, s_ExePathStr, MAX_PATH); + char s_ExePathStr[MAX_PATH]; + auto s_PathSize = GetModuleFileNameA(nullptr, s_ExePathStr, MAX_PATH); - if (s_PathSize == 0) - return; + if (s_PathSize == 0) + return; - std::filesystem::path s_ExePath(s_ExePathStr); - auto s_ExeDir = s_ExePath.parent_path(); + std::filesystem::path s_ExePath(s_ExePathStr); + auto s_ExeDir = s_ExePath.parent_path(); - const auto s_ModulePath = absolute(s_ExeDir / ("mods/" + p_Name + ".dll")); + const auto s_ModulePath = absolute(s_ExeDir / ("mods/" + p_Name + ".dll")); - if (!exists(s_ModulePath) || !is_regular_file(s_ModulePath)) - { - Logger::Warn("Could not find mod '{}'.", p_Name); - } + if (!exists(s_ModulePath) || !is_regular_file(s_ModulePath)) { + Logger::Warn("Could not find mod '{}'.", p_Name); + } - Logger::Info("Attempting to load mod '{}'.", p_Name); - Logger::Debug("Module path is '{}'.", s_ModulePath.string()); + Logger::Info("Attempting to load mod '{}'.", p_Name); + Logger::Debug("Module path is '{}'.", s_ModulePath.string()); - const auto s_Module = LoadLibraryA(s_ModulePath.string().c_str()); + const auto s_Module = LoadLibraryA(s_ModulePath.string().c_str()); - if (s_Module == nullptr) - { - Logger::Warn("Failed to load mod. Error: {}", GetLastError()); - return; - } + if (s_Module == nullptr) { + Logger::Warn("Failed to load mod. Error: {}", GetLastError()); + return; + } - const auto s_GetPluginInterfaceAddr = GetProcAddress(s_Module, "GetPluginInterface"); + const auto s_GetPluginInterfaceAddr = GetProcAddress(s_Module, "GetPluginInterface"); - if (s_GetPluginInterfaceAddr == nullptr) - { - Logger::Warn("Could not find plugin interface for mod. Make sure that the 'GetPluginInterface' method is exported."); - FreeLibrary(s_Module); - return; - } + if (s_GetPluginInterfaceAddr == nullptr) { + Logger::Warn("Could not find plugin interface for mod. Make sure that the 'GetPluginInterface' method is exported."); + FreeLibrary(s_Module); + return; + } - const auto s_GetPluginInterface = reinterpret_cast(s_GetPluginInterfaceAddr); + const auto s_GetPluginInterface = reinterpret_cast(s_GetPluginInterfaceAddr); - auto* s_PluginInterface = s_GetPluginInterface(); + s_PluginInterface = s_GetPluginInterface(); - if (s_PluginInterface == nullptr) - { - Logger::Warn("Mod returned a null plugin interface."); - FreeLibrary(s_Module); - return; - } + if (s_PluginInterface == nullptr) { + Logger::Warn("Mod returned a null plugin interface."); + FreeLibrary(s_Module); + return; + } - LoadedMod s_Mod {}; - s_Mod.Module = s_Module; - s_Mod.PluginInterface = s_PluginInterface; + LoadedMod s_Mod{}; + s_Mod.Module = s_Module; + s_Mod.PluginInterface = s_PluginInterface; + s_Mod.Settings = new ModSettings(p_Name, s_ExeDir / "mods"); - m_LoadedMods[s_Name] = s_Mod; - m_ModList.push_back(s_PluginInterface); + m_LoadedMods[s_Name] = s_Mod; + m_ModList.push_back(s_PluginInterface); + } ModSDK::GetInstance()->OnModLoaded(s_Name, s_PluginInterface, p_LiveLoad); } @@ -294,6 +293,7 @@ void ModLoader::UnloadMod(const std::string& p_Name) } delete s_ModMapIt->second.PluginInterface; + delete s_ModMapIt->second.Settings; FreeLibrary(s_ModMapIt->second.Module); m_LoadedMods.erase(s_ModMapIt); @@ -365,3 +365,16 @@ IPluginInterface* ModLoader::GetModByName(const std::string& p_Name) return it->second.PluginInterface; } + +ModSettings* ModLoader::GetModSettings(IPluginInterface* p_PluginInterface) +{ + std::shared_lock s_Lock(m_Mutex); + + for (auto& s_Pair : m_LoadedMods) { + if (s_Pair.second.PluginInterface == p_PluginInterface) { + return s_Pair.second.Settings; + } + } + + return nullptr; +} \ No newline at end of file diff --git a/ZHMModSDK/Src/ModLoader.h b/ZHMModSDK/Src/ModLoader.h index 3598f2cf..31d42029 100644 --- a/ZHMModSDK/Src/ModLoader.h +++ b/ZHMModSDK/Src/ModLoader.h @@ -5,6 +5,7 @@ #include #include #include +#include "ModSettings.h" class IPluginInterface; @@ -15,6 +16,7 @@ class ModLoader { HMODULE Module; IPluginInterface* PluginInterface; + ModSettings* Settings; }; public: @@ -34,6 +36,7 @@ class ModLoader void UnloadAllMods(); void ReloadAllMods(); IPluginInterface* GetModByName(const std::string& p_Name); + ModSettings* GetModSettings(IPluginInterface* p_PluginInterface); std::vector GetLoadedMods() const { diff --git a/ZHMModSDK/Src/ModSDK.cpp b/ZHMModSDK/Src/ModSDK.cpp index b61df358..ef89cd1a 100644 --- a/ZHMModSDK/Src/ModSDK.cpp +++ b/ZHMModSDK/Src/ModSDK.cpp @@ -482,6 +482,209 @@ void ModSDK::ImGuiGameRenderTarget(ZRenderDestination* p_RT, const ImVec2& p_Siz ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_ResetDescriptorHeap, nullptr); } +void ModSDK::SetPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, const ZString& p_Value) { + if (!p_Plugin) { + return; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->SetSetting(p_Section.c_str(), p_Name.c_str(), p_Value.c_str()); +} + +void ModSDK::SetPluginSettingInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, int64_t p_Value) { + if (!p_Plugin) { + return; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->SetSetting(p_Section.c_str(), p_Name.c_str(), std::to_string(p_Value)); +} + +void ModSDK::SetPluginSettingUInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, uint64_t p_Value) { + if (!p_Plugin) { + return; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->SetSetting(p_Section.c_str(), p_Name.c_str(), std::to_string(p_Value)); +} + +void ModSDK::SetPluginSettingDouble(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, double p_Value) { + if (!p_Plugin) + return; + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->SetSetting(p_Section.c_str(), p_Name.c_str(), std::to_string(p_Value)); +} + +void ModSDK::SetPluginSettingBool(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, bool p_Value) { + if (!p_Plugin) { + return; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->SetSetting(p_Section.c_str(), p_Name.c_str(), p_Value ? "true" : "false"); +} + +ZString ModSDK::GetPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, const ZString& p_DefaultValue) { + if (!p_Plugin) { + return p_DefaultValue; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return p_DefaultValue; + } + + return s_Settings->GetSetting(p_Section.c_str(), p_Name.c_str(), p_DefaultValue.c_str()); +} + +int64_t ModSDK::GetPluginSettingInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, int64_t p_DefaultValue) { + if (!p_Plugin) { + return p_DefaultValue; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return p_DefaultValue; + } + + const auto s_Value = s_Settings->GetSetting(p_Section.c_str(), p_Name.c_str(), std::to_string(p_DefaultValue)); + + try { + return std::stoll(s_Value); + } + catch (const std::exception&) { + return p_DefaultValue; + } +} + +uint64_t ModSDK::GetPluginSettingUInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, uint64_t p_DefaultValue) { + if (!p_Plugin) { + return p_DefaultValue; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return p_DefaultValue; + } + + const auto s_Value = s_Settings->GetSetting(p_Section.c_str(), p_Name.c_str(), std::to_string(p_DefaultValue)); + + try { + return std::stoull(s_Value); + } + catch (const std::exception&) { + return p_DefaultValue; + } +} + +double ModSDK::GetPluginSettingDouble(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, double p_DefaultValue) { + if (!p_Plugin) { + return p_DefaultValue; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return p_DefaultValue; + } + + const auto s_Value = s_Settings->GetSetting(p_Section.c_str(), p_Name.c_str(), std::to_string(p_DefaultValue)); + + try { + return std::stod(s_Value); + } + catch (const std::exception&) { + return p_DefaultValue; + } +} + +bool ModSDK::GetPluginSettingBool(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, bool p_DefaultValue) { + if (!p_Plugin) { + return p_DefaultValue; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return p_DefaultValue; + } + + const auto s_Value = s_Settings->GetSetting(p_Section.c_str(), p_Name.c_str(), p_DefaultValue ? "true" : "false"); + + return s_Value == "true" || s_Value == "1" || s_Value == "yes" || s_Value == "on" || s_Value == "y"; +} + +bool ModSDK::HasPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name) { + if (!p_Plugin) { + return false; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return false; + } + + return s_Settings->HasSetting(p_Section.c_str(), p_Name.c_str()); +} + +void ModSDK::RemovePluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name) { + if (!p_Plugin) { + return; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->RemoveSetting(p_Section.c_str(), p_Name.c_str()); +} + +void ModSDK::ReloadPluginSettings(IPluginInterface* p_Plugin) { + if (!p_Plugin) { + return; + } + + auto s_Settings = m_ModLoader->GetModSettings(p_Plugin); + + if (!s_Settings) { + return; + } + + s_Settings->Reload(); +} DEFINE_DETOUR_WITH_CONTEXT(ModSDK, bool, Engine_Init, void* th, void* a2) { diff --git a/ZHMModSDK/Src/ModSDK.h b/ZHMModSDK/Src/ModSDK.h index e04d742f..1dd89345 100644 --- a/ZHMModSDK/Src/ModSDK.h +++ b/ZHMModSDK/Src/ModSDK.h @@ -106,6 +106,21 @@ class ModSDK : public IModSDK bool PatchCode(const char* p_Pattern, const char* p_Mask, void* p_NewCode, size_t p_CodeSize, ptrdiff_t p_Offset) override; void ImGuiGameRenderTarget(ZRenderDestination* p_RT, const ImVec2& p_Size = { 0, 0 }) override; + // Plugin settings + void SetPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, const ZString& p_Value) override; + void SetPluginSettingInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, int64_t p_Value) override; + void SetPluginSettingUInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, uint64_t p_Value) override; + void SetPluginSettingDouble(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, double p_Value) override; + void SetPluginSettingBool(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, bool p_Value) override; + ZString GetPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, const ZString& p_DefaultValue) override; + int64_t GetPluginSettingInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, int64_t p_DefaultValue) override; + uint64_t GetPluginSettingUInt(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, uint64_t p_DefaultValue) override; + double GetPluginSettingDouble(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, double p_DefaultValue) override; + bool GetPluginSettingBool(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name, bool p_DefaultValue) override; + bool HasPluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name) override; + void RemovePluginSetting(IPluginInterface* p_Plugin, const ZString& p_Section, const ZString& p_Name) override; + void ReloadPluginSettings(IPluginInterface* p_Plugin) override; + private: DECLARE_DETOUR_WITH_CONTEXT(ModSDK, bool, Engine_Init, void* th, void* a2); DECLARE_DETOUR_WITH_CONTEXT(ModSDK, EOS_PlatformHandle*, EOS_Platform_Create, EOS_Platform_Options* Options); diff --git a/ZHMModSDK/Src/ModSettings.cpp b/ZHMModSDK/Src/ModSettings.cpp new file mode 100644 index 00000000..9f6db226 --- /dev/null +++ b/ZHMModSDK/Src/ModSettings.cpp @@ -0,0 +1,102 @@ +#include "ModSettings.h" + +#include +#include +#include + +ModSettings::ModSettings(std::string p_ModName, std::filesystem::path p_ModDirectory) : + m_ModName(std::move(p_ModName)), + m_ModDirectory(std::move(p_ModDirectory)) +{ + Reload(); +} + +ModSettings::~ModSettings() { + Save(); +} + +void ModSettings::Reload() { + m_Settings.clear(); + + std::filesystem::path s_SettingsIniPath = m_ModDirectory / (m_ModName + ".ini"); + + if (!std::filesystem::exists(s_SettingsIniPath)) { + return; + } + + mINI::INIFile s_File(s_SettingsIniPath.string()); + + mINI::INIStructure s_Ini; + + s_File.read(s_Ini); + + for (auto const& it: s_Ini) { + auto const& s_SectionName = it.first; + auto const& s_SectionItems = it.second; + + std::unordered_map s_Section; + + for (auto const& it2: s_SectionItems) { + s_Section[it2.first] = it2.second; + } + + m_Settings[s_SectionName] = s_Section; + } +} + +void ModSettings::Save() { + std::filesystem::path s_SettingsIniPath = m_ModDirectory / (m_ModName + ".ini"); + + mINI::INIFile s_File(s_SettingsIniPath.string()); + + mINI::INIStructure s_Ini; + + for (auto const& it: m_Settings) { + auto const& s_SectionName = it.first; + auto const& s_SectionItems = it.second; + + mINI::INIMap s_Section; + + for (auto const& it2: s_SectionItems) { + s_Section.set(it2.first, it2.second); + } + + s_Ini.set(s_SectionName, s_Section); + } + + s_File.generate(s_Ini, true); +} + +bool ModSettings::HasSetting(const std::string& p_Section, const std::string& p_Name) { + return m_Settings.find(p_Section) != m_Settings.end() && m_Settings[p_Section].find(p_Name) != m_Settings[p_Section].end(); +} + +std::string ModSettings::GetSetting(const std::string& p_Section, const std::string& p_Name, const std::string& p_DefaultValue) { + if (!HasSetting(p_Section, p_Name)) { + return p_DefaultValue; + } + + return m_Settings[p_Section][p_Name]; +} + +void ModSettings::SetSetting(const std::string& p_Section, const std::string& p_Name, const std::string& p_Value) { + if (m_Settings.find(p_Section) == m_Settings.end()) { + m_Settings[p_Section] = std::unordered_map(); + } + + m_Settings[p_Section][p_Name] = p_Value; + Save(); +} + +void ModSettings::RemoveSetting(const std::string& p_Section, const std::string& p_Name) { + if (m_Settings.find(p_Section) == m_Settings.end()) { + return; + } + + if (m_Settings[p_Section].find(p_Name) == m_Settings[p_Section].end()) { + return; + } + + m_Settings[p_Section].erase(p_Name); + Save(); +} \ No newline at end of file diff --git a/ZHMModSDK/Src/ModSettings.h b/ZHMModSDK/Src/ModSettings.h new file mode 100644 index 00000000..e8844812 --- /dev/null +++ b/ZHMModSDK/Src/ModSettings.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +class ModSettings { +public: + ModSettings(std::string p_ModName, std::filesystem::path p_ModDirectory); + ~ModSettings(); + +public: + void Reload(); + void Save(); + bool HasSetting(const std::string& p_Section, const std::string& p_Name); + std::string GetSetting(const std::string& p_Section, const std::string& p_Name, const std::string& p_DefaultValue); + void SetSetting(const std::string& p_Section, const std::string& p_Name, const std::string& p_Value); + void RemoveSetting(const std::string& p_Section, const std::string& p_Name); + +private: + std::string m_ModName; + std::filesystem::path m_ModDirectory; + std::unordered_map> m_Settings; +}; \ No newline at end of file