mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Implement timers for official plug-in compatibility layer.
This commit is contained in:
parent
ed07b17c22
commit
1297635b89
@ -71,194 +71,393 @@ void Routine::Deinitialize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
struct RoutineBuilder
|
||||||
|
{
|
||||||
|
HSQUIRRELVM mVM{nullptr};
|
||||||
|
SQRESULT mRes{SQ_OK};
|
||||||
|
SQInteger mTop{0};
|
||||||
|
SQInteger mSlot{-1};
|
||||||
|
HSQOBJECT mEnv{};
|
||||||
|
HSQOBJECT mFunc{};
|
||||||
|
HSQOBJECT mInst{};
|
||||||
|
SQInteger mInterval{0};
|
||||||
|
SQInteger mIterations{0};
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Base constructor.
|
||||||
|
*/
|
||||||
|
RoutineBuilder(HSQUIRRELVM vm, SQInteger slot)
|
||||||
|
: mVM(vm), mRes(), mTop(sq_gettop(vm)), mSlot(slot), mEnv(), mFunc(), mInst(), mInterval(0), mIterations(0)
|
||||||
|
{
|
||||||
|
sq_resetobject(&mEnv);
|
||||||
|
sq_resetobject(&mFunc);
|
||||||
|
sq_resetobject(&mInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy/Move constructor (disabled).
|
||||||
|
*/
|
||||||
|
RoutineBuilder(const RoutineBuilder &) = delete;
|
||||||
|
RoutineBuilder(RoutineBuilder &&) = delete;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~RoutineBuilder() = default;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy/Move assignment operator (disabled).
|
||||||
|
*/
|
||||||
|
RoutineBuilder & operator = (const RoutineBuilder &) = delete;
|
||||||
|
RoutineBuilder & operator = (RoutineBuilder &&) = delete;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Initialize routine creation.
|
||||||
|
*/
|
||||||
|
SQRESULT Begin()
|
||||||
|
{
|
||||||
|
mRes = SQ_OK;
|
||||||
|
// See if we have where to store this routine
|
||||||
|
if (mSlot < 0)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Reached the maximum number of active routines");
|
||||||
|
}
|
||||||
|
// See if too many arguments were specified
|
||||||
|
else if (mTop >= 20) /* 5 base + 14 parameters = 19 */
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Too many parameters specified");
|
||||||
|
}
|
||||||
|
// Was there was an environment specified?
|
||||||
|
else if (mTop <= 1)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Missing routine environment");
|
||||||
|
}
|
||||||
|
// Was there was a callback specified?
|
||||||
|
else if (mTop <= 2)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Missing routine callback");
|
||||||
|
}
|
||||||
|
// Validate the callback type
|
||||||
|
else if (sq_gettype(mVM, 3) != OT_CLOSURE && sq_gettype(mVM, 3) != OT_NATIVECLOSURE)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Invalid callback type");
|
||||||
|
}
|
||||||
|
// Return the result
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Extract target.
|
||||||
|
*/
|
||||||
|
SQRESULT Target(SQInteger env, SQInteger func)
|
||||||
|
{
|
||||||
|
// Get the type of the environment object
|
||||||
|
const SQObjectType type = sq_gettype(mVM, env);
|
||||||
|
// Whether to default to the root table
|
||||||
|
bool use_root = (type == OT_NULL);
|
||||||
|
|
||||||
|
// Is the specified environment a boolean (true) value?
|
||||||
|
if (type == OT_STRING)
|
||||||
|
{
|
||||||
|
StackStrF val(mVM, env);
|
||||||
|
// Attempt to generate the string value
|
||||||
|
mRes = val.Proc(false);
|
||||||
|
// Have we failed to retrieve the string?
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
return mRes; // Propagate the error!
|
||||||
|
}
|
||||||
|
// If the string is empty or "root" then we use the root table
|
||||||
|
else if (!val.mLen || sqmod_stricmp(val.mPtr, "root") == 0)
|
||||||
|
{
|
||||||
|
use_root = true;
|
||||||
|
}
|
||||||
|
// If the string is "self" then we leave it null and default to self
|
||||||
|
else if (sqmod_stricmp(val.mPtr, "self") == 0)
|
||||||
|
{
|
||||||
|
use_root = false; // Just in case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the specified environment a null value?
|
||||||
|
if (use_root)
|
||||||
|
{
|
||||||
|
// Push the root table on the stack
|
||||||
|
sq_pushroottable(mVM);
|
||||||
|
// Attempt to retrieve the table object
|
||||||
|
mRes = sq_getstackobj(mVM, -1, &mEnv);
|
||||||
|
// Preserve the stack state
|
||||||
|
sq_poptop(mVM);
|
||||||
|
}
|
||||||
|
// Should we treat it as a valid environment object?
|
||||||
|
else if (type != OT_STRING)
|
||||||
|
{
|
||||||
|
mRes = sq_getstackobj(mVM, env, &mEnv); // Just retrieve the specified environment
|
||||||
|
}
|
||||||
|
// Can we attempt to retrieve the callback?
|
||||||
|
if (SQ_SUCCEEDED(mRes))
|
||||||
|
{
|
||||||
|
// Fetch the specified callback object
|
||||||
|
mRes = sq_getstackobj(mVM, func, &mFunc);
|
||||||
|
}
|
||||||
|
// Return result
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Extract options.
|
||||||
|
*/
|
||||||
|
SQRESULT Opts(SQInteger iv, SQInteger it)
|
||||||
|
{
|
||||||
|
// Was there an interval specified?
|
||||||
|
if (mTop >= iv)
|
||||||
|
{
|
||||||
|
// Grab the interval from the stack
|
||||||
|
mRes = sq_getinteger(mVM, iv, &mInterval);
|
||||||
|
// Validate the result
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
return mRes; // Propagate the error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Was there a number of iterations specified?
|
||||||
|
if (mTop >= it)
|
||||||
|
{
|
||||||
|
// Grab the iterations from the stack
|
||||||
|
mRes = sq_getinteger(mVM, it, &mIterations);
|
||||||
|
// Validate the result
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
return mRes; // Propagate the error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully processed
|
||||||
|
return SQ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Create instance.
|
||||||
|
*/
|
||||||
|
SQRESULT Inst()
|
||||||
|
{
|
||||||
|
// Attempt to create a routine instance
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DeleteGuard< Routine > dg(new Routine());
|
||||||
|
ClassType< Routine >::PushInstance(mVM, dg.Get());
|
||||||
|
dg.Release();
|
||||||
|
}
|
||||||
|
catch (const std::exception & e)
|
||||||
|
{
|
||||||
|
return (mRes = sq_throwerrorf(mVM, "Unable to create the routine instance: %s", e.what()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the created routine object
|
||||||
|
mRes = sq_getstackobj(mVM, -1, &mInst);
|
||||||
|
// Validate the result
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
return mRes; // Propagate the error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully created
|
||||||
|
return SQ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Extract arguments.
|
||||||
|
*/
|
||||||
|
SQRESULT Args(SQInteger idx)
|
||||||
|
{
|
||||||
|
// At this point we can grab a reference to our slot
|
||||||
|
Routine::Instance & inst = Routine::s_Instances[mSlot];
|
||||||
|
// Were there any arguments specified?
|
||||||
|
if (mTop >= idx)
|
||||||
|
{
|
||||||
|
// Grab a pointer to the arguments array
|
||||||
|
Routine::Argument * args = inst.mArgv;
|
||||||
|
// Reset the argument counter
|
||||||
|
inst.mArgc = 0;
|
||||||
|
// Grab the specified arguments from the stack
|
||||||
|
for (SQInteger i = idx; i <= mTop; ++i)
|
||||||
|
{
|
||||||
|
mRes = sq_getstackobj(mVM, i, &(args[inst.mArgc].mObj));
|
||||||
|
// Validate the result
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
// Clear previous arguments
|
||||||
|
inst.Clear();
|
||||||
|
// Propagate the error
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
|
// Keep a strong reference to the argument
|
||||||
|
sq_addref(mVM, &(args[inst.mArgc].mObj));
|
||||||
|
// Increase the argument counter
|
||||||
|
++inst.mArgc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully processed
|
||||||
|
return SQ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Finish routine creation.
|
||||||
|
*/
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
SQRESULT Finish(bool refs = false)
|
||||||
|
#else
|
||||||
|
SQRESULT Finish()
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Grab a reference to our slot
|
||||||
|
Routine::Instance & inst = Routine::s_Instances[mSlot];
|
||||||
|
// Attempt to retrieve the routine from the stack and associate it with the slot
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Var< Routine * >(mVM, -1).value->m_Slot = ConvTo< uint32_t >::From(mSlot);
|
||||||
|
}
|
||||||
|
catch (const std::exception & e)
|
||||||
|
{
|
||||||
|
// Clear extracted arguments
|
||||||
|
inst.Clear();
|
||||||
|
// Now it's safe to throw the error
|
||||||
|
return (mRes = sq_throwerrorf(mVM, "Unable to create the routine instance: %s", e.what()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alright, at this point we can initialize the slot
|
||||||
|
inst.Init(mEnv, mFunc, mInst, mInterval, static_cast< Routine::Iterator >(mIterations));
|
||||||
|
// Now initialize the timer
|
||||||
|
Routine::s_Intervals[mSlot] = mInterval;
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
// Drop the temporary callback reference
|
||||||
|
if (refs)
|
||||||
|
{
|
||||||
|
sq_release(mVM, &mFunc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Successfully finished
|
||||||
|
return SQ_OK;
|
||||||
|
}
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Initialize timer creation.
|
||||||
|
*/
|
||||||
|
SQRESULT BeginComp()
|
||||||
|
{
|
||||||
|
mRes = SQ_OK;
|
||||||
|
// See if we have where to store this timers
|
||||||
|
if (mSlot < 0)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Reached the maximum number of active routines");
|
||||||
|
}
|
||||||
|
// See if too many arguments were specified
|
||||||
|
else if (mTop >= 19) /* 4 base + 14 parameters = 18 */
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Too many parameters specified");
|
||||||
|
}
|
||||||
|
// Was there was a callback specified?
|
||||||
|
else if (mTop <= 1)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Missing timer callback");
|
||||||
|
}
|
||||||
|
// Validate the callback type
|
||||||
|
else if (sq_gettype(mVM, 2) != OT_STRING)
|
||||||
|
{
|
||||||
|
mRes = sq_throwerror(mVM, "Invalid callback type");
|
||||||
|
}
|
||||||
|
// Return the result
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Extract target.
|
||||||
|
*/
|
||||||
|
SQRESULT TargetComp(SQInteger func)
|
||||||
|
{
|
||||||
|
StackStrF val(mVM, func);
|
||||||
|
// Attempt to generate the string value
|
||||||
|
mRes = val.Proc(false);
|
||||||
|
// Have we failed to retrieve the string?
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
return mRes; // Propagate the error!
|
||||||
|
}
|
||||||
|
// Push the root table on the stack
|
||||||
|
sq_pushroottable(mVM);
|
||||||
|
// Attempt to retrieve the table object
|
||||||
|
mRes = sq_getstackobj(mVM, -1, &mEnv);
|
||||||
|
// Have we failed to retrieve the string?
|
||||||
|
if (SQ_FAILED(mRes))
|
||||||
|
{
|
||||||
|
return mRes; // Propagate the error!
|
||||||
|
}
|
||||||
|
// Push the callback name on the stack
|
||||||
|
sq_pushobject(mVM, val.mObj);
|
||||||
|
// Attempt to retrieve the value from the root table
|
||||||
|
mRes = sq_get(mVM, -2);
|
||||||
|
// Do we have the callback on the stack?
|
||||||
|
if (SQ_SUCCEEDED(mRes))
|
||||||
|
{
|
||||||
|
// Attempt to retrieve the function object
|
||||||
|
mRes = sq_getstackobj(mVM, -1, &mFunc);
|
||||||
|
// Keep a reference to it for now
|
||||||
|
if (SQ_SUCCEEDED(mRes))
|
||||||
|
{
|
||||||
|
sq_addref(mVM, &mFunc);
|
||||||
|
}
|
||||||
|
// Pop the callback and root table
|
||||||
|
sq_pop(mVM, 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sq_poptop(mVM); // Pop the root table
|
||||||
|
}
|
||||||
|
// Return the result
|
||||||
|
return mRes;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
SQInteger Routine::Create(HSQUIRRELVM vm)
|
SQInteger Routine::Create(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
// Locate the identifier of a free slot
|
RoutineBuilder b(vm, FindUnused());
|
||||||
const SQInteger slot = FindUnused();
|
// Initialize routine
|
||||||
// See if we have where to store this routine
|
if (SQ_FAILED(b.Begin()) ||
|
||||||
if (slot < 0)
|
SQ_FAILED(b.Target(2, 3)) ||
|
||||||
|
SQ_FAILED(b.Opts(4, 5)) ||
|
||||||
|
SQ_FAILED(b.Args(6)) ||
|
||||||
|
SQ_FAILED(b.Inst()) ||
|
||||||
|
SQ_FAILED(b.Finish()))
|
||||||
{
|
{
|
||||||
return sq_throwerror(vm, "Reached the maximum number of active routines");
|
return b.mRes; // Propagate result
|
||||||
}
|
}
|
||||||
// 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 */
|
|
||||||
{
|
|
||||||
return sq_throwerror(vm, "Too many parameters specified");
|
|
||||||
}
|
|
||||||
// Was there was an environment specified?
|
|
||||||
else if (top <= 1)
|
|
||||||
{
|
|
||||||
return sq_throwerror(vm, "Missing routine environment");
|
|
||||||
}
|
|
||||||
// Was there was a callback specified?
|
|
||||||
else if (top <= 2)
|
|
||||||
{
|
|
||||||
return sq_throwerror(vm, "Missing routine callback");
|
|
||||||
}
|
|
||||||
// Validate the callback type
|
|
||||||
else if (sq_gettype(vm, 3) != OT_CLOSURE && sq_gettype(vm, 3) != OT_NATIVECLOSURE)
|
|
||||||
{
|
|
||||||
return sq_throwerror(vm, "Invalid callback type");
|
|
||||||
}
|
|
||||||
|
|
||||||
SQRESULT res = SQ_OK;
|
|
||||||
// Prepare an object for the environment
|
|
||||||
HSQOBJECT env;
|
|
||||||
// Get the type of the environment object
|
|
||||||
const SQObjectType etype = sq_gettype(vm, 2);
|
|
||||||
// Whether to default to the root table
|
|
||||||
bool use_root = etype == OT_NULL;
|
|
||||||
// Is the specified environment a boolean (true) value?
|
|
||||||
if (etype == OT_STRING)
|
|
||||||
{
|
|
||||||
// Attempt to generate the string value
|
|
||||||
StackStrF val(vm, 2);
|
|
||||||
// Have we failed to retrieve the string?
|
|
||||||
if (SQ_FAILED(val.Proc()))
|
|
||||||
{
|
|
||||||
return val.mRes; // Propagate the error!
|
|
||||||
}
|
|
||||||
// If the string is empty or "root" then we use the root table
|
|
||||||
else if (!val.mLen || sqmod_stricmp(val.mPtr, "root") == 0)
|
|
||||||
{
|
|
||||||
use_root = true;
|
|
||||||
}
|
|
||||||
// If the string is "self" then we leave it null and default to self
|
|
||||||
else if (sqmod_stricmp(val.mPtr, "self") == 0)
|
|
||||||
{
|
|
||||||
sq_resetobject(&env); // Make sure environment is null
|
|
||||||
use_root = false; // Just in case
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Is the specified environment a null value?
|
|
||||||
if (use_root)
|
|
||||||
{
|
|
||||||
// Push the root table on the stack
|
|
||||||
sq_pushroottable(vm);
|
|
||||||
// Attempt to retrieve the table object
|
|
||||||
res = sq_getstackobj(vm, -1, &env);
|
|
||||||
// Preserve the stack state
|
|
||||||
sq_poptop(vm);
|
|
||||||
}
|
|
||||||
// Should we treat it as a valid environment object?
|
|
||||||
else if (etype != OT_STRING)
|
|
||||||
{
|
|
||||||
sq_getstackobj(vm, 2, &env); // Just retrieve the specified environment
|
|
||||||
}
|
|
||||||
// Validate the result
|
|
||||||
if (SQ_FAILED(res))
|
|
||||||
{
|
|
||||||
return res; // Propagate the error
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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))
|
|
||||||
{
|
|
||||||
return res; // Propagate the error
|
|
||||||
}
|
|
||||||
|
|
||||||
// The number of iterations and interval to execute the routine
|
|
||||||
SQInteger intrv = 0, itr = 0;
|
|
||||||
// Was there an interval specified?
|
|
||||||
if (top > 3)
|
|
||||||
{
|
|
||||||
// Grab the interval from the stack
|
|
||||||
res = sq_getinteger(vm, 4, &intrv);
|
|
||||||
// Validate the result
|
|
||||||
if (SQ_FAILED(res))
|
|
||||||
{
|
|
||||||
return res; // Propagate the error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Was there a number of iterations specified?
|
|
||||||
if (top > 4)
|
|
||||||
{
|
|
||||||
// Grab the iterations from the stack
|
|
||||||
res = sq_getinteger(vm, 5, &itr);
|
|
||||||
// Validate the result
|
|
||||||
if (SQ_FAILED(res))
|
|
||||||
{
|
|
||||||
return res; // Propagate the error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to create a routine instance
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DeleteGuard< Routine > dg(new Routine());
|
|
||||||
ClassType< Routine >::PushInstance(vm, dg.Get());
|
|
||||||
dg.Release();
|
|
||||||
}
|
|
||||||
catch (const std::exception & e)
|
|
||||||
{
|
|
||||||
return sq_throwerrorf(vm, "Unable to create the routine instance: %s", e.what());
|
|
||||||
}
|
|
||||||
// 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))
|
|
||||||
{
|
|
||||||
return res; // Propagate the error
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point we can grab a reference to our slot
|
|
||||||
Instance & inst = s_Instances[slot];
|
|
||||||
// Were there any arguments specified?
|
|
||||||
if (top > 5)
|
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to retrieve the routine from the stack and associate it with the slot
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Var< Routine * >(vm, -1).value->m_Slot = ConvTo< uint32_t >::From(slot);
|
|
||||||
}
|
|
||||||
catch (const std::exception & e)
|
|
||||||
{
|
|
||||||
// Clear extracted arguments
|
|
||||||
inst.Clear();
|
|
||||||
// Now it's safe to throw the error
|
|
||||||
return sq_throwerrorf(vm, "Unable to create the routine instance: %s", e.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alright, at this point we can initialize the slot
|
|
||||||
inst.Init(env, func, obj, intrv, static_cast< Iterator >(itr));
|
|
||||||
// Now initialize the timer
|
|
||||||
s_Intervals[slot] = intrv;
|
|
||||||
// We have the created routine on the stack, so let's return it
|
// We have the created routine on the stack, so let's return it
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQInteger Routine::CreateOfficial(HSQUIRRELVM vm)
|
||||||
|
{
|
||||||
|
RoutineBuilder b(vm, FindUnused());
|
||||||
|
// Initialize routine
|
||||||
|
if (SQ_FAILED(b.BeginComp()) ||
|
||||||
|
SQ_FAILED(b.TargetComp(2)) ||
|
||||||
|
SQ_FAILED(b.Opts(3, 4)) ||
|
||||||
|
SQ_FAILED(b.Args(5)) ||
|
||||||
|
SQ_FAILED(b.Inst()) ||
|
||||||
|
SQ_FAILED(b.Finish(true)))
|
||||||
|
{
|
||||||
|
return b.mRes; // Propagate result
|
||||||
|
}
|
||||||
|
// We have the created routine on the stack, so let's return it
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool Routine::IsWithTag(StackStrF & tag)
|
bool Routine::IsWithTag(StackStrF & tag)
|
||||||
{
|
{
|
||||||
@ -361,6 +560,9 @@ void Register_Routine(HSQUIRRELVM vm)
|
|||||||
RootTable(vm).FmtFunc(_SC("SqFindRoutineByTag"), &Routine::FindByTag);
|
RootTable(vm).FmtFunc(_SC("SqFindRoutineByTag"), &Routine::FindByTag);
|
||||||
RootTable(vm).FmtFunc(_SC("SqIsRoutineWithTag"), &Routine::IsWithTag);
|
RootTable(vm).FmtFunc(_SC("SqIsRoutineWithTag"), &Routine::IsWithTag);
|
||||||
RootTable(vm).FmtFunc(_SC("SqTerminateRoutineWithTag"), &Routine::TerminateWithTag);
|
RootTable(vm).FmtFunc(_SC("SqTerminateRoutineWithTag"), &Routine::TerminateWithTag);
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
RootTable(vm).SquirrelFunc(_SC("NewTimer"), &Routine::CreateOfficial);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
@ -6,19 +6,23 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
struct RoutineBuilder;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Execute callbacks after specific intervals of time.
|
* Execute callbacks after specific intervals of time.
|
||||||
*/
|
*/
|
||||||
class Routine
|
class Routine
|
||||||
{
|
{
|
||||||
|
friend struct RoutineBuilder;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Simplify future changes to a single point of change.
|
* Simplify future changes to a single point of change.
|
||||||
*/
|
*/
|
||||||
typedef int64_t Time;
|
typedef int64_t Time;
|
||||||
typedef SQInteger Interval;
|
typedef SQInteger Interval;
|
||||||
typedef uint32_t Iterator;
|
typedef uint32_t Iterator;
|
||||||
typedef LightObj Argument;
|
typedef LightObj Argument;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -40,7 +44,7 @@ private:
|
|||||||
bool mQuiet; // Whether this instance is allowed to handle errors.
|
bool mQuiet; // Whether this instance is allowed to handle errors.
|
||||||
bool mEndure; // Whether this instance is allowed to terminate itself on errors.
|
bool mEndure; // Whether this instance is allowed to terminate itself on errors.
|
||||||
bool mExecuting; // Whether this instance is currently being executed.
|
bool mExecuting; // Whether this instance is currently being executed.
|
||||||
uint8_t mArgc; // The number of arguments that the routine must forward.
|
uint8_t mArgc; // The number of arguments that the routine must forward.
|
||||||
Argument mArgv[14]; // The arguments that the routine must forward.
|
Argument mArgv[14]; // The arguments that the routine must forward.
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------------------
|
||||||
@ -329,6 +333,7 @@ public:
|
|||||||
}
|
}
|
||||||
// Unable to find such routine
|
// Unable to find such routine
|
||||||
STHROWF("Unable to find a routine with tag ({})", tag.mPtr);
|
STHROWF("Unable to find a routine with tag ({})", tag.mPtr);
|
||||||
|
SQ_UNREACHABLE;
|
||||||
// Should not reach this point but if it did, we have to return something
|
// Should not reach this point but if it did, we have to return something
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
@ -366,7 +371,12 @@ public:
|
|||||||
* Create a routine with the specified parameters.
|
* Create a routine with the specified parameters.
|
||||||
*/
|
*/
|
||||||
static SQInteger Create(HSQUIRRELVM vm);
|
static SQInteger Create(HSQUIRRELVM vm);
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Create a routine with the specified parameters using the official compatibility layer.
|
||||||
|
*/
|
||||||
|
static SQInteger CreateOfficial(HSQUIRRELVM vm);
|
||||||
|
#endif
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user