mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
Initial revision of the script loading system to be more flexible and accurate.
This commit is contained in:
parent
54531071c7
commit
8846cb9351
@ -66,7 +66,7 @@ extern "C" {
|
|||||||
//logging utilities
|
//logging utilities
|
||||||
typedef void (*SqEx_LogMessage) (const SQChar * fmt, ...);
|
typedef void (*SqEx_LogMessage) (const SQChar * fmt, ...);
|
||||||
//script loading
|
//script loading
|
||||||
typedef SQRESULT (*SqEx_LoadScript) (const SQChar * filepath);
|
typedef SQRESULT (*SqEx_LoadScript) (const SQChar * filepath, SQBool delay);
|
||||||
//numeric utilities
|
//numeric utilities
|
||||||
typedef SQRESULT (*SqEx_GetSLongValue) (HSQUIRRELVM vm, SQInteger idx, SqInt64 * num);
|
typedef SQRESULT (*SqEx_GetSLongValue) (HSQUIRRELVM vm, SQInteger idx, SqInt64 * num);
|
||||||
typedef SQRESULT (*SqEx_PushSLongObject) (HSQUIRRELVM vm, SqInt64 num);
|
typedef SQRESULT (*SqEx_PushSLongObject) (HSQUIRRELVM vm, SqInt64 num);
|
||||||
|
216
source/Core.cpp
216
source/Core.cpp
@ -38,6 +38,56 @@ extern void TerminateRoutines();
|
|||||||
extern void InitializeCmdManager();
|
extern void InitializeCmdManager();
|
||||||
extern void TerminateCmdManager();
|
extern void TerminateCmdManager();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
extern Buffer GetRealFilePath(CSStr path);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* Loader used to process a section from the configuration file and look for scripts to load.
|
||||||
|
*/
|
||||||
|
class ScriptLoader
|
||||||
|
{
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
CSimpleIniA & m_Config; // The processed configuration.
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
ScriptLoader(CSimpleIniA & conf)
|
||||||
|
: m_Config(conf)
|
||||||
|
{
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Function call operator.
|
||||||
|
*/
|
||||||
|
bool operator () (CCStr key, CCStr val) const
|
||||||
|
{
|
||||||
|
// Validate the specified key
|
||||||
|
if (!key || *key == '\0')
|
||||||
|
{
|
||||||
|
return true; // Move to the next element!
|
||||||
|
}
|
||||||
|
// Identify the load option
|
||||||
|
if (std::strcmp(key, "Section") == 0)
|
||||||
|
{
|
||||||
|
return m_Config.ProcAllValues(val, ScriptLoader(m_Config));
|
||||||
|
}
|
||||||
|
else if (std::strcmp(key, "Compile") == 0)
|
||||||
|
{
|
||||||
|
return Core::Get().LoadScript(val, true);
|
||||||
|
}
|
||||||
|
else if (std::strcmp(key, "Execute") == 0)
|
||||||
|
{
|
||||||
|
return Core::Get().LoadScript(val, false);
|
||||||
|
}
|
||||||
|
// Move to the next element!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Core Core::s_Inst;
|
Core Core::s_Inst;
|
||||||
|
|
||||||
@ -60,6 +110,7 @@ Core::Core()
|
|||||||
, m_IncomingNameBuffer(nullptr)
|
, m_IncomingNameBuffer(nullptr)
|
||||||
, m_IncomingNameCapacity(0)
|
, m_IncomingNameCapacity(0)
|
||||||
, m_Debugging(false)
|
, m_Debugging(false)
|
||||||
|
, m_Executed(false)
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
@ -195,49 +246,16 @@ bool Core::Initialize()
|
|||||||
return false; // Can't execute scripts without a valid API!
|
return false; // Can't execute scripts without a valid API!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to obtain collections of script paths
|
CSimpleIniA::TNamesDepend scripts;
|
||||||
CSimpleIniA::TNamesDepend bundles, scripts;
|
// Attempt to retrieve the list of keys to make sure there's actually something to process
|
||||||
|
if (conf.GetAllKeys("Scripts", scripts) && scripts.size() > 0)
|
||||||
// Attempt to retrieve the list of scripts specified in the configuration file
|
|
||||||
if (conf.GetAllValues("Scripts", "Source", scripts) && scripts.size() > 0)
|
|
||||||
{
|
{
|
||||||
LogDbg("Found (%u) scripts in the configuration file", scripts.size());
|
// Attempt to load the specified scripts
|
||||||
// Sort the list in it's original order
|
if (!conf.ProcAllValues("Scripts", ScriptLoader(conf)))
|
||||||
scripts.sort(CSimpleIniA::Entry::LoadOrder());
|
|
||||||
// Process each specified script path
|
|
||||||
for (const auto & script : scripts)
|
|
||||||
{
|
{
|
||||||
// Attempt to queue the specified script path for loading
|
LogErr("Unable to load the specified scripts");
|
||||||
LoadScript(script.pItem);
|
// Either no script was found or failed to load
|
||||||
}
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to retrieve the list of bundles specified in the configuration file
|
|
||||||
if (conf.GetAllValues("Scripts", "Bundle", bundles) && bundles.size() > 0)
|
|
||||||
{
|
|
||||||
LogDbg("Found (%u) bundles in the configuration file", bundles.size());
|
|
||||||
// Sort the list in it's original order
|
|
||||||
bundles.sort(CSimpleIniA::Entry::LoadOrder());
|
|
||||||
// Process each specified script bundle
|
|
||||||
for (const auto & bundle : bundles)
|
|
||||||
{
|
|
||||||
// Attempt to retrieve the list of scripts specified in the current bundle
|
|
||||||
if (!conf.GetAllValues(bundle.pItem, "Source", scripts))
|
|
||||||
{
|
|
||||||
LogWrn("Unable to locate script bundle (%s)", bundle.pItem);
|
|
||||||
}
|
|
||||||
else if (scripts.size() > 0)
|
|
||||||
{
|
|
||||||
LogDbg("Found (%u) scripts in bundle (%s)", scripts.size(), bundle.pItem);
|
|
||||||
// Sort the list in it's original order
|
|
||||||
scripts.sort(CSimpleIniA::Entry::LoadOrder());
|
|
||||||
// Process each specified script path
|
|
||||||
for (const auto & script : scripts)
|
|
||||||
{
|
|
||||||
// Attempt to queue the specified script path for loading
|
|
||||||
LoadScript(script.pItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +319,12 @@ bool Core::Execute()
|
|||||||
// Compile scripts first so that the constants can take effect
|
// Compile scripts first so that the constants can take effect
|
||||||
for (auto & s : m_Scripts)
|
for (auto & s : m_Scripts)
|
||||||
{
|
{
|
||||||
|
// Is this script already compiled?
|
||||||
|
if (!s.mExec.IsNull())
|
||||||
|
{
|
||||||
|
continue; // Already compiled!
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to load and compile the script file
|
// Attempt to load and compile the script file
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -312,14 +336,15 @@ bool Core::Execute()
|
|||||||
// Failed to execute properly
|
// Failed to execute properly
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// At this point the script should be completely loaded
|
|
||||||
LogDbg("Successfully compiled script: %s", s.mPath.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
LogDbg("Attempting to execute the specified scripts");
|
LogDbg("Successfully compiled script: %s", s.mPath.c_str());
|
||||||
// Execute scripts only after compilation successful
|
|
||||||
for (auto & s : m_Scripts)
|
// Should we delay the execution of this script?
|
||||||
{
|
if (s.mDelay)
|
||||||
|
{
|
||||||
|
continue; // Execute later!
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to execute the compiled script code
|
// Attempt to execute the compiled script code
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -331,7 +356,32 @@ bool Core::Execute()
|
|||||||
// Failed to execute properly
|
// Failed to execute properly
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// At this point the script should be completely loaded
|
|
||||||
|
LogScs("Successfully executed script: %s", s.mPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDbg("Attempting to execute the specified scripts");
|
||||||
|
// Execute scripts only after compilation successful
|
||||||
|
for (auto & s : m_Scripts)
|
||||||
|
{
|
||||||
|
// Was this script delayed from execution?
|
||||||
|
if (!s.mDelay)
|
||||||
|
{
|
||||||
|
continue; // Already executed!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to execute the compiled script code
|
||||||
|
try
|
||||||
|
{
|
||||||
|
s.mExec.Run();
|
||||||
|
}
|
||||||
|
catch (const Sqrat::Exception & e)
|
||||||
|
{
|
||||||
|
LogFtl("Unable to execute: %s", s.mPath.c_str());
|
||||||
|
// Failed to execute properly
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LogScs("Successfully executed script: %s", s.mPath.c_str());
|
LogScs("Successfully executed script: %s", s.mPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +398,7 @@ bool Core::Execute()
|
|||||||
EmitScriptLoaded();
|
EmitScriptLoaded();
|
||||||
|
|
||||||
// Successfully executed
|
// Successfully executed
|
||||||
return true;
|
return (m_Executed = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@ -386,6 +436,8 @@ void Core::Terminate()
|
|||||||
ResetFunc();
|
ResetFunc();
|
||||||
// Release the script instances
|
// Release the script instances
|
||||||
m_Scripts.clear();
|
m_Scripts.clear();
|
||||||
|
// Specify that no scripts are left executed
|
||||||
|
m_Executed = false;
|
||||||
// Assertions during close may cause double delete/close!
|
// Assertions during close may cause double delete/close!
|
||||||
HSQUIRRELVM sq_vm = m_VM;
|
HSQUIRRELVM sq_vm = m_VM;
|
||||||
m_VM = nullptr;
|
m_VM = nullptr;
|
||||||
@ -442,15 +494,35 @@ void Core::SetOption(CSStr name, CSStr value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool Core::LoadScript(CSStr filepath)
|
bool Core::LoadScript(CSStr filepath, bool delay)
|
||||||
{
|
{
|
||||||
// Is the specified path empty?
|
// Is the specified path empty?
|
||||||
if (!filepath || *filepath == '\0')
|
if (!filepath || *filepath == '\0')
|
||||||
{
|
{
|
||||||
return false; // Simply ignore it!
|
LogErr("Cannot load script with empty or invalid path");
|
||||||
|
// Failed to load
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// Get the file path as a string
|
Buffer bpath;
|
||||||
String path(filepath);
|
// Attempt to get the real file path
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bpath = GetRealFilePath(filepath);
|
||||||
|
}
|
||||||
|
catch (const Sqrat::Exception & e)
|
||||||
|
{
|
||||||
|
LogErr("Unable to load script: %s", e.Message().c_str());
|
||||||
|
// Failed to load
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (const std::exception & e)
|
||||||
|
{
|
||||||
|
LogErr("Unable to load script: %s", e.what());
|
||||||
|
// Failed to load
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Make the path into a string
|
||||||
|
String path(bpath.Data(), bpath.Position());
|
||||||
// See if it wasn't already loaded
|
// See if it wasn't already loaded
|
||||||
if (std::find_if(m_Scripts.cbegin(), m_Scripts.cend(), [&path](Scripts::const_reference s) {
|
if (std::find_if(m_Scripts.cbegin(), m_Scripts.cend(), [&path](Scripts::const_reference s) {
|
||||||
return (s.mPath == path);
|
return (s.mPath == path);
|
||||||
@ -458,11 +530,45 @@ bool Core::LoadScript(CSStr filepath)
|
|||||||
{
|
{
|
||||||
LogWrn("Script was specified before: %s", path.c_str());
|
LogWrn("Script was specified before: %s", path.c_str());
|
||||||
}
|
}
|
||||||
|
// Were the scripts already executed? Then there's no need to queue them
|
||||||
|
else if (m_Executed)
|
||||||
|
{
|
||||||
|
// Create a new script container and insert it into the script pool
|
||||||
|
m_Scripts.emplace_back(m_VM, std::move(path), delay, m_Debugging);
|
||||||
|
|
||||||
|
// Attempt to load and compile the script file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_Scripts.back().mExec.CompileFile(m_Scripts.back().mPath);
|
||||||
|
}
|
||||||
|
catch (const Sqrat::Exception & e)
|
||||||
|
{
|
||||||
|
LogFtl("Unable to compile: %s", m_Scripts.back().mPath.c_str());
|
||||||
|
// Failed to execute properly
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// At this point the script should be completely loaded
|
||||||
|
LogDbg("Successfully compiled script: %s", m_Scripts.back().mPath.c_str());
|
||||||
|
|
||||||
|
// Attempt to execute the compiled script code
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_Scripts.back().mExec.Run();
|
||||||
|
}
|
||||||
|
catch (const Sqrat::Exception & e)
|
||||||
|
{
|
||||||
|
LogFtl("Unable to execute: %s", m_Scripts.back().mPath.c_str());
|
||||||
|
// Failed to execute properly
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// At this point the script should be completely loaded
|
||||||
|
LogScs("Successfully executed script: %s", m_Scripts.back().mPath.c_str());
|
||||||
|
}
|
||||||
// We don't compile the scripts yet. We just store their path and prepare the objects
|
// We don't compile the scripts yet. We just store their path and prepare the objects
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 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(m_VM, path, m_Debugging);
|
m_Scripts.emplace_back(m_VM, std::move(path), delay, m_Debugging);
|
||||||
}
|
}
|
||||||
// At this point the script exists in the pool
|
// At this point the script exists in the pool
|
||||||
return true;
|
return true;
|
||||||
|
@ -392,6 +392,7 @@ private:
|
|||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
bool m_Debugging; // Enable debugging features, if any.
|
bool m_Debugging; // Enable debugging features, if any.
|
||||||
|
bool m_Executed; // Whether the scripts were executed.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -439,6 +440,22 @@ public:
|
|||||||
return m_State;
|
return m_State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See whether debugging option was enabled in the plugin.
|
||||||
|
*/
|
||||||
|
bool IsDebugging() const
|
||||||
|
{
|
||||||
|
return m_Debugging;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See whether all queued scripts were executed and the plugin fully started.
|
||||||
|
*/
|
||||||
|
bool IsExecuted() const
|
||||||
|
{
|
||||||
|
return m_Executed;
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Retrieve the value of the specified option.
|
* Retrieve the value of the specified option.
|
||||||
*/
|
*/
|
||||||
@ -515,7 +532,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Adds a script to the load queue.
|
* Adds a script to the load queue.
|
||||||
*/
|
*/
|
||||||
bool LoadScript(CSStr filepath);
|
bool LoadScript(CSStr filepath, bool delay);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Modify the name for the currently assigned incoming connection.
|
* Modify the name for the currently assigned incoming connection.
|
||||||
|
@ -40,10 +40,10 @@ static HSQUIRRELVM GetSquirrelVM()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
static SQRESULT SqEx_LoadScript(const SQChar * filepath)
|
static SQRESULT SqEx_LoadScript(const SQChar * filepath, SQBool delay)
|
||||||
{
|
{
|
||||||
// Attempt to add the specified script to the load queue
|
// Attempt to add the specified script to the load queue
|
||||||
if (Core::Get().LoadScript(filepath))
|
if (Core::Get().LoadScript(filepath, delay))
|
||||||
{
|
{
|
||||||
return SQ_OK; // The script as added or already existed
|
return SQ_OK; // The script as added or already existed
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user