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

Fix the script loading process and further improve it with multi stage loading of scripts.

This commit is contained in:
Sandu Liviu Catalin 2016-08-19 19:46:26 +03:00
parent e99e6259f7
commit a35b127871
2 changed files with 121 additions and 72 deletions

View File

@ -127,6 +127,7 @@ Core::Core()
: m_State(0) : m_State(0)
, m_VM(nullptr) , m_VM(nullptr)
, m_Scripts() , m_Scripts()
, m_PendingScripts()
, m_Options() , m_Options()
, m_Blips() , m_Blips()
, m_Checkpoints() , m_Checkpoints()
@ -300,7 +301,7 @@ bool Core::Initialize()
} }
// See if any script could be queued for loading // See if any script could be queued for loading
if (m_Scripts.empty() && !conf.GetBoolValue("Squirrel", "EmptyInit", false)) if (m_PendingScripts.empty() && !conf.GetBoolValue("Squirrel", "EmptyInit", false))
{ {
LogErr("No scripts loaded. No reason to load the plug-in"); LogErr("No scripts loaded. No reason to load the plug-in");
// No point in loading the plug-in // No point in loading the plug-in
@ -344,7 +345,7 @@ bool Core::Initialize()
bool Core::Execute() bool Core::Execute()
{ {
// Are there any scripts to execute? // Are there any scripts to execute?
if (cLogErr(m_Scripts.empty(), "No scripts to execute. Plug-in has no purpose")) if (cLogErr(m_PendingScripts.empty(), "No scripts to execute. Plug-in has no purpose"))
{ {
return false; // No reason to execute the plug-in return false; // No reason to execute the plug-in
} }
@ -353,74 +354,21 @@ bool Core::Execute()
// Tell modules to do their monkey business // Tell modules to do their monkey business
_Func->SendPluginCommand(SQMOD_LOAD_CMD, ""); _Func->SendPluginCommand(SQMOD_LOAD_CMD, "");
LogDbg("Attempting to compile the specified scripts"); // Load pending scripts while we're in the bounds of the allowed recursiveness
// Compile scripts first so that the constants can take effect for (unsigned levels = 0; (m_PendingScripts.empty() == false) && (levels < 8); ++levels)
for (auto & s : m_Scripts)
{ {
// Is this script already compiled? // Remember the last script from the pool
if (!s.mExec.IsNull()) const Scripts::size_type last = m_Scripts.size();
// Push pending scripts to the back of the list
std::move(m_PendingScripts.begin(), m_PendingScripts.end(), std::back_inserter(m_Scripts));
// Clear all pending scripts, if any
m_PendingScripts.clear();
// Process all pending scripts
if (DoScripts(m_Scripts.begin() + last, m_Scripts.end()) == false)
{ {
continue; // Already compiled! return false; // One of the scripts failed to execute
} }
LogDbg("Completed execution of stage (%u) scripts", levels);
// Attempt to load and compile the script file
try
{
s.mExec.CompileFile(s.mPath);
}
catch (const Sqrat::Exception & e)
{
LogFtl("Unable to compile: %s", s.mPath.c_str());
// Failed to execute properly
return false;
}
LogDbg("Successfully compiled script: %s", s.mPath.c_str());
// Should we delay the execution of this script?
if (s.mDelay)
{
continue; // Execute later!
}
// 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());
}
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());
} }
// Create the null entity instances // Create the null entity instances
@ -496,6 +444,7 @@ void Core::Terminate(bool shutdown)
ResetFunc(); ResetFunc();
// Release the script instances // Release the script instances
m_Scripts.clear(); m_Scripts.clear();
m_PendingScripts.clear(); // Just in case
// Specify that no scripts are left executed // Specify that no scripts are left executed
m_Executed = false; m_Executed = false;
// Assertions during close may cause double delete/close! // Assertions during close may cause double delete/close!
@ -509,7 +458,7 @@ void Core::Terminate(bool shutdown)
_Func->SendPluginCommand(SQMOD_RELEASED_CMD, ""); _Func->SendPluginCommand(SQMOD_RELEASED_CMD, "");
} }
LogDbg("Squirrel plugin was successfully terminated"); LogDbg("Squirrel plug---in was successfully terminated");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -569,6 +518,7 @@ bool Core::LoadScript(CSStr filepath, bool delay)
// Failed to load // Failed to load
return false; return false;
} }
Buffer bpath; Buffer bpath;
// Attempt to get the real file path // Attempt to get the real file path
try try
@ -587,8 +537,10 @@ bool Core::LoadScript(CSStr filepath, bool delay)
// Failed to load // Failed to load
return false; return false;
} }
// Make the path into a string // Make the path into a string
String path(bpath.Data(), bpath.Position()); 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);
@ -596,6 +548,13 @@ bool Core::LoadScript(CSStr filepath, bool delay)
{ {
LogWrn("Script was specified before: %s", path.c_str()); LogWrn("Script was specified before: %s", path.c_str());
} }
// Also check the pending scripts container
else if (std::find_if(m_PendingScripts.cbegin(), m_PendingScripts.cend(), [&path](Scripts::const_reference s) {
return (s.mPath == path);
}) != m_PendingScripts.end())
{
LogWrn("Script was specified before: %s", path.c_str());
}
// Were the scripts already executed? Then there's no need to queue them // Were the scripts already executed? Then there's no need to queue them
else if (m_Executed) else if (m_Executed)
{ {
@ -610,7 +569,9 @@ bool Core::LoadScript(CSStr filepath, bool delay)
catch (const Sqrat::Exception & e) catch (const Sqrat::Exception & e)
{ {
LogFtl("Unable to compile: %s", m_Scripts.back().mPath.c_str()); LogFtl("Unable to compile: %s", m_Scripts.back().mPath.c_str());
// Failed to execute properly // Remove the script container since it's invalid
m_Scripts.pop_back();
// Failed to compile properly
return false; return false;
} }
// At this point the script should be completely loaded // At this point the script should be completely loaded
@ -624,6 +585,8 @@ bool Core::LoadScript(CSStr filepath, bool delay)
catch (const Sqrat::Exception & e) catch (const Sqrat::Exception & e)
{ {
LogFtl("Unable to execute: %s", m_Scripts.back().mPath.c_str()); LogFtl("Unable to execute: %s", m_Scripts.back().mPath.c_str());
// Remove the script container since it's invalid
m_Scripts.pop_back();
// Failed to execute properly // Failed to execute properly
return false; return false;
} }
@ -633,10 +596,11 @@ bool Core::LoadScript(CSStr filepath, bool delay)
// 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 pending script pool
m_Scripts.emplace_back(m_VM, std::move(path), delay, m_Debugging); m_PendingScripts.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 one of the pools
return true; return true;
} }
@ -671,6 +635,85 @@ void Core::SetIncomingName(CSStr name)
m_IncomingNameBuffer[len] = '\0'; m_IncomingNameBuffer[len] = '\0';
} }
// ------------------------------------------------------------------------------------------------
bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end)
{
Scripts::iterator itr_state = itr;
LogDbg("Attempting to compile the specified scripts");
// Compile scripts first so that the constants can take effect
for (; itr != end; ++itr)
{
// Is this script already compiled?
if (!(*itr).mExec.IsNull())
{
continue; // Already compiled!
}
// Attempt to load and compile the script file
try
{
(*itr).mExec.CompileFile((*itr).mPath);
}
catch (const Sqrat::Exception & e)
{
LogFtl("Unable to compile: %s", (*itr).mPath.c_str());
// Failed to execute properly
return false;
}
LogDbg("Successfully compiled script: %s", (*itr).mPath.c_str());
// Should we delay the execution of this script?
if ((*itr).mDelay)
{
continue; // Execute later!
}
// Attempt to execute the compiled script code
try
{
(*itr).mExec.Run();
}
catch (const Sqrat::Exception & e)
{
LogFtl("Unable to execute: %s", (*itr).mPath.c_str());
// Failed to execute properly
return false;
}
LogScs("Successfully executed script: %s", (*itr).mPath.c_str());
}
LogDbg("Attempting to execute the specified scripts");
// Execute scripts only after compilation successful
for (itr = itr_state; itr != end; ++itr)
{
// Was this script delayed from execution?
if (!(*itr).mDelay)
{
continue; // Already executed!
}
// Attempt to execute the compiled script code
try
{
(*itr).mExec.Run();
}
catch (const Sqrat::Exception & e)
{
LogFtl("Unable to execute: %s", (*itr).mPath.c_str());
// Failed to execute properly
return false;
}
LogScs("Successfully executed script: %s", (*itr).mPath.c_str());
}
// At this point the scripts were loaded and executed successfully
return true;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Core::PrintFunc(HSQUIRRELVM /*vm*/, CSStr msg, ...) void Core::PrintFunc(HSQUIRRELVM /*vm*/, CSStr msg, ...)
{ {

View File

@ -536,6 +536,7 @@ private:
Int32 m_State; // Current plug-in state. Int32 m_State; // Current plug-in state.
HSQUIRRELVM m_VM; // Script virtual machine. HSQUIRRELVM m_VM; // Script virtual machine.
Scripts m_Scripts; // Loaded scripts objects. Scripts m_Scripts; // Loaded scripts objects.
Scripts m_PendingScripts; // Pending scripts objects.
Options m_Options; // Custom configuration options. Options m_Options; // Custom configuration options.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@ -735,6 +736,11 @@ public:
protected: protected:
/* --------------------------------------------------------------------------------------------
* Script execution process.
*/
static bool DoScripts(Scripts::iterator itr, Scripts::iterator end);
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Script output handlers. * Script output handlers.
*/ */