mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-09 01:07:16 +01:00
1046 lines
32 KiB
C++
1046 lines
32 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Routine.hpp"
|
|
#include "Library/Chrono.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <algorithm>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Time Routine::s_Last = 0;
|
|
Routine::Time Routine::s_Prev = 0;
|
|
Routine::Routines Routine::s_Routines;
|
|
Routine::Objects Routine::s_Objects;
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
SQInteger Routine::Typename(HSQUIRRELVM vm)
|
|
{
|
|
static const SQChar name[] = _SC("SqRoutine");
|
|
sq_pushstring(vm, name, sizeof(name));
|
|
return 1;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
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 (auto & r : s_Routines)
|
|
{
|
|
// Is this routine valid?
|
|
if (!r.second)
|
|
{
|
|
continue;
|
|
}
|
|
// Decrease the elapsed time
|
|
r.first -= delta;
|
|
// Have we completed the routine interval?
|
|
if (r.first <= 0)
|
|
{
|
|
// Reset the elapsed time
|
|
r.first = r.second->m_Interval;
|
|
// Execute the routine
|
|
r.second->Execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Initialize()
|
|
{
|
|
// Clear all slots
|
|
s_Routines.fill(Element(0, nullptr));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Deinitialize()
|
|
{
|
|
// Process all routine instances
|
|
for (auto & r : s_Objects)
|
|
{
|
|
// Release all resources
|
|
r.first->Release();
|
|
// Mark it as terminated
|
|
r.first->m_Terminated = true;
|
|
}
|
|
// Release all references
|
|
s_Objects.clear();
|
|
// Clear all slots
|
|
s_Routines.fill(Element(0, nullptr));
|
|
// Clear the last time-stamp in case of a reload
|
|
s_Last = 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Associate(Routine * routine)
|
|
{
|
|
// Attempt to see if this instance already exists in the pool
|
|
Objects::iterator itr = s_Objects.find(routine);
|
|
// Is this routine remembered for the first time?
|
|
if (itr == s_Objects.end())
|
|
{
|
|
// Obtain the initial stack size
|
|
const StackGuard sg;
|
|
// Push this instance on the stack
|
|
ClassType< Routine >::PushInstance(DefaultVM::Get(), routine);
|
|
// Initialize this element into the pool
|
|
itr = s_Objects.emplace(routine, Var< Object >(DefaultVM::Get(), -1).value).first;
|
|
// If the iterator still points to a null element then we failed
|
|
if (itr == s_Objects.end())
|
|
{
|
|
// NOTE: Routine instance is destroyed by the script object if necessary!
|
|
STHROWF("Unable to remember routine instance");
|
|
}
|
|
}
|
|
// Does this routine still keep a strong reference to it self?
|
|
else if (itr->second.IsNull())
|
|
{
|
|
// Obtain the initial stack size
|
|
const StackGuard sg;
|
|
// Push this instance on the stack
|
|
ClassType< Routine >::PushInstance(DefaultVM::Get(), routine);
|
|
// Obtain a strong reference to it
|
|
itr->second = Var< Object >(DefaultVM::Get(), -1).value;
|
|
}
|
|
// Return the object that we have
|
|
return itr->second;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Dissociate(Routine * routine)
|
|
{
|
|
// Attempt to see if this instance already exists in the pool
|
|
Objects::iterator itr = s_Objects.find(routine);
|
|
// Was this routine even stored in the pool?
|
|
if (itr != s_Objects.end() && !itr->second.IsNull())
|
|
{
|
|
itr->second.Release(); // Release the reference to self
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool Routine::Associated(Routine * routine)
|
|
{
|
|
// Attempt to see if this instance already exists in the pool
|
|
Objects::iterator itr = s_Objects.find(routine);
|
|
// Return whether this routine is pooled and references itself
|
|
return (itr != s_Objects.end() && !itr->second.IsNull());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Forget(Routine * routine)
|
|
{
|
|
s_Objects.erase(routine);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Insert(Routine * routine, bool associate)
|
|
{
|
|
// Do we even have what to insert?
|
|
if (!routine)
|
|
{
|
|
return;
|
|
}
|
|
// See if this routine is already inserted
|
|
Routines::iterator itr = std::find_if(s_Routines.begin(), s_Routines.end(),
|
|
[routine](Element & e) -> bool { return (e.second == routine); });
|
|
// Is this instance already inserted?
|
|
if (itr != s_Routines.end())
|
|
{
|
|
return; // We have what we came here for!
|
|
}
|
|
// Attempt to locate an unused routine slot
|
|
itr = std::find_if(s_Routines.begin(), s_Routines.end(),
|
|
[](Element & e) -> bool { return (e.second == nullptr); });
|
|
// Are there any slots available?
|
|
if (itr == s_Routines.end())
|
|
{
|
|
STHROWF("Maximum number of active routines was reached: %d", SQMOD_MAX_ROUTINES);
|
|
}
|
|
// Insert the routine at the obtained slot
|
|
itr->first = routine->m_Interval;
|
|
itr->second = routine;
|
|
// Associate this slot with the routine instance
|
|
routine->m_Slot = std::distance(s_Routines.begin(), itr);
|
|
// Keep a string reference to this routine instance, if requested
|
|
if (associate)
|
|
{
|
|
Associate(routine);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Remove(Routine * routine)
|
|
{
|
|
// Do we even have what to remove?
|
|
if (!routine)
|
|
{
|
|
return;
|
|
}
|
|
Routines::iterator itr;
|
|
// Make sure the routine wasn't activated multiple time (paranoia)
|
|
do {
|
|
// Search for the slot with the specified routine instance
|
|
itr = std::find_if(s_Routines.begin(), s_Routines.end(),
|
|
[routine](Element & e) -> bool { return (e.second == routine); });
|
|
// Was this routine instance activated?
|
|
if (itr != s_Routines.end())
|
|
{
|
|
itr->first = 0;
|
|
itr->second = nullptr;
|
|
}
|
|
} while (itr != s_Routines.end());
|
|
// Reset the routine instance slot
|
|
routine->m_Slot = 0xFFFF;
|
|
// Release any strong reference to this routine instance
|
|
Dissociate(routine);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::Release()
|
|
{
|
|
// Release the callback
|
|
m_Callback.ReleaseGently();
|
|
// Release the arguments
|
|
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::Execute()
|
|
{
|
|
// Is this routine suspended or has nothing to call?
|
|
if (m_Suspended || m_Callback.IsNull())
|
|
{
|
|
return; // We're done here!
|
|
}
|
|
// Make sure that we have a known number of arguments
|
|
else if (m_Arguments > 14)
|
|
{
|
|
STHROWF("Routine [%s] => Out of range argument count [%d]", m_Tag.c_str(), m_Arguments);
|
|
}
|
|
// Attempt to forward the call
|
|
try
|
|
{
|
|
switch (m_Arguments)
|
|
{
|
|
// Attempt to identify how many arguments should be passed
|
|
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;
|
|
}
|
|
}
|
|
catch (const Sqrat::Exception & e)
|
|
{
|
|
LogErr("Routine [%s] => Squirrel error [%s]", m_Tag.c_str(), e.Message().c_str());
|
|
}
|
|
catch (const std::exception & e)
|
|
{
|
|
LogErr("Routine [%s] => Program error [%s]", m_Tag.c_str(), e.what());
|
|
}
|
|
catch (...)
|
|
{
|
|
LogErr("Routine [%s] => Unknown error", m_Tag.c_str());
|
|
}
|
|
// Decrease the number of iterations if necessary
|
|
if (m_Iterations && (--m_Iterations) == 0)
|
|
{
|
|
Terminate(); // This routine reached the end of it's life
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Routine(Object & env, Function & func, Interval interval)
|
|
: m_Iterations(0)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(0)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
Routine::Routine(Object & env, Function & func, Interval interval, Iterator iterations)
|
|
: m_Iterations(iterations)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(0)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Routine(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1)
|
|
: m_Iterations(iterations)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(1)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
, m_Arg1(a1)
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Routine(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2)
|
|
: m_Iterations(iterations)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(2)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
, m_Arg1(a1), m_Arg2(a2)
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Routine(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2, Object & a3)
|
|
: m_Iterations(iterations)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(3)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
, m_Arg1(a1), m_Arg2(a2), m_Arg3(a3)
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Routine(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2, Object & a3, Object & a4)
|
|
: m_Iterations(iterations)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(4)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
, m_Arg1(a1), m_Arg2(a2), m_Arg3(a3), m_Arg4(a4)
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Routine(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2, Object & a3, Object & a4, Object & a5)
|
|
: m_Iterations(iterations)
|
|
, m_Interval(interval)
|
|
, m_Slot(0xFFFF)
|
|
, m_Arguments(5)
|
|
, m_Suspended(false)
|
|
, m_Terminated(false)
|
|
, m_Callback()
|
|
, m_Tag(_SC(""))
|
|
, m_Data()
|
|
, m_Arg1(a1), m_Arg2(a2), m_Arg3(a3), m_Arg4(a4), m_Arg5(a5)
|
|
{
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
else
|
|
{
|
|
// Does the callback need a custom environment?
|
|
if (env.IsNull())
|
|
{
|
|
m_Callback = func;
|
|
}
|
|
else
|
|
{
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
// Activate this routine
|
|
Insert(this, false);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::~Routine()
|
|
{
|
|
// Remove this instance from the pool
|
|
Forget(this);
|
|
// Was the routine already terminated?
|
|
if (!m_Terminated)
|
|
{
|
|
return; // Nothing to release!
|
|
}
|
|
// Remove it from the pool
|
|
Remove(this);
|
|
// Release script resources
|
|
Release();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
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);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
const String & Routine::GetTag() const
|
|
{
|
|
return m_Tag;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::SetTag(CSStr tag)
|
|
{
|
|
m_Tag.assign(tag ? tag : _SC(""));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object & Routine::GetData()
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Return the requested information
|
|
return m_Data;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::SetData(Object & data)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Apply the specified value
|
|
m_Data = data;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::ApplyTag(CSStr tag)
|
|
{
|
|
m_Tag.assign(tag ? tag : _SC(""));
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::ApplyData(Object & data)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Apply the specified value
|
|
m_Data = data;
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::Activate()
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Make sure the interval is good
|
|
if (m_Interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
// Make sure no slot is associated
|
|
else if (m_Slot >= s_Routines.size())
|
|
{
|
|
Insert(this);
|
|
}
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::Deactivate()
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Remove it from the pool
|
|
Remove(this);
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::Terminate()
|
|
{
|
|
// Was the routine already terminated?
|
|
if (m_Terminated)
|
|
{
|
|
STHROWF("Routine was already terminated");
|
|
}
|
|
// Remove it from the pool
|
|
Remove(this);
|
|
// Release script resources
|
|
Release();
|
|
// Mark it as terminated
|
|
m_Terminated = true;
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::Reanimate()
|
|
{
|
|
// Allow the instance to be used
|
|
m_Terminated = false;
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine & Routine::SetArg(Uint16 num, Object & val)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Identify which argument was requested
|
|
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: STHROWF("Argument is out of range: %d", num);
|
|
}
|
|
// Allow chaining
|
|
return *this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object & Routine::GetArg(Uint16 num)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Identify which argument was requested
|
|
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: STHROWF("Argument is out of range: %d", num);
|
|
}
|
|
// Shouldn't really reach this point
|
|
return NullObject();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Interval Routine::GetInterval() const
|
|
{
|
|
return m_Interval;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::SetInterval(Interval interval)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Is the specified interval valid?
|
|
if (interval < 0)
|
|
{
|
|
STHROWF("Invalid routine interval");
|
|
}
|
|
// Do we have any slot to update?
|
|
if (m_Slot >= s_Routines.size())
|
|
{
|
|
// Update the interval
|
|
m_Interval = interval;
|
|
// We're done here!
|
|
return;
|
|
}
|
|
// Make changes visible immediately
|
|
if (interval > m_Interval)
|
|
{
|
|
s_Routines[m_Slot].first += (interval - m_Interval);
|
|
}
|
|
else
|
|
{
|
|
s_Routines[m_Slot].first -= (m_Interval - interval);
|
|
}
|
|
// Update the interval
|
|
m_Interval = interval;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Routine::Iterator Routine::GetIterations() const
|
|
{
|
|
return m_Iterations;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::SetIterations(Iterator iterations)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Perform the requested operation
|
|
m_Iterations = iterations;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Uint16 Routine::GetArguments() const
|
|
{
|
|
return m_Arguments;
|
|
}
|
|
|
|
void Routine::SetArguments(Uint16 num)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Is the specified argument count valid?
|
|
if (num > 14)
|
|
{
|
|
STHROWF("Argument is out of range: %d", num);
|
|
}
|
|
// Perform the requested operation
|
|
m_Arguments = num;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool Routine::GetSuspended() const
|
|
{
|
|
return m_Suspended;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::SetSuspended(bool toggle)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Perform the requested operation
|
|
m_Suspended = toggle;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool Routine::GetTerminated() const
|
|
{
|
|
return m_Terminated;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Function & Routine::GetCallback()
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Return the requested information
|
|
return m_Callback;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void Routine::SetCallback(Object & env, Function & func)
|
|
{
|
|
// Validate the routine lifetime
|
|
Validate();
|
|
// Perform the requested operation
|
|
m_Callback = Function(env.GetVM(), env, func.GetFunc());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval)
|
|
{
|
|
return Associate(new Routine(env, func, interval));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval, Iterator iterations)
|
|
{
|
|
return Associate(new Routine(env, func, interval, iterations));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1)
|
|
{
|
|
return Associate(new Routine(env, func, interval, iterations, a1));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2)
|
|
{
|
|
return Associate(new Routine(env, func, interval, iterations, a1, a2));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2, Object & a3)
|
|
{
|
|
return Associate(new Routine(env, func, interval, iterations, a1, a2, a3));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2, Object & a3, Object & a4)
|
|
{
|
|
return Associate(new Routine(env, func, interval, iterations, a1, a2, a3, a4));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::Create(Object & env, Function & func, Interval interval, Iterator iterations
|
|
, Object & a1, Object & a2, Object & a3, Object & a4, Object & a5)
|
|
{
|
|
return Associate(new Routine(env, func, interval, iterations, a1, a2, a3, a4, a5));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Object Routine::FindByTag(CSStr tag)
|
|
{
|
|
// Perform a validity check on the specified tag
|
|
if (!tag || *tag == '\0')
|
|
{
|
|
STHROWF("The specified routine tag is invalid: null/empty");
|
|
}
|
|
// Process each routine in the pool
|
|
for (const auto & elem : s_Objects)
|
|
{
|
|
// Is this routine valid (should always be) and does the tag match the specified one?
|
|
if (elem.first != nullptr && elem.first->m_Tag.compare(tag) == 0)
|
|
{
|
|
// Do we need to obtain the script object again?
|
|
if (elem.second.IsNull())
|
|
{
|
|
// Obtain the initial stack size
|
|
const StackGuard sg;
|
|
// Push this instance on the stack
|
|
ClassType< Routine >::PushInstance(DefaultVM::Get(), elem.first);
|
|
// Obtain a strong reference to it and return it
|
|
return Var< Object >(DefaultVM::Get(), -1).value;
|
|
}
|
|
// Stop searching and return this routine
|
|
return elem.second;
|
|
}
|
|
}
|
|
// Unable to locate a routine matching the specified tag
|
|
return NullObject();
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* 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();
|
|
}
|
|
|
|
// ================================================================================================
|
|
void Register_Routine(HSQUIRRELVM vm)
|
|
{
|
|
RootTable(vm).Bind(_SC("SqRoutine"),
|
|
Class< Routine, NoConstructor< Routine > >(vm, _SC("SqRoutine"))
|
|
// Meta-methods
|
|
.Func(_SC("_cmp"), &Routine::Cmp)
|
|
.SquirrelFunc(_SC("_typename"), &Routine::Typename)
|
|
.Func(_SC("_tostring"), &Routine::ToString)
|
|
// Properties
|
|
.Prop(_SC("Tag"), &Routine::GetTag, &Routine::SetTag)
|
|
.Prop(_SC("Data"), &Routine::GetData, &Routine::SetData)
|
|
.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("SetTag"), &Routine::ApplyTag)
|
|
.Func(_SC("SetData"), &Routine::ApplyData)
|
|
.Func(_SC("Terminate"), &Routine::Terminate)
|
|
.Func(_SC("Bind"), &Routine::SetCallback)
|
|
.Func(_SC("GetArg"), &Routine::GetArg)
|
|
.Func(_SC("SetArg"), &Routine::SetArg)
|
|
// Static Functions
|
|
.StaticFunc(_SC("FindByTag"), &Routine::FindByTag)
|
|
// Static Overloads
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval) >
|
|
(_SC("Create"), &Routine::Create)
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval, Routine::Iterator) >
|
|
(_SC("Create"), &Routine::Create)
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval, Routine::Iterator,
|
|
Object &) >
|
|
(_SC("Create"), &Routine::Create)
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval, Routine::Iterator,
|
|
Object &, Object &) >
|
|
(_SC("Create"), &Routine::Create)
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval, Routine::Iterator,
|
|
Object &, Object &, Object &) >
|
|
(_SC("Create"), &Routine::Create)
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval, Routine::Iterator,
|
|
Object &, Object &, Object &, Object &) >
|
|
(_SC("Create"), &Routine::Create)
|
|
.StaticOverload< Object (*)(Object &, Function &, Routine::Interval, Routine::Iterator,
|
|
Object &, Object &, Object &, Object &, Object &) >
|
|
(_SC("Create"), &Routine::Create)
|
|
);
|
|
}
|
|
|
|
} // Namespace:: SqMod
|