From b222cf5c27a103645fb6b1a702b599b29da5011f Mon Sep 17 00:00:00 2001 From: Chris Feger Date: Wed, 6 Dec 2023 10:26:20 -0700 Subject: [PATCH 1/3] Add an unconditional Lua script to mods --- .../Extender/Client/ExtensionStateClient.h | 7 +- .../Extender/Server/ExtensionStateServer.h | 7 +- .../Extender/Shared/ExtensionState.cpp | 71 ++++++++++++++++++- BG3Extender/Extender/Shared/ExtensionState.h | 7 +- 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/BG3Extender/Extender/Client/ExtensionStateClient.h b/BG3Extender/Extender/Client/ExtensionStateClient.h index 61c50b8c8..f0cc0dbbf 100644 --- a/BG3Extender/Extender/Client/ExtensionStateClient.h +++ b/BG3Extender/Extender/Client/ExtensionStateClient.h @@ -35,6 +35,11 @@ class ExtensionState : public ExtensionStateBase void OnInputEvent(SDL_Event* event, int& result); + inline char const * GetUnconditionalFileName() override + { + return "OverrideClient.lua"; + } + protected: friend LuaStatePin; std::unique_ptr Lua; @@ -47,4 +52,4 @@ class ExtensionState : public ExtensionStateBase void FireInputEvents(); }; -END_NS() \ No newline at end of file +END_NS() diff --git a/BG3Extender/Extender/Server/ExtensionStateServer.h b/BG3Extender/Extender/Server/ExtensionStateServer.h index ddc173cdb..d8401d97c 100644 --- a/BG3Extender/Extender/Server/ExtensionStateServer.h +++ b/BG3Extender/Extender/Server/ExtensionStateServer.h @@ -26,6 +26,11 @@ namespace bg3se::esv return "BootstrapServer.lua"; } + inline char const * GetUnconditionalFileName() override + { + return "OverrideServer.lua"; + } + inline std::unordered_set const& GetPersistentStats() const { return persistentStats_; @@ -62,4 +67,4 @@ namespace bg3se::esv void DoLuaReset() override; void LuaStartup() override; }; -} \ No newline at end of file +} diff --git a/BG3Extender/Extender/Shared/ExtensionState.cpp b/BG3Extender/Extender/Shared/ExtensionState.cpp index 3eddb84fe..445d5c07e 100644 --- a/BG3Extender/Extender/Shared/ExtensionState.cpp +++ b/BG3Extender/Extender/Shared/ExtensionState.cpp @@ -53,8 +53,21 @@ namespace bg3se return; } + std::unordered_set mods; + + auto isLoaded = [&mods, &modManager](const Module& mod){ + if (mods.size() == 0) + { + for (const Module& mod : modManager->BaseModule.LoadOrderedModules) + { + mods.emplace(mod.Info.ModuleUUIDString); + } + } + return mods.contains(mod.Info.ModuleUUIDString); + }; + unsigned numConfigs{ 0 }; - for (auto const& mod : modManager->BaseModule.LoadOrderedModules) { + for (auto const& mod : modManager->AvailableMods) { auto dir = mod.Info.Directory; auto configFile = "Mods/" + dir + "/ScriptExtender/Config.json"; auto reader = GetStaticSymbols().MakeFileReader(configFile); @@ -82,6 +95,8 @@ namespace bg3se continue; } + config.IsLoaded = isLoaded(mod); + if (config.MinimumVersion > CurrentVersion) { OsiError("Module '" << mod.Info.Name << " is targeting version v" << config.MinimumVersion << " that's more recent than the current version!"); } @@ -536,9 +551,17 @@ namespace bg3se } if (context_ == ExtensionStateContext::Game) { - LuaLoadGameBootstrap(config, mod); + LuaLoadGameUnconditional(config, mod); + if (config.IsLoaded) + { + LuaLoadGameBootstrap(config, mod); + } } else if (context_ == ExtensionStateContext::Load) { - LuaLoadPreinitBootstrap(config, mod); + LuaLoadPreinitUnconditional(config, mod); + if (config.IsLoaded) + { + LuaLoadPreinitBootstrap(config, mod); + } } else { ERR("Bootstrap request with Uninitialized extension context?"); } @@ -549,6 +572,48 @@ namespace bg3se lua->FinishStartup(); } + void ExtensionStateBase::LuaLoadPreinitUnconditional(ExtensionModConfig const& config, Module const& mod) + { + auto bootstrapFileName = "OverrideModule.lua"; + auto const& sym = GetStaticSymbols(); + + auto path = ResolveModScriptPath(mod, bootstrapFileName); + if (!sym.FileExists(path)) { + return; + } + + LuaVirtualPin lua(*this); + auto L = lua->GetState(); + lua::push(L, mod.Info.ModuleUUID); + lua_setglobal(L, "ModuleUUID"); + + OsiMsg("Loading preinit override script: " << path); + lua->LoadBootstrap(bootstrapFileName, config.ModTable); + + lua::push(L, nullptr); + lua_setglobal(L, "ModuleUUID"); + } + + void ExtensionStateBase::LuaLoadGameUnconditional(ExtensionModConfig const& config, Module const& mod) + { + auto bootstrapFileName = GetUnconditionalFileName(); + auto const& sym = GetStaticSymbols(); + + auto bootstrapPath = ResolveModScriptPath(mod, bootstrapFileName); + if (!bootstrapPath.empty() && sym.FileExists(bootstrapPath)) { + LuaVirtualPin lua(*this); + auto L = lua->GetState(); + lua::push(L, mod.Info.ModuleUUIDString); + lua_setglobal(L, "ModuleUUID"); + + OsiMsg("Loading override script: " << bootstrapPath); + lua->LoadBootstrap(bootstrapFileName, config.ModTable); + + lua::push(L, nullptr); + lua_setglobal(L, "ModuleUUID"); + } + } + void ExtensionStateBase::LuaLoadGameBootstrap(ExtensionModConfig const& config, Module const& mod) { auto bootstrapFileName = GetBootstrapFileName(); diff --git a/BG3Extender/Extender/Shared/ExtensionState.h b/BG3Extender/Extender/Shared/ExtensionState.h index b5c92ecd1..4323c6466 100644 --- a/BG3Extender/Extender/Shared/ExtensionState.h +++ b/BG3Extender/Extender/Shared/ExtensionState.h @@ -17,6 +17,8 @@ namespace bg3se // Name to use in Lua Mods global table (>= v43) STDString ModTable; std::unordered_set FeatureFlags; + + bool IsLoaded; }; enum class ExtensionStateContext @@ -47,6 +49,7 @@ namespace bg3se virtual lua::State * GetLua() = 0; virtual ModManager * GetModManager() = 0; virtual char const * GetBootstrapFileName() = 0; + virtual char const * GetUnconditionalFileName() = 0; void LoadConfigs(); bool LoadConfig(Module const & mod, STDString const & configText, ExtensionModConfig & config); @@ -152,6 +155,8 @@ namespace bg3se void LuaResetInternal(); virtual void DoLuaReset() = 0; virtual void LuaStartup(); + void LuaLoadPreinitUnconditional(ExtensionModConfig const& config, Module const& mod); + void LuaLoadGameUnconditional(ExtensionModConfig const& config, Module const& mod); void LuaLoadGameBootstrap(ExtensionModConfig const& config, Module const& mod); void LuaLoadPreinitBootstrap(ExtensionModConfig const& config, Module const& mod); }; @@ -261,4 +266,4 @@ namespace bg3se T & state_; }; -} \ No newline at end of file +} From e8b9f25b9988be9c286de96bd2d9ccf6208485e7 Mon Sep 17 00:00:00 2001 From: Chris Feger Date: Thu, 7 Dec 2023 13:40:52 -0700 Subject: [PATCH 2/3] Use available mods over loaded ones where relevant --- .../Extender/Shared/ExtensionState.cpp | 2 +- .../Extender/Shared/StatLoadOrderHelper.inl | 2 +- BG3Extender/Extender/Shared/UserVariables.inl | 6 +-- BG3Extender/GameDefinitions/GameHelpers.cpp | 2 +- BG3Extender/Lua/Libs/Mod.inl | 48 ++++++++++++++++++- 5 files changed, 52 insertions(+), 8 deletions(-) diff --git a/BG3Extender/Extender/Shared/ExtensionState.cpp b/BG3Extender/Extender/Shared/ExtensionState.cpp index 445d5c07e..c632ce407 100644 --- a/BG3Extender/Extender/Shared/ExtensionState.cpp +++ b/BG3Extender/Extender/Shared/ExtensionState.cpp @@ -539,7 +539,7 @@ namespace bg3se } lua::Restriction restriction(*lua, lua::State::RestrictAll); - for (auto const& mod : modManager->BaseModule.LoadOrderedModules) { + for (auto const& mod : modManager->AvailableMods) { auto configIt = modConfigs_.find(mod.Info.ModuleUUIDString); if (configIt != modConfigs_.end()) { auto const & config = configIt->second; diff --git a/BG3Extender/Extender/Shared/StatLoadOrderHelper.inl b/BG3Extender/Extender/Shared/StatLoadOrderHelper.inl index 399085784..ca8bc86a0 100644 --- a/BG3Extender/Extender/Shared/StatLoadOrderHelper.inl +++ b/BG3Extender/Extender/Shared/StatLoadOrderHelper.inl @@ -24,7 +24,7 @@ void StatLoadOrderHelper::UpdateModDirectoryMap() auto modManager = gExtender->GetCurrentExtensionState()->GetModManager(); if (modManager) { - for (auto const& mod : modManager->BaseModule.LoadOrderedModules) { + for (auto const& mod : modManager->AvailableMods) { modDirectoryToModMap_.insert(std::make_pair(mod.Info.Directory, mod.Info.ModuleUUIDString)); } } diff --git a/BG3Extender/Extender/Shared/UserVariables.inl b/BG3Extender/Extender/Shared/UserVariables.inl index 531860817..152e08f48 100644 --- a/BG3Extender/Extender/Shared/UserVariables.inl +++ b/BG3Extender/Extender/Shared/UserVariables.inl @@ -757,7 +757,7 @@ void ModVariableManager::OnSessionLoading() auto modManager = isServer_ ? GetStaticSymbols().GetModManagerServer() : GetStaticSymbols().GetModManagerClient(); if (modManager != nullptr) { uint32_t nextIndex{ 0 }; - for (auto const& mod : modManager->BaseModule.LoadOrderedModules) { + for (auto const& mod : modManager->AvailableMods) { modIndices_.set(mod.Info.ModuleUUID, nextIndex++); } } else { @@ -1291,9 +1291,9 @@ CachedModVariableManager::~CachedModVariableManager() Guid CachedModVariableManager::ModIndexToGuid(uint32_t modIndex) { if (isServer_) { - return GetStaticSymbols().GetModManagerServer()->BaseModule.LoadOrderedModules[modIndex].Info.ModuleUUID; + return GetStaticSymbols().GetModManagerServer()->AvailableMods[modIndex].Info.ModuleUUID; } else { - return GetStaticSymbols().GetModManagerClient()->BaseModule.LoadOrderedModules[modIndex].Info.ModuleUUID; + return GetStaticSymbols().GetModManagerClient()->AvailableMods[modIndex].Info.ModuleUUID; } } diff --git a/BG3Extender/GameDefinitions/GameHelpers.cpp b/BG3Extender/GameDefinitions/GameHelpers.cpp index 76857f66a..056dc6109 100644 --- a/BG3Extender/GameDefinitions/GameHelpers.cpp +++ b/BG3Extender/GameDefinitions/GameHelpers.cpp @@ -188,7 +188,7 @@ namespace bg3se return nullptr; } - for (auto const& mod : BaseModule.LoadOrderedModules) { + for (auto const& mod : AvailableMods) { if (mod.Info.ModuleUUIDString == modUuidFS) { return &mod; } diff --git a/BG3Extender/Lua/Libs/Mod.inl b/BG3Extender/Lua/Libs/Mod.inl index fa8581120..6d0d32765 100644 --- a/BG3Extender/Lua/Libs/Mod.inl +++ b/BG3Extender/Lua/Libs/Mod.inl @@ -35,6 +35,48 @@ bool IsModLoaded(lua_State* L, FixedString modNameGuid) return false; } +/// +/// Returns whether the module with the specified GUID is available, i.e. in the mod directory. +/// +/// Example: +/// ```lua +/// if (Ext.IsModAvailable("5cc23efe-f451-c414-117d-b68fbc53d32d")) then +/// Ext.Print("Mod available") +/// end +/// ``` +/// +/// UUID of mod to check +bool IsModAvailable(char const* modNameGuid) +{ + auto modUuid = Guid::Parse(modNameGuid); + if (modUuid) { + auto modManager = gExtender->GetCurrentExtensionState()->GetModManager(); + for (auto const& mod : modManager->AvailableMods) { + if (mod.Info.ModuleUUID == *modUuid) { + return true; + } + } + } + + return false; +} + +/// +/// Returns the list of available module UUIDs. +/// +/// +ObjectSet GetAvailableMods() +{ + ObjectSet mods; + auto modManager = gExtender->GetCurrentExtensionState()->GetModManager(); + + for (auto const& mod : modManager->AvailableMods) { + mods.Add(mod.Info.ModuleUUID); + } + + return mods; +} + /// /// Returns the list of loaded module UUIDs in the order they're loaded in. /// @@ -52,7 +94,7 @@ Array GetLoadOrder(lua_State* L) } /// -/// Returns detailed information about the specified (loaded) module. +/// Returns detailed information about the specified (available) module. /// /// Mod UUID to query Module* GetMod(lua_State* L, FixedString modNameGuid) @@ -61,7 +103,7 @@ Module* GetMod(lua_State* L, FixedString modNameGuid) auto modUuid = Guid::Parse(modNameGuid.GetStringView()); if (modUuid) { - for (auto& mod : modManager->BaseModule.LoadOrderedModules) { + for (auto& mod : modManager->AvailableMods) { if (mod.Info.ModuleUUID == *modUuid) { return &mod; } @@ -92,7 +134,9 @@ void RegisterModLib() DECLARE_MODULE(Mod, Both) BEGIN_MODULE() MODULE_FUNCTION(IsModLoaded) + MODULE_FUNCTION(IsModAvailable) MODULE_FUNCTION(GetLoadOrder) + MODULE_FUNCTION(GetAvailableMods) MODULE_FUNCTION(GetMod) MODULE_FUNCTION(GetBaseMod) MODULE_FUNCTION(GetModManager) From 97f204458eff9eba05f8a9d2b62b7ef8c774ab5a Mon Sep 17 00:00:00 2001 From: Chris Feger Date: Sat, 25 Jan 2025 20:23:48 -0500 Subject: [PATCH 3/3] Fix previous merge --- BG3Extender/Extender/Client/ExtensionStateClient.h | 8 ++++---- BG3Extender/GameDefinitions/GameHelpers.cpp | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/BG3Extender/Extender/Client/ExtensionStateClient.h b/BG3Extender/Extender/Client/ExtensionStateClient.h index 9180cf789..5acd71fc8 100644 --- a/BG3Extender/Extender/Client/ExtensionStateClient.h +++ b/BG3Extender/Extender/Client/ExtensionStateClient.h @@ -36,10 +36,10 @@ class ExtensionState : public ExtensionStateBase void OnInputEvent(SDL_Event* event, int& result); - inline char const * GetUnconditionalFileName() override - { - return "OverrideClient.lua"; - } + inline char const * GetUnconditionalFileName() override + { + return "OverrideClient.lua"; + } protected: friend LuaStatePin; diff --git a/BG3Extender/GameDefinitions/GameHelpers.cpp b/BG3Extender/GameDefinitions/GameHelpers.cpp index 322c6fd26..a43ea8e43 100644 --- a/BG3Extender/GameDefinitions/GameHelpers.cpp +++ b/BG3Extender/GameDefinitions/GameHelpers.cpp @@ -195,6 +195,9 @@ namespace bg3se } } + return nullptr; + } + esv::Status* esv::StatusMachine::GetStatus(FixedString const& statusId) const { for (auto status : Statuses) {