1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Implement script loading with notification.

This commit is contained in:
Sandu Liviu Catalin 2021-07-03 19:46:39 +03:00
parent a710ceebff
commit f2c1f8afd7
6 changed files with 120 additions and 28 deletions

View File

@ -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. * 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. CSimpleIniA & m_Config; // The processed configuration.
Function m_Callback{}; // Null callback.
public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Default constructor. * Default constructor.
*/ */
explicit ScriptLoader(CSimpleIniA & conf) explicit ScriptLoader(CSimpleIniA & conf)
: m_Config(conf) : m_Config(conf), m_Callback()
{ {
/* ... */ /* ... */
} }
@ -90,7 +89,7 @@ public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Function call operator. * Function call operator.
*/ */
bool operator () (const char * key, const char * val) const bool operator () (const char * key, const char * val)
{ {
// Validate the specified key // Validate the specified key
if (!key || *key == '\0') if (!key || *key == '\0')
@ -104,11 +103,11 @@ public:
} }
else if (std::strcmp(key, "Compile") == 0) 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) 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! // Move to the next element!
return true; 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? // Is the specified path empty?
if (!filepath || *filepath == '\0') if (!filepath || *filepath == '\0')
@ -761,7 +760,7 @@ bool Core::LoadScript(const SQChar * filepath, bool delay)
else if (m_Executed) else if (m_Executed)
{ {
// Create a new script container and insert it into the script pool // 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 // Attempt to load and compile the script file
try try
@ -782,7 +781,14 @@ bool Core::LoadScript(const SQChar * filepath, bool delay)
// Attempt to execute the compiled script code // Attempt to execute the compiled script code
try 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) catch (const std::exception & e)
{ {
@ -803,7 +809,7 @@ bool Core::LoadScript(const SQChar * filepath, bool delay)
try try
{ {
// Create a new script container and insert it into the pending script pool // 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) 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 // Attempt to execute the compiled script code
try 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) 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 // Attempt to execute the compiled script code
try 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) 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 // Failed to execute properly
return false; return false;
} }
@ -2477,12 +2497,19 @@ static SQInteger SqLoadScript(HSQUIRRELVM vm)
{ {
return sq_throwerror(vm, "Failed to retrieve the delay parameter"); return sq_throwerror(vm, "Failed to retrieve the delay parameter");
} }
Function cb;
// Forward the call to the actual implementation // 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 // We have an argument on the stack
return 1; return 1;
} }
// ------------------------------------------------------------------------------------------------
static bool SqLoadScriptNotify(bool delay, StackStrF & path, Function & cb)
{
return Core::Get().LoadScript(path.mPtr, cb, delay);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static SQInteger SqGetEvents(HSQUIRRELVM vm) static SQInteger SqGetEvents(HSQUIRRELVM vm)
{ {
@ -2813,6 +2840,7 @@ void Register_Core(HSQUIRRELVM vm)
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent) .Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent) .Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
.Func(_SC("OnUnload"), &SqGetUnloadEvent) .Func(_SC("OnUnload"), &SqGetUnloadEvent)
.CbFunc(_SC("LoadScriptNotify"), &SqLoadScriptNotify)
.SquirrelFunc(_SC("ForceEnableNullEntities"), &SqForceEnableNullEntities) .SquirrelFunc(_SC("ForceEnableNullEntities"), &SqForceEnableNullEntities)
.SquirrelFunc(_SC("LoadScript"), &SqLoadScript, -3, ".b.") .SquirrelFunc(_SC("LoadScript"), &SqLoadScript, -3, ".b.")
.SquirrelFunc(_SC("On"), &SqGetEvents); .SquirrelFunc(_SC("On"), &SqGetEvents);

View File

@ -368,7 +368,7 @@ public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Adds a script to the load queue. * 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. * Modify the name for the currently assigned incoming connection.

View File

@ -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() : mExec()
, mFunc(std::move(cb))
, mPath(path) , mPath(path)
, mData() , mData()
, mLine() , mLine()

View File

@ -19,20 +19,19 @@ class Core;
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Hold a information about loaded scripts as it's contents and executable code. * 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; typedef std::vector< std::pair< uint32_t, uint32_t > > Line;
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
Script mExec; // Reference to the script object. Script mExec{}; // Reference to the script object.
String mPath; // Path to the script file. Function mFunc{}; // Callback to invoke after script was executed.
String mData; // The contents of the script file. String mPath{}; // Path to the script file.
Line mLine; // List of lines of code in the data. String mData{}; // The contents of the script file.
bool mInfo; // Whether this script contains line information. Line mLine{}; // List of lines of code in the data.
bool mDelay; // Don't execute immediately after compilation. 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. * Read file contents and calculate information about the lines of code.
@ -42,7 +41,7 @@ public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Base constructor. * 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. * Copy constructor.

View File

@ -42,6 +42,8 @@ namespace Sqrat {
class Script : public Object { class Script : public Object {
public: public:
using Object::Object;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor /// 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<Script> {
Script value; ///< The actual value of get operations
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Attempts to get the value off the stack at idx as an Script
///
/// \param vm Target VM
/// \param idx Index trying to be read
///
/// \remarks
/// This function MUST have its Error handled if it occurred.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Var(HSQUIRRELVM vm, SQInteger idx) : value(idx, vm) {
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Called by Sqrat::PushVar to put an Script on the stack
///
/// \param vm Target VM
/// \param value Value to push on to the VM's stack
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void push(HSQUIRRELVM vm, const Script& value) {
sq_pushobject(vm, value.GetObj());
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Used to get and push Script instances to and from the stack as references (Script is always a reference)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Var<Script&> : Var<Script> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Script>(vm, idx) {}};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Used to get and push Script instances to and from the stack as references (Script is always a reference)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Var<const Script&> : Var<Script> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Script>(vm, idx) {}};
} }

View File

@ -328,6 +328,23 @@ public:
return *this; return *this;
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sets a key in the Table to a specific function with callback support
///
/// \param name The key in the table being assigned a value
/// \param method Function that is being placed in the Table
///
/// \tparam F Type of function (only define this if you need to choose a certain template specialization or overload)
///
/// \return The Table itself so the call can be chained
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class F>
TableBase& CbFunc(const SQChar* name, F method) {
BindFunc(name, &method, sizeof(method), SqGlobalFunc(method));
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sets a key in the Table to a specific function and allows the key to be overloaded with functions of a different amount of arguments /// Sets a key in the Table to a specific function and allows the key to be overloaded with functions of a different amount of arguments
/// ///