1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 16:57:16 +01:00
SqMod/source/Misc/Routine.cpp

308 lines
9.7 KiB
C++
Raw Normal View History

2016-02-21 08:25:46 +01:00
// ------------------------------------------------------------------------------------------------
#include "Misc/Routine.hpp"
#include "Library/Chrono.hpp"
2016-02-21 08:25:46 +01:00
// ------------------------------------------------------------------------------------------------
2016-11-17 22:10:31 +01:00
#include <cstdio>
#include <cstdlib>
#include <cstring>
// ------------------------------------------------------------------------------------------------
#include <utility>
2016-02-21 08:25:46 +01:00
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
2016-11-17 22:10:31 +01:00
SQMODE_DECL_TYPENAME(Typename, _SC("SqRoutineBase"))
2016-02-21 08:25:46 +01:00
// ------------------------------------------------------------------------------------------------
Routine::Time Routine::s_Last = 0;
Routine::Time Routine::s_Prev = 0;
2016-11-17 22:10:31 +01:00
Routine::Interval Routine::s_Intervals[SQMOD_MAX_ROUTINES];
Routine::Instance Routine::s_Instances[SQMOD_MAX_ROUTINES];
// ------------------------------------------------------------------------------------------------
void Routine::Process()
{
// Is this the first call?
if (s_Last == 0)
{
s_Last = Chrono::GetCurrentSysTime();
// We'll do it text time
return;
}
// Backup the last known time-stamp
s_Prev = s_Last;
// Get the current time-stamp
s_Last = Chrono::GetCurrentSysTime();
// Calculate the elapsed time
const Int32 delta = Int32((s_Last - s_Prev) / 1000L);
// Process all active routines
for (Interval * itr = s_Intervals; itr != (s_Intervals + SQMOD_MAX_ROUTINES); ++itr)
{
// Is this routine valid?
2016-11-17 22:10:31 +01:00
if (*itr)
{
2016-11-17 22:10:31 +01:00
// Decrease the elapsed time
(*itr) -= delta;
// Have we completed the routine interval?
if ((*itr) <= 0)
{
// Execute and reset the elapsed time
(*itr) = s_Instances[itr - s_Intervals].Execute();
}
}
}
}
// ------------------------------------------------------------------------------------------------
void Routine::Initialize()
{
2016-11-17 22:10:31 +01:00
std::memset(s_Intervals, 0, sizeof(s_Intervals));
}
// ------------------------------------------------------------------------------------------------
void Routine::Deinitialize()
{
2016-11-17 22:10:31 +01:00
// Release any script resources that the routines might store
for (auto & r : s_Instances)
{
2016-11-17 22:10:31 +01:00
r.Terminate();
}
}
// ------------------------------------------------------------------------------------------------
2016-11-17 22:10:31 +01:00
SQInteger Routine::Create(HSQUIRRELVM vm)
{
2016-11-17 22:10:31 +01:00
// Locate the identifier of a free slot
const SQInteger slot = FindUnused();
// See if we have where to store this routine
if (slot < 0)
{
2016-11-17 22:10:31 +01:00
return sq_throwerror(vm, "Reached the maximum number of active routines");
}
2016-11-17 22:10:31 +01:00
// Grab the top of the stack
const SQInteger top = sq_gettop(vm);
// See if too many arguments were specified
if (top >= 20) /* 5 base + 14 parameters = 19 */
{
2016-11-17 22:10:31 +01:00
return sq_throwerror(vm, "Too many parameters specified");
}
2016-11-17 22:10:31 +01:00
// Was there was an environment specified?
else if (top <= 1)
{
2016-11-17 22:10:31 +01:00
return sq_throwerror(vm, "Missing routine environment");
}
2016-11-17 22:10:31 +01:00
// Was there was a callback specified?
else if (top <= 2)
{
2016-11-17 22:10:31 +01:00
return sq_throwerror(vm, "Missing routine callback");
}
2016-11-17 22:10:31 +01:00
// Validate the callback type
else if (sq_gettype(vm, 3) != OT_CLOSURE && sq_gettype(vm, 3) != OT_NATIVECLOSURE)
{
2016-11-17 22:10:31 +01:00
return sq_throwerror(vm, "Invalid callback type");
}
2016-11-17 22:10:31 +01:00
SQRESULT res = SQ_OK;
// Prepare an object for the environment
HSQOBJECT env;
// Is the specified environment a null value?
if (sq_gettype(vm, 2) == OT_NULL)
{
2016-11-17 22:10:31 +01:00
// Preserve the stack state
const StackGuard sg(vm);
// Push the root table on the stack
sq_pushroottable(vm);
// Attempt to retrieve the table object
res = sq_getstackobj(vm, -1, &env);
}
else
{
2016-11-17 22:10:31 +01:00
sq_getstackobj(vm, 2, &env); // Just retrieve the specified environment
}
2016-11-17 22:10:31 +01:00
// Validate the result
if (SQ_FAILED(res))
{
2016-11-17 22:10:31 +01:00
return res; // Propagate the error
}
2016-02-21 08:25:46 +01:00
2016-11-17 22:10:31 +01:00
// Prepare an object for the function
HSQOBJECT func;
// Fetch the specified callback object
res = sq_getstackobj(vm, 3, &func);
// Validate the result
if (SQ_FAILED(res))
{
2016-11-17 22:10:31 +01:00
return res; // Propagate the error
}
2016-02-21 08:25:46 +01:00
2016-11-17 22:10:31 +01:00
// The number of iterations and interval to execute the routine
SQInteger intrv = 0, itr = 0;
// Was there an interval specified?
if (top > 3)
{
2016-11-17 22:10:31 +01:00
// Grab the interval from the stack
res = sq_getinteger(vm, 4, &intrv);
// Validate the result
if (SQ_FAILED(res))
{
2016-11-17 22:10:31 +01:00
return res; // Propagate the error
}
}
2016-11-17 22:10:31 +01:00
// Was there a number of iterations specified?
if (top > 4)
{
2016-11-17 22:10:31 +01:00
// Grab the iterations from the stack
res = sq_getinteger(vm, 5, &itr);
// Validate the result
if (SQ_FAILED(res))
{
2016-11-17 22:10:31 +01:00
return res; // Propagate the error
}
}
2016-02-21 08:25:46 +01:00
2016-11-17 22:10:31 +01:00
// Attempt to create a routine instance
try
{
2016-11-17 22:10:31 +01:00
ClassType< Routine >::PushInstance(vm, new Routine());
}
2016-11-17 22:10:31 +01:00
catch (const Sqrat::Exception & e)
{
2016-11-17 22:10:31 +01:00
return sq_throwerror(vm, "Unable to create the routine instance");
}
2016-11-17 22:10:31 +01:00
// Prepare an object for the routine
HSQOBJECT obj;
// Fetch the created routine object
res = sq_getstackobj(vm, -1, &obj);
// Validate the result
if (SQ_FAILED(res))
{
2016-11-17 22:10:31 +01:00
return res; // Propagate the error
}
2016-02-21 08:25:46 +01:00
2016-11-17 22:10:31 +01:00
// At this point we can grab a reference to our slot
Instance & inst = s_Instances[slot];
// Were there any arguments specified?
if (top > 5)
{
2016-11-17 22:10:31 +01:00
// Grab a pointer to the arguments array
Argument * args = inst.mArgv;
// Reset the argument counter
inst.mArgc = 0;
// Grab the specified arguments from the stack
for (SQInteger i = 6; i <= top; ++i)
{
2016-11-17 22:10:31 +01:00
res = sq_getstackobj(vm, i, &(args[inst.mArgc].mObj));
// Validate the result
if (SQ_FAILED(res))
{
// Clear previous arguments
inst.Clear();
// Propagate the error
return res;
}
// Keep a strong reference to the argument
sq_addref(vm, &(args[inst.mArgc].mObj));
// Increase the argument counter
++inst.mArgc;
}
}
2016-02-21 08:25:46 +01:00
2016-11-17 22:10:31 +01:00
// Attempt to retrieve the routine from the stack and associate it with the slot
try
{
2016-11-17 22:10:31 +01:00
Var< Routine * >(vm, -1).value->m_Slot = ConvTo< Uint32 >::From(slot);
}
2016-11-17 22:10:31 +01:00
catch (const Sqrat::Exception & e)
{
2016-11-17 22:10:31 +01:00
// Clear extracted arguments
inst.Clear();
// Now it's safe to throw the error
return sq_throwerror(vm, "Unable to create the routine instance");
}
2016-02-21 08:25:46 +01:00
2016-11-17 22:10:31 +01:00
// Alright, at this point we can initialize the slot
inst.Init(env, func, obj, intrv, itr);
// Now initialize the timer
s_Intervals[slot] = intrv;
// We have the created routine on the stack, so let's return it
return 1;
}
// ------------------------------------------------------------------------------------------------
bool Routine::IsWithTag(StackStrF & tag)
{
// Is the specified tag valid?
if (tag.mPtr != nullptr)
{
// Iterate routine list
for (const auto & r : s_Instances)
{
if (!r.mInst.IsNull() && r.mTag.compare(tag.mPtr) == 0)
{
return true; // Yup, we're doing this
}
}
}
// Unable to find such routine
return false;
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to process routines.
*/
void ProcessRoutines()
{
Routine::Process();
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to initialize routines.
*/
void InitializeRoutines()
{
Routine::Initialize();
}
/* ------------------------------------------------------------------------------------------------
* Forward the call to terminate routines.
*/
void TerminateRoutines()
{
Routine::Deinitialize();
}
2016-02-21 08:25:46 +01:00
// ================================================================================================
void Register_Routine(HSQUIRRELVM vm)
{
RootTable(vm).Bind(Typename::Str,
Class< Routine, NoConstructor< Routine > >(vm, Typename::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Routine::ToString)
// Properties
.Prop(_SC("Tag"), &Routine::GetTag, &Routine::SetTag)
2016-11-17 22:10:31 +01:00
.Prop(_SC("Env"), &Routine::GetEnv, &Routine::SetEnv)
.Prop(_SC("Func"), &Routine::GetFunc, &Routine::SetFunc)
.Prop(_SC("Data"), &Routine::GetData, &Routine::SetData)
2016-02-21 08:25:46 +01:00
.Prop(_SC("Interval"), &Routine::GetInterval, &Routine::SetInterval)
.Prop(_SC("Iterations"), &Routine::GetIterations, &Routine::SetIterations)
.Prop(_SC("Suspended"), &Routine::GetSuspended, &Routine::SetSuspended)
.Prop(_SC("Quiet"), &Routine::GetQuiet, &Routine::SetQuiet)
.Prop(_SC("Endure"), &Routine::GetEndure, &Routine::SetEndure)
2016-11-17 22:10:31 +01:00
.Prop(_SC("Arguments"), &Routine::GetArguments)
// Member Methods
.FmtFunc(_SC("SetTag"), &Routine::SetTag)
2016-02-21 08:25:46 +01:00
.Func(_SC("Terminate"), &Routine::Terminate)
2016-11-17 22:10:31 +01:00
.Func(_SC("GetArgument"), &Routine::GetArgument)
2016-02-21 08:25:46 +01:00
);
2016-11-17 22:10:31 +01:00
// Global functions
RootTable(vm).SquirrelFunc(_SC("SqRoutine"), &Routine::Create);
RootTable(vm).FmtFunc(_SC("SqFindRoutineByTag"), &Routine::FindByTag);
RootTable(vm).FmtFunc(_SC("SqIsRoutineWithTag"), &Routine::IsWithTag);
2016-02-21 08:25:46 +01:00
}
} // Namespace:: SqMod