diff --git a/SKSE/Plugins/EnderalSE.dll b/SKSE/Plugins/EnderalSE.dll index 322381a1..f169fb6c 100644 --- a/SKSE/Plugins/EnderalSE.dll +++ b/SKSE/Plugins/EnderalSE.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82ba7402253520095db4ee25e1f07759b0cc0913465293ec5a9d45029a00e8bb -size 738304 +oid sha256:e5a11c44f90d68c3ce54dc019838aa64d1420799dcc2641c454a85ce3b87dd71 +size 719872 diff --git a/scripts/_00e_game_skillmenusc.pex b/scripts/_00e_game_skillmenusc.pex index 28fc71ee..10a1613c 100644 Binary files a/scripts/_00e_game_skillmenusc.pex and b/scripts/_00e_game_skillmenusc.pex differ diff --git a/scripts/_00e_playersetupscript.pex b/scripts/_00e_playersetupscript.pex index 5e7b3445..acdf3b3a 100644 Binary files a/scripts/_00e_playersetupscript.pex and b/scripts/_00e_playersetupscript.pex differ diff --git a/scripts/_00e_questfunctions.pex b/scripts/_00e_questfunctions.pex index 45e777f2..8f41a404 100644 Binary files a/scripts/_00e_questfunctions.pex and b/scripts/_00e_questfunctions.pex differ diff --git a/scripts/_00e_theriantrophist_alchemycontrol.pex b/scripts/_00e_theriantrophist_alchemycontrol.pex index c9ad14ab..4fe133e3 100644 Binary files a/scripts/_00e_theriantrophist_alchemycontrol.pex and b/scripts/_00e_theriantrophist_alchemycontrol.pex differ diff --git a/source/Enderal DLL/src/EventListener.cpp b/source/Enderal DLL/src/EventListener.cpp index bcbf9e8f..873c0a59 100644 --- a/source/Enderal DLL/src/EventListener.cpp +++ b/source/Enderal DLL/src/EventListener.cpp @@ -8,6 +8,7 @@ auto EventListener::GetSingleton() -> EventListener* return std::addressof(singleton); } +// Unused void EventListener::Install() { RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink(EventListener::GetSingleton()); @@ -57,6 +58,9 @@ auto EventListener::ProcessEvent( movie->Invoke("_root.QuestJournalFader.Menu_mc.RestoreSavedSettings", nullptr, args.data(), static_cast(args.size())); } } + } else if (!a_event->opening && a_event->menuName == RE::MainMenu::MENU_NAME) { + RE::UI::GetSingleton()->RemoveEventSink(EventListener::GetSingleton()); + CheckScriptVersions(); } return RE::BSEventNotifyControl::kContinue; diff --git a/source/Enderal DLL/src/Main.cpp b/source/Enderal DLL/src/Main.cpp index 29303b84..2c17e3ea 100644 --- a/source/Enderal DLL/src/Main.cpp +++ b/source/Enderal DLL/src/Main.cpp @@ -141,6 +141,7 @@ SKSEPluginLoad(const LoadInterface* skse) { InitializeMessaging(); SKSE::GetModCallbackEventSource()->AddEventSink(EventListener::GetSingleton()); + RE::UI::GetSingleton()->AddEventSink(EventListener::GetSingleton()); GetPapyrusInterface()->Register(Papyrus::Bind); diff --git a/source/Enderal DLL/src/Util.h b/source/Enderal DLL/src/Util.h index 82883927..e2d67ec6 100644 --- a/source/Enderal DLL/src/Util.h +++ b/source/Enderal DLL/src/Util.h @@ -65,6 +65,72 @@ inline void CheckIncompatibleMods() CheckEnderalStatics(); } +inline bool PapyrusGlobalFunctionExists(const char* scriptName, const char* funcName) +{ + logger::info("Real - GetGlobalFunctionNames of {}", scriptName); + std::vector functionNames; + RE::BSTSmartPointer typeInfoPtr; + RE::BSScript::Internal::VirtualMachine::GetSingleton()->GetScriptObjectType(RE::BSFixedString(scriptName), typeInfoPtr); + auto functionCount = typeInfoPtr->GetNumGlobalFuncs(); + auto functions = typeInfoPtr->GetGlobalFuncIter(); + for (uint32_t i = 0; i < functionCount; i++) { + if (functions[i].func->GetName().c_str() == funcName) { + return true; + } + } + return false; +} + +inline void CheckScriptVersions() +{ + class ScriptVersionCallback : public RE::BSScript::IStackCallbackFunctor + { + private: + std::uint32_t expectedVersion; + const RE::BSFixedString scriptName; + const RE::BSFixedString funcName = "_GetScriptVersion"; + public: + ScriptVersionCallback(const RE::BSFixedString a_scriptName, int a_version) : + scriptName(a_scriptName), + expectedVersion(a_version) + { + if (PapyrusGlobalFunctionExists(scriptName.c_str(), funcName.c_str())) { + const auto vm = RE::BSScript::Internal::VirtualMachine::GetSingleton(); + auto callbackPtr = RE::BSTSmartPointer(this); + vm->DispatchStaticCall(scriptName, funcName, RE::MakeFunctionArguments(), callbackPtr); + } else { + auto a_script = scriptName; + auto a_version = expectedVersion; + SKSE::GetTaskInterface()->AddTask([a_script, a_version]() { + RE::DebugMessageBox(std::format("Script {} is overwritten by a mod, incompatible with current version of Enderal. Expected version: {}, installed version: N/A.", a_script.c_str(), a_version).c_str()); + }); + } + } + + void operator()(RE::BSScript::Variable a_result) + { + if (a_result.GetUInt() != expectedVersion) { + RE::DebugMessageBox(std::format("Script {} is overwritten by a mod, incompatible with current version of Enderal. Expected version: {}, installed version: {}.", scriptName.c_str(), expectedVersion, a_result.GetUInt()).c_str()); + } + } + bool CanSave() { return false; } + void SetObject(const RE::BSTSmartPointer&) {} + }; + + RE::BSTSmartPointer{ + new ScriptVersionCallback("_00E_PlayerSetUpScript", 1) + }; + RE::BSTSmartPointer{ + new ScriptVersionCallback("_00E_QuestFunctions", 1) + }; + RE::BSTSmartPointer{ + new ScriptVersionCallback("_00E_Game_SkillmenuSC", 1) + }; + RE::BSTSmartPointer{ + new ScriptVersionCallback("_00E_Theriantrophist_AlchemyControl", 1) + }; +} + inline void LoadINI(std::map* settings, const char* iniPath) { for (auto it = settings->begin(); it != settings->end(); it++) { diff --git a/source/scripts/_00e_game_skillmenusc.psc b/source/scripts/_00e_game_skillmenusc.psc index a222c6f9..66c4b356 100644 --- a/source/scripts/_00e_game_skillmenusc.psc +++ b/source/scripts/_00e_game_skillmenusc.psc @@ -11,6 +11,10 @@ Import Math Import ActorValueInfo Import _00E_QuestFunctions +int function _GetScriptVersion() Global + return 1 +endFunction + ; This script handles the custom character menu ;===================================================================================== diff --git a/source/scripts/_00e_playersetupscript.psc b/source/scripts/_00e_playersetupscript.psc index db085833..dafbeea5 100644 --- a/source/scripts/_00e_playersetupscript.psc +++ b/source/scripts/_00e_playersetupscript.psc @@ -3,6 +3,9 @@ Scriptname _00E_PlayerSetUpScript extends ObjectReference Float Property CURRENT_PATCH_VERSION = 2.13 AutoReadOnly +int function _GetScriptVersion() Global + return 1 +endFunction ;===================================================================================== ; EVENTS diff --git a/source/scripts/_00e_questfunctions.psc b/source/scripts/_00e_questfunctions.psc index 8430b42b..90b3bd5d 100644 --- a/source/scripts/_00e_questfunctions.psc +++ b/source/scripts/_00e_questfunctions.psc @@ -4,6 +4,10 @@ Scriptname _00E_QuestFunctions extends Quest Conditional Import math Import Utility +int function _GetScriptVersion() Global + return 1 +endFunction + ;===================================================================================== ; EXP ;===================================================================================== diff --git a/source/scripts/_00e_theriantrophist_alchemycontrol.psc b/source/scripts/_00e_theriantrophist_alchemycontrol.psc index 39bd250c..ed266ec0 100644 --- a/source/scripts/_00e_theriantrophist_alchemycontrol.psc +++ b/source/scripts/_00e_theriantrophist_alchemycontrol.psc @@ -91,6 +91,10 @@ string[] aPotionModels ; FUNCTIONS ;===================================================================================== +int function _GetScriptVersion() Global + return 1 +endFunction + function _addNamedPotion(Potion aPotion, string sName, string sModel) if ! aPotion || sName == ""