From f2c1f8afd7ae0dabd156dd73504387444c84cc32 Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sat, 3 Jul 2021 19:46:39 +0300 Subject: [PATCH] Implement script loading with notification. --- module/Core.cpp | 60 ++++++++++++++++++++++++++++---------- module/Core.hpp | 2 +- module/Core/Script.cpp | 3 +- module/Core/Script.hpp | 19 ++++++------ module/Sqrat/sqratScript.h | 47 +++++++++++++++++++++++++++++ module/Sqrat/sqratTable.h | 17 +++++++++++ 6 files changed, 120 insertions(+), 28 deletions(-) diff --git a/module/Core.cpp b/module/Core.cpp index a6b22b34..2d8d57c3 100644 --- a/module/Core.cpp +++ b/module/Core.cpp @@ -71,18 +71,17 @@ extern Buffer GetRealFilePath(const SQChar * path); /* ------------------------------------------------------------------------------------------------ * Loader used to process a section from the configuration file and look for scripts to load. */ -class ScriptLoader +struct ScriptLoader { // -------------------------------------------------------------------------------------------- - CSimpleIniA & m_Config; // The processed configuration. - -public: + CSimpleIniA & m_Config; // The processed configuration. + Function m_Callback{}; // Null callback. /* -------------------------------------------------------------------------------------------- * Default constructor. */ explicit ScriptLoader(CSimpleIniA & conf) - : m_Config(conf) + : m_Config(conf), m_Callback() { /* ... */ } @@ -90,7 +89,7 @@ public: /* -------------------------------------------------------------------------------------------- * Function call operator. */ - bool operator () (const char * key, const char * val) const + bool operator () (const char * key, const char * val) { // Validate the specified key if (!key || *key == '\0') @@ -104,11 +103,11 @@ public: } else if (std::strcmp(key, "Compile") == 0) { - return Core::Get().LoadScript(val, true); + return Core::Get().LoadScript(val, m_Callback, true); } else if (std::strcmp(key, "Execute") == 0) { - return Core::Get().LoadScript(val, false); + return Core::Get().LoadScript(val, m_Callback, false); } // Move to the next element! return true; @@ -717,7 +716,7 @@ Core::Scripts::iterator Core::FindPendingScript(const SQChar * src) } // ------------------------------------------------------------------------------------------------ -bool Core::LoadScript(const SQChar * filepath, bool delay) +bool Core::LoadScript(const SQChar * filepath, Function & cb, bool delay) { // Is the specified path empty? if (!filepath || *filepath == '\0') @@ -761,7 +760,7 @@ bool Core::LoadScript(const SQChar * filepath, bool delay) else if (m_Executed) { // Create a new script container and insert it into the script pool - m_Scripts.emplace_back(path, delay, m_Debugging); + m_Scripts.emplace_back(path, cb, delay, m_Debugging); // Attempt to load and compile the script file try @@ -782,7 +781,14 @@ bool Core::LoadScript(const SQChar * filepath, bool delay) // Attempt to execute the compiled script code try { - m_Scripts.back().mExec.Run(); + auto & s = m_Scripts.back(); + // Attempt to run the script + s.mExec.Run(); + // Does someone need to be notified? + if (!s.mFunc.IsNull()) + { + s.mFunc.Execute(s.mPath, s.mExec); + } } catch (const std::exception & e) { @@ -803,7 +809,7 @@ bool Core::LoadScript(const SQChar * filepath, bool delay) try { // Create a new script container and insert it into the pending script pool - m_PendingScripts.emplace_back(path, delay, m_Debugging); + m_PendingScripts.emplace_back(path, cb, delay, m_Debugging); } catch (const std::exception & e) { @@ -900,7 +906,14 @@ bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end) // Attempt to execute the compiled script code try { - (*itr).mExec.Run(); + auto & s = *itr; + // Attempt to run the script + s.mExec.Run(); + // Does someone need to be notified? + if (!s.mFunc.IsNull()) + { + s.mFunc.Execute(s.mPath, s.mExec); + } } catch (const std::exception & e) { @@ -925,11 +938,18 @@ bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end) // Attempt to execute the compiled script code try { - (*itr).mExec.Run(); + auto & s = *itr; + // Attempt to run the script + s.mExec.Run(); + // Does someone need to be notified? + if (!s.mFunc.IsNull()) + { + s.mFunc.Execute(s.mPath, s.mExec); + } } catch (const std::exception & e) { - LogFtl("Unable to execute: %s", (*itr).mPath.c_str()); + LogFtl("Unable to execute (%s) exception caught: %s", (*itr).mPath.c_str(), e.what()); // Failed to execute properly return false; } @@ -2477,12 +2497,19 @@ static SQInteger SqLoadScript(HSQUIRRELVM vm) { return sq_throwerror(vm, "Failed to retrieve the delay parameter"); } + Function cb; // Forward the call to the actual implementation - sq_pushbool(vm, Core::Get().LoadScript(val.mPtr, static_cast< bool >(delay))); + sq_pushbool(vm, Core::Get().LoadScript(val.mPtr, cb, static_cast< bool >(delay))); // We have an argument on the stack return 1; } +// ------------------------------------------------------------------------------------------------ +static bool SqLoadScriptNotify(bool delay, StackStrF & path, Function & cb) +{ + return Core::Get().LoadScript(path.mPtr, cb, delay); +} + // ------------------------------------------------------------------------------------------------ static SQInteger SqGetEvents(HSQUIRRELVM vm) { @@ -2813,6 +2840,7 @@ void Register_Core(HSQUIRRELVM vm) .Func(_SC("OnPreLoad"), &SqGetPreLoadEvent) .Func(_SC("OnPostLoad"), &SqGetPostLoadEvent) .Func(_SC("OnUnload"), &SqGetUnloadEvent) + .CbFunc(_SC("LoadScriptNotify"), &SqLoadScriptNotify) .SquirrelFunc(_SC("ForceEnableNullEntities"), &SqForceEnableNullEntities) .SquirrelFunc(_SC("LoadScript"), &SqLoadScript, -3, ".b.") .SquirrelFunc(_SC("On"), &SqGetEvents); diff --git a/module/Core.hpp b/module/Core.hpp index fec0d577..a8314997 100644 --- a/module/Core.hpp +++ b/module/Core.hpp @@ -368,7 +368,7 @@ public: /* -------------------------------------------------------------------------------------------- * Adds a script to the load queue. */ - bool LoadScript(const SQChar * filepath, bool delay); + bool LoadScript(const SQChar * filepath, Function & cb, bool delay = false); /* -------------------------------------------------------------------------------------------- * Modify the name for the currently assigned incoming connection. diff --git a/module/Core/Script.cpp b/module/Core/Script.cpp index 9b6f0b4f..b5a43b6f 100644 --- a/module/Core/Script.cpp +++ b/module/Core/Script.cpp @@ -148,8 +148,9 @@ void ScriptSrc::Process() } // ------------------------------------------------------------------------------------------------ -ScriptSrc::ScriptSrc(const String & path, bool delay, bool info) // NOLINT(modernize-pass-by-value) +ScriptSrc::ScriptSrc(const String & path, Function & cb, bool delay, bool info) // NOLINT(modernize-pass-by-value) : mExec() + , mFunc(std::move(cb)) , mPath(path) , mData() , mLine() diff --git a/module/Core/Script.hpp b/module/Core/Script.hpp index 2df7abf6..7cb8ce39 100644 --- a/module/Core/Script.hpp +++ b/module/Core/Script.hpp @@ -19,20 +19,19 @@ class Core; /* ------------------------------------------------------------------------------------------------ * Hold a information about loaded scripts as it's contents and executable code. */ -class ScriptSrc +struct ScriptSrc { -public: - // -------------------------------------------------------------------------------------------- typedef std::vector< std::pair< uint32_t, uint32_t > > Line; // -------------------------------------------------------------------------------------------- - Script mExec; // Reference to the script object. - String mPath; // Path to the script file. - String mData; // The contents of the script file. - Line mLine; // List of lines of code in the data. - bool mInfo; // Whether this script contains line information. - bool mDelay; // Don't execute immediately after compilation. + Script mExec{}; // Reference to the script object. + Function mFunc{}; // Callback to invoke after script was executed. + String mPath{}; // Path to the script file. + String mData{}; // The contents of the script file. + Line mLine{}; // List of lines of code in the data. + bool mInfo{false}; // Whether this script contains line information. + bool mDelay{false}; // Don't execute immediately after compilation. /* -------------------------------------------------------------------------------------------- * Read file contents and calculate information about the lines of code. @@ -42,7 +41,7 @@ public: /* -------------------------------------------------------------------------------------------- * Base constructor. */ - explicit ScriptSrc(const String & path, bool delay = false, bool info = false); + explicit ScriptSrc(const String & path, Function & cb, bool delay = false, bool info = false); /* -------------------------------------------------------------------------------------------- * Copy constructor. diff --git a/module/Sqrat/sqratScript.h b/module/Sqrat/sqratScript.h index d88d9463..8d08d476 100644 --- a/module/Sqrat/sqratScript.h +++ b/module/Sqrat/sqratScript.h @@ -42,6 +42,8 @@ namespace Sqrat { class Script : public Object { public: + using Object::Object; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Default constructor /// @@ -245,4 +247,49 @@ public: } }; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Used to get and push Script instances to and from the stack as references (Script is always a reference) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template<> +struct Var