From 1f62e1f88be41e29b29b8cb893e4895452fcaadc Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sun, 21 Feb 2016 09:25:46 +0200 Subject: [PATCH] Initial implemenattion of routines. --- cbp/Module.cbp | 2 + source/Core.cpp | 5 +- source/Register.cpp | 2 +- source/Routine.cpp | 516 ++++++++++++++++++++++++++++++++++++++++++++ source/Routine.hpp | 317 +++++++++++++++++++++++++++ 5 files changed, 839 insertions(+), 3 deletions(-) create mode 100644 source/Routine.cpp create mode 100644 source/Routine.hpp diff --git a/cbp/Module.cbp b/cbp/Module.cbp index 1314e0de..38b67a9c 100644 --- a/cbp/Module.cbp +++ b/cbp/Module.cbp @@ -290,6 +290,8 @@ + + diff --git a/source/Core.cpp b/source/Core.cpp index 7a1d43dc..d6efd30d 100644 --- a/source/Core.cpp +++ b/source/Core.cpp @@ -2,6 +2,7 @@ #include "Core.hpp" #include "Logger.hpp" #include "Command.hpp" +#include "Routine.hpp" // ------------------------------------------------------------------------------------------------ #include "Entity/Blip.hpp" @@ -334,7 +335,7 @@ void Core::Terminate() // Release all resources from command manager _Cmd->Terminate(); // Release all resources from routines - //Routine::Cleanup(); + Routine::Cleanup(); // Is there a VM to close? if (m_VM) { @@ -1663,7 +1664,7 @@ void Core::EmitForcefieldExited(Int32 player, Int32 forcefield) void Core::EmitServerFrame(Float32 delta) { Emit(mOnServerFrame, delta); - //Routine::Process(); + Routine::Process(); } void Core::EmitServerStartup() diff --git a/source/Register.cpp b/source/Register.cpp index 1f56950a..561c9e0f 100644 --- a/source/Register.cpp +++ b/source/Register.cpp @@ -88,7 +88,7 @@ bool RegisterAPI(HSQUIRRELVM vm) Register_Log(vm); Register_Core(vm); Register_Command(vm); - //Register_Routine(vm); + Register_Routine(vm); Register_Misc(vm); diff --git a/source/Routine.cpp b/source/Routine.cpp new file mode 100644 index 00000000..107a8e73 --- /dev/null +++ b/source/Routine.cpp @@ -0,0 +1,516 @@ +// ------------------------------------------------------------------------------------------------ +#include "Routine.hpp" +#include "Library/Time.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +bool Routine::s_Lock = false; +Routine::Time Routine::s_Last = 0; +Routine::Time Routine::s_Prev = 0; +Routine::Queue Routine::s_Queue; +Routine::Buckets Routine::s_Buckets; + +// ------------------------------------------------------------------------------------------------ +Routine::Routine(Object & env, Function & func, Interval interval) + : m_Iterations(0) + , m_Interval(interval) + , m_Arguments(0) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) +{ + /* ... */ +} + +Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations) + : m_Iterations(iterations) + , m_Interval(interval) + , m_Arguments(0) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) +{ + Create(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1) + : m_Iterations(iterations) + , m_Interval(interval) + , m_Arguments(1) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) + , m_Arg1(a1) +{ + Create(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2) + : m_Iterations(iterations) + , m_Interval(interval) + , m_Arguments(2) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) + , m_Arg1(a1), m_Arg2(a2) +{ + Create(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2, Object & a3) + : m_Iterations(iterations) + , m_Interval(interval) + , m_Arguments(3) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) + , m_Arg1(a1), m_Arg2(a2), m_Arg3(a3) +{ + Create(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2, Object & a3, Object & a4) + : m_Iterations(iterations) + , m_Interval(interval) + , m_Arguments(4) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) + , m_Arg1(a1), m_Arg2(a2), m_Arg3(a3), m_Arg4(a4) +{ + Create(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2, Object & a3, Object & a4, Object & a5) + : m_Iterations(iterations) + , m_Interval(interval) + , m_Arguments(5) + , m_Suspended(false) + , m_Terminated(false) + , m_Callback(env.GetVM(), env, func.GetFunc()) + , m_Arg1(a1), m_Arg2(a2), m_Arg3(a3), m_Arg4(a4), m_Arg5(a5) +{ + Create(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::~Routine() +{ + if (!m_Terminated) + Terminate(); +} + +// ------------------------------------------------------------------------------------------------ +Int32 Routine::Cmp(const Routine & o) const +{ + if (m_Interval == o.m_Interval) + return 0; + else if (m_Interval > o.m_Interval) + return 1; + else + return -1; +} + +CSStr Routine::ToString() const +{ + return ToStrF(_PRINT_INT_FMT, m_Interval); +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Terminate() +{ + if (m_Terminated) + SqThrow("Routine was already terminated"); + else if (s_Lock) + s_Queue.push_back(Queue::value_type(false, this)); + else + { + Detach(); + Release(); + } +} + +// ------------------------------------------------------------------------------------------------ +void Routine::SetArg(Uint8 num, Object & val) +{ + if (m_Terminated) + { + SqThrow("Routine was terminated"); + return; + } + + switch (num) + { + case 1: m_Arg1 = val; break; + case 2: m_Arg2 = val; break; + case 3: m_Arg3 = val; break; + case 4: m_Arg4 = val; break; + case 5: m_Arg5 = val; break; + case 6: m_Arg6 = val; break; + case 7: m_Arg7 = val; break; + case 8: m_Arg8 = val; break; + case 9: m_Arg9 = val; break; + case 10: m_Arg10 = val; break; + case 11: m_Arg11 = val; break; + case 12: m_Arg12 = val; break; + case 13: m_Arg13 = val; break; + case 14: m_Arg14 = val; break; + default: SqThrow("Argument is out of range: %d", num); + } +} + +Object & Routine::GetArg(Uint8 num) +{ + if (m_Terminated) + { + SqThrow("Routine was terminated"); + return NullObject(); + } + + switch (num) + { + case 1: return m_Arg1; + case 2: return m_Arg2; + case 3: return m_Arg3; + case 4: return m_Arg4; + case 5: return m_Arg5; + case 6: return m_Arg6; + case 7: return m_Arg7; + case 8: return m_Arg8; + case 9: return m_Arg9; + case 10: return m_Arg10; + case 11: return m_Arg11; + case 12: return m_Arg12; + case 13: return m_Arg13; + case 14: return m_Arg14; + default: SqThrow("Argument is out of range: %d", num); + } + + return NullObject(); +} + +// ------------------------------------------------------------------------------------------------ +Routine::Interval Routine::GetInterval() const +{ + return m_Interval; +} + +void Routine::SetInterval(Interval interval) +{ + if (m_Terminated) + SqThrow("Routine was terminated"); + else if (!interval) + SqThrow("Invalid routine interval"); + else + { + Detach(); + m_Interval = interval; + Attach(); + } +} + +// ------------------------------------------------------------------------------------------------ +Routine::Iterate Routine::GetIterations() const +{ + return m_Iterations; +} + +void Routine::SetIterations(Iterate iterations) +{ + if (m_Terminated) + SqThrow("Routine was terminated"); + else + m_Iterations = iterations; +} + +// ------------------------------------------------------------------------------------------------ +Uint8 Routine::GetArguments() const +{ + return m_Arguments; +} + +void Routine::SetArguments(Uint8 num) +{ + if (m_Terminated) + SqThrow("Routine was terminated"); + else if (num > 14) + SqThrow("Argument is out of range: %d", num); + else + m_Arguments = num; +} + +// ------------------------------------------------------------------------------------------------ +bool Routine::GetSuspended() const +{ + return m_Suspended; +} + +void Routine::SetSuspended(bool toggle) +{ + if (m_Terminated) + SqThrow("Routine was terminated"); + else + m_Suspended = toggle; +} + +// ------------------------------------------------------------------------------------------------ +bool Routine::GetTerminated() const +{ + return m_Terminated; +} + +// ------------------------------------------------------------------------------------------------ +Function & Routine::GetCallback() +{ + if (m_Terminated) + SqThrow("Routine was terminated"); + else + return m_Callback; + return NullFunction(); +} + +void Routine::SetCallback(Object & env, Function & func) +{ + if (m_Terminated) + SqThrow("Routine was terminated"); + else + m_Callback = Function(env.GetVM(), env, func.GetFunc()); +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Release() +{ + if (m_Terminated) + return; + m_Terminated = true; + m_Callback.Release2(); + m_Arg1.Release(); + m_Arg2.Release(); + m_Arg3.Release(); + m_Arg4.Release(); + m_Arg5.Release(); + m_Arg6.Release(); + m_Arg7.Release(); + m_Arg8.Release(); + m_Arg9.Release(); + m_Arg10.Release(); + m_Arg11.Release(); + m_Arg12.Release(); + m_Arg13.Release(); + m_Arg14.Release(); +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Create() +{ + if (!m_Interval) + SqThrow("Invalid routine interval"); + else if (m_Callback.IsNull()) + SqThrow("Invalid routine callback"); + else + { + Attach(); + return; + } + Release(); +} + +void Routine::Attach() +{ + if (!m_Interval) + return; + else if (s_Lock) + { + s_Queue.push_back(Queue::value_type(true, this)); + return; + } + Buckets::iterator itr = std::find_if(s_Buckets.begin(), s_Buckets.end(), IntrvFunc(m_Interval)); + if (itr == s_Buckets.end()) + { + s_Buckets.push_back(Buckets::value_type(m_Interval)); + s_Buckets.back().mRoutines.push_back(this); + } + else if (std::find(itr->mRoutines.begin(), itr->mRoutines.end(), this) != itr->mRoutines.end()) + return; + else + itr->mRoutines.push_back(this); +} + +void Routine::Detach() +{ + if (!m_Interval) + return; + else if (s_Lock) + { + s_Queue.push_back(Queue::value_type(false, this)); + return; + } + Buckets::iterator bitr = std::find_if(s_Buckets.begin(), s_Buckets.end(), IntrvFunc(m_Interval)); + if (bitr == s_Buckets.end()) + return; + Routines::iterator ritr = std::find(bitr->mRoutines.begin(), bitr->mRoutines.end(), this); + if (ritr != bitr->mRoutines.end()) + bitr->mRoutines.erase(ritr); + // Any reason to keep this bucket? + if (bitr->mRoutines.empty()) + s_Buckets.erase(bitr); +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Execute() +{ + if (m_Suspended || m_Callback.IsNull()) + return; + switch (m_Arguments) + { + case 0: m_Callback.Execute(); + break; + case 1: m_Callback.Execute(m_Arg1); + break; + case 2: m_Callback.Execute(m_Arg1, m_Arg2); + break; + case 3: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3); + break; + case 4: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4); + break; + case 5: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5); + break; + case 6: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6); + break; + case 7: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7); + break; + case 8: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8); + break; + case 9: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9); + break; + case 10: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9, m_Arg10); + break; + case 11: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9, m_Arg10, m_Arg11); + break; + case 12: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12); + break; + case 13: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12, m_Arg13); + break; + case 14: m_Callback.Execute(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12, m_Arg13, m_Arg14); + break; + default: + SqThrow("Unknown argument count: %d", m_Arguments); + } + + if (m_Iterations && (--m_Iterations) == 0) + { + Terminate(); + } + +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Process() +{ + s_Lock = false; /* In case an exception prevented the unlock last time */ + if (!s_Queue.empty()) + { + for (Queue::iterator itr = s_Queue.begin(); itr != s_Queue.end(); ++itr) + { + if (itr->first && itr->second) + itr->second->Attach(); + else if (itr->second) + itr->second->Terminate(); + } + s_Queue.clear(); + } + // Is this the first call? + if (s_Last == 0) + { + s_Last = GetCurrentSysTime(); + return; + } + s_Lock = true; + s_Prev = s_Last; + s_Last = GetCurrentSysTime(); + Int32 delta = Int32((s_Last - s_Prev) / 1000L); + for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket) + { + bucket->mElapsed += delta; + if (bucket->mElapsed < bucket->mInterval) + continue; + Routines::iterator itr = bucket->mRoutines.begin(); + Routines::iterator end = bucket->mRoutines.end(); + for (; itr != end; ++itr) + (*itr)->Execute(); + bucket->mElapsed = 0; + } + s_Lock = false; +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Cleanup() +{ + for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket) + { + Routines::iterator itr = bucket->mRoutines.begin(); + Routines::iterator end = bucket->mRoutines.end(); + for (; itr != end; ++itr) + (*itr)->Release(); + } +} + +// ================================================================================================ +void Register_Routine(HSQUIRRELVM vm) +{ + RootTable(vm).Bind(_SC("SqRoutine"), + Class< Routine, NoCopy< Routine > >(vm, _SC("SqRoutine")) + /* Constructors */ + .Ctor< Object &, Function &, Routine::Interval >() + .Ctor< Object &, Function &, Routine::Interval, Routine::Iterate >() + .Ctor< Object &, Function &, Routine::Interval, Routine::Iterate + , Object & >() + .Ctor< Object &, Function &, Routine::Interval, Routine::Iterate + , Object &, Object & >() + .Ctor< Object &, Function &, Routine::Interval, Routine::Iterate + , Object &, Object &, Object & >() + .Ctor< Object &, Function &, Routine::Interval, Routine::Iterate + , Object &, Object &, Object &, Object & >() + .Ctor< Object &, Function &, Routine::Interval, Routine::Iterate + , Object &, Object &, Object &, Object &, Object & >() + /* Metamethods */ + .Func(_SC("_cmp"), &Routine::Cmp) + .Func(_SC("_tostring"), &Routine::ToString) + /* Properties */ + .Prop(_SC("Interval"), &Routine::GetInterval, &Routine::SetInterval) + .Prop(_SC("Iterations"), &Routine::GetIterations, &Routine::SetIterations) + .Prop(_SC("Arguments"), &Routine::GetArguments, &Routine::SetArguments) + .Prop(_SC("Suspended"), &Routine::GetSuspended, &Routine::SetSuspended) + .Prop(_SC("Terminated"), &Routine::GetTerminated) + .Prop(_SC("Callback"), &Routine::GetCallback) + /* Functions */ + .Func(_SC("Terminate"), &Routine::Terminate) + .Func(_SC("Bind"), &Routine::SetCallback) + .Func(_SC("GetArg"), &Routine::GetArg) + .Func(_SC("SetArg"), &Routine::SetArg) + ); +} + +} // Namespace:: SqMod diff --git a/source/Routine.hpp b/source/Routine.hpp new file mode 100644 index 00000000..cf520f24 --- /dev/null +++ b/source/Routine.hpp @@ -0,0 +1,317 @@ +#ifndef _ROUTINE_HPP_ +#define _ROUTINE_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Base/Shared.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Execute callbacks after specific intervals of time. +*/ +class Routine +{ +public: + + /* -------------------------------------------------------------------------------------------- + * Simplify future changes to a single point of change. + */ + typedef SQInteger Interval; + typedef Uint32 Iterate; + typedef std::vector< Routine * > Routines; + +protected: + + /* -------------------------------------------------------------------------------------------- + * Group of routines that have the same interval. + */ + struct Bucket + { + // ---------------------------------------------------------------------------------------- + Interval mInterval; /* The interval of time between calls. */ + Interval mElapsed; /* Time elapsed since the last pulse. */ + Routines mRoutines; /* Routines to trigger on completion. */ + + /* ---------------------------------------------------------------------------------------- + * Base constructor. + */ + Bucket(Interval interval) + : mInterval(interval), mElapsed(0), mRoutines() + { + /* ... */ + } + + /* ---------------------------------------------------------------------------------------- + * Copy constructor. + */ + Bucket(const Bucket & o) + : mInterval(o.mInterval), mElapsed(o.mElapsed), mRoutines(o.mRoutines) + { + /* ... */ + } + + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~Bucket() + { + /* ... */ + } + + /* ---------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Bucket & operator = (const Bucket & o) + { + mInterval = o.mInterval; + mElapsed = o.mElapsed; + mRoutines = o.mRoutines; + return *this; + } + }; + + // -------------------------------------------------------------------------------------------- + typedef Int64 Time; + typedef std::vector< Bucket > Buckets; + typedef std::vector< std::pair< bool, Routine * > > Queue; + + /* -------------------------------------------------------------------------------------------- + * Functor used to search for buckets with a certain interval. + */ + struct IntrvFunc + { + private: + + // ---------------------------------------------------------------------------------------- + Interval m_Interval; /* The interval to be matched. */ + + public: + + /* ---------------------------------------------------------------------------------------- + * Base constructor. + */ + IntrvFunc(Interval interval) + : m_Interval(interval) + { + /* ... */ + } + + /* ---------------------------------------------------------------------------------------- + * Function call operator. + */ + bool operator () (Buckets::reference elem) const + { + return (elem.mInterval == m_Interval); + } + }; + + // -------------------------------------------------------------------------------------------- + static bool s_Lock; /* Avoid further changes to the bucket pool. */ + static Time s_Last; /* Last time point. */ + static Time s_Prev; /* Previous time point. */ + static Queue s_Queue; /* Actions to be performed when the buckets aren't locked */ + static Buckets s_Buckets; /* Buckets of routines grouped by similar intervals. */ + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + Routine(const Routine &); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + Routine & operator = (const Routine &); + +public: + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval. + */ + Routine(Object & env, Function & func, Interval interval); + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval and explicit iterations. + */ + Routine(Object & env, Function & func, Interval interval, Iterate iterations); + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval, explicit iterations and arguments. + */ + Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1); + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval, explicit iterations and arguments. + */ + Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2); + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval, explicit iterations and arguments. + */ + Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2, Object & a3); + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval, explicit iterations and arguments. + */ + Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2, Object & a3, Object & a4); + + /* -------------------------------------------------------------------------------------------- + * Constructor with just an interval, explicit iterations and arguments. + */ + Routine(Object & env, Function & func, Interval interval, Iterate iterations + , Object & a1, Object & a2, Object & a3, Object & a4, Object & a5); + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~Routine(); + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const Routine & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Terminate this routine by releasing all resources and sscheduling it for detachment. + */ + void Terminate(); + + /* -------------------------------------------------------------------------------------------- + * Modify an explicit value to be passed as the specified argument. + */ + void SetArg(Uint8 num, Object & val); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value that is passed as the specified argument. + */ + Object & GetArg(Uint8 num); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the amount of time required to wait between calls to the routine. + */ + Interval GetInterval() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the amount of time required to wait between calls to the routine. + */ + void SetInterval(Interval interval); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of times that the routine can be called before terminating itself. + */ + Iterate GetIterations() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the number of times that the routine can be called before terminating itself. + */ + void SetIterations(Iterate iterations); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of arguments that are forwarded when executing the callback. + */ + Uint8 GetArguments() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the number of arguments that are forwarded when executing the callback. + */ + void SetArguments(Uint8 num); + + /* -------------------------------------------------------------------------------------------- + * See whether the routine is suspended from further calls. + */ + bool GetSuspended() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the routine is suspended from further calls. + */ + void SetSuspended(bool toggle); + + /* -------------------------------------------------------------------------------------------- + * See whether the routine was terminated or not. + */ + bool GetTerminated() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the currently binded callback. + */ + Function & GetCallback(); + + /* -------------------------------------------------------------------------------------------- + * Bind a certain function to be executed when this routine is triggered. + */ + void SetCallback(Object & env, Function & func); + +protected: + + /* -------------------------------------------------------------------------------------------- + * Release routine resources. + */ + void Release(); + + /* -------------------------------------------------------------------------------------------- + * Create the routine for the first time. + */ + void Create(); + + /* -------------------------------------------------------------------------------------------- + * Attach the routine to the associated bucket. + */ + void Attach(); + + /* -------------------------------------------------------------------------------------------- + * Attach the routine from the associated bucket. + */ + void Detach(); + + /* -------------------------------------------------------------------------------------------- + * Execute the binded callback. + */ + void Execute(); + +private: + + // -------------------------------------------------------------------------------------------- + Iterate m_Iterations; /* Number of iterations before self destruct. */ + Interval m_Interval; /* Interval between calls. */ + Uint8 m_Arguments; /* Number of arguments to forward. */ + bool m_Suspended; /* Whether calls should be ignored. */ + bool m_Terminated; /* Whether the routine was terminated. */ + + // -------------------------------------------------------------------------------------------- + Function m_Callback; /* The callback to be executed when triggered. */ + + /* -------------------------------------------------------------------------------------------- + * Arguments to be forwarded to the callback. + */ + Object m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, + m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12, m_Arg13, m_Arg14; + +public: + + /* -------------------------------------------------------------------------------------------- + * Process all active routines and update elapsed time. + */ + static void Process(); + + /* -------------------------------------------------------------------------------------------- + * Release all resources and prepare for shutdown. + */ + static void Cleanup(); +}; + +} // Namespace:: SqMod + +#endif // _ROUTINE_HPP_