From 64416c093c9d397b07a9adb58c4d454ecd5b11bd Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Thu, 25 Aug 2016 03:08:44 +0300 Subject: [PATCH] Implement a simple system for snippets to be notified when the scripts were loaded and about to be unloaded. --- source/Core.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++ source/Core.hpp | 25 ++++++++++ source/CoreFuncs.cpp | 42 +++++++++++++++++ 3 files changed, 175 insertions(+) diff --git a/source/Core.cpp b/source/Core.cpp index 590c9875..56e5e20d 100644 --- a/source/Core.cpp +++ b/source/Core.cpp @@ -144,6 +144,9 @@ Core::Core() , m_Debugging(false) , m_Executed(false) , m_Shutdown(false) + , m_LockPreLoadSignal(false) + , m_LockPostLoadSignal(false) + , m_LockUnloadSignal(false) { /* ... */ } @@ -350,6 +353,11 @@ bool Core::Execute() return false; // No reason to execute the plug-in } + // Unlock signal containers + m_LockPreLoadSignal = false; + m_LockPostLoadSignal = false; + m_LockUnloadSignal = false; + LogDbg("Signaling outside plug-ins to register their API"); // Tell modules to do their monkey business _Func->SendPluginCommand(SQMOD_LOAD_CMD, ""); @@ -380,9 +388,27 @@ bool Core::Execute() m_NullPlayer = Object(new CPlayer(-1)); m_NullVehicle = Object(new CVehicle(-1)); + m_LockPreLoadSignal = true; + // Trigger functions that must initialize stuff before the loaded event is triggered + for (FuncData & fn : m_PreLoadSignal) + { + Emit(fn.first, fn.second); + } + // Clear the functions + m_PreLoadSignal.clear(); + // Notify the script callback that the scripts were loaded EmitScriptLoaded(); + m_LockPostLoadSignal = true; + // Trigger functions that must initialize stuff after the loaded event is triggered + for (FuncData & fn : m_PostLoadSignal) + { + Emit(fn.first, fn.second); + } + // Clear the functions + m_PostLoadSignal.clear(); + // Import already existing entities ImportPlayers(); ImportBlips(); @@ -403,6 +429,15 @@ void Core::Terminate(bool shutdown) // Is there a virtual machine present? if (m_VM) { + m_LockUnloadSignal = true; + // Trigger functions that must de-initialize stuff before the scripts are unloaded + for (FuncData & fn : m_UnloadSignal) + { + Emit(fn.first, fn.second, shutdown); + } + // Clear the functions + m_UnloadSignal.clear(); + LogDbg("Signaling outside plug-ins to release their resources"); // Tell modules to do their monkey business _Func->SendPluginCommand(SQMOD_TERMINATE_CMD, ""); @@ -436,6 +471,10 @@ void Core::Terminate(bool shutdown) m_NullPickup.Release(); m_NullPlayer.Release(); m_NullVehicle.Release(); + // Clear any functions added during shutdown + m_PreLoadSignal.clear(); + m_PostLoadSignal.clear(); + m_UnloadSignal.clear(); // Is there a VM to close? if (m_VM) { @@ -767,6 +806,75 @@ void Core::CompilerErrorHandler(HSQUIRRELVM /*vm*/, CSStr desc, CSStr src, SQInt LogFtl("Message: %s\n[\n=>Location: %s\n=>Line: %d\n=>Column: %d\n]", desc, src, line, column); } +// ------------------------------------------------------------------------------------------------ +void Core::BindPreLoad(Object & env, Function & func, Object & payload) +{ + if (m_LockPreLoadSignal) + { + STHROWF("Cannot bind functions to pre-load signal anymore"); + } + else if (func.IsNull()) + { + STHROWF("Cannot bind null as callback to pre-load signal"); + } + // Does this function need a custom environment? + else if (env.IsNull()) + { + m_PreLoadSignal.emplace_back(func, payload); + } + // Assign the specified environment and function + else + { + m_PreLoadSignal.emplace_back(Function(env.GetVM(), env, func.GetFunc()), payload); + } +} + +// ------------------------------------------------------------------------------------------------ +void Core::BindPostLoad(Object & env, Function & func, Object & payload) +{ + if (m_LockPostLoadSignal) + { + STHROWF("Cannot bind functions to post-load signal anymore"); + } + else if (func.IsNull()) + { + STHROWF("Cannot bind null as callback to post-load signal"); + } + // Does this function need a custom environment? + else if (env.IsNull()) + { + m_PostLoadSignal.emplace_back(func, payload); + } + // Assign the specified environment and function + else + { + m_PostLoadSignal.emplace_back(Function(env.GetVM(), env, func.GetFunc()), payload); + } +} + +// ------------------------------------------------------------------------------------------------ +void Core::BindUnload(Object & env, Function & func, Object & payload) +{ + if (m_LockUnloadSignal) + { + STHROWF("Cannot bind functions to unload signal anymore"); + } + else if (func.IsNull()) + { + STHROWF("Cannot bind null as callback to unload signal"); + } + // Does this function need a custom environment? + else if (env.IsNull()) + { + m_UnloadSignal.emplace_back(func, payload); + } + // Assign the specified environment and function + else + { + m_UnloadSignal.emplace_back(Function(env.GetVM(), env, func.GetFunc()), payload); + } +} + // ------------------------------------------------------------------------------------------------ void Core::BindEvent(Int32 id, Object & env, Function & func) { diff --git a/source/Core.hpp b/source/Core.hpp index b5e7455f..0d9b72bb 100644 --- a/source/Core.hpp +++ b/source/Core.hpp @@ -526,6 +526,8 @@ public: // -------------------------------------------------------------------------------------------- typedef std::vector< ScriptSrc > Scripts; // List of loaded scripts. + typedef std::pair< Function, Object > FuncData; // Data about a function to be called. + typedef std::vector< FuncData > Functions; // List of functions to execute. // -------------------------------------------------------------------------------------------- typedef std::unordered_map< String, String > Options; // List of custom options. @@ -563,6 +565,14 @@ private: bool m_Debugging; // Enable debugging features, if any. bool m_Executed; // Whether the scripts were executed. bool m_Shutdown; // Whether the server currently shutting down. + bool m_LockPreLoadSignal; // Lock pre load signal container. + bool m_LockPostLoadSignal; // Lock post load signal container. + bool m_LockUnloadSignal; // Lock unload signal container. + + // -------------------------------------------------------------------------------------------- + Functions m_PreLoadSignal; // Functions to call before the loaded event. + Functions m_PostLoadSignal; // Functions to call after the loaded event. + Functions m_UnloadSignal; // Functions to call before unloading scripts. // -------------------------------------------------------------------------------------------- Object m_NullBlip; // Null Blips instance. @@ -913,6 +923,21 @@ protected: public: + /* -------------------------------------------------------------------------------------------- + * Pre load signal binder. + */ + void BindPreLoad(Object & env, Function & func, Object & payload); + + /* -------------------------------------------------------------------------------------------- + * Post load signal binder. + */ + void BindPostLoad(Object & env, Function & func, Object & payload); + + /* -------------------------------------------------------------------------------------------- + * Unload signal binder. + */ + void BindUnload(Object & env, Function & func, Object & payload); + /* -------------------------------------------------------------------------------------------- * Global event binder. */ diff --git a/source/CoreFuncs.cpp b/source/CoreFuncs.cpp index 93ebe7a9..8b65c146 100644 --- a/source/CoreFuncs.cpp +++ b/source/CoreFuncs.cpp @@ -41,6 +41,42 @@ static SQInteger SqLoadScript(HSQUIRRELVM vm) return 1; } +// ------------------------------------------------------------------------------------------------ +static void SqBindPreLoad(Object & env, Function & func) +{ + Core::Get().BindPreLoad(env, func, NullObject()); +} + +// ------------------------------------------------------------------------------------------------ +static void SqBindPostLoad(Object & env, Function & func) +{ + Core::Get().BindPostLoad(env, func, NullObject()); +} + +// ------------------------------------------------------------------------------------------------ +static void SqBindUnload(Object & env, Function & func) +{ + Core::Get().BindUnload(env, func, NullObject()); +} + +// ------------------------------------------------------------------------------------------------ +static void SqBindPreLoadEx(Object & env, Function & func, Object & payload) +{ + Core::Get().BindPreLoad(env, func, payload); +} + +// ------------------------------------------------------------------------------------------------ +static void SqBindPostLoadEx(Object & env, Function & func, Object & payload) +{ + Core::Get().BindPostLoad(env, func, payload); +} + +// ------------------------------------------------------------------------------------------------ +static void SqBindUnloadEx(Object & env, Function & func, Object & payload) +{ + Core::Get().BindUnload(env, func, payload); +} + // ------------------------------------------------------------------------------------------------ static void SqBindEvent(Int32 id, Object & env, Function & func) { @@ -284,6 +320,12 @@ void Register_Core(HSQUIRRELVM vm) RootTable(vm) .Bind(_SC("SqCore"), Table(vm) .Func(_SC("Bind"), &SqBindEvent) + .Func(_SC("BindPreLoad"), &SqBindPreLoad) + .Func(_SC("BindPostLoad"), &SqBindPostLoad) + .Func(_SC("BindUnload"), &SqBindUnload) + .Func(_SC("BindPreLoadEx"), &SqBindPreLoadEx) + .Func(_SC("BindPostLoadEx"), &SqBindPostLoadEx) + .Func(_SC("BindUnloadEx"), &SqBindUnloadEx) .Func(_SC("CustomEvent"), &SqCustomEvent) .Func(_SC("Reload"), &SqSetReloadStatus) .Func(_SC("Reloading"), &SqGetReloadStatus)