mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2026-08-03 06:17:10 +02:00
Major plugin refactor and cleanup.
Switched to POCO library for unified platform/library interface. Deprecated the external module API. It was creating more problems than solving. Removed most built-in libraries in favor of system libraries for easier maintenance. Cleaned and secured code with help from static analyzers.
This commit is contained in:
@@ -0,0 +1,483 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Areas.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <algorithm>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(AreaTypename, _SC("SqArea"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AreaManager AreaManager::s_Inst;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Area::AddArray(const Sqrat::Array & a)
|
||||
{
|
||||
float values[2];
|
||||
|
||||
a.Foreach([this, &values, n = int(0)](HSQUIRRELVM vm, SQInteger i) mutable -> SQRESULT {
|
||||
// Retrieve the type of the value
|
||||
const SQObjectType type = sq_gettype(vm, -1);
|
||||
// Are we dealing with a vector?
|
||||
if (type == OT_INSTANCE)
|
||||
{
|
||||
// Next time, start again for floats
|
||||
n = 0;
|
||||
// Grab the instance from the stack
|
||||
this->AddPoint(*ClassType< Vector2 >::GetInstance(vm, -1));
|
||||
}
|
||||
else if (type & SQOBJECT_NUMERIC)
|
||||
{
|
||||
// Retrieve the value from the stack
|
||||
values[n] = Var< float >(vm, -1).value;
|
||||
// Do we have enough to form a vector?
|
||||
if (++n == 2)
|
||||
{
|
||||
this->AddPointEx(values[0], values[1]);
|
||||
// Reset the counter
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
// Ignore anything else
|
||||
return SQ_OK;
|
||||
});
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Area::AddCircleEx(SQFloat cx, SQFloat cy, SQFloat cr, SQInteger num_segments)
|
||||
{
|
||||
for(SQInteger i = 0; i < num_segments; ++i)
|
||||
{
|
||||
CheckLock();
|
||||
// Get the current angle
|
||||
#ifdef SQUSEDOUBLE
|
||||
SQFloat theta = 2.0d * SQMOD_PI64 * static_cast< SQFloat >(i) / static_cast< SQFloat >(num_segments);
|
||||
#else
|
||||
SQFloat theta = 2.0f * SQMOD_PI * static_cast< SQFloat >(i) / static_cast< SQFloat >(num_segments);
|
||||
#endif // SQUSEDOUBLE
|
||||
// Calculate the x component
|
||||
SQFloat x = (cr * std::cos(theta)) + cx;
|
||||
// Calculate the y component
|
||||
SQFloat y = (cr * std::sin(theta)) + cy;
|
||||
// Insert the point into the list
|
||||
mPoints.emplace_back(x, y);
|
||||
// Update the bounding box
|
||||
Expand(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Area::Manage()
|
||||
{
|
||||
// Are we connected to any cells?
|
||||
if (!mCells.empty())
|
||||
{
|
||||
STHROWF("The area is already managed");
|
||||
}
|
||||
// We expect this to be called only from the script so that the first parameter in the vm
|
||||
// is the area instance
|
||||
LightObj obj(1, SqVM());
|
||||
// Attempt to manage this area
|
||||
AreaManager::Get().InsertArea(*this, obj);
|
||||
// Return whether the area is now managed by any cells
|
||||
return !mCells.empty();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Area::Unmanage()
|
||||
{
|
||||
// Are we connected to any cells?
|
||||
if (mCells.empty())
|
||||
{
|
||||
return true; // Already unmanaged
|
||||
}
|
||||
// Attempt to unmanage this area
|
||||
AreaManager::Get().RemoveArea(*this);
|
||||
// Return whether the area is not managed by any cells
|
||||
return mCells.empty();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Area::IsInside(float x, float y) const
|
||||
{
|
||||
// Is the an area to test?
|
||||
if (mPoints.size() < 3)
|
||||
{
|
||||
return false; // Can't possibly be in an area that doesn't exist
|
||||
}
|
||||
// http://sidvind.com/wiki/Point-in-polygon:_Jordan_Curve_Theorem
|
||||
// The points creating the polygon
|
||||
float x1, x2;
|
||||
// How many times the ray crosses a line segment
|
||||
int crossings = 0;
|
||||
// Iterate through each line
|
||||
for (uint32_t i = 0, n = static_cast< uint32_t >(mPoints.size()); i < n; ++i)
|
||||
{
|
||||
Points::const_reference a = mPoints[i];
|
||||
Points::const_reference b = mPoints[(i + 1) % n];
|
||||
// This is done to ensure that we get the same result when
|
||||
// the line goes from left to right and right to left.
|
||||
if (a.x < b.x)
|
||||
{
|
||||
x1 = a.x;
|
||||
x2 = b.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = b.x;
|
||||
x2 = a.x;
|
||||
}
|
||||
// First check if the ray is able to cross the line
|
||||
if (x > x1 && x <= x2 && (y < a.y || y <= b.y))
|
||||
{
|
||||
// Calculate the equation of the line
|
||||
const float dx = (b.x - a.x);
|
||||
const float dy = (b.y - a.y);
|
||||
float k;
|
||||
|
||||
if (fabsf(dx) < 0.000001f)
|
||||
{
|
||||
k = static_cast< float >(0xffffffffu); // NOLINT(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
|
||||
}
|
||||
else
|
||||
{
|
||||
k = (dy / dx);
|
||||
}
|
||||
|
||||
const float m = (a.y - k * a.x);
|
||||
const float y2 = (k * x + m);
|
||||
// Does the ray cross the line?
|
||||
if (y <= y2)
|
||||
{
|
||||
++crossings;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return if the crossings are not even
|
||||
return (crossings % 2 == 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AreaManager::AreaManager(size_t sz) noexcept
|
||||
: m_Queue(), m_ProcList(), m_Grid{}
|
||||
{
|
||||
// Negative half grid size (left)
|
||||
int l = (-GRIDH * CELLD);
|
||||
// Positive half grid size minus one cell (bottom)
|
||||
int b = (abs(l) - CELLD);
|
||||
// Negative half grid size minus one cell (right)
|
||||
int r = (l + CELLD);
|
||||
// Positive half grid size (top)
|
||||
int t = abs(l);
|
||||
// Initialize the grid cells
|
||||
for (auto & a : m_Grid)
|
||||
{
|
||||
for (auto & c : a)
|
||||
{
|
||||
// Grab a reference to the cell
|
||||
// Configure the range of the cell
|
||||
c.mL = static_cast< float >(l);
|
||||
c.mB = static_cast< float >(b);
|
||||
c.mR = static_cast< float >(r);
|
||||
c.mT = static_cast< float >(t);
|
||||
// Reserve area memory if requested
|
||||
c.mAreas.reserve(sz);
|
||||
// Reset the locks on this area
|
||||
c.mLocks = 0;
|
||||
// Advance the left side
|
||||
l = r;
|
||||
// Advance the right side
|
||||
r += CELLD;
|
||||
// Should we advance to the next row?
|
||||
if (r > (GRIDH * CELLD))
|
||||
{
|
||||
// Reset the left side
|
||||
l = (-GRIDH * CELLD);
|
||||
// Reset the right side
|
||||
r = (l + CELLD);
|
||||
// Advance the bottom
|
||||
b -= CELLD;
|
||||
// Advance the top
|
||||
t -= CELLD;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reserve some space in the queue
|
||||
m_Queue.reserve(128);
|
||||
m_ProcList.reserve(128);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AreaManager::Insert(AreaCell & c, Area & a, LightObj & obj)
|
||||
{
|
||||
// Is this cell currently locked?
|
||||
if (c.mLocks)
|
||||
{
|
||||
m_Queue.emplace_back(c, a, obj); // Queue this request for now
|
||||
}
|
||||
else
|
||||
{
|
||||
c.mAreas.emplace_back(&a, obj);
|
||||
}
|
||||
// Associate the area with this cell so it can't be managed again (even while in the queue)
|
||||
a.mCells.push_back(&c);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AreaManager::Remove(AreaCell & c, Area & a)
|
||||
{
|
||||
// Is this cell currently locked?
|
||||
if (c.mLocks)
|
||||
{
|
||||
m_Queue.emplace_back(c, a); // Queue this request for now
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to locate this area in the cell
|
||||
auto itr = std::find_if(c.mAreas.begin(), c.mAreas.end(),
|
||||
[&a](AreaCell::Areas::reference p) -> bool {
|
||||
return (p.first == &a);
|
||||
});
|
||||
// Have we found it?
|
||||
if (itr != c.mAreas.end())
|
||||
{
|
||||
c.mAreas.erase(itr); // Erase it
|
||||
}
|
||||
}
|
||||
// Dissociate the area with this cell so it can be managed again (even while in the queue)
|
||||
auto itr = std::find(a.mCells.begin(), a.mCells.end(), &c);
|
||||
// Was is associated?
|
||||
if (itr != a.mCells.end())
|
||||
{
|
||||
a.mCells.erase(itr); // Dissociate them
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AreaManager::ProcQueue()
|
||||
{
|
||||
// Look for actions that can be completed
|
||||
for (auto itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
||||
{
|
||||
// Was this cell unlocked in the meantime?
|
||||
if (itr->mCell->mLocks <= 0)
|
||||
{
|
||||
m_ProcList.push_back(itr);
|
||||
}
|
||||
}
|
||||
// Process the actions that are ready
|
||||
for (auto & itr : m_ProcList)
|
||||
{
|
||||
// Was this a remove request?
|
||||
if (itr->mObj.IsNull())
|
||||
{
|
||||
Remove(*(itr->mCell), *(itr->mArea));
|
||||
}
|
||||
else
|
||||
{
|
||||
Insert(*(itr->mCell), *(itr->mArea), itr->mObj);
|
||||
}
|
||||
}
|
||||
// Remove processed requests
|
||||
for (auto & itr : m_ProcList)
|
||||
{
|
||||
m_Queue.erase(itr);
|
||||
}
|
||||
// Actions were processed
|
||||
m_ProcList.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AreaManager::Clear()
|
||||
{
|
||||
// Clear the cells
|
||||
for (AreaCell (&row)[GRIDN] : m_Grid)
|
||||
{
|
||||
for (AreaCell & c : row)
|
||||
{
|
||||
c.mAreas.clear();
|
||||
}
|
||||
}
|
||||
// Clear the queue as well
|
||||
m_Queue.clear();
|
||||
m_ProcList.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AreaManager::InsertArea(Area & a, LightObj & obj)
|
||||
{
|
||||
// See if this area is already managed
|
||||
if (!a.mCells.empty() || a.mPoints.empty())
|
||||
{
|
||||
return; // Already managed or nothing to manage
|
||||
}
|
||||
// Go through each cell and check if the area touches it
|
||||
for (auto & y : m_Grid)
|
||||
{
|
||||
for (auto & c : y)
|
||||
{
|
||||
// Does the bounding box of this cell intersect with the one of the area?
|
||||
if (a.mL <= c.mR && c.mL <= a.mR && a.mB <= c.mT && c.mB <= a.mT)
|
||||
{
|
||||
Insert(c, a, obj); // Attempt to insert the area into this cell
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AreaManager::RemoveArea(Area & a)
|
||||
{
|
||||
// Just remove the associated cells
|
||||
for (auto c : a.mCells)
|
||||
{
|
||||
Remove(*c, a);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Vector2i AreaManager::LocateCell(float x, float y)
|
||||
{
|
||||
// Transform the world coordinates into a cell coordinates
|
||||
// and cast to integral after rounding the value
|
||||
int xc = static_cast< int >(std::round(x / CELLD));
|
||||
int yc = static_cast< int >(std::round(y / CELLD));
|
||||
// Grab the absolute cell coordinates for range checking
|
||||
const int xca = std::abs(xc);
|
||||
const int yca = std::abs(yc);
|
||||
// Make sure the cell coordinates are within range
|
||||
if (xca > (GRIDH+1) || yca > (GRIDH+1))
|
||||
{
|
||||
return {NOCELL, NOCELL}; // Out of our scanning area
|
||||
}
|
||||
// Clamp the x coordinate if necessary
|
||||
if (xca >= (GRIDH))
|
||||
{
|
||||
xc = xc < 0 ? -(GRIDH-1) : (GRIDH-1);
|
||||
}
|
||||
// Clamp the y coordinate if necessary
|
||||
if (yca >= (GRIDH))
|
||||
{
|
||||
yc = xc < 0 ? -(GRIDH-1) : (GRIDH-1);
|
||||
}
|
||||
// Return the identified cell row and column
|
||||
return {GRIDH+xc, GRIDH-yc};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPointEx(float x, float y, Function & func)
|
||||
{
|
||||
// Is the function valid?
|
||||
if (func.IsNull())
|
||||
{
|
||||
STHROWF("Invalid callback object");
|
||||
}
|
||||
// Begin testing
|
||||
AreaManager::Get().TestPoint([&func](AreaCell::Areas::reference ap) -> void {
|
||||
func.Execute(ap.second);
|
||||
}, x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPoint(const Vector2 & v, Function & func)
|
||||
{
|
||||
Areas_TestPointEx(v.x, v.y, func);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPointOnEx(float x, float y, Object & ctx, Function & func)
|
||||
{
|
||||
// Begin testing
|
||||
AreaManager::Get().TestPoint([&ctx, &func](AreaCell::Areas::reference ap) -> void {
|
||||
func.Execute(ctx, ap.second);
|
||||
}, x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPointOn(const Vector2 & v, Object & ctx, Function & func)
|
||||
{
|
||||
Areas_TestPointOnEx(v.x, v.y, ctx, func);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static Vector2i Areas_LocatePointCell(const Vector2 & v)
|
||||
{
|
||||
return AreaManager::Get().LocateCell(v.x, v.y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static Vector2i Areas_LocatePointCellEx(float x, float y)
|
||||
{
|
||||
return AreaManager::Get().LocateCell(x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TerminateAreas()
|
||||
{
|
||||
AreaManager::Get().Clear();
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Areas(HSQUIRRELVM vm)
|
||||
{
|
||||
RootTable(vm).Bind(_SC("SqArea"),
|
||||
Class< Area >(vm, AreaTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< StackStrF & >()
|
||||
.Ctor< SQInteger, StackStrF & >()
|
||||
.Ctor< const Vector2 &, const Vector2 &, const Vector2 & >()
|
||||
.Ctor< const Vector2 &, const Vector2 &, const Vector2 &, StackStrF & >()
|
||||
.Ctor< const Vector2 &, const Vector2 &, const Vector2 &, SQInteger, StackStrF & >()
|
||||
.Ctor< float, float, float, float, float, float >()
|
||||
.Ctor< float, float, float, float, float, float, StackStrF & >()
|
||||
.Ctor< float, float, float, float, float, float, SQInteger, StackStrF & >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &AreaTypename::Fn)
|
||||
.Func(_SC("_tostring"), &Area::ToString)
|
||||
// Member Properties
|
||||
.Prop(_SC("Name"), &Area::GetName, &Area::SetName)
|
||||
.Prop(_SC("ID"), &Area::GetID, &Area::SetID)
|
||||
.Prop(_SC("Locked"), &Area::IsLocked)
|
||||
.Prop(_SC("IsLocked"), &Area::IsLocked)
|
||||
.Prop(_SC("Center"), &Area::GetCenter)
|
||||
.Prop(_SC("Box"), &Area::GetBoundingBox, &Area::SetBoundingBox)
|
||||
.Prop(_SC("Empty"), &Area::Empty)
|
||||
.Prop(_SC("Empty"), &Area::Empty)
|
||||
.Prop(_SC("Size"), &Area::Size)
|
||||
.Prop(_SC("Points"), &Area::Size)
|
||||
.Prop(_SC("Capacity"), &Area::Capacity)
|
||||
// Member Methods
|
||||
.FmtFunc(_SC("SetName"), &Area::ApplyName)
|
||||
.Func(_SC("SetID"), &Area::ApplyID)
|
||||
.Func(_SC("Clear"), &Area::Clear)
|
||||
.Func(_SC("Reserve"), &Area::Reserve)
|
||||
.Func(_SC("SetBox"), &Area::SetBoundingBoxEx)
|
||||
.Func(_SC("SetBoundingBox"), &Area::SetBoundingBoxEx)
|
||||
.Func(_SC("Add"), &Area::AddPoint)
|
||||
.Func(_SC("AddEx"), &Area::AddPointEx)
|
||||
.Func(_SC("AddVirtual"), &Area::AddVirtualPoint)
|
||||
.Func(_SC("AddVirtualEx"), &Area::AddVirtualPointEx)
|
||||
.Func(_SC("AddCircle"), &Area::AddCircle)
|
||||
.Func(_SC("AddCircleEx"), &Area::AddCircleEx)
|
||||
.Func(_SC("AddFake"), &Area::AddVirtualPoint)
|
||||
.Func(_SC("AddFakeEx"), &Area::AddVirtualPointEx)
|
||||
.Func(_SC("AddArray"), &Area::AddArray)
|
||||
.Func(_SC("Test"), &Area::Test)
|
||||
.Func(_SC("TestEx"), &Area::TestEx)
|
||||
.Func(_SC("Manage"), &Area::Manage)
|
||||
.Func(_SC("Unmanage"), &Area::Unmanage)
|
||||
// Static Functions
|
||||
.StaticFunc(_SC("GlobalTest"), &Areas_TestPoint)
|
||||
.StaticFunc(_SC("GlobalTestEx"), &Areas_TestPointEx)
|
||||
.StaticFunc(_SC("GlobalTestOn"), &Areas_TestPointOn)
|
||||
.StaticFunc(_SC("GlobalTestOnEx"), &Areas_TestPointOnEx)
|
||||
.StaticFunc(_SC("LocatePointCell"), &Areas_LocatePointCell)
|
||||
.StaticFunc(_SC("LocatePointCellEx"), &Areas_LocatePointCellEx)
|
||||
.StaticFunc(_SC("UnmanageAll"), &TerminateAreas)
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,701 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Base/Circle.hpp"
|
||||
#include "Base/Vector2.hpp"
|
||||
#include "Base/Vector4.hpp"
|
||||
#include "Base/Vector2i.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Various information associated with an area cell.
|
||||
*/
|
||||
struct AreaCell
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::pair< Area *, LightObj > AreaPair; // A reference to an area object.
|
||||
typedef std::vector< AreaPair > Areas; // A list of area objects.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
float mL, mB, mR, mT; // Left-Bottom, Right-Top components of the cell bounding box.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Areas mAreas; // Areas that intersect with the cell.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
int mLocks; // The amount of locks on the cell.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
AreaCell()
|
||||
: mL(0), mB(0), mR(0), mT(0), mAreas(0), mLocks(0)
|
||||
{
|
||||
//...
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Area implementation used to store area points.
|
||||
*/
|
||||
struct Area
|
||||
{
|
||||
typedef std::vector< Vector2 > Points;
|
||||
typedef std::vector< AreaCell * > Cells;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static constexpr float DEF_L = std::numeric_limits< float >::infinity();
|
||||
static constexpr float DEF_B = std::numeric_limits< float >::infinity();
|
||||
static constexpr float DEF_R = -std::numeric_limits< float >::infinity();
|
||||
static constexpr float DEF_T = -std::numeric_limits< float >::infinity();
|
||||
// --------------------------------------------------------------------------------------------
|
||||
float mL, mB, mR, mT; // Left-Bottom, Right-Top components of the bounding box.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Points mPoints; // Collection of points that make up the area.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SQInteger mID; // The user identifier given to this area.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Cells mCells; // The cells covered by this area.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
String mName; // The user name given to this area.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Area()
|
||||
: mL(DEF_L), mB(DEF_B), mR(DEF_R), mT(DEF_T), mPoints(), mID(0), mCells(), mName()
|
||||
{
|
||||
//...
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Named constructor.
|
||||
*/
|
||||
explicit Area(StackStrF & name)
|
||||
: Area(16, name)
|
||||
{
|
||||
//...
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Area(SQInteger sz, StackStrF & name)
|
||||
: mL(DEF_L), mB(DEF_B), mR(DEF_R), mT(DEF_T), mPoints(), mID(0), mCells()
|
||||
, mName(name.mPtr, static_cast< size_t >(name.mLen <= 0 ? 0 : name.mLen))
|
||||
|
||||
{
|
||||
// Should we reserve some space for points in advance?
|
||||
if (sz > 0)
|
||||
{
|
||||
mPoints.reserve(static_cast< size_t >(sz));
|
||||
}
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Vector2 constructor.
|
||||
*/
|
||||
Area(const Vector2 & a, const Vector2 & b, const Vector2 & c)
|
||||
: Area(a.x, a.y, b.x, b.y, c.x, c.y, 16, StackStrF::Dummy())
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Vector2 constructor with name.
|
||||
*/
|
||||
Area(const Vector2 & a, const Vector2 & b, const Vector2 & c, StackStrF & name)
|
||||
: Area(a.x, a.y, b.x, b.y, c.x, c.y, 16, name)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Vector2 constructor with name and memory to reserve.
|
||||
*/
|
||||
Area(const Vector2 & a, const Vector2 & b, const Vector2 & c, SQInteger sz, StackStrF & name)
|
||||
: Area(a.x, a.y, b.x, b.y, c.x, c.y, sz, name)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Extended constructor.
|
||||
*/
|
||||
Area(float ax, float ay, float bx, float by, float cx, float cy)
|
||||
: Area(ax, ay, bx, by, cx, cy, 16, StackStrF::Dummy())
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Extended constructor with name.
|
||||
*/
|
||||
Area(float ax, float ay, float bx, float by, float cx, float cy, StackStrF & name)
|
||||
: Area(ax, ay, bx, by, cx, cy, 16, name)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Area(float ax, float ay, float bx, float by, float cx, float cy, SQInteger sz, StackStrF & name)
|
||||
: mL(DEF_L), mB(DEF_B), mR(DEF_R), mT(DEF_T), mPoints(), mID(0), mCells()
|
||||
, mName(name.mPtr, static_cast<size_t>(name.mLen <= 0 ? 0 : name.mLen))
|
||||
{
|
||||
// Should we reserve some space for points in advance?
|
||||
if (sz > 0)
|
||||
{
|
||||
mPoints.reserve(static_cast< size_t >(sz));
|
||||
}
|
||||
// Insert the given points
|
||||
AddPointEx(ax, ay);
|
||||
AddPointEx(bx, by);
|
||||
AddPointEx(cx, cy);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
Area(const Area & o)
|
||||
: mL(o.mL), mB(o.mB), mR(o.mR), mT(o.mT), mPoints(o.mPoints), mID(o.mID), mCells(0), mName(o.mName)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
Area(Area && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Area & operator = (const Area & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
Area & operator = (Area && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert this instance to a string.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & ToString() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Checks if the area is locked from changes and throws an exception if it is.
|
||||
*/
|
||||
void CheckLock() const
|
||||
{
|
||||
// Are we connected to any cells?
|
||||
if (!mCells.empty())
|
||||
{
|
||||
STHROWF("The area cannot be modified while being managed");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the name of this area.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & GetName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the name of this area.
|
||||
*/
|
||||
void SetName(StackStrF & name)
|
||||
{
|
||||
if (name.mLen <= 0)
|
||||
{
|
||||
mName.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
mName.assign(name.mPtr, static_cast< size_t >(name.mLen));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the name of this area. (allows chaining function calls)
|
||||
*/
|
||||
Area & ApplyName(StackStrF & name)
|
||||
{
|
||||
SetName(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the identifier of this area.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetID() const
|
||||
{
|
||||
return mID;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the identifier of this area.
|
||||
*/
|
||||
void SetID(SQInteger id)
|
||||
{
|
||||
mID = id;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the identifier of this area. (allows chaining function calls)
|
||||
*/
|
||||
Area & ApplyID(SQInteger id)
|
||||
{
|
||||
mID = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if the area is locked from changes
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsLocked() const
|
||||
{
|
||||
return mCells.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the center of this area.
|
||||
*/
|
||||
SQMOD_NODISCARD Vector2 GetCenter() const
|
||||
{
|
||||
return {(mL * 0.5f) + (mR * 0.5f), (mB * 0.5f) + (mT * 0.5f)};
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the bounding box of this area.
|
||||
*/
|
||||
SQMOD_NODISCARD Vector4 GetBoundingBox() const
|
||||
{
|
||||
return {mL, mB, mR, mT};
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the bounding box of this area.
|
||||
*/
|
||||
void SetBoundingBox(const Vector4 & b)
|
||||
{
|
||||
CheckLock();
|
||||
// Apply the given bounding box
|
||||
mL = b.x;
|
||||
mB = b.y;
|
||||
mR = b.z;
|
||||
mT = b.w;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the bounding box of this area.
|
||||
*/
|
||||
void SetBoundingBoxEx(float l, float b, float r, float t)
|
||||
{
|
||||
CheckLock();
|
||||
// Apply the given bounding box
|
||||
mL = l;
|
||||
mB = b;
|
||||
mR = r;
|
||||
mT = t;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the area has no points.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Empty() const
|
||||
{
|
||||
return mPoints.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of points in this area.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Size() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(mPoints.size());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of points this area has allocated for.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Capacity() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(mPoints.capacity());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all points in this area.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
CheckLock();
|
||||
// Perform the requested action
|
||||
mPoints.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all points in this area.
|
||||
*/
|
||||
void Reserve(SQInteger sz)
|
||||
{
|
||||
// Perform the requested action
|
||||
if (sz > 0)
|
||||
{
|
||||
mPoints.reserve(static_cast< size_t >(sz));
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add a 2D vector to the point list.
|
||||
*/
|
||||
void AddPoint(const Vector2 & v)
|
||||
{
|
||||
CheckLock();
|
||||
// Perform the requested action
|
||||
mPoints.emplace_back(v);
|
||||
// Update the bounding box
|
||||
Expand(v.x, v.y);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add a point to the point list.
|
||||
*/
|
||||
void AddPointEx(float x, float y)
|
||||
{
|
||||
CheckLock();
|
||||
// Perform the requested action
|
||||
mPoints.emplace_back(x, y);
|
||||
// Update the bounding box
|
||||
Expand(x, y);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add a 2D vector to the bounding box only. Not stored in the list.
|
||||
*/
|
||||
void AddVirtualPoint(const Vector2 & v)
|
||||
{
|
||||
CheckLock();
|
||||
// Update the bounding box
|
||||
Expand(v.x, v.y);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add a point to the bounding box only. Not stored in the list.
|
||||
*/
|
||||
void AddVirtualPointEx(float x, float y)
|
||||
{
|
||||
CheckLock();
|
||||
// Update the bounding box
|
||||
Expand(x, y);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add an array of points to the point list.
|
||||
*/
|
||||
void AddArray(const Sqrat::Array & a);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add a 2D circle to the point list.
|
||||
*/
|
||||
void AddCircle(const Circle & c, SQInteger num_segments)
|
||||
{
|
||||
AddCircleEx(c.pos.x, c.pos.y, c.rad, num_segments);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add a 2D circle to the point list.
|
||||
*/
|
||||
void AddCircleEx(SQFloat cx, SQFloat cy, SQFloat cr, SQInteger num_segments);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Test if a point is inside the bounding box and then the area.
|
||||
*/
|
||||
bool Test(const Vector2 & v)
|
||||
{
|
||||
// Is the given point in this bounding box at least?
|
||||
if (mL <= v.x && mR >= v.x && mB <= v.y && mT >= v.y)
|
||||
{
|
||||
return mPoints.empty() || IsInside(v.x, v.y);
|
||||
}
|
||||
// Not in this area
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Test if a point is inside the bounding box and then the area.
|
||||
*/
|
||||
bool TestEx(float x, float y)
|
||||
{
|
||||
// Is the given point in this bounding box at least?
|
||||
if (mL <= x && mR >= x && mB <= y && mT >= y)
|
||||
{
|
||||
return mPoints.empty() || IsInside(x, y);
|
||||
}
|
||||
// Not in this area
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add this area to the manager to be scanned. MUST BE CALLED ONLY FROM SCRIPT!
|
||||
*/
|
||||
bool Manage();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Remove this area from the manager to no longer be scanned.
|
||||
*/
|
||||
bool Unmanage();
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Test if a point is inside the area.
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsInside(float x, float y) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Expand the bounding box area to include the given point.
|
||||
*/
|
||||
void Expand(float x, float y)
|
||||
{
|
||||
mL = std::fmin(mL, x);
|
||||
mB = std::fmin(mB, y);
|
||||
mR = std::fmax(mR, x);
|
||||
mT = std::fmax(mT, y);
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Manager responsible for storing and partitioning areas.
|
||||
*/
|
||||
class AreaManager
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static AreaManager s_Inst; // Manager instance.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
explicit AreaManager(size_t sz = 16) noexcept;
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper used to make sure a cell is properly processed after leaving the scope.
|
||||
*/
|
||||
struct CellGuard
|
||||
{
|
||||
AreaCell & mCell;
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
explicit CellGuard(AreaCell & cell)
|
||||
: mCell(cell)
|
||||
{
|
||||
++(cell.mLocks); // Place a lock on the cell to prevent iterator invalidation
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~CellGuard()
|
||||
{
|
||||
// Remove the lock from the cell so it can be processed
|
||||
--(mCell.mLocks);
|
||||
// Process requested actions during the lock
|
||||
AreaManager::Get().ProcQueue();
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static constexpr int GRIDN = 16; // Number of horizontal and vertical number of cells.
|
||||
static constexpr int GRIDH = GRIDN/2; // Half of the grid horizontal and vertical size.
|
||||
static constexpr int CELLS = GRIDN*GRIDN; // Total number of cells in the grid.
|
||||
static constexpr int CELLH = CELLS/2; // Half total number of cells in the grid.
|
||||
static constexpr int CELLD = 256; // Area covered by a cell in the world.
|
||||
static constexpr int NOCELL = std::numeric_limits< int >::max(); // Inexistent cell index.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper used to queue a certain action if the cell is locked.
|
||||
*/
|
||||
struct QueueElement
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------
|
||||
AreaCell * mCell; // The cell to be affected.
|
||||
Area * mArea; // The area that made the request.
|
||||
LightObj mObj; // Strong reference to the object.
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
QueueElement(AreaCell & cell, Area & area)
|
||||
: mCell(&cell), mArea(&area), mObj()
|
||||
{
|
||||
//...
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
QueueElement(AreaCell & cell, Area & area, LightObj & obj)
|
||||
: mCell(&cell), mArea(&area), mObj(obj)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
QueueElement(const QueueElement & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
QueueElement(QueueElement && o) noexcept
|
||||
: mCell(o.mCell), mArea(o.mArea), mObj(std::move(o.mObj))
|
||||
{
|
||||
// Take ownership
|
||||
o.mCell = nullptr;
|
||||
o.mArea = nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
QueueElement & operator = (const QueueElement & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
QueueElement & operator = (QueueElement && o) noexcept
|
||||
{
|
||||
// Avoid self assignment
|
||||
if (this != &o)
|
||||
{
|
||||
// Transfer values
|
||||
mCell = o.mCell;
|
||||
mArea = o.mArea;
|
||||
mObj = std::move(o.mObj);
|
||||
// Take ownership
|
||||
o.mCell = nullptr;
|
||||
o.mArea = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::vector< QueueElement > Queue; // Queued actions.
|
||||
typedef std::vector< Queue::iterator > ProcList; // Elements in the queue redy to process.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to insert an area into a cell or queue the action if not possible.
|
||||
*/
|
||||
void Insert(AreaCell & c, Area & a, LightObj & obj);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to remove an area from a cell or queue the action if not possible.
|
||||
*/
|
||||
void Remove(AreaCell & c, Area & a);
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Queue m_Queue; // Actions currently queued.
|
||||
ProcList m_ProcList; // Actions ready to be completed.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
AreaCell m_Grid[GRIDN][GRIDN]; // A grid of area lists.
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
AreaManager(const AreaManager & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
AreaManager(AreaManager && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
AreaManager & operator = (const AreaManager & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
AreaManager & operator = (AreaManager && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the core instance.
|
||||
*/
|
||||
SQMOD_NODISCARD static AreaManager & Get()
|
||||
{
|
||||
return s_Inst;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to process elements in the queue that can be completed.
|
||||
*/
|
||||
void ProcQueue();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all cell lists and release any script references.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add an area to be managed.
|
||||
*/
|
||||
void InsertArea(Area & a, LightObj & obj);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Add an area to be managed.
|
||||
*/
|
||||
void RemoveArea(Area & a);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all cell lists and release any script references.
|
||||
*/
|
||||
static Vector2i LocateCell(float x, float y);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Test a point to see whether it intersects with any areas
|
||||
*/
|
||||
template < typename F > void TestPoint(F && f, float x, float y)
|
||||
{
|
||||
// Transform the world coordinates into a cell coordinates
|
||||
const Vector2i cc(LocateCell(x, y));
|
||||
// Were these coordinates valid?
|
||||
if (cc.x == NOCELL)
|
||||
{
|
||||
return; // Not our problem
|
||||
}
|
||||
// Retrieve a reference to the identified cell
|
||||
AreaCell & c = m_Grid[cc.y][cc.x];
|
||||
// Is this cell empty?
|
||||
if (c.mAreas.empty())
|
||||
{
|
||||
return; // Nothing to test
|
||||
}
|
||||
// Guard the cell while processing
|
||||
const CellGuard cg(c);
|
||||
// Finally, begin processing the areas in this cell
|
||||
for (auto & a : c.mAreas)
|
||||
{
|
||||
if (a.first->TestEx(x, y))
|
||||
{
|
||||
f(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,224 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Buffer.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstring>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Compute the next power of two for the specified number.
|
||||
*/
|
||||
SQMOD_NODISCARD inline unsigned int NextPow2(unsigned int num)
|
||||
{
|
||||
--num;
|
||||
num |= num >> 1u;
|
||||
num |= num >> 2u;
|
||||
num |= num >> 4u;
|
||||
num |= num >> 8u;
|
||||
num |= num >> 16u;
|
||||
return ++num;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer::Buffer(const Buffer & o)
|
||||
: m_Ptr(nullptr), m_Cap(o.m_Cap), m_Cur(o.m_Cur)
|
||||
{
|
||||
if (m_Cap)
|
||||
{
|
||||
Request(o.m_Cap);
|
||||
std::memcpy(m_Ptr, o.m_Ptr, o.m_Cap);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
// Do we have a buffer?
|
||||
if (m_Ptr)
|
||||
{
|
||||
Release(); // Release it!
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer & Buffer::operator = (const Buffer & o) // NOLINT(cert-oop54-cpp)
|
||||
{
|
||||
if (m_Ptr != o.m_Ptr)
|
||||
{
|
||||
// Can we work in the current buffer?
|
||||
if (m_Cap && o.m_Cap <= m_Cap)
|
||||
{
|
||||
// It's safe to copy the data
|
||||
std::memcpy(m_Ptr, o.m_Ptr, o.m_Cap);
|
||||
}
|
||||
// Do we even have data to copy?
|
||||
else if (!o.m_Cap)
|
||||
{
|
||||
// Do we have a buffer?
|
||||
if (m_Ptr)
|
||||
{
|
||||
Release(); // Release it!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do we have a buffer?
|
||||
if (m_Ptr)
|
||||
{
|
||||
Release(); // Release it!
|
||||
}
|
||||
// Request a larger buffer
|
||||
Request(o.m_Cap);
|
||||
// Now it's safe to copy the data
|
||||
std::memcpy(m_Ptr, o.m_Ptr, o.m_Cap);
|
||||
}
|
||||
// Also copy the edit cursor
|
||||
m_Cur = o.m_Cur;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Buffer::Grow(SzType n)
|
||||
{
|
||||
// Backup the current memory
|
||||
Buffer bkp(m_Ptr, m_Cap, m_Cur);
|
||||
// Acquire a bigger buffer
|
||||
Request(bkp.m_Cap + n);
|
||||
// Copy the data from the old buffer
|
||||
std::memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap);
|
||||
// Copy the previous edit cursor
|
||||
m_Cur = bkp.m_Cur;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Buffer::Request(SzType n)
|
||||
{
|
||||
// NOTE: Function assumes (n > 0)
|
||||
assert(n > 0);
|
||||
// Round up the size to a power of two number
|
||||
n = (n & (n - 1)) ? NextPow2(n) : n;
|
||||
// Release previous memory if any
|
||||
delete[] m_Ptr; // Implicitly handles null!
|
||||
// Attempt to allocate memory
|
||||
m_Ptr = new Value[n];
|
||||
// If no errors occurred then we can set the size
|
||||
m_Cap = n;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Buffer::Release()
|
||||
{
|
||||
// Deallocate the memory
|
||||
delete[] m_Ptr; // Implicitly handles null!
|
||||
// Explicitly reset the buffer
|
||||
m_Ptr = nullptr;
|
||||
m_Cap = 0;
|
||||
m_Cur = 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer::SzType Buffer::Write(SzType pos, ConstPtr data, SzType size)
|
||||
{
|
||||
// Do we have what to write?
|
||||
if (!data || !size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// See if the buffer size must be adjusted
|
||||
else if ((pos + size) >= m_Cap)
|
||||
{
|
||||
// Acquire a larger buffer
|
||||
Grow((pos + size) - m_Cap + 32);
|
||||
}
|
||||
// Copy the data into the internal buffer
|
||||
std::memcpy(m_Ptr + pos, data, size);
|
||||
// Return the amount of data written to the buffer
|
||||
return size;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, ...)
|
||||
{
|
||||
// Initialize the variable argument list
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// Call the function that takes the variable argument list
|
||||
const SzType ret = WriteF(pos, fmt, args);
|
||||
// Finalize the variable argument list
|
||||
va_end(args);
|
||||
// Return the result
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, va_list args)
|
||||
{
|
||||
// Is the specified position within range?
|
||||
if (pos >= m_Cap)
|
||||
{
|
||||
// Acquire a larger buffer
|
||||
Grow(pos - m_Cap + 32);
|
||||
}
|
||||
// Backup the variable argument list
|
||||
va_list args_cpy;
|
||||
va_copy(args_cpy, args);
|
||||
// Attempt to write to the current buffer
|
||||
// (if empty, it should tell us the necessary size)
|
||||
int ret = std::vsnprintf(m_Ptr + pos, m_Cap, fmt, args);
|
||||
// Do we need a bigger buffer?
|
||||
if ((pos + ret) >= m_Cap)
|
||||
{
|
||||
// Acquire a larger buffer
|
||||
Grow((pos + ret) - m_Cap + 32);
|
||||
// Retry writing the requested information
|
||||
ret = std::vsnprintf(m_Ptr + pos, m_Cap, fmt, args_cpy);
|
||||
}
|
||||
// Return the value 0 if data could not be written
|
||||
if (ret < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Return the number of written characters
|
||||
return static_cast< SzType >(ret);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Buffer::SzType Buffer::WriteS(SzType pos, ConstPtr str)
|
||||
{
|
||||
// Is there any string to write?
|
||||
if (str && *str != '\0')
|
||||
{
|
||||
// Forward this to the regular write function
|
||||
return Write(pos, str, static_cast< SzType >(std::strlen(str)));
|
||||
}
|
||||
// Nothing to write
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Buffer::AppendF(const char * fmt, ...)
|
||||
{
|
||||
// Initialize the variable argument list
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// Forward this to the regular write function
|
||||
m_Cur += WriteF(m_Cur, fmt, args);
|
||||
// Finalize the variable argument list
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Buffer::AppendS(const char * str)
|
||||
{
|
||||
// Is there any string to write?
|
||||
if (str)
|
||||
{
|
||||
m_Cur += Write(m_Cur, str, static_cast< SzType >(std::strlen(str)));
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,863 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <utility>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "SqBase.hpp"
|
||||
#include <fmt/core.h>
|
||||
#include <sqratUtil.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template < class... Args > void ThrowMemExcept(Args &&... args)
|
||||
{
|
||||
throw Sqrat::Exception(fmt::format(std::forward< Args >(args)...));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Reusable and re-scalable buffer memory for quick memory allocations.
|
||||
*/
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef char Value; // The type of value used to represent a byte.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef Value & Reference; // A reference to the stored value type.
|
||||
typedef const Value & ConstRef; // A const reference to the stored value type.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef Value * Pointer; // A pointer to the stored value type.
|
||||
typedef const Value * ConstPtr; // A const pointer to the stored value type.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef unsigned int SzType; // The type used to represent size in general.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static_assert(sizeof(Value) == 1, "Value type must be 1 byte");
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Disambiguation tags that can be passed to constructors to indicate that memory can be owned.
|
||||
*/
|
||||
struct OwnIt {
|
||||
explicit OwnIt() = default;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct and take ownership of the specified buffer.
|
||||
*/
|
||||
Buffer(Pointer & ptr, SzType & cap, SzType & cur)
|
||||
: m_Ptr(ptr)
|
||||
, m_Cap(cap)
|
||||
, m_Cur(cur)
|
||||
{
|
||||
ptr = nullptr;
|
||||
cap = 0;
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor. (null)
|
||||
*/
|
||||
Buffer()
|
||||
: m_Ptr(nullptr), m_Cap(0), m_Cur(0)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit size constructor.
|
||||
*/
|
||||
explicit Buffer(SzType size)
|
||||
: Buffer()
|
||||
{
|
||||
Request(size < 8 ? 8 : size);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit size and cursor position constructor.
|
||||
*/
|
||||
Buffer(SzType size, SzType pos)
|
||||
: Buffer()
|
||||
{
|
||||
Request(size < 8 ? 8 : size);
|
||||
Move(pos);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit size and buffer constructor.
|
||||
*/
|
||||
Buffer(ConstPtr data, SzType size)
|
||||
: Buffer()
|
||||
{
|
||||
Request(size < 8 ? 8 : size);
|
||||
m_Cur += Write(m_Cur, data, size);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit size and buffer constructor with buffer stealing.
|
||||
*/
|
||||
Buffer(Pointer data, SzType size, OwnIt)
|
||||
: m_Ptr(data), m_Cap(size), m_Cur(0)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit size, data and cursor position constructor.
|
||||
*/
|
||||
Buffer(ConstPtr data, SzType size, SzType pos)
|
||||
: Buffer()
|
||||
{
|
||||
Request(size < 8 ? 8 : size);
|
||||
Write(m_Cur, data, size);
|
||||
Move(pos);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit size, data and cursor position constructor with buffer stealing.
|
||||
*/
|
||||
Buffer(Pointer data, SzType size, SzType pos, OwnIt)
|
||||
: m_Ptr(data), m_Cap(size), m_Cur(0)
|
||||
{
|
||||
Move(pos);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
Buffer(const Buffer & o);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
Buffer(Buffer && o) noexcept
|
||||
: m_Ptr(o.m_Ptr), m_Cap(o.m_Cap), m_Cur(o.m_Cur)
|
||||
{
|
||||
o.m_Ptr = nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Buffer();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
Buffer & operator = (const Buffer & o);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
Buffer & operator = (Buffer && o) noexcept
|
||||
{
|
||||
if (m_Ptr != o.m_Ptr)
|
||||
{
|
||||
if (m_Ptr)
|
||||
{
|
||||
Release();
|
||||
}
|
||||
m_Ptr = o.m_Ptr;
|
||||
m_Cap = o.m_Cap;
|
||||
m_Cur = o.m_Cur;
|
||||
o.m_Ptr = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Equality comparison operator.
|
||||
*/
|
||||
bool operator == (const Buffer & o) const
|
||||
{
|
||||
return (m_Cap == o.m_Cap);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Inequality comparison operator.
|
||||
*/
|
||||
bool operator != (const Buffer & o) const
|
||||
{
|
||||
return (m_Cap != o.m_Cap);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Less than comparison operator.
|
||||
*/
|
||||
bool operator < (const Buffer & o) const
|
||||
{
|
||||
return (m_Cap < o.m_Cap);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Greater than comparison operator.
|
||||
*/
|
||||
bool operator > (const Buffer & o) const
|
||||
{
|
||||
return (m_Cap > o.m_Cap);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Less than or equal comparison operator.
|
||||
*/
|
||||
bool operator <= (const Buffer & o) const
|
||||
{
|
||||
return (m_Cap <= o.m_Cap);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Greater than or equal comparison operator.
|
||||
*/
|
||||
bool operator >= (const Buffer & o) const
|
||||
{
|
||||
return (m_Cap >= o.m_Cap);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Implicit conversion to boolean.
|
||||
*/
|
||||
explicit operator bool () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
return (m_Ptr != nullptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Negation operator.
|
||||
*/
|
||||
bool operator ! () const
|
||||
{
|
||||
return (!m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD Pointer Data()
|
||||
{
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD ConstPtr Data() const
|
||||
{
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer casted as a different type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T * Get()
|
||||
{
|
||||
return reinterpret_cast< T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer casted as a different type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T * Get() const
|
||||
{
|
||||
return reinterpret_cast< const T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a certain element type at the specified position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & At(SzType n)
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Make sure that the specified element is withing buffer range
|
||||
else if (n > (m_Cap - sizeof(T)))
|
||||
{
|
||||
ThrowMemExcept("Element of size (%d) at index (%u) is out of buffer capacity (%u)",
|
||||
sizeof(T), n, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + n);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a certain element type at the specified position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & At(SzType n) const
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Make sure that the specified element is withing buffer range
|
||||
else if (n > (m_Cap - sizeof(T)))
|
||||
{
|
||||
ThrowMemExcept("Element of size (%d) at index (%u) is out of buffer capacity (%u)",
|
||||
sizeof(T), n, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + n);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer casted as a different type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T * Begin()
|
||||
{
|
||||
return reinterpret_cast< T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer casted as a different type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T * Begin() const
|
||||
{
|
||||
return reinterpret_cast< const T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer casted as a different type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T * End()
|
||||
{
|
||||
return reinterpret_cast< T * >(m_Ptr) + (m_Cap / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the internal buffer casted as a different type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T * End() const
|
||||
{
|
||||
return reinterpret_cast< const T * >(m_Ptr) + (m_Cap / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element at the front of the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & Front()
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element at the front of the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & Front() const
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element after the first element in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & Next()
|
||||
{
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element after the first element in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & Next() const
|
||||
{
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element at the back of the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & Back()
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + (m_Cap - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element at the back of the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & Back() const
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + (m_Cap - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element before the last element in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & Prev()
|
||||
{
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + (m_Cap - (sizeof(T) * 2)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element before the last element in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & Prev() const
|
||||
{
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + (m_Cap - (sizeof(T) * 2)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Reposition the edit cursor to the specified number of elements ahead.
|
||||
*/
|
||||
template < typename T = Value > void Advance(SzType n)
|
||||
{
|
||||
// Do we need to scale the buffer?
|
||||
if ((m_Cur + (n * sizeof(T))) > m_Cap)
|
||||
{
|
||||
Grow(m_Cur + (n * sizeof(T)));
|
||||
}
|
||||
// Advance to the specified position
|
||||
m_Cur += (n * sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Reposition the edit cursor to the specified number of elements behind.
|
||||
*/
|
||||
template < typename T = Value > void Retreat(SzType n)
|
||||
{
|
||||
// Can we move that much backward?
|
||||
if ((n * sizeof(T)) <= m_Cur)
|
||||
{
|
||||
m_Cur -= (n * sizeof(T));
|
||||
}
|
||||
// Just got to the beginning
|
||||
else
|
||||
{
|
||||
m_Cur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Reposition the edit cursor to a fixed position within the buffer.
|
||||
*/
|
||||
template < typename T = Value > void Move(SzType n)
|
||||
{
|
||||
// Do we need to scale the buffer?
|
||||
if ((n * sizeof(T)) > m_Cap)
|
||||
{
|
||||
Grow(n * sizeof(T));
|
||||
}
|
||||
// Move to the specified position
|
||||
m_Cur = (n * sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a value to the current cursor location and advance the cursor.
|
||||
*/
|
||||
template < typename T = Value > void Push(T v)
|
||||
{
|
||||
// Do we need to scale the buffer?
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
Grow(m_Cap + sizeof(T));
|
||||
}
|
||||
// Assign the specified value
|
||||
*reinterpret_cast< T * >(m_Ptr + m_Cur) = v;
|
||||
// Move to the next element
|
||||
m_Cur += sizeof(T);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element at the cursor position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & Cursor()
|
||||
{
|
||||
// Make sure that at least one element of this type exists after the cursor
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + m_Cur);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element at the cursor position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & Cursor() const
|
||||
{
|
||||
// Make sure that at least one element of this type exists after the cursor
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + m_Cur);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element before the cursor position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & Before()
|
||||
{
|
||||
// The cursor must have at least one element of this type behind
|
||||
if (m_Cur < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Cannot read an element of size (%u) before the cursor at (%u)",
|
||||
sizeof(T), m_Cur);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + (m_Cur - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element before the cursor position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & Before() const
|
||||
{
|
||||
// The cursor must have at least one element of this type behind
|
||||
if (m_Cur < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Cannot read an element of size (%u) before the cursor at (%u)",
|
||||
sizeof(T), m_Cur);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + (m_Cur - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element after the cursor position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD T & After()
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// There must be buffer left for at least two elements of this type after the cursor
|
||||
else if ((m_Cur + (sizeof(T) * 2)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + m_Cur + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the element after the cursor position.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD const T & After() const
|
||||
{
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// There must be buffer left for at least two elements of this type after the cursor
|
||||
else if ((m_Cur + (sizeof(T) * 2)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + m_Cur + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve maximum elements it can hold for a certain type.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD static SzType Max()
|
||||
{
|
||||
return static_cast< SzType >(0xFFFFFFFF / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current buffer capacity in element count.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD SzType Size() const
|
||||
{
|
||||
return static_cast< SzType >(m_Cap / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current buffer capacity in byte count.
|
||||
*/
|
||||
SQMOD_NODISCARD SzType Capacity() const
|
||||
{
|
||||
return m_Cap;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current buffer capacity in byte count.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD SzType CapacityAs() const
|
||||
{
|
||||
return static_cast< SzType >(m_Cap / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current position of the cursor in the buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD SzType Position() const
|
||||
{
|
||||
return m_Cur;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current position of the cursor in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SQMOD_NODISCARD SzType PositionAs() const
|
||||
{
|
||||
return static_cast< SzType >(m_Cur / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the amount of unused buffer after the edit cursor.
|
||||
*/
|
||||
SQMOD_NODISCARD SzType Remaining() const
|
||||
{
|
||||
return m_Cap - m_Cur;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Grow the size of the internal buffer by the specified amount of bytes.
|
||||
*/
|
||||
void Grow(SzType n);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Makes sure there is enough capacity to hold the specified element count.
|
||||
*/
|
||||
template < typename T = Value > Buffer Adjust(SzType n)
|
||||
{
|
||||
// Do we meet the minimum size?
|
||||
if (n < 8)
|
||||
{
|
||||
n = 8; // Adjust to minimum size
|
||||
}
|
||||
// See if the requested capacity doesn't exceed the limit
|
||||
if (n > Max< T >())
|
||||
{
|
||||
ThrowMemExcept("Requested buffer of (%u) elements exceeds the (%u) limit", n, Max< T >());
|
||||
}
|
||||
// Is there an existing buffer?
|
||||
else if (n && !m_Cap)
|
||||
{
|
||||
Request(n * sizeof(T)); // Request the memory
|
||||
}
|
||||
// Should the size be increased?
|
||||
else if (n > m_Cap)
|
||||
{
|
||||
// Backup the current memory
|
||||
Buffer bkp(m_Ptr, m_Cap, m_Cur);
|
||||
// Request the memory
|
||||
Request(n * sizeof(T));
|
||||
// Return the backup
|
||||
return bkp;
|
||||
}
|
||||
// Return an empty buffer
|
||||
return Buffer();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release the managed memory.
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
if (m_Ptr)
|
||||
{
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release the managed memory.
|
||||
*/
|
||||
void ResetAll()
|
||||
{
|
||||
if (m_Ptr)
|
||||
{
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Swap the contents of two buffers.
|
||||
*/
|
||||
void Swap(Buffer & o)
|
||||
{
|
||||
Pointer p = m_Ptr;
|
||||
SzType n = m_Cap;
|
||||
m_Ptr = o.m_Ptr;
|
||||
m_Cap = o.m_Cap;
|
||||
o.m_Ptr = p;
|
||||
o.m_Cap = n;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a portion of a buffer to the internal buffer.
|
||||
*/
|
||||
SzType Write(SzType pos, ConstPtr data, SzType size);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write another buffer to the internal buffer.
|
||||
*/
|
||||
SzType Write(SzType pos, const Buffer & b)
|
||||
{
|
||||
return Write(pos, b.m_Ptr, b.m_Cur);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a formatted string to the internal buffer.
|
||||
*/
|
||||
SzType WriteF(SzType pos, const char * fmt, ...);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a formatted string to the internal buffer.
|
||||
*/
|
||||
SzType WriteF(SzType pos, const char * fmt, va_list args);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a string to the internal buffer.
|
||||
*/
|
||||
SzType WriteS(SzType pos, const char * str);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a portion of a string to the internal buffer.
|
||||
*/
|
||||
SzType WriteS(SzType pos, const char * str, SzType size)
|
||||
{
|
||||
return Write(pos, str, size);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a portion of a buffer to the internal buffer.
|
||||
*/
|
||||
void Append(ConstPtr data, SzType size)
|
||||
{
|
||||
m_Cur += Write(m_Cur, data, size);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append another buffer to the internal buffer.
|
||||
*/
|
||||
void Append(const Buffer & b)
|
||||
{
|
||||
m_Cur += Write(m_Cur, b.m_Ptr, b.m_Cur);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a formatted string to the internal buffer.
|
||||
*/
|
||||
void AppendF(const char * fmt, ...);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a formatted string to the internal buffer.
|
||||
*/
|
||||
void AppendF(const char * fmt, va_list args)
|
||||
{
|
||||
m_Cur += WriteF(m_Cur, fmt, args);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a string to the internal buffer.
|
||||
*/
|
||||
void AppendS(const char * str);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a portion of a string to the internal buffer.
|
||||
*/
|
||||
void AppendS(const char * str, SzType size)
|
||||
{
|
||||
m_Cur += Write(m_Cur, str, size);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Request the memory specified in the capacity.
|
||||
*/
|
||||
void Request(SzType n);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release the managed memory buffer.
|
||||
*/
|
||||
void Release();
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Pointer m_Ptr; /* Pointer to the memory buffer. */
|
||||
SzType m_Cap; /* The total size of the buffer. */
|
||||
SzType m_Cur; /* The buffer edit cursor. */
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,440 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Common.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/Numeric/Long.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cerrno>
|
||||
#include <cstdarg>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#ifdef SQMOD_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // SQMOD_OS_WINDOWS
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PluginFuncs * _Func = nullptr; //NOLINT(bugprone-reserved-identifier)
|
||||
PluginCallbacks * _Clbk = nullptr; //NOLINT(bugprone-reserved-identifier)
|
||||
PluginInfo * _Info = nullptr; //NOLINT(bugprone-reserved-identifier)
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Raw console message output.
|
||||
*/
|
||||
static inline void OutputMessageImpl(const char * msg, va_list args)
|
||||
{
|
||||
#ifdef SQMOD_OS_WINDOWS
|
||||
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO csb_before;
|
||||
GetConsoleScreenBufferInfo( hstdout, &csb_before);
|
||||
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN);
|
||||
std::printf("[SQMOD] ");
|
||||
|
||||
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); // NOLINT(hicpp-signed-bitwise)
|
||||
std::vprintf(msg, args);
|
||||
std::puts("");
|
||||
|
||||
SetConsoleTextAttribute(hstdout, csb_before.wAttributes);
|
||||
#else
|
||||
std::printf("\033[21;32m[SQMOD]\033[0m");
|
||||
std::vprintf(msg, args);
|
||||
std::puts("");
|
||||
#endif // SQMOD_OS_WINDOWS
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Raw console error output.
|
||||
*/
|
||||
static inline void OutputErrorImpl(const char * msg, va_list args)
|
||||
{
|
||||
#ifdef SQMOD_OS_WINDOWS
|
||||
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO csb_before;
|
||||
GetConsoleScreenBufferInfo( hstdout, &csb_before);
|
||||
SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY); // NOLINT(hicpp-signed-bitwise)
|
||||
std::printf("[SQMOD] ");
|
||||
|
||||
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); // NOLINT(hicpp-signed-bitwise)
|
||||
std::vprintf(msg, args);
|
||||
std::puts("");
|
||||
|
||||
SetConsoleTextAttribute(hstdout, csb_before.wAttributes);
|
||||
#else
|
||||
std::printf("\033[21;91m[SQMOD]\033[0m");
|
||||
std::vprintf(msg, args);
|
||||
std::puts("");
|
||||
#endif // SQMOD_OS_WINDOWS
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void OutputDebug(const char * msg, ...)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// Initialize the arguments list
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
// Call the output function
|
||||
OutputMessageImpl(msg, args);
|
||||
// Finalize the arguments list
|
||||
va_end(args);
|
||||
#else
|
||||
SQMOD_UNUSED_VAR(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void OutputMessage(const char * msg, ...)
|
||||
{
|
||||
// Initialize the arguments list
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
// Call the output function
|
||||
OutputMessageImpl(msg, args);
|
||||
// Finalize the arguments list
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void OutputError(const char * msg, ...)
|
||||
{
|
||||
// Initialize the arguments list
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
// Call the output function
|
||||
OutputErrorImpl(msg, args);
|
||||
// Finalize the arguments list
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SqThrowLastF(const SQChar * msg, ...)
|
||||
{
|
||||
// Acquire a moderately sized buffer
|
||||
Buffer b(128);
|
||||
// Prepare the arguments list
|
||||
va_list args;
|
||||
va_start (args, msg);
|
||||
// Attempt to run the specified format
|
||||
if (b.WriteF(0, msg, args) == 0)
|
||||
{
|
||||
b.At(0) = '\0'; // Make sure the string is null terminated
|
||||
}
|
||||
// Finalize the argument list
|
||||
va_end(args);
|
||||
#ifdef SQMOD_OS_WINDOWS
|
||||
// Get the error message, if any.
|
||||
const DWORD error_num = ::GetLastError();
|
||||
// Was there an error recorded?
|
||||
if(error_num == 0)
|
||||
{
|
||||
// Invoker is responsible for making sure this doesn't happen!
|
||||
SqThrowF("%s [Unknown error]", b.Data());
|
||||
}
|
||||
// The resulted message buffer
|
||||
LPSTR msg_buff = nullptr;
|
||||
// Attempt to obtain the error message
|
||||
const std::size_t size = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // NOLINT(hicpp-signed-bitwise)
|
||||
nullptr, error_num, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // NOLINT(hicpp-signed-bitwise)
|
||||
reinterpret_cast< LPSTR >(&msg_buff), 0, nullptr);
|
||||
// Copy the message buffer before freeing it
|
||||
std::string message(msg_buff, size);
|
||||
//Free the message buffer
|
||||
LocalFree(msg_buff);
|
||||
// Now it's safe to throw the error
|
||||
SqThrowF("%s [%s]", b.Data(), message.c_str());
|
||||
#else
|
||||
SqThrowF("%s [%s]", b.Data(), std::strerror(errno));
|
||||
#endif // SQMOD_OS_WINDOWS
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object & NullObject()
|
||||
{
|
||||
static Object o;
|
||||
o.Release();
|
||||
return o;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & NullLightObj()
|
||||
{
|
||||
static LightObj o;
|
||||
o.Release();
|
||||
return o;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Table & NullTable()
|
||||
{
|
||||
static Table t;
|
||||
t.Release();
|
||||
return t;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Array & NullArray()
|
||||
{
|
||||
static Array a;
|
||||
a.Release();
|
||||
return a;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Function & NullFunction()
|
||||
{
|
||||
static Function f;
|
||||
f.Release();
|
||||
return f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
String & NullString()
|
||||
{
|
||||
static String s;
|
||||
s.resize(0);
|
||||
return s;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * SqTypeName(SQObjectType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OT_NULL: return _SC("null");
|
||||
case OT_INTEGER: return _SC("integer");
|
||||
case OT_FLOAT: return _SC("float");
|
||||
case OT_BOOL: return _SC("bool");
|
||||
case OT_STRING: return _SC("string");
|
||||
case OT_TABLE: return _SC("table");
|
||||
case OT_ARRAY: return _SC("array");
|
||||
case OT_USERDATA: return _SC("userdata");
|
||||
case OT_CLOSURE: return _SC("closure");
|
||||
case OT_NATIVECLOSURE: return _SC("nativeclosure");
|
||||
case OT_GENERATOR: return _SC("generator");
|
||||
case OT_USERPOINTER: return _SC("userpointer");
|
||||
case OT_THREAD: return _SC("thread");
|
||||
case OT_FUNCPROTO: return _SC("funcproto");
|
||||
case OT_CLASS: return _SC("class");
|
||||
case OT_INSTANCE: return _SC("instance");
|
||||
case OT_WEAKREF: return _SC("weakref");
|
||||
case OT_OUTER: return _SC("outer");
|
||||
default: return _SC("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
String SqTypeName(HSQUIRRELVM vm, SQInteger idx)
|
||||
{
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Attempt to retrieve the type name of the specified value
|
||||
if (SQ_FAILED(sq_typeof(vm, idx)))
|
||||
{
|
||||
return _SC("unknown");
|
||||
}
|
||||
// Attempt to convert the obtained value to a string
|
||||
StackStrF val(vm, -1);
|
||||
// Did the conversion failed?
|
||||
if (SQ_FAILED(val.Proc(false)))
|
||||
{
|
||||
return _SC("unknown");
|
||||
}
|
||||
// Return the obtained string value
|
||||
return String(val.mPtr, static_cast< size_t >(val.mLen));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj BufferToStrObj(const Buffer & b)
|
||||
{
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg(SqVM());
|
||||
// Push the string onto the stack
|
||||
sq_pushstring(SqVM(), b.Data(), b.Position());
|
||||
// Obtain the object from the stack and return it
|
||||
return Var< LightObj >(SqVM(), -1).value;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj BufferToStrObj(const Buffer & b, uint32_t size)
|
||||
{
|
||||
// Perform a range check on the specified buffer
|
||||
if (size > b.Capacity())
|
||||
{
|
||||
STHROWF("The specified buffer size is out of range: %u >= %u", size, b.Capacity());
|
||||
}
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg(SqVM());
|
||||
// Push the string onto the stack
|
||||
sq_pushstring(SqVM(), b.Data(), size);
|
||||
// Obtain the object from the stack and return it
|
||||
return Var< LightObj >(SqVM(), -1).value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger PopStackInteger(HSQUIRRELVM vm, SQInteger idx)
|
||||
{
|
||||
// Identify which type must be extracted
|
||||
switch (sq_gettype(vm, idx))
|
||||
{
|
||||
case OT_INTEGER:
|
||||
{
|
||||
SQInteger val;
|
||||
sq_getinteger(vm, idx, &val);
|
||||
return val;
|
||||
}
|
||||
case OT_FLOAT:
|
||||
{
|
||||
SQFloat val;
|
||||
sq_getfloat(vm, idx, &val);
|
||||
return ConvTo< SQInteger >::From(val);
|
||||
}
|
||||
case OT_BOOL:
|
||||
{
|
||||
SQBool val;
|
||||
sq_getbool(vm, idx, &val);
|
||||
return static_cast< SQInteger >(val);
|
||||
}
|
||||
case OT_STRING:
|
||||
{
|
||||
const SQChar * val = nullptr;
|
||||
// Attempt to retrieve and convert the string
|
||||
if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0')
|
||||
{
|
||||
return ConvTo< SQInteger >::From(std::strtoll(val, nullptr, 10));
|
||||
} else break;
|
||||
}
|
||||
case OT_ARRAY:
|
||||
case OT_TABLE:
|
||||
case OT_CLASS:
|
||||
case OT_USERDATA:
|
||||
{
|
||||
return sq_getsize(vm, idx);
|
||||
}
|
||||
case OT_INSTANCE:
|
||||
{
|
||||
// Attempt to treat the value as a signed long instance
|
||||
try
|
||||
{
|
||||
return ConvTo< SQInteger >::From(Var< const SLongInt & >(vm, idx).value.GetNum());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Just ignore it...
|
||||
}
|
||||
// Attempt to treat the value as a unsigned long instance
|
||||
try
|
||||
{
|
||||
return ConvTo< SQInteger >::From(Var< const ULongInt & >(vm, idx).value.GetNum());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Just ignore it...
|
||||
}
|
||||
// Attempt to get the size of the instance as a fall back
|
||||
return sq_getsize(vm, idx);
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
// Default to 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx)
|
||||
{
|
||||
// Identify which type must be extracted
|
||||
switch (sq_gettype(vm, idx))
|
||||
{
|
||||
case OT_FLOAT:
|
||||
{
|
||||
SQFloat val;
|
||||
sq_getfloat(vm, idx, &val);
|
||||
return val;
|
||||
}
|
||||
case OT_INTEGER:
|
||||
{
|
||||
SQInteger val;
|
||||
sq_getinteger(vm, idx, &val);
|
||||
return ConvTo< SQFloat >::From(val);
|
||||
}
|
||||
case OT_BOOL:
|
||||
{
|
||||
SQBool val;
|
||||
sq_getbool(vm, idx, &val);
|
||||
return ConvTo< SQFloat >::From(val);
|
||||
}
|
||||
case OT_STRING:
|
||||
{
|
||||
const SQChar * val = nullptr;
|
||||
// Attempt to retrieve and convert the string
|
||||
if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0')
|
||||
{
|
||||
#ifdef SQUSEDOUBLE
|
||||
return std::strtod(val, nullptr);
|
||||
#else
|
||||
return std::strtof(val, nullptr);
|
||||
#endif // SQUSEDOUBLE
|
||||
} else break;
|
||||
}
|
||||
case OT_ARRAY:
|
||||
case OT_TABLE:
|
||||
case OT_CLASS:
|
||||
case OT_USERDATA:
|
||||
{
|
||||
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
|
||||
}
|
||||
case OT_INSTANCE:
|
||||
{
|
||||
// Attempt to treat the value as a signed long instance
|
||||
try
|
||||
{
|
||||
return ConvTo< SQFloat >::From(Var< const SLongInt & >(vm, idx).value.GetNum());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Just ignore it...
|
||||
}
|
||||
// Attempt to treat the value as a unsigned long instance
|
||||
try
|
||||
{
|
||||
return ConvTo< SQFloat >::From(Var< const ULongInt & >(vm, idx).value.GetNum());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Just ignore it...
|
||||
}
|
||||
// Attempt to get the size of the instance as a fall back
|
||||
return ConvTo< SQFloat >::From(sq_getsize(vm, idx));
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
// Default to 0
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool SToB(const SQChar * str)
|
||||
{
|
||||
// Temporary buffer to store the lowercase string
|
||||
SQChar buffer[8];
|
||||
// The currently processed character
|
||||
unsigned i = 0;
|
||||
// Convert only the necessary characters to lowercase
|
||||
while (i < 7 && *str != '\0')
|
||||
{
|
||||
buffer[i++] = static_cast< SQChar >(std::tolower(*(str++)));
|
||||
}
|
||||
// Add the null terminator
|
||||
buffer[i] = '\0';
|
||||
// Compare the lowercase string and return the result
|
||||
return std::strcmp(buffer, "true") == 0 || std::strcmp(buffer, "yes") == 0 ||
|
||||
std::strcmp(buffer, "on") == 0 || std::strcmp(buffer, "1") == 0;
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,269 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "SqBase.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cinttypes>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <new>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <typeinfo>
|
||||
#include <typeindex>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <vcmp.h>
|
||||
#include <squirrelex.h>
|
||||
#include <sqratAllocator.h>
|
||||
#include <sqratArray.h>
|
||||
#include <sqratClass.h>
|
||||
#include <sqratClassType.h>
|
||||
#include <sqratFunction.h>
|
||||
#include <sqratLightObj.h>
|
||||
#include <sqratObject.h>
|
||||
#include <sqratTable.h>
|
||||
#include <sqratUtil.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Proxies to communicate with the server.
|
||||
*/
|
||||
extern PluginFuncs * _Func; //NOLINT(bugprone-reserved-identifier)
|
||||
extern PluginCallbacks * _Clbk; //NOLINT(bugprone-reserved-identifier)
|
||||
extern PluginInfo * _Info; //NOLINT(bugprone-reserved-identifier)
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper to register pure typename functions for better performance.
|
||||
*/
|
||||
#define SQMOD_DECL_TYPENAME(t, s) /*
|
||||
*/ namespace { /*
|
||||
*/ struct t { /*
|
||||
*/ static const SQChar Str[]; /*
|
||||
*/ static SQInteger Fn(HSQUIRRELVM vm); /*
|
||||
*/ }; /*
|
||||
*/ const SQChar t::Str[] = s; /*
|
||||
*/ SQInteger t::Fn(HSQUIRRELVM vm) { /*
|
||||
*/ sq_pushstring(vm, Str, sizeof(Str) / sizeof(SQChar)); /*
|
||||
*/ return 1; /*
|
||||
*/ } /*
|
||||
*/ } /*
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward declarations of the logging functions to avoid including the logger everywhere.
|
||||
* Primary logging functions.
|
||||
*/
|
||||
extern void LogDbg(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogUsr(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogScs(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogInf(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogWrn(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogErr(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogFtl(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward declarations of the logging functions to avoid including the logger everywhere.
|
||||
* Secondary logging functions.
|
||||
*/
|
||||
extern void LogSDbg(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogSUsr(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogSScs(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogSInf(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogSWrn(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogSErr(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
extern void LogSFtl(const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 1, 2);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward declarations of the logging functions to avoid including the logger everywhere.
|
||||
* Primary logging functions.
|
||||
*/
|
||||
extern void LogDbgV(const char * fmt, va_list vlist);
|
||||
extern void LogUsrV(const char * fmt, va_list vlist);
|
||||
extern void LogScsV(const char * fmt, va_list vlist);
|
||||
extern void LogInfV(const char * fmt, va_list vlist);
|
||||
extern void LogWrnV(const char * fmt, va_list vlist);
|
||||
extern void LogErrV(const char * fmt, va_list vlist);
|
||||
extern void LogFtlV(const char * fmt, va_list vlist);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward declarations of the logging functions to avoid including the logger everywhere.
|
||||
* Secondary logging functions.
|
||||
*/
|
||||
extern void LogSDbgV(const char * fmt, va_list vlist);
|
||||
extern void LogSUsrV(const char * fmt, va_list vlist);
|
||||
extern void LogSScsV(const char * fmt, va_list vlist);
|
||||
extern void LogSInfV(const char * fmt, va_list vlist);
|
||||
extern void LogSWrnV(const char * fmt, va_list vlist);
|
||||
extern void LogSErrV(const char * fmt, va_list vlist);
|
||||
extern void LogSFtlV(const char * fmt, va_list vlist);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward declarations of the logging functions to avoid including the logger everywhere.
|
||||
* Primary conditional logging functions.
|
||||
*/
|
||||
extern bool cLogDbg(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogUsr(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogScs(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogInf(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogWrn(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogErr(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogFtl(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward declarations of the logging functions to avoid including the logger everywhere.
|
||||
* Secondary conditional logging functions.
|
||||
*/
|
||||
extern bool cLogSDbg(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogSUsr(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogSScs(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogSInf(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogSWrn(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogSErr(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
extern bool cLogSFtl(bool exp, const char * fmt, ...) SQMOD_FORMAT_ATTR(printf, 2, 3);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper used to reference and keep track of signal instances.
|
||||
*/
|
||||
typedef std::pair< Signal *, LightObj > SignalPair;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Initialize a signal instance into the specified pair.
|
||||
*/
|
||||
extern void InitSignalPair(SignalPair & sp, LightObj & et, const char * name);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Reset/release the specified signal pair.
|
||||
*/
|
||||
extern void ResetSignalPair(SignalPair & sp, bool clear = true);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Output a message only if the _DEBUG was defined.
|
||||
*/
|
||||
void OutputDebug(const char * msg, ...);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Output a formatted user message to the console.
|
||||
*/
|
||||
void OutputMessage(const char * msg, ...);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Output a formatted error message to the console.
|
||||
*/
|
||||
void OutputError(const char * msg, ...);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Generate a formatted string and throw it as a sqrat exception.
|
||||
*/
|
||||
template < class... Args > void SqThrowF(Args &&... args)
|
||||
{
|
||||
throw Sqrat::Exception(fmt::format(std::forward< Args >(args)...));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Generate a formatted string and throw it as a squirrel exception.
|
||||
*/
|
||||
template < class... Args > SQRESULT SqThrowErrorF(HSQUIRRELVM vm, Args &&... args)
|
||||
{
|
||||
String msg;
|
||||
try
|
||||
{
|
||||
msg = fmt::format(std::forward< Args >(args)...);
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
return sq_throwerror(vm, msg.c_str());
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Throw the last system error as an exception.
|
||||
*/
|
||||
void SqThrowLastF(const SQChar * msg, ...);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve a reference to a null script object.
|
||||
*/
|
||||
SQMOD_NODISCARD Object & NullObject();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve a reference to a null script object.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj & NullLightObj();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve a reference to a null/empty script table.
|
||||
*/
|
||||
SQMOD_NODISCARD Table & NullTable();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve a reference to a null/empty script array.
|
||||
*/
|
||||
SQMOD_NODISCARD Array & NullArray();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve a reference to a null script function.
|
||||
*/
|
||||
SQMOD_NODISCARD Function & NullFunction();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve a reference to a null string.
|
||||
*/
|
||||
SQMOD_NODISCARD String & NullString();
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve the string representation of a certain type.
|
||||
*/
|
||||
SQMOD_NODISCARD const SQChar * SqTypeName(SQObjectType type);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve the string representation of a certain type from a value on the stack.
|
||||
*/
|
||||
SQMOD_NODISCARD String SqTypeName(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Create a script string instance from a buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj BufferToStrObj(const Buffer & b);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Create a script string instance from a portion of a buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj BufferToStrObj(const Buffer & b, uint32_t size);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Attempt to pop the value at the specified index on the stack as a native integer.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger PopStackInteger(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Attempt to pop the value at the specified index on the stack as a native float.
|
||||
*/
|
||||
SQMOD_NODISCARD SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Simple function to check whether the specified string can be considered as a boolean value
|
||||
*/
|
||||
SQMOD_NODISCARD bool SToB(const SQChar * str);
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -1,7 +1,21 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Entity.hpp"
|
||||
#include "Core.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Entity/Blip.hpp"
|
||||
#include "Entity/Checkpoint.hpp"
|
||||
#include "Entity/KeyBind.hpp"
|
||||
#include "Entity/Object.hpp"
|
||||
#include "Entity/Pickup.hpp"
|
||||
#include "Entity/Player.hpp"
|
||||
#include "Entity/Vehicle.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#define SQMOD_CATCH_EVENT_EXCEPTION(action) /*
|
||||
*/ catch (const Sqrat::Exception & e) /*
|
||||
*/ { /*
|
||||
@@ -11,10 +25,73 @@ namespace SqMod {
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void CleanupTasks(Int32 id, Int32 type);
|
||||
extern void CleanupTasks(int32_t id, int32_t type);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::BlipInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
BlipInst::~BlipInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(!Core::Get().ShuttingDown(), SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CheckpointInst::~CheckpointInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(!Core::Get().ShuttingDown(), SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
KeyBindInst::~KeyBindInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(!Core::Get().ShuttingDown(), SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ObjectInst::~ObjectInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(!Core::Get().ShuttingDown(), SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PickupInst::~PickupInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(!Core::Get().ShuttingDown(), SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PlayerInst::~PlayerInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(false, SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
VehicleInst::~VehicleInst()
|
||||
{
|
||||
if (VALID_ENTITY(mID))
|
||||
{
|
||||
Destroy(!Core::Get().ShuttingDown(), SQMOD_DESTROY_CLEANUP, NullLightObj());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlipInst::Destroy(bool destroy, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -44,7 +121,7 @@ void Core::BlipInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
if (destroy && VALID_ENTITY(mID) && (mFlags & ENF_OWNED))
|
||||
{
|
||||
// Block the entity pool changes notification from triggering the destroy event
|
||||
const BitGuardU32 bg(mFlags, static_cast< Uint32 >(ENF_LOCKED));
|
||||
const BitGuardU32 bg(mFlags, static_cast< uint32_t >(ENF_LOCKED));
|
||||
// Now attempt to destroy this entity from the server
|
||||
_Func->DestroyCoordBlip(mID);
|
||||
}
|
||||
@@ -55,7 +132,7 @@ void Core::BlipInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::CheckpointInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
void CheckpointInst::Destroy(bool destroy, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -85,7 +162,7 @@ void Core::CheckpointInst::Destroy(bool destroy, Int32 header, LightObj & payloa
|
||||
if (destroy && VALID_ENTITY(mID) && (mFlags & ENF_OWNED))
|
||||
{
|
||||
// Block the entity pool changes notification from triggering the destroy event
|
||||
const BitGuardU32 bg(mFlags, static_cast< Uint32 >(ENF_LOCKED));
|
||||
const BitGuardU32 bg(mFlags, static_cast< uint32_t >(ENF_LOCKED));
|
||||
// Now attempt to destroy this entity from the server
|
||||
_Func->DeleteCheckPoint(mID);
|
||||
}
|
||||
@@ -96,7 +173,7 @@ void Core::CheckpointInst::Destroy(bool destroy, Int32 header, LightObj & payloa
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::KeybindInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
void KeyBindInst::Destroy(bool destroy, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -104,7 +181,7 @@ void Core::KeybindInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
// Don't leave exceptions to prevent us from releasing this instance
|
||||
try
|
||||
{
|
||||
Core::Get().EmitKeybindDestroyed(mID, header, payload);
|
||||
Core::Get().EmitKeyBindDestroyed(mID, header, payload);
|
||||
}
|
||||
SQMOD_CATCH_EVENT_EXCEPTION("while destroying keybind")
|
||||
}
|
||||
@@ -126,7 +203,7 @@ void Core::KeybindInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
if (destroy && VALID_ENTITY(mID) && (mFlags & ENF_OWNED))
|
||||
{
|
||||
// Block the entity pool changes notification from triggering the destroy event
|
||||
const BitGuardU32 bg(mFlags, static_cast< Uint32 >(ENF_LOCKED));
|
||||
const BitGuardU32 bg(mFlags, static_cast< uint32_t >(ENF_LOCKED));
|
||||
// Now attempt to destroy this entity from the server
|
||||
_Func->RemoveKeyBind(mID);
|
||||
}
|
||||
@@ -137,7 +214,7 @@ void Core::KeybindInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ObjectInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
void ObjectInst::Destroy(bool destroy, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -167,7 +244,7 @@ void Core::ObjectInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
if (destroy && VALID_ENTITY(mID) && (mFlags & ENF_OWNED))
|
||||
{
|
||||
// Block the entity pool changes notification from triggering the destroy event
|
||||
const BitGuardU32 bg(mFlags, static_cast< Uint32 >(ENF_LOCKED));
|
||||
const BitGuardU32 bg(mFlags, static_cast< uint32_t >(ENF_LOCKED));
|
||||
// Now attempt to destroy this entity from the server
|
||||
_Func->DeleteObject(mID);
|
||||
}
|
||||
@@ -178,7 +255,7 @@ void Core::ObjectInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PickupInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
void PickupInst::Destroy(bool destroy, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -208,7 +285,7 @@ void Core::PickupInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
if (destroy && VALID_ENTITY(mID) && (mFlags & ENF_OWNED))
|
||||
{
|
||||
// Block the entity pool changes notification from triggering the destroy event
|
||||
const BitGuardU32 bg(mFlags, static_cast< Uint32 >(ENF_LOCKED));
|
||||
const BitGuardU32 bg(mFlags, static_cast< uint32_t >(ENF_LOCKED));
|
||||
// Now attempt to destroy this entity from the server
|
||||
_Func->DeletePickup(mID);
|
||||
}
|
||||
@@ -219,7 +296,7 @@ void Core::PickupInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PlayerInst::Destroy(bool /*destroy*/, Int32 header, LightObj & payload)
|
||||
void PlayerInst::Destroy(bool /*destroy*/, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -254,7 +331,7 @@ void Core::PlayerInst::Destroy(bool /*destroy*/, Int32 header, LightObj & payloa
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::VehicleInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
void VehicleInst::Destroy(bool destroy, int32_t header, LightObj & payload)
|
||||
{
|
||||
// Should we notify that this entity is being cleaned up?
|
||||
if (VALID_ENTITY(mID))
|
||||
@@ -284,7 +361,7 @@ void Core::VehicleInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
if (destroy && VALID_ENTITY(mID) && (mFlags & ENF_OWNED))
|
||||
{
|
||||
// Block the entity pool changes notification from triggering the destroy event
|
||||
const BitGuardU32 bg(mFlags, static_cast< Uint32 >(ENF_LOCKED));
|
||||
const BitGuardU32 bg(mFlags, static_cast< uint32_t >(ENF_LOCKED));
|
||||
// Now attempt to destroy this entity from the server
|
||||
_Func->DeleteVehicle(mID);
|
||||
}
|
||||
@@ -295,7 +372,7 @@ void Core::VehicleInst::Destroy(bool destroy, Int32 header, LightObj & payload)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::BlipInst::ResetInstance()
|
||||
void BlipInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
@@ -307,14 +384,14 @@ void Core::BlipInst::ResetInstance()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::CheckpointInst::ResetInstance()
|
||||
void CheckpointInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::KeybindInst::ResetInstance()
|
||||
void KeyBindInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
@@ -325,21 +402,21 @@ void Core::KeybindInst::ResetInstance()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ObjectInst::ResetInstance()
|
||||
void ObjectInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PickupInst::ResetInstance()
|
||||
void PickupInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PlayerInst::ResetInstance()
|
||||
void PlayerInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
@@ -360,7 +437,7 @@ void Core::PlayerInst::ResetInstance()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::VehicleInst::ResetInstance()
|
||||
void VehicleInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
@@ -376,7 +453,7 @@ void Core::VehicleInst::ResetInstance()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::BlipInst::InitEvents()
|
||||
void BlipInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -395,7 +472,7 @@ void Core::BlipInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::BlipInst::DropEvents()
|
||||
void BlipInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -403,7 +480,7 @@ void Core::BlipInst::DropEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::CheckpointInst::InitEvents()
|
||||
void CheckpointInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -429,7 +506,7 @@ void Core::CheckpointInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::CheckpointInst::DropEvents()
|
||||
void CheckpointInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -444,7 +521,7 @@ void Core::CheckpointInst::DropEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::KeybindInst::InitEvents()
|
||||
void KeyBindInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -465,7 +542,7 @@ void Core::KeybindInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::KeybindInst::DropEvents()
|
||||
void KeyBindInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -475,7 +552,7 @@ void Core::KeybindInst::DropEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ObjectInst::InitEvents()
|
||||
void ObjectInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -502,7 +579,7 @@ void Core::ObjectInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ObjectInst::DropEvents()
|
||||
void ObjectInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -518,7 +595,7 @@ void Core::ObjectInst::DropEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PickupInst::InitEvents()
|
||||
void PickupInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -548,7 +625,7 @@ void Core::PickupInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PickupInst::DropEvents()
|
||||
void PickupInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -567,7 +644,7 @@ void Core::PickupInst::DropEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PlayerInst::InitEvents()
|
||||
void PlayerInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -632,7 +709,7 @@ void Core::PlayerInst::InitEvents()
|
||||
InitSignalPair(mOnKeyRelease, mEvents, "KeyRelease");
|
||||
InitSignalPair(mOnSpectate, mEvents, "Spectate");
|
||||
InitSignalPair(mOnUnspectate, mEvents, "Unspectate");
|
||||
InitSignalPair(mOnCrashreport, mEvents, "Crashreport");
|
||||
InitSignalPair(mOnCrashReport, mEvents, "CrashReport");
|
||||
InitSignalPair(mOnModuleList, mEvents, "ModuleList");
|
||||
InitSignalPair(mOnObjectShot, mEvents, "ObjectShot");
|
||||
InitSignalPair(mOnObjectTouched, mEvents, "ObjectTouched");
|
||||
@@ -665,7 +742,7 @@ void Core::PlayerInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::PlayerInst::DropEvents()
|
||||
void PlayerInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -718,7 +795,7 @@ void Core::PlayerInst::DropEvents()
|
||||
ResetSignalPair(mOnKeyRelease);
|
||||
ResetSignalPair(mOnSpectate);
|
||||
ResetSignalPair(mOnUnspectate);
|
||||
ResetSignalPair(mOnCrashreport);
|
||||
ResetSignalPair(mOnCrashReport);
|
||||
ResetSignalPair(mOnModuleList);
|
||||
ResetSignalPair(mOnObjectShot);
|
||||
ResetSignalPair(mOnObjectTouched);
|
||||
@@ -752,7 +829,7 @@ void Core::PlayerInst::DropEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::VehicleInst::InitEvents()
|
||||
void VehicleInst::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!mEvents.IsNull())
|
||||
@@ -794,7 +871,7 @@ void Core::VehicleInst::InitEvents()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::VehicleInst::DropEvents()
|
||||
void VehicleInst::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnDestroyed);
|
||||
ResetSignalPair(mOnCustom);
|
||||
@@ -0,0 +1,555 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Base/Color4.hpp"
|
||||
#include "Base/Vector3.hpp"
|
||||
#include "Base/Quaternion.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <vector>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::vector< std::pair< Area *, LightObj > > AreaList; // List of collided areas.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a blip entity instance on the server.
|
||||
*/
|
||||
struct BlipInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
BlipInst() = default;
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~BlipInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CBlip * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mWorld{-1}; // The identifier of the world in which this blip was created.
|
||||
int32_t mScale{-1}; // The scale of the blip.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mSprID{-1};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
Vector3 mPosition{};
|
||||
Color4 mColor{};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a checkpoint entity instance on the server.
|
||||
*/
|
||||
struct CheckpointInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
CheckpointInst() = default;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~CheckpointInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CCheckpoint * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
SignalPair mOnStream{};
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnEntered{};
|
||||
SignalPair mOnExited{};
|
||||
SignalPair mOnWorld{};
|
||||
SignalPair mOnRadius{};
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a key-bind entity instance on the server.
|
||||
*/
|
||||
struct KeyBindInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
KeyBindInst() = default;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~KeyBindInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CKeyBind * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mFirst{-1}; // Key-code of the first button from the triggering combination.
|
||||
int32_t mSecond{-1}; // Key-code of the second button from the triggering combination.
|
||||
int32_t mThird{-1}; // Key-code of the third button from the triggering combination.
|
||||
int32_t mRelease{-1}; // Whether the key-bind reacts to button press or release.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnKeyPress{};
|
||||
SignalPair mOnKeyRelease{};
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify an object entity instance on the server.
|
||||
*/
|
||||
struct ObjectInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
ObjectInst() = default;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~ObjectInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CObject * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
SignalPair mOnStream{};
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnShot{};
|
||||
SignalPair mOnTouched{};
|
||||
SignalPair mOnWorld{};
|
||||
SignalPair mOnAlpha{};
|
||||
SignalPair mOnReport{};
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a pickup entity instance on the server.
|
||||
*/
|
||||
struct PickupInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
PickupInst() = default;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~PickupInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CPickup * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
SignalPair mOnStream{};
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnRespawn{};
|
||||
SignalPair mOnClaimed{};
|
||||
SignalPair mOnCollected{};
|
||||
SignalPair mOnWorld{};
|
||||
SignalPair mOnAlpha{};
|
||||
SignalPair mOnAutomatic{};
|
||||
SignalPair mOnAutoTimer{};
|
||||
SignalPair mOnOption{};
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a player entity instance on the server.
|
||||
*/
|
||||
struct PlayerInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
PlayerInst() = default;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~PlayerInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CPlayer * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
AreaList mAreas{}; // Areas the player is currently in.
|
||||
double mDistance{0}; // Distance traveled while tracking was enabled.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SQInteger mTrackPosition{0}; // The number of times to track position changes.
|
||||
SQInteger mTrackHeading{0}; // The number of times to track heading changes.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mTrackPositionHeader{0}; // Header to send when triggering position callback.
|
||||
LightObj mTrackPositionPayload{}; // Payload to send when triggering position callback.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mKickBanHeader{0}; // Header to send when triggering kick/ban callback.
|
||||
LightObj mKickBanPayload{}; // Payload to send when triggering kick/ban callback.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mLastWeapon{-1}; // Last known weapon of the player entity.
|
||||
float mLastHealth{0}; // Last known health of the player entity.
|
||||
float mLastArmour{0}; // Last known armor of the player entity.
|
||||
float mLastHeading{0}; // Last known heading of the player entity.
|
||||
Vector3 mLastPosition{}; // Last known position of the player entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mAuthority{0}; // The authority level of the managed player.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
SignalPair mOnStream{};
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnRequestClass{};
|
||||
SignalPair mOnRequestSpawn{};
|
||||
SignalPair mOnSpawn{};
|
||||
SignalPair mOnWasted{};
|
||||
SignalPair mOnKilled{};
|
||||
SignalPair mOnEmbarking{};
|
||||
SignalPair mOnEmbarked{};
|
||||
SignalPair mOnDisembark{};
|
||||
SignalPair mOnRename{};
|
||||
SignalPair mOnState{};
|
||||
SignalPair mOnStateNone{};
|
||||
SignalPair mOnStateNormal{};
|
||||
SignalPair mOnStateAim{};
|
||||
SignalPair mOnStateDriver{};
|
||||
SignalPair mOnStatePassenger{};
|
||||
SignalPair mOnStateEnterDriver{};
|
||||
SignalPair mOnStateEnterPassenger{};
|
||||
SignalPair mOnStateExit{};
|
||||
SignalPair mOnStateUnspawned{};
|
||||
SignalPair mOnAction{};
|
||||
SignalPair mOnActionNone{};
|
||||
SignalPair mOnActionNormal{};
|
||||
SignalPair mOnActionAiming{};
|
||||
SignalPair mOnActionShooting{};
|
||||
SignalPair mOnActionJumping{};
|
||||
SignalPair mOnActionLieDown{};
|
||||
SignalPair mOnActionGettingUp{};
|
||||
SignalPair mOnActionJumpVehicle{};
|
||||
SignalPair mOnActionDriving{};
|
||||
SignalPair mOnActionDying{};
|
||||
SignalPair mOnActionWasted{};
|
||||
SignalPair mOnActionEmbarking{};
|
||||
SignalPair mOnActionDisembarking{};
|
||||
SignalPair mOnBurning{};
|
||||
SignalPair mOnCrouching{};
|
||||
SignalPair mOnGameKeys{};
|
||||
SignalPair mOnStartTyping{};
|
||||
SignalPair mOnStopTyping{};
|
||||
SignalPair mOnAway{};
|
||||
SignalPair mOnMessage{};
|
||||
SignalPair mOnCommand{};
|
||||
SignalPair mOnPrivateMessage{};
|
||||
SignalPair mOnKeyPress{};
|
||||
SignalPair mOnKeyRelease{};
|
||||
SignalPair mOnSpectate{};
|
||||
SignalPair mOnUnspectate{};
|
||||
SignalPair mOnCrashReport{};
|
||||
SignalPair mOnModuleList{};
|
||||
SignalPair mOnObjectShot{};
|
||||
SignalPair mOnObjectTouched{};
|
||||
SignalPair mOnPickupClaimed{};
|
||||
SignalPair mOnPickupCollected{};
|
||||
SignalPair mOnCheckpointEntered{};
|
||||
SignalPair mOnCheckpointExited{};
|
||||
SignalPair mOnClientScriptData{};
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
SignalPair mOnEntityStream{};
|
||||
#endif
|
||||
SignalPair mOnUpdate{};
|
||||
SignalPair mOnHealth{};
|
||||
SignalPair mOnArmour{};
|
||||
SignalPair mOnWeapon{};
|
||||
SignalPair mOnHeading{};
|
||||
SignalPair mOnPosition{};
|
||||
SignalPair mOnOption{};
|
||||
SignalPair mOnAdmin{};
|
||||
SignalPair mOnWorld{};
|
||||
SignalPair mOnTeam{};
|
||||
SignalPair mOnSkin{};
|
||||
SignalPair mOnMoney{};
|
||||
SignalPair mOnScore{};
|
||||
SignalPair mOnWantedLevel{};
|
||||
SignalPair mOnImmunity{};
|
||||
SignalPair mOnAlpha{};
|
||||
SignalPair mOnEnterArea{};
|
||||
SignalPair mOnLeaveArea{};
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a vehicle entity instance on the server.
|
||||
*/
|
||||
struct VehicleInst
|
||||
{
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
VehicleInst() = default;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~VehicleInst();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destroy the entity instance from the server, if necessary.
|
||||
*/
|
||||
void Destroy(bool destroy, int32_t header, LightObj & payload);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Reset the instance to the default values.
|
||||
*/
|
||||
void ResetInstance();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Create the associated signals.
|
||||
*/
|
||||
void InitEvents();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the associated signals.
|
||||
*/
|
||||
void DropEvents();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mID{-1}; // The unique number that identifies this entity on the server.
|
||||
uint32_t mFlags{ENF_DEFAULT}; // Various options and states that can be toggled on the instance.
|
||||
CVehicle * mInst{nullptr}; // Pointer to the actual instance used to interact this entity.
|
||||
LightObj mObj{}; // Script object of the instance used to interact this entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
AreaList mAreas{}; // Areas the vehicle is currently in.
|
||||
double mDistance{0}; // Distance traveled while tracking was enabled.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SQInteger mTrackPosition{0}; // The number of times to track position changes.
|
||||
SQInteger mTrackRotation{0}; // The number of times to track rotation changes.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
int32_t mLastPrimaryColor{-1}; // Last known secondary-color of the player entity.
|
||||
int32_t mLastSecondaryColor{-1}; // Last known primary-color of the player entity.
|
||||
float mLastHealth{0}; // Last known health of the player entity.
|
||||
Vector3 mLastPosition{}; // Last known position of the player entity.
|
||||
Quaternion mLastRotation{}; // Last known rotation of the player entity.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEvents{}; // Table containing the emitted entity events.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnDestroyed{};
|
||||
SignalPair mOnCustom{};
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
SignalPair mOnStream{};
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SignalPair mOnEmbarking{};
|
||||
SignalPair mOnEmbarked{};
|
||||
SignalPair mOnDisembark{};
|
||||
SignalPair mOnExplode{};
|
||||
SignalPair mOnRespawn{};
|
||||
SignalPair mOnUpdate{};
|
||||
SignalPair mOnColor{};
|
||||
SignalPair mOnHealth{};
|
||||
SignalPair mOnPosition{};
|
||||
SignalPair mOnRotation{};
|
||||
SignalPair mOnOption{};
|
||||
SignalPair mOnWorld{};
|
||||
SignalPair mOnImmunity{};
|
||||
SignalPair mOnPartStatus{};
|
||||
SignalPair mOnTyreStatus{};
|
||||
SignalPair mOnDamageData{};
|
||||
SignalPair mOnRadio{};
|
||||
SignalPair mOnHandlingRule{};
|
||||
SignalPair mOnEnterArea{};
|
||||
SignalPair mOnLeaveArea{};
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -1,826 +0,0 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::ImportBlips()
|
||||
{
|
||||
// Information about the blip entity
|
||||
Int32 world = -1, scale = -1, sprid = -1;
|
||||
Uint32 color = 0;
|
||||
Float32 x = 0.0, y = 0.0, z = 0.0;
|
||||
|
||||
for (Int32 i = 0; i < SQMOD_BLIP_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if (_Func->CheckEntityExists(vcmpEntityPoolBlip, i) && INVALID_ENTITY(m_Blips[i].mID))
|
||||
{
|
||||
_Func->GetCoordBlipInfo(i, &world, &x, &y, &z, &scale, &color, &sprid);
|
||||
// Make the properties available before triggering the event
|
||||
m_Blips[i].mWorld = world;
|
||||
m_Blips[i].mScale = scale;
|
||||
m_Blips[i].mSprID = sprid;
|
||||
m_Blips[i].mPosition.SetVector3Ex(x, y, z);
|
||||
m_Blips[i].mColor.SetRGBA(color);
|
||||
// Attempt to allocate the instance
|
||||
AllocBlip(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ImportCheckpoints()
|
||||
{
|
||||
for (Int32 i = 0; i < SQMOD_CHECKPOINT_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if (_Func->CheckEntityExists(vcmpEntityPoolCheckPoint, i) && INVALID_ENTITY(m_Checkpoints[i].mID))
|
||||
{
|
||||
AllocCheckpoint(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ImportKeybinds()
|
||||
{
|
||||
/* @NOTE This function is disabled because VC:MP server seems bugged
|
||||
* and does not return vcmpErrorNoSuchEntity when the keybind does not exist.
|
||||
* Therefore causing incorrect behavior in the plugin.
|
||||
*/
|
||||
return;
|
||||
|
||||
// Information about the key-bind entity
|
||||
Uint8 release = 0;
|
||||
Int32 first = -1, second = -1, third = -1;
|
||||
|
||||
for (Int32 i = 0; i < SQMOD_KEYBIND_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if ((_Func->GetKeyBindData(i, &release, &first, &second, &third) != vcmpErrorNoSuchEntity)
|
||||
&& (INVALID_ENTITY(m_Keybinds[i].mID)))
|
||||
{
|
||||
// Make the properties available before triggering the event
|
||||
m_Keybinds[i].mFirst = first;
|
||||
m_Keybinds[i].mSecond = second;
|
||||
m_Keybinds[i].mThird = third;
|
||||
m_Keybinds[i].mRelease = release;
|
||||
// Attempt to allocate the instance
|
||||
AllocKeybind(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ImportObjects()
|
||||
{
|
||||
for (Int32 i = 0; i < SQMOD_OBJECT_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if (_Func->CheckEntityExists(vcmpEntityPoolObject, i) && INVALID_ENTITY(m_Objects[i].mID))
|
||||
{
|
||||
AllocObject(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ImportPickups()
|
||||
{
|
||||
for (Int32 i = 0; i < SQMOD_PICKUP_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if (_Func->CheckEntityExists(vcmpEntityPoolPickup, i) && (INVALID_ENTITY(m_Pickups[i].mID)))
|
||||
{
|
||||
AllocPickup(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ImportPlayers()
|
||||
{
|
||||
for (Int32 i = 0; i < SQMOD_PLAYER_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if (_Func->IsPlayerConnected(i) && (INVALID_ENTITY(m_Players[i].mID)))
|
||||
{
|
||||
ConnectPlayer(i, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ImportVehicles()
|
||||
{
|
||||
for (Int32 i = 0; i < SQMOD_VEHICLE_POOL; ++i)
|
||||
{
|
||||
// See if this entity exists on the server and whether was not allocated already
|
||||
if (_Func->CheckEntityExists(vcmpEntityPoolVehicle, i) && INVALID_ENTITY(m_Vehicles[i].mID))
|
||||
{
|
||||
AllocVehicle(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Core::BlipInst & Core::AllocBlip(Int32 id, bool owned, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate blip with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
BlipInst & inst = m_Blips[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return inst; // Return the existing instance
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CBlip > dg(new CBlip(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
// Now we can throw the error
|
||||
STHROWF("Unable to create a blip instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Specify whether the entity is owned by this plug-in
|
||||
if (owned)
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
else if (inst.mFlags & ENF_OWNED)
|
||||
{
|
||||
inst.mFlags ^= ENF_OWNED;
|
||||
}
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitBlipCreated(id, header, payload);
|
||||
// Return the allocated instance
|
||||
return inst;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Core::CheckpointInst & Core::AllocCheckpoint(Int32 id, bool owned, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate checkpoint with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
CheckpointInst & inst = m_Checkpoints[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return inst; // Return the existing instance
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CCheckpoint > dg(new CCheckpoint(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
// Now we can throw the error
|
||||
STHROWF("Unable to create a checkpoint instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Specify whether the entity is owned by this plug-in
|
||||
if (owned)
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
else if (inst.mFlags & ENF_OWNED)
|
||||
{
|
||||
inst.mFlags ^= ENF_OWNED;
|
||||
}
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitCheckpointCreated(id, header, payload);
|
||||
// Return the allocated instance
|
||||
return inst;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Core::KeybindInst & Core::AllocKeybind(Int32 id, bool owned, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate keybind with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
KeybindInst & inst = m_Keybinds[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return inst; // Return the existing instance
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CKeybind > dg(new CKeybind(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
// Now we can throw the error
|
||||
STHROWF("Unable to create a keybind instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Specify whether the entity is owned by this plug-in
|
||||
if (owned)
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
else if (inst.mFlags & ENF_OWNED)
|
||||
{
|
||||
inst.mFlags ^= ENF_OWNED;
|
||||
}
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitKeybindCreated(id, header, payload);
|
||||
// Return the allocated instance
|
||||
return inst;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Core::ObjectInst & Core::AllocObject(Int32 id, bool owned, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate object with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
ObjectInst & inst = m_Objects[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return inst; // Return the existing instance
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CObject > dg(new CObject(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
// Now we can throw the error
|
||||
STHROWF("Unable to create a object instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Specify whether the entity is owned by this plug-in
|
||||
if (owned)
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
else if (inst.mFlags & ENF_OWNED)
|
||||
{
|
||||
inst.mFlags ^= ENF_OWNED;
|
||||
}
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitObjectCreated(id, header, payload);
|
||||
// Return the allocated instance
|
||||
return inst;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Core::PickupInst & Core::AllocPickup(Int32 id, bool owned, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate pickup with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
PickupInst & inst = m_Pickups[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return inst; // Return the existing instance
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CPickup > dg(new CPickup(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
// Now we can throw the error
|
||||
STHROWF("Unable to create a pickup instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Specify whether the entity is owned by this plug-in
|
||||
if (owned)
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
else if (inst.mFlags & ENF_OWNED)
|
||||
{
|
||||
inst.mFlags ^= ENF_OWNED;
|
||||
}
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitPickupCreated(id, header, payload);
|
||||
// Return the allocated instance
|
||||
return inst;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Core::VehicleInst & Core::AllocVehicle(Int32 id, bool owned, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate vehicle with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
VehicleInst & inst = m_Vehicles[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return inst; // Return the existing instance
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CVehicle > dg(new CVehicle(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
// Now we can throw the error
|
||||
STHROWF("Unable to create a vehicle instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Specify whether the entity is owned by this plug-in
|
||||
if (owned)
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
else if (inst.mFlags & ENF_OWNED)
|
||||
{
|
||||
inst.mFlags ^= ENF_OWNED;
|
||||
}
|
||||
// Should we enable area tracking?
|
||||
if (m_AreasEnabled)
|
||||
{
|
||||
inst.mFlags |= ENF_AREA_TRACK;
|
||||
}
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitVehicleCreated(id, header, payload);
|
||||
// Return the allocated instance
|
||||
return inst;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::DeallocBlip(Int32 id, bool destroy, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate blip with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
BlipInst & inst = m_Blips[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::DeallocCheckpoint(Int32 id, bool destroy, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate checkpoint with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
CheckpointInst & inst = m_Checkpoints[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::DeallocKeybind(Int32 id, bool destroy, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate keybind with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
KeybindInst & inst = m_Keybinds[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::DeallocObject(Int32 id, bool destroy, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate object with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
ObjectInst & inst = m_Objects[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::DeallocPickup(Int32 id, bool destroy, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate pickup with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
PickupInst & inst = m_Pickups[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Core::DeallocVehicle(Int32 id, bool destroy, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate vehicle with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
VehicleInst & inst = m_Vehicles[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj & Core::NewBlip(Int32 index, Int32 world, Float32 x, Float32 y, Float32 z,
|
||||
Int32 scale, Uint32 color, Int32 sprid,
|
||||
Int32 header, LightObj & payload)
|
||||
{
|
||||
// Request the server to create this entity
|
||||
const Int32 id = _Func->CreateCoordBlip(index, world, x, y, z, scale, color, sprid);
|
||||
// See if the entity creation failed on the server
|
||||
if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
||||
{
|
||||
STHROWF("Blip pool was exhausted: %d", id);
|
||||
}
|
||||
// Validate the identifier returned by the server
|
||||
else if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
||||
{
|
||||
STHROWF("Server returned invalid blip: %d", id);
|
||||
}
|
||||
// Attempt to allocate this entity and grab the reference to the instance
|
||||
BlipInst & inst = AllocBlip(id, true, header, payload);
|
||||
// Just in case it was created during the notification for changes in entity pool
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
// Now we can return the script object
|
||||
return inst.mObj;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj & Core::NewCheckpoint(Int32 player, Int32 world, bool sphere, Float32 x, Float32 y, Float32 z,
|
||||
Uint8 r, Uint8 g, Uint8 b, Uint8 a, Float32 radius,
|
||||
Int32 header, LightObj & payload)
|
||||
{
|
||||
// Request the server to create this entity
|
||||
const Int32 id = _Func->CreateCheckPoint(player, world, sphere, x, y, z, r, g, b, a, radius);
|
||||
// See if the entity creation failed on the server
|
||||
if (_Func->GetLastError() == vcmpErrorNoSuchEntity)
|
||||
{
|
||||
STHROWF("Invalid player reference: %d", player);
|
||||
}
|
||||
else if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
||||
{
|
||||
STHROWF("Checkpoint pool was exhausted: %d", id);
|
||||
}
|
||||
// Validate the identifier returned by the server
|
||||
else if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
||||
{
|
||||
STHROWF("Server returned invalid checkpoint: %d", id);
|
||||
}
|
||||
// Attempt to allocate this entity and grab the reference to the instance
|
||||
CheckpointInst & inst = AllocCheckpoint(id, true, header, payload);
|
||||
// Just in case it was created during the notification for changes in entity pool
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
// Now we can return the script object
|
||||
return inst.mObj;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj & Core::NewKeybind(Int32 slot, bool release, Int32 primary, Int32 secondary, Int32 alternative,
|
||||
Int32 header, LightObj & payload)
|
||||
{
|
||||
// Should we obtain a new keybind slot automatically?
|
||||
if (slot < 0)
|
||||
{
|
||||
slot = _Func->GetKeyBindUnusedSlot();
|
||||
}
|
||||
// Validate the keybind slot returned by the server
|
||||
if (INVALID_ENTITYEX(slot, SQMOD_KEYBIND_POOL))
|
||||
{
|
||||
STHROWF("Server returned invalid keybind slot: %d", slot);
|
||||
}
|
||||
// Request the server to create this entity
|
||||
const vcmpError result = _Func->RegisterKeyBind(slot, release, primary, secondary, alternative);
|
||||
// See if the entity creation failed on the server
|
||||
if (result == vcmpErrorArgumentOutOfBounds)
|
||||
{
|
||||
STHROWF("Out of bounds keybind argument: %d", slot);
|
||||
}
|
||||
// Attempt to allocate this entity and grab the reference to the instance
|
||||
KeybindInst & inst = AllocKeybind(slot, true, header, payload);
|
||||
// Just in case it was created during the notification for changes in entity pool
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
// Now we can return the script object
|
||||
return inst.mObj;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj & Core::NewObject(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Int32 alpha,
|
||||
Int32 header, LightObj & payload)
|
||||
{
|
||||
// Request the server to create this entity
|
||||
const Int32 id = _Func->CreateObject(model, world, x, y, z, alpha);
|
||||
// See if the entity creation failed on the server
|
||||
if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
||||
{
|
||||
STHROWF("Object pool was exhausted: %d", id);
|
||||
}
|
||||
// Validate the identifier returned by the server
|
||||
else if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
||||
{
|
||||
STHROWF("Server returned invalid object: %d", id);
|
||||
}
|
||||
// Attempt to allocate this entity and grab the reference to the instance
|
||||
ObjectInst & inst = AllocObject(id, true, header, payload);
|
||||
// Just in case it was created during the notification for changes in entity pool
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
// Now we can return the script object
|
||||
return inst.mObj;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj & Core::NewPickup(Int32 model, Int32 world, Int32 quantity,
|
||||
Float32 x, Float32 y, Float32 z, Int32 alpha, bool automatic,
|
||||
Int32 header, LightObj & payload)
|
||||
{
|
||||
// Request the server to create this entity
|
||||
const Int32 id = _Func->CreatePickup(model, world, quantity, x, y, z, alpha, automatic);
|
||||
// See if the entity creation failed on the server
|
||||
if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
||||
{
|
||||
STHROWF("Pickup pool was exhausted: %d", id);
|
||||
}
|
||||
// Validate the identifier returned by the server
|
||||
else if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
||||
{
|
||||
STHROWF("Server returned invalid pickup: %d", id);
|
||||
}
|
||||
// Attempt to allocate this entity and grab the reference to the instance
|
||||
PickupInst & inst = AllocPickup(id, true, header, payload);
|
||||
// Just in case it was created during the notification for changes in entity pool
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
// Now we can return the script object
|
||||
return inst.mObj;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj & Core::NewVehicle(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z,
|
||||
Float32 angle, Int32 primary, Int32 secondary,
|
||||
Int32 header, LightObj & payload)
|
||||
{
|
||||
|
||||
// Request the server to create this entity
|
||||
const Int32 id = _Func->CreateVehicle(model, world, x, y, z, angle, primary, secondary);
|
||||
// See if the entity creation failed on the server
|
||||
if (_Func->GetLastError() == vcmpErrorArgumentOutOfBounds)
|
||||
{
|
||||
STHROWF("Out of bounds vehicle argument: %d", id);
|
||||
}
|
||||
else if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
||||
{
|
||||
STHROWF("Vehicle pool was exhausted: %d", id);
|
||||
}
|
||||
// Validate the identifier returned by the server
|
||||
else if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
||||
{
|
||||
STHROWF("Server returned invalid vehicle: %d", id);
|
||||
}
|
||||
// Attempt to allocate this entity and grab the reference to the instance
|
||||
VehicleInst & inst = AllocVehicle(id, true, header, payload);
|
||||
// Just in case it was created during the notification for changes in entity pool
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
inst.mFlags |= ENF_OWNED;
|
||||
}
|
||||
// Now we can return the script object
|
||||
return inst.mObj;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
bool Core::DelBlip(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Attempt to destroy and deallocate the specified entity instance
|
||||
DeallocBlip(id, true, header, payload);
|
||||
// The entity could be destroyed
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Core::DelCheckpoint(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Attempt to destroy and deallocate the specified entity instance
|
||||
DeallocCheckpoint(id, true, header, payload);
|
||||
// The entity could be destroyed
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Core::DelKeybind(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Attempt to destroy and deallocate the specified entity instance
|
||||
DeallocKeybind(id, true, header, payload);
|
||||
// The entity could be destroyed
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Core::DelObject(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Attempt to destroy and deallocate the specified entity instance
|
||||
DeallocObject(id, true, header, payload);
|
||||
// The entity could be destroyed
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Core::DelPickup(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Attempt to destroy and deallocate the specified entity instance
|
||||
DeallocPickup(id, true, header, payload);
|
||||
// The entity could be destroyed
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Core::DelVehicle(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Attempt to destroy and deallocate the specified entity instance
|
||||
DeallocVehicle(id, true, header, payload);
|
||||
// The entity could be destroyed
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ConnectPlayer(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PLAYER_POOL))
|
||||
{
|
||||
STHROWF("Cannot allocate player with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
PlayerInst & inst = m_Players[id];
|
||||
// Make sure that the instance isn't already allocated
|
||||
if (VALID_ENTITY(inst.mID))
|
||||
{
|
||||
return; // Nothing to allocate!
|
||||
}
|
||||
// Instantiate the entity manager
|
||||
DeleteGuard< CPlayer > dg(new CPlayer(id));
|
||||
// Create the script object
|
||||
inst.mObj = LightObj(dg.Get(), m_VM);
|
||||
// Store the manager instance itself
|
||||
inst.mInst = dg.Get();
|
||||
// The instance is now managed by the script
|
||||
dg.Release();
|
||||
// Make sure that both the instance and script object could be created
|
||||
if (!inst.mInst || inst.mObj.IsNull())
|
||||
{
|
||||
inst.ResetInstance();
|
||||
STHROWF("Unable to create a player instance for: %d", id);
|
||||
}
|
||||
// Assign the specified entity identifier
|
||||
inst.mID = id;
|
||||
// Should we enable area tracking?
|
||||
if (m_AreasEnabled)
|
||||
{
|
||||
inst.mFlags |= ENF_AREA_TRACK;
|
||||
}
|
||||
// Initialize the position
|
||||
_Func->GetPlayerPosition(id, &inst.mLastPosition.x, &inst.mLastPosition.y, &inst.mLastPosition.z);
|
||||
// Initialize the remaining attributes
|
||||
inst.mLastWeapon = _Func->GetPlayerWeapon(id);
|
||||
inst.mLastHealth = _Func->GetPlayerHealth(id);
|
||||
inst.mLastArmour = _Func->GetPlayerArmour(id);
|
||||
inst.mLastHeading = _Func->GetPlayerHeading(id);
|
||||
// Initialize the instance events
|
||||
inst.InitEvents();
|
||||
// Let the script callbacks know about this entity
|
||||
EmitPlayerCreated(id, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::DisconnectPlayer(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Make sure that the specified entity identifier is valid
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PLAYER_POOL))
|
||||
{
|
||||
STHROWF("Cannot deallocate player with invalid identifier: %d", id);
|
||||
}
|
||||
// Retrieve the specified entity instance
|
||||
PlayerInst & inst = m_Players[id];
|
||||
// Make sure that the instance is even allocated and we are allowed to destroy it
|
||||
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
||||
{
|
||||
inst.Destroy(false, header, payload); // Now attempt to destroy the entity from the server
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
+182
-182
File diff suppressed because it is too large
Load Diff
@@ -1,375 +0,0 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern bool GetReloadStatus();
|
||||
extern void SetReloadStatus(bool toggle);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMODE_DECL_TYPENAME(CoreStateTypename, _SC("SqCoreState"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqLoadScript(HSQUIRRELVM vm)
|
||||
{
|
||||
const Int32 top = sq_gettop(vm);
|
||||
// Was the delay option specified?
|
||||
if (top <= 1)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing delay parameter");
|
||||
}
|
||||
// Was the script path specified?
|
||||
else if (top <= 2)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing script path");
|
||||
}
|
||||
// Whether the script execution is delayed
|
||||
SQBool delay = SQFalse;
|
||||
// Attempt to generate the string value
|
||||
StackStrF val(vm, 3);
|
||||
// Have we failed to retrieve the string?
|
||||
if (SQ_FAILED(val.Proc(true)))
|
||||
{
|
||||
return val.mRes; // Propagate the error!
|
||||
}
|
||||
else if (SQ_FAILED(sq_getbool(vm, 2, &delay)))
|
||||
{
|
||||
return sq_throwerror(vm, "Failed to retrieve the delay parameter");
|
||||
}
|
||||
// Forward the call to the actual implementation
|
||||
sq_pushbool(vm, Core::Get().LoadScript(val.mPtr, static_cast< bool >(delay)));
|
||||
// We have an argument on the stack
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqGetEvents(HSQUIRRELVM vm)
|
||||
{
|
||||
// Push the events table object on the stack
|
||||
sq_pushobject(vm, Core::Get().GetEvents().mObj);
|
||||
// Specify that we're returning a value
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqEmitCustomEvent(Int32 group, Int32 header, LightObj & payload)
|
||||
{
|
||||
Core::Get().EmitCustomEvent(group, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqForceEnableNullEntities(HSQUIRRELVM vm)
|
||||
{
|
||||
Core::Get().EnableNullEntities();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetPreLoadEvent()
|
||||
{
|
||||
return Core::Get().GetPreLoadEvent();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetPostLoadEvent()
|
||||
{
|
||||
return Core::Get().GetPostLoadEvent();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetUnloadEvent()
|
||||
{
|
||||
return Core::Get().GetUnloadEvent();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqGetReloadStatus()
|
||||
{
|
||||
return GetReloadStatus();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqSetReloadStatus(bool toggle)
|
||||
{
|
||||
SetReloadStatus(toggle);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqReloadBecause(Int32 header, LightObj & payload)
|
||||
{
|
||||
// Assign the reload info
|
||||
Core::Get().SetReloadInfo(header, payload);
|
||||
// Enable reloading
|
||||
SetReloadStatus(true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqSetReloadInfo(Int32 header, LightObj & payload)
|
||||
{
|
||||
Core::Get().SetReloadInfo(header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static Int32 SqGetReloadHeader()
|
||||
{
|
||||
return Core::Get().GetReloadHeader();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetReloadPayload()
|
||||
{
|
||||
return Core::Get().GetReloadPayload();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static Int32 SqGetState()
|
||||
{
|
||||
return Core::Get().GetState();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqSetState(Int32 value)
|
||||
{
|
||||
return Core::Get().SetState(value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqGetAreasEnabled()
|
||||
{
|
||||
return Core::Get().AreasEnabled();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqSetAreasEnabled(bool toggle)
|
||||
{
|
||||
Core::Get().AreasEnabled(toggle);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const String & SqGetOption(StackStrF & name)
|
||||
{
|
||||
return Core::Get().GetOption(String(name.mPtr, name.mLen));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const String & SqGetOptionOr(StackStrF & name, StackStrF & value)
|
||||
{
|
||||
return Core::Get().GetOption(String(name.mPtr, name.mLen), StringRef(value.mPtr));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqSetOption(StackStrF & name, StackStrF & value)
|
||||
{
|
||||
Core::Get().SetOption(String(name.mPtr, name.mLen), String(value.mPtr, value.mLen));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetBlip(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
||||
{
|
||||
STHROWF("Out of range blip identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetBlip(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetCheckpoint(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
||||
{
|
||||
STHROWF("Out of range checkpoint identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetCheckpoint(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetKeybind(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
||||
{
|
||||
STHROWF("Out of range keybind identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetKeybind(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetObj(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
||||
{
|
||||
STHROWF("Out of range object identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetObj(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetPickup(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
||||
{
|
||||
STHROWF("Out of range blip identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetPickup(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetPlayer(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PLAYER_POOL))
|
||||
{
|
||||
STHROWF("Out of range player identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetPlayer(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & SqGetVehicle(Int32 id)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
||||
{
|
||||
STHROWF("Out of range vehicle identifier: %d", id);
|
||||
}
|
||||
// Return the requested information
|
||||
return Core::Get().GetVehicle(id).mObj;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqDelBlip(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
||||
{
|
||||
STHROWF("Out of range blip identifier: %d", id);
|
||||
}
|
||||
// Perform the requested operation
|
||||
return Core::Get().DelBlip(id, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqDelCheckpoint(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
||||
{
|
||||
STHROWF("Out of range checkpoint identifier: %d", id);
|
||||
}
|
||||
// Perform the requested operation
|
||||
return Core::Get().DelCheckpoint(id, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqDelKeybind(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
||||
{
|
||||
STHROWF("Out of range keybind identifier: %d", id);
|
||||
}
|
||||
// Perform the requested operation
|
||||
return Core::Get().DelKeybind(id, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqDelObject(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
||||
{
|
||||
STHROWF("Out of range object identifier: %d", id);
|
||||
}
|
||||
// Perform the requested operation
|
||||
return Core::Get().DelObject(id, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqDelPickup(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
||||
{
|
||||
STHROWF("Out of range blip identifier: %d", id);
|
||||
}
|
||||
// Perform the requested operation
|
||||
return Core::Get().DelPickup(id, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool SqDelVehicle(Int32 id, Int32 header, LightObj & payload)
|
||||
{
|
||||
// Validate the identifier first
|
||||
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
||||
{
|
||||
STHROWF("Out of range vehicle identifier: %d", id);
|
||||
}
|
||||
// Perform the requested operation
|
||||
return Core::Get().DelVehicle(id, header, payload);
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Core(HSQUIRRELVM vm)
|
||||
{
|
||||
Table corens(vm);
|
||||
|
||||
corens.Bind(_SC("State"),
|
||||
Class< CoreState, NoCopy< CoreState > >(vm, CoreStateTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< int >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &CoreStateTypename::Fn)
|
||||
// Member Properties
|
||||
.Prop(_SC("Value"), &CoreState::GetValue)
|
||||
);
|
||||
|
||||
corens
|
||||
.Func(_SC("Reload"), &SqSetReloadStatus)
|
||||
.Func(_SC("Reloading"), &SqGetReloadStatus)
|
||||
.Func(_SC("ReloadBecause"), &SqReloadBecause)
|
||||
.Func(_SC("SetReloadInfo"), &SqSetReloadInfo)
|
||||
.Func(_SC("GetReloadHeader"), &SqGetReloadHeader)
|
||||
.Func(_SC("GetReloadPayload"), &SqGetReloadPayload)
|
||||
.Func(_SC("CustomEvent"), &SqEmitCustomEvent)
|
||||
.Func(_SC("GetState"), &SqGetState)
|
||||
.Func(_SC("SetState"), &SqSetState)
|
||||
.Func(_SC("AreasEnabled"), &SqGetAreasEnabled)
|
||||
.Func(_SC("SetAreasEnabled"), &SqSetAreasEnabled)
|
||||
.Func(_SC("GetOption"), &SqGetOption)
|
||||
.Func(_SC("GetOptionOr"), &SqGetOptionOr)
|
||||
.Func(_SC("SetOption"), &SqSetOption)
|
||||
.Func(_SC("GetBlip"), &SqGetBlip)
|
||||
.Func(_SC("GetCheckpoint"), &SqGetCheckpoint)
|
||||
.Func(_SC("GetKeybind"), &SqGetKeybind)
|
||||
.Func(_SC("GetObj"), &SqGetObj)
|
||||
.Func(_SC("GetPickup"), &SqGetPickup)
|
||||
.Func(_SC("GetPlayer"), &SqGetPlayer)
|
||||
.Func(_SC("GetVehicle"), &SqGetVehicle)
|
||||
.Func(_SC("DestroyBlip"), &SqDelBlip)
|
||||
.Func(_SC("DestroyCheckpoint"), &SqDelCheckpoint)
|
||||
.Func(_SC("DestroyKeybind"), &SqDelKeybind)
|
||||
.Func(_SC("DestroyObject"), &SqDelObject)
|
||||
.Func(_SC("DestroyPickup"), &SqDelPickup)
|
||||
.Func(_SC("DestroyVehicle"), &SqDelVehicle)
|
||||
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
|
||||
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
|
||||
.Func(_SC("OnUnload"), &SqGetUnloadEvent)
|
||||
.SquirrelFunc(_SC("ForceEnableNullEntities"), &SqForceEnableNullEntities)
|
||||
.SquirrelFunc(_SC("LoadScript"), &SqLoadScript, -3, ".b.")
|
||||
.SquirrelFunc(_SC("On"), &SqGetEvents);
|
||||
|
||||
RootTable(vm).Bind(_SC("SqCore"), corens);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,366 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Routine.hpp"
|
||||
#include "Library/Chrono.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstring>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(Typename, _SC("SqRoutineInstance"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Routine::Time Routine::s_Last = 0;
|
||||
Routine::Time Routine::s_Prev = 0;
|
||||
Routine::Interval Routine::s_Intervals[SQMOD_MAX_ROUTINES];
|
||||
Routine::Instance Routine::s_Instances[SQMOD_MAX_ROUTINES];
|
||||
bool Routine::s_Silenced = false;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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 auto delta = int32_t((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?
|
||||
if (*itr)
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
std::memset(s_Intervals, 0, sizeof(s_Intervals));
|
||||
SetSilenced(!ErrorHandling::IsEnabled());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Routine::Deinitialize()
|
||||
{
|
||||
// Release any script resources that the routines might store
|
||||
for (auto & r : s_Instances)
|
||||
{
|
||||
r.Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Routine::Create(HSQUIRRELVM vm)
|
||||
{
|
||||
// Locate the identifier of a free slot
|
||||
const SQInteger slot = FindUnused();
|
||||
// See if we have where to store this routine
|
||||
if (slot < 0)
|
||||
{
|
||||
return sq_throwerror(vm, "Reached the maximum number of active routines");
|
||||
}
|
||||
// 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_throwerror(vm, "Unable to create the routine instance");
|
||||
}
|
||||
// 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_throwerror(vm, "Unable to create the routine instance");
|
||||
}
|
||||
|
||||
// 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
|
||||
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 == tag.mPtr)
|
||||
{
|
||||
return true; // Yup, we're doing this
|
||||
}
|
||||
}
|
||||
}
|
||||
// Unable to find such routine
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Routine::TerminateWithTag(StackStrF & tag)
|
||||
{
|
||||
// Is the specified tag valid?
|
||||
if (tag.mPtr != nullptr)
|
||||
{
|
||||
// Iterate routine list
|
||||
for (auto & r : s_Instances)
|
||||
{
|
||||
if (!r.mInst.IsNull() && r.mTag == tag.mPtr)
|
||||
{
|
||||
r.Terminate(); // Yup, we're doing this
|
||||
return true; // A routine was terminated
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
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)
|
||||
.Prop(_SC("Env"), &Routine::GetEnv, &Routine::SetEnv)
|
||||
.Prop(_SC("Func"), &Routine::GetFunc, &Routine::SetFunc)
|
||||
.Prop(_SC("Data"), &Routine::GetData, &Routine::SetData)
|
||||
.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)
|
||||
.Prop(_SC("Arguments"), &Routine::GetArguments)
|
||||
// Member Methods
|
||||
.FmtFunc(_SC("SetTag"), &Routine::ApplyTag)
|
||||
.Func(_SC("SetData"), &Routine::ApplyData)
|
||||
.Func(_SC("SetInterval"), &Routine::ApplyInterval)
|
||||
.Func(_SC("SetIterations"), &Routine::ApplyIterations)
|
||||
.Func(_SC("SetSuspended"), &Routine::ApplySuspended)
|
||||
.Func(_SC("SetQuiet"), &Routine::ApplyQuiet)
|
||||
.Func(_SC("SetEndure"), &Routine::ApplyEndure)
|
||||
.Func(_SC("Terminate"), &Routine::Terminate)
|
||||
.Func(_SC("GetArgument"), &Routine::GetArgument)
|
||||
.Func(_SC("DropEnv"), &Routine::DropEnv)
|
||||
.StaticFunc(_SC("UsedCount"), &Routine::GetUsed)
|
||||
.StaticFunc(_SC("AreSilenced"), &Routine::GetSilenced)
|
||||
.StaticFunc(_SC("SetSilenced"), &Routine::SetSilenced)
|
||||
);
|
||||
// Global functions
|
||||
RootTable(vm).SquirrelFunc(_SC("SqRoutine"), &Routine::Create);
|
||||
RootTable(vm).FmtFunc(_SC("SqFindRoutineByTag"), &Routine::FindByTag);
|
||||
RootTable(vm).FmtFunc(_SC("SqIsRoutineWithTag"), &Routine::IsWithTag);
|
||||
RootTable(vm).FmtFunc(_SC("SqTerminateRoutineWithTag"), &Routine::TerminateWithTag);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,678 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Execute callbacks after specific intervals of time.
|
||||
*/
|
||||
class Routine
|
||||
{
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Simplify future changes to a single point of change.
|
||||
*/
|
||||
typedef int64_t Time;
|
||||
typedef SQInteger Interval;
|
||||
typedef uint32_t Iterator;
|
||||
typedef LightObj Argument;
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Structure that represents an active routine and keeps track of the routine information.
|
||||
*/
|
||||
struct Instance
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------
|
||||
LightObj mEnv; // A reference to the managed environment object.
|
||||
LightObj mFunc; // A reference to the managed function object.
|
||||
LightObj mInst; // Reference to the routine associated with this instance.
|
||||
LightObj mData; // A reference to the arbitrary data associated with this instance.
|
||||
String mTag; // An arbitrary string which represents the tag.
|
||||
Iterator mIterations; // Number of iterations before self destruct.
|
||||
Interval mInterval; // Interval between routine invocations.
|
||||
bool mSuspended; // Whether this instance is allowed to receive calls.
|
||||
bool mQuiet; // Whether this instance is allowed to handle errors.
|
||||
bool mEndure; // Whether this instance is allowed to terminate itself on errors.
|
||||
bool mExecuting; // Whether this instance is currently being executed.
|
||||
uint8_t mArgc; // The number of arguments that the routine must forward.
|
||||
Argument mArgv[14]; // The arguments that the routine must forward.
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Instance() noexcept
|
||||
: mEnv()
|
||||
, mFunc()
|
||||
, mInst()
|
||||
, mData()
|
||||
, mTag()
|
||||
, mIterations(0)
|
||||
, mInterval(0)
|
||||
, mSuspended(false)
|
||||
, mQuiet(GetSilenced())
|
||||
, mEndure(false)
|
||||
, mExecuting(false)
|
||||
, mArgc(0)
|
||||
, mArgv()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
Instance(const Instance & o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
Instance(Instance && o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Instance()
|
||||
{
|
||||
Terminate();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Instance & operator = (const Instance & o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
Instance & operator = (Instance && o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Initializes the routine parameters. (assumes previous values are already released)
|
||||
*/
|
||||
void Init(HSQOBJECT & env, HSQOBJECT & func, HSQOBJECT & inst, Interval intrv, Iterator itr)
|
||||
{
|
||||
// Initialize the callback objects
|
||||
mEnv = LightObj{env};
|
||||
mFunc = LightObj{func};
|
||||
// Associate with the routine instance
|
||||
mInst = LightObj{inst};
|
||||
// Initialize the routine options
|
||||
mIterations = itr;
|
||||
mInterval = intrv;
|
||||
// This can't be true now
|
||||
mExecuting = false;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Release managed script resources.
|
||||
*/
|
||||
void Release()
|
||||
{
|
||||
mEnv.Release();
|
||||
mFunc.Release();
|
||||
mInst.Release();
|
||||
mData.Release();
|
||||
mIterations = 0;
|
||||
mInterval = 0;
|
||||
mTag.clear();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Execute the managed routine.
|
||||
*/
|
||||
Interval Execute()
|
||||
{
|
||||
// Is this even a valid routine?
|
||||
if (mInst.IsNull())
|
||||
{
|
||||
return 0; // Dunno how we got here but it ends now
|
||||
}
|
||||
// Are we allowed to forward calls?
|
||||
else if (!mSuspended)
|
||||
{
|
||||
// Grab the virtual machine once
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Push the function on the stack
|
||||
sq_pushobject(vm, mFunc);
|
||||
// Push the environment on the stack
|
||||
if (!mEnv.IsNull())
|
||||
{
|
||||
sq_pushobject(vm, mEnv); // Push object
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, mInst); // Push self
|
||||
}
|
||||
// Push function parameters, if any
|
||||
for (uint32_t n = 0; n < mArgc; ++n)
|
||||
{
|
||||
sq_pushobject(vm, mArgv[n].mObj);
|
||||
}
|
||||
// This routine is currently executing
|
||||
mExecuting = true;
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, mArgc + 1, static_cast< SQBool >(false), static_cast< SQBool >(!mQuiet));
|
||||
// This routine has finished executing
|
||||
mExecuting = false;
|
||||
// Pop the callback object from the stack
|
||||
sq_pop(vm, 1);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
// Should we endure the errors?
|
||||
if (!mEndure)
|
||||
{
|
||||
Terminate(); // Destroy our self on error
|
||||
}
|
||||
}
|
||||
}
|
||||
// Decrease the number of iterations if necessary
|
||||
if (mIterations && (--mIterations) == 0)
|
||||
{
|
||||
Terminate(); // This routine reached the end of it's life
|
||||
}
|
||||
// Return the current interval
|
||||
return mInterval;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the arguments.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
// Now release the arguments
|
||||
for (auto & a : mArgv)
|
||||
{
|
||||
a.Release();
|
||||
}
|
||||
// Reset the counter
|
||||
mArgc = 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Terminate the routine.
|
||||
*/
|
||||
void Terminate()
|
||||
{
|
||||
Release();
|
||||
Clear();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static Time s_Last; // Last time point.
|
||||
static Time s_Prev; // Previous time point.
|
||||
static Interval s_Intervals[SQMOD_MAX_ROUTINES]; // List of intervals to be processed.
|
||||
static Instance s_Instances[SQMOD_MAX_ROUTINES]; // List of routines to be executed.
|
||||
static bool s_Silenced; // Error reporting independent from global setting.
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* The index of the slot in the pool of active routines.
|
||||
*/
|
||||
uint32_t m_Slot;
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Routine()
|
||||
: m_Slot(SQMOD_MAX_ROUTINES)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
explicit Routine(uint32_t slot)
|
||||
: m_Slot(slot)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Find an unoccupied routine slot.
|
||||
*/
|
||||
static SQInteger FindUnused()
|
||||
{
|
||||
for (const auto & r : s_Instances)
|
||||
{
|
||||
// Either not used or not currently being executing
|
||||
if (r.mInst.IsNull() && !(r.mExecuting))
|
||||
{
|
||||
return (&r - s_Instances); // Return the index of this element
|
||||
}
|
||||
}
|
||||
// No available slot
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
~Routine()
|
||||
{
|
||||
if (m_Slot < SQMOD_MAX_ROUTINES)
|
||||
{
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
Routine(const Routine & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
Routine(Routine && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Routine & operator = (const Routine & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
Routine & operator = (Routine && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of used routine slots.
|
||||
*/
|
||||
static SQInteger GetUsed()
|
||||
{
|
||||
SQInteger n = 0;
|
||||
// Iterate routine list
|
||||
for (const auto & r : s_Instances)
|
||||
{
|
||||
if (!r.mInst.IsNull())
|
||||
{
|
||||
++n;
|
||||
}
|
||||
}
|
||||
// Return the final count
|
||||
return n;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of used routine slots.
|
||||
*/
|
||||
static const LightObj & FindByTag(StackStrF & tag)
|
||||
{
|
||||
// Is the specified tag valid?
|
||||
if (!tag.mPtr)
|
||||
{
|
||||
STHROWF("Invalid routine tag");
|
||||
}
|
||||
// Iterate routine list
|
||||
for (const auto & r : s_Instances)
|
||||
{
|
||||
if (!r.mInst.IsNull() && r.mTag == tag.mPtr)
|
||||
{
|
||||
return r.mInst; // Return this routine instance
|
||||
}
|
||||
}
|
||||
// Unable to find such routine
|
||||
STHROWF("Unable to find a routine with tag (%s)", tag.mPtr);
|
||||
// Should not reach this point but if it did, we have to return something
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
return s_Instances[SQMOD_MAX_ROUTINES].mInst; // Intentional Buffer overflow!
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if a routine with a certain tag exists.
|
||||
*/
|
||||
static bool IsWithTag(StackStrF & tag);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if a routine with a certain tag exists.
|
||||
*/
|
||||
static bool TerminateWithTag(StackStrF & tag);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Process all active routines and update elapsed time.
|
||||
*/
|
||||
static void Process();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Initialize all resources and prepare for startup.
|
||||
*/
|
||||
static void Initialize();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release all resources and prepare for shutdown.
|
||||
*/
|
||||
static void Deinitialize();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create a routine with the specified parameters.
|
||||
*/
|
||||
static SQInteger Create(HSQUIRRELVM vm);
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether this routine is valid otherwise throw an exception.
|
||||
*/
|
||||
void Validate() const
|
||||
{
|
||||
if (m_Slot >= SQMOD_MAX_ROUTINES)
|
||||
{
|
||||
STHROWF("This instance does not reference a valid routine");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether this routine is valid otherwise throw an exception.
|
||||
*/
|
||||
SQMOD_NODISCARD Instance & GetValid() const
|
||||
{
|
||||
if (m_Slot >= SQMOD_MAX_ROUTINES)
|
||||
{
|
||||
STHROWF("This instance does not reference a valid routine");
|
||||
}
|
||||
// We know it's valid so let's return it
|
||||
return s_Instances[m_Slot];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a string.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & ToString() const
|
||||
{
|
||||
return (m_Slot >= SQMOD_MAX_ROUTINES) ? NullString() : s_Instances[m_Slot].mTag;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Terminate the routine.
|
||||
*/
|
||||
void Terminate()
|
||||
{
|
||||
GetValid().Terminate();
|
||||
s_Intervals[m_Slot] = 0;
|
||||
m_Slot = SQMOD_MAX_ROUTINES;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the associated user tag.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & GetTag() const
|
||||
{
|
||||
return GetValid().mTag;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the associated user tag.
|
||||
*/
|
||||
void SetTag(StackStrF & tag)
|
||||
{
|
||||
GetValid().mTag.assign(tag.mPtr, static_cast< size_t >(ClampMin(tag.mLen, 0)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the associated user tag.
|
||||
*/
|
||||
Routine & ApplyTag(StackStrF & tag)
|
||||
{
|
||||
SetTag(tag);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the environment object.
|
||||
*/
|
||||
SQMOD_NODISCARD const LightObj & GetEnv() const
|
||||
{
|
||||
return GetValid().mEnv;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the environment object.
|
||||
*/
|
||||
void SetEnv(const LightObj & env)
|
||||
{
|
||||
GetValid().mEnv = env.IsNull() ? LightObj(RootTable{}.GetObj()) : env;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the function object.
|
||||
*/
|
||||
SQMOD_NODISCARD const LightObj & GetFunc() const
|
||||
{
|
||||
return GetValid().mFunc;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the function object.
|
||||
*/
|
||||
void SetFunc(const Function & func)
|
||||
{
|
||||
// Validate the specified
|
||||
if (!sq_isclosure(func.GetFunc()) && !sq_isnativeclosure(func.GetFunc()))
|
||||
{
|
||||
STHROWF("Invalid callback type %s", SqTypeName(GetValid().mFunc.GetType()));
|
||||
}
|
||||
// Store the function without the environment
|
||||
GetValid().mFunc = LightObj(func.GetFunc());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the arbitrary user data object.
|
||||
*/
|
||||
SQMOD_NODISCARD const LightObj & GetData() const
|
||||
{
|
||||
return GetValid().mData;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the arbitrary user data object.
|
||||
*/
|
||||
void SetData(const LightObj & data)
|
||||
{
|
||||
GetValid().mData = data;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the arbitrary user data object.
|
||||
*/
|
||||
Routine & ApplyData(const LightObj & data)
|
||||
{
|
||||
SetData(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the execution interval.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetInterval() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(GetValid().mInterval);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the execution interval.
|
||||
*/
|
||||
void SetInterval(SQInteger itr)
|
||||
{
|
||||
GetValid().mInterval = ClampMin(ConvTo< Interval >::From(itr), static_cast< Interval >(0));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the execution interval.
|
||||
*/
|
||||
Routine & ApplyInterval(SQInteger itr)
|
||||
{
|
||||
SetInterval(itr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of iterations.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetIterations() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(GetValid().mIterations);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the number of iterations.
|
||||
*/
|
||||
void SetIterations(SQInteger itr)
|
||||
{
|
||||
GetValid().mIterations = ConvTo< Iterator >::From(itr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the number of iterations.
|
||||
*/
|
||||
Routine & ApplyIterations(SQInteger itr)
|
||||
{
|
||||
SetIterations(itr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the routine is suspended.
|
||||
*/
|
||||
SQMOD_NODISCARD bool GetSuspended() const
|
||||
{
|
||||
return GetValid().mSuspended;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the routine should be suspended.
|
||||
*/
|
||||
void SetSuspended(bool toggle)
|
||||
{
|
||||
GetValid().mSuspended = toggle;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the routine should be suspended.
|
||||
*/
|
||||
Routine & ApplySuspended(bool toggle)
|
||||
{
|
||||
SetSuspended(toggle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the routine is quite.
|
||||
*/
|
||||
SQMOD_NODISCARD bool GetQuiet() const
|
||||
{
|
||||
return GetValid().mQuiet;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the routine should be quiet.
|
||||
*/
|
||||
void SetQuiet(bool toggle)
|
||||
{
|
||||
GetValid().mQuiet = toggle;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the routine should be quiet.
|
||||
*/
|
||||
Routine & ApplyQuiet(bool toggle)
|
||||
{
|
||||
SetQuiet(toggle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the routine endures.
|
||||
*/
|
||||
SQMOD_NODISCARD bool GetEndure() const
|
||||
{
|
||||
return GetValid().mEndure;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the routine should endure.
|
||||
*/
|
||||
void SetEndure(bool toggle)
|
||||
{
|
||||
GetValid().mEndure = toggle;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the routine should endure.
|
||||
*/
|
||||
Routine & ApplyEndure(bool toggle)
|
||||
{
|
||||
SetEndure(toggle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of arguments to be forwarded.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetArguments() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(GetValid().mArgc);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a certain argument.
|
||||
*/
|
||||
SQMOD_NODISCARD const Argument & GetArgument(SQInteger arg) const
|
||||
{
|
||||
// Cast the index to the proper value
|
||||
uint8_t idx = ConvTo< uint8_t >::From(arg);
|
||||
// Validate the specified index
|
||||
if (idx >= 14)
|
||||
{
|
||||
STHROWF("The specified index is out of range: %u >= %u", idx, 14);
|
||||
}
|
||||
// Return the requested argument
|
||||
return GetValid().mArgv[idx];
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release the environment object and default to self.
|
||||
*/
|
||||
void DropEnv()
|
||||
{
|
||||
GetValid().mEnv.Release();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if error reporting is enabled for all newly created routines.
|
||||
*/
|
||||
static bool GetSilenced()
|
||||
{
|
||||
return s_Silenced;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set if error reporting should be enabled for all newly created routines.
|
||||
*/
|
||||
static void SetSilenced(bool toggle)
|
||||
{
|
||||
s_Silenced = toggle;
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,187 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Script.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper class to ensure the file handle is closed regardless of the situation.
|
||||
*/
|
||||
class FileHandle
|
||||
{
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
std::FILE * mFile; // Handle to the opened file.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
explicit FileHandle(const SQChar * path)
|
||||
: mFile(std::fopen(path, "rb"))
|
||||
{
|
||||
if (!mFile)
|
||||
{
|
||||
STHROWF("Unable to open script source (%s)", path);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
FileHandle(const FileHandle & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
FileHandle(FileHandle && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~FileHandle()
|
||||
{
|
||||
if (mFile)
|
||||
{
|
||||
std::fclose(mFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
FileHandle & operator = (const FileHandle & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
FileHandle & operator = (FileHandle && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Implicit conversion to the managed file handle.
|
||||
*/
|
||||
operator std::FILE * () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
return mFile;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ScriptSrc::Process()
|
||||
{
|
||||
// Attempt to open the specified file
|
||||
FileHandle fp(mPath.c_str());
|
||||
// First 2 bytes of the file will tell if this is a compiled script
|
||||
std::uint16_t tag;
|
||||
// Go to the end of the file
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
// Calculate buffer size from beginning to current position
|
||||
const long length = std::ftell(fp);
|
||||
// Go back to the beginning
|
||||
std::fseek(fp, 0, SEEK_SET);
|
||||
// Read the first 2 bytes of the file and determine the file type
|
||||
if ((length >= 2) && (std::fread(&tag, 1, 2, fp) != 2 || tag == SQ_BYTECODE_STREAM_TAG))
|
||||
{
|
||||
return; // Probably an empty file or compiled script
|
||||
}
|
||||
// Allocate enough space to hold the file data
|
||||
mData.resize(static_cast< size_t >(length), 0);
|
||||
// Go back to the beginning
|
||||
std::fseek(fp, 0, SEEK_SET);
|
||||
// Read the file contents into allocated data
|
||||
std::fread(&mData[0], 1, static_cast< size_t >(length), fp);
|
||||
// Where the last line ended
|
||||
size_t line_start = 0, line_end = 0;
|
||||
// Process the file data and locate new lines
|
||||
for (String::const_iterator itr = mData.cbegin(); itr != mData.cend();)
|
||||
{
|
||||
// Is this a Unix style line ending?
|
||||
if (*itr == '\n')
|
||||
{
|
||||
// Extract the line length
|
||||
line_end = static_cast< size_t >(std::distance(mData.cbegin(), itr));
|
||||
// Store the beginning of the line
|
||||
mLine.emplace_back(line_start, line_end);
|
||||
// Advance to the next line
|
||||
line_start = line_end+1;
|
||||
// The line end character was not included
|
||||
++itr;
|
||||
}
|
||||
// Is this a Windows style line ending?
|
||||
else if (*itr == '\r')
|
||||
{
|
||||
if (*(++itr) == '\n')
|
||||
{
|
||||
// Extract the line length
|
||||
line_end = static_cast< size_t >(std::distance(mData.cbegin(), itr) - 1);
|
||||
// Store the beginning of the line
|
||||
mLine.emplace_back(line_start, line_end);
|
||||
// Advance to the next line
|
||||
line_start = line_end+2;
|
||||
// The line end character was not included
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
// Should we add the last line as well?
|
||||
if (mData.size() - line_start > 0)
|
||||
{
|
||||
mLine.emplace_back(line_start, mData.size());
|
||||
}
|
||||
// Specify that this script contains line information
|
||||
mInfo = true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ScriptSrc::ScriptSrc(const String & path, bool delay, bool info) // NOLINT(modernize-pass-by-value)
|
||||
: mExec()
|
||||
, mPath(path)
|
||||
, mData()
|
||||
, mLine()
|
||||
, mInfo(info)
|
||||
, mDelay(delay)
|
||||
{
|
||||
// Is the specified path empty?
|
||||
if (mPath.empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid or empty script path");
|
||||
}
|
||||
// Should we load the file contents for debugging purposes?
|
||||
else if (mInfo)
|
||||
{
|
||||
Process();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
String ScriptSrc::FetchLine(size_t line, bool trim) const
|
||||
{
|
||||
// Do we have such line?
|
||||
if (line > mLine.size())
|
||||
{
|
||||
return String(); // Nope!
|
||||
}
|
||||
// Grab it's range in the file
|
||||
Line::const_reference l = mLine.at(line);
|
||||
// Grab the code from that line
|
||||
String code = mData.substr(l.first, l.second - l.first);
|
||||
// Trim whitespace from the beginning of the code code
|
||||
if (trim)
|
||||
{
|
||||
code.erase(0, code.find_first_not_of(" \t\n\r\f\v"));
|
||||
}
|
||||
// Return the resulting string
|
||||
return code;
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Common.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sqratScript.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class Core;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Hold a information about loaded scripts as it's contents and executable code.
|
||||
*/
|
||||
class ScriptSrc
|
||||
{
|
||||
public:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::vector< std::pair< uint32_t, uint32_t > > Line;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Script mExec; // Reference to the script object.
|
||||
String mPath; // Path to the script file.
|
||||
String mData; // The contents of the script file.
|
||||
Line mLine; // List of lines of code in the data.
|
||||
bool mInfo; // Whether this script contains line information.
|
||||
bool mDelay; // Don't execute immediately after compilation.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Read file contents and calculate information about the lines of code.
|
||||
*/
|
||||
void Process();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
explicit ScriptSrc(const String & path, bool delay = false, bool info = false);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
ScriptSrc(const ScriptSrc & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
ScriptSrc(ScriptSrc && o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
ScriptSrc & operator = (const ScriptSrc & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
ScriptSrc & operator = (ScriptSrc && o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Fetches a line from the code. Can also trim whitespace at the beginning.
|
||||
*/
|
||||
SQMOD_NODISCARD String FetchLine(size_t line, bool trim = true) const;
|
||||
};
|
||||
|
||||
|
||||
} // Namespace:: SqMod
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,765 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct Signal;
|
||||
struct SignalWrapper;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Class used to deliver events to one or more listeners.
|
||||
*/
|
||||
struct Signal
|
||||
{
|
||||
friend class SignalWrapper;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef unsigned int SizeType; // Type of value used to represent sizes and/or indexes.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
enum { SMB_SIZE = 8 };
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Signal();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
explicit Signal(const char * name)
|
||||
: Signal(String(name))
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
explicit Signal(const String & name)
|
||||
: Signal(String(name))
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
explicit Signal(String && name);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor (disabled).
|
||||
*/
|
||||
Signal(const Signal & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor (disabled).
|
||||
*/
|
||||
Signal(Signal && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Signal();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
Signal & operator = (const Signal & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator (disabled).
|
||||
*/
|
||||
Signal & operator = (Signal && o) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Adjust the internal buffer size if necessary.
|
||||
*/
|
||||
bool AdjustSlots(SizeType capacity);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Structure responsible for storing information about a slot.
|
||||
*/
|
||||
struct Slot
|
||||
{
|
||||
SQHash mThisHash; // The hash of the specified environment.
|
||||
SQHash mFuncHash; // The hash of the specified callback.
|
||||
HSQOBJECT mThisRef; // The specified script environment.
|
||||
HSQOBJECT mFuncRef; // The specified script callback.
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Slot()
|
||||
: mThisHash(0)
|
||||
, mFuncHash(0)
|
||||
, mThisRef()
|
||||
, mFuncRef()
|
||||
{
|
||||
sq_resetobject(&mThisRef);
|
||||
sq_resetobject(&mFuncRef);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Forwarding constructor.
|
||||
*/
|
||||
Slot(Object & env, ::Sqrat::Function & func)
|
||||
: Slot(env.GetObj(), func.GetFunc())
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Slot(HSQOBJECT & env, HSQOBJECT & func)
|
||||
: mThisHash(0)
|
||||
, mFuncHash(0)
|
||||
, mThisRef(env)
|
||||
, mFuncRef(func)
|
||||
{
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Is there an explicit environment?
|
||||
if (!sq_isnull(mThisRef))
|
||||
{
|
||||
// Keep a reference to this environment
|
||||
sq_addref(vm, &mThisRef);
|
||||
// Push the environment on the stack
|
||||
sq_pushobject(vm, mThisRef);
|
||||
// Grab the hash of the environment object
|
||||
mThisHash = sq_gethash(vm, -1);
|
||||
}
|
||||
// Is there an explicit function?
|
||||
if (!sq_isnull(mFuncRef))
|
||||
{
|
||||
// Keep a reference to this function
|
||||
sq_addref(vm, &mFuncRef);
|
||||
// Push the callback on the stack
|
||||
sq_pushobject(vm, mFuncRef);
|
||||
// Grab the hash of the callback object
|
||||
mFuncHash = sq_gethash(vm, -1);
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Slot(HSQOBJECT & env, HSQOBJECT & func, SQHash envh, SQHash funch)
|
||||
: mThisHash(envh)
|
||||
, mFuncHash(funch)
|
||||
, mThisRef(env)
|
||||
, mFuncRef(func)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
Slot(const Slot & o)
|
||||
: mThisHash(o.mThisHash)
|
||||
, mFuncHash(o.mFuncHash)
|
||||
, mThisRef(o.mThisRef)
|
||||
, mFuncRef(o.mFuncRef)
|
||||
{
|
||||
// Track reference
|
||||
if (mFuncHash != 0)
|
||||
{
|
||||
sq_addref(SqVM(), &mThisRef);
|
||||
sq_addref(SqVM(), &mFuncRef);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
Slot(Slot && o) noexcept
|
||||
: mThisHash(o.mThisHash)
|
||||
, mFuncHash(o.mFuncHash)
|
||||
, mThisRef(o.mThisRef)
|
||||
, mFuncRef(o.mFuncRef)
|
||||
{
|
||||
// Take ownership
|
||||
sq_resetobject(&o.mThisRef);
|
||||
sq_resetobject(&o.mFuncRef);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Slot()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Slot & operator = (const Slot & o)
|
||||
{
|
||||
if (this != &o)
|
||||
{
|
||||
// Release current resources, if any
|
||||
Release();
|
||||
// Replicate data
|
||||
mThisHash = o.mThisHash;
|
||||
mFuncHash = o.mFuncHash;
|
||||
mThisRef = o.mThisRef;
|
||||
mFuncRef = o.mFuncRef;
|
||||
// Track reference
|
||||
sq_addref(SqVM(), &const_cast< HSQOBJECT & >(o.mThisRef));
|
||||
sq_addref(SqVM(), &const_cast< HSQOBJECT & >(o.mFuncRef));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
Slot & operator = (Slot && o) noexcept
|
||||
{
|
||||
if (this != &o)
|
||||
{
|
||||
// Release current resources, if any
|
||||
Release();
|
||||
// Replicate data
|
||||
mThisHash = o.mThisHash;
|
||||
mFuncHash = o.mFuncHash;
|
||||
mThisRef = o.mThisRef;
|
||||
mFuncRef = o.mFuncRef;
|
||||
// Take ownership
|
||||
sq_resetobject(&o.mThisRef);
|
||||
sq_resetobject(&o.mFuncRef);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Equality comparison operator.
|
||||
*/
|
||||
bool operator == (const Slot & o) const
|
||||
{
|
||||
return (mThisHash == o.mThisHash) && (mFuncHash == o.mFuncHash);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Inequality comparison operator.
|
||||
*/
|
||||
bool operator != (const Slot & o) const
|
||||
{
|
||||
return (mThisHash != o.mThisHash) || (mFuncHash != o.mFuncHash);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Release managed script resources.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Available() const
|
||||
{
|
||||
return (mFuncHash == 0);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Release managed script resources.
|
||||
*/
|
||||
void Release()
|
||||
{
|
||||
// Should we release any environment object?
|
||||
if (mThisHash != 0)
|
||||
{
|
||||
sq_release(SqVM(), &mThisRef);
|
||||
sq_resetobject(&mThisRef);
|
||||
// Also reset the hash
|
||||
mThisHash = 0;
|
||||
}
|
||||
// Should we release any callback object?
|
||||
if (mFuncHash != 0)
|
||||
{
|
||||
sq_release(SqVM(), &mFuncRef);
|
||||
sq_resetobject(&mFuncRef);
|
||||
// Also reset the hash
|
||||
mFuncHash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Swap the values of two slots.
|
||||
*/
|
||||
void Swap(Slot & s)
|
||||
{
|
||||
// Swap the environment hash
|
||||
SQHash h = mThisHash;
|
||||
mThisHash = s.mThisHash;
|
||||
s.mThisHash = h;
|
||||
// Swap the callback hash
|
||||
h = mFuncHash;
|
||||
mFuncHash = s.mFuncHash;
|
||||
s.mFuncHash = h;
|
||||
// Swap the environment object
|
||||
HSQOBJECT o = mThisRef;
|
||||
mThisRef = s.mThisRef;
|
||||
s.mThisRef = o;
|
||||
// Swap the callback object
|
||||
o = mFuncRef;
|
||||
mFuncRef = s.mFuncRef;
|
||||
s.mFuncRef = o;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef Slot ValueType; // Value type used to represent a slot.
|
||||
typedef ValueType & Reference; // Reference to the stored value type
|
||||
typedef const ValueType & ConstReference; // Constant reference to the stored value type.
|
||||
typedef ValueType * Pointer; // Pointer to the stored value type
|
||||
typedef const ValueType * ConstPointer; // Constant pointer to the stored value type.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
/// Execution scope used to adjust iterators when removing slots or adjusting the buffer.
|
||||
struct Scope
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------
|
||||
Pointer mItr; ///< Currently executed slot.
|
||||
Pointer mEnd; ///< Where the execution ends.
|
||||
Scope * mParent; ///< Previous execution scope.
|
||||
Scope * mChild; ///< Next execution scope.
|
||||
// ----------------------------------------------------------------------------------------
|
||||
/// Default constructor.
|
||||
Scope(Scope * parent, Pointer begin, Pointer end)
|
||||
: mItr(begin), mEnd(end), mParent(parent), mChild(nullptr)
|
||||
{
|
||||
if (mParent != nullptr) mParent->mChild = this;
|
||||
}
|
||||
// ----------------------------------------------------------------------------------------
|
||||
/// Destructor.
|
||||
~Scope() {
|
||||
if (mParent != nullptr) mParent->mChild = nullptr;
|
||||
}
|
||||
// ----------------------------------------------------------------------------------------
|
||||
/// Adjust the iterators to account for the fact that the specified slot was removed.
|
||||
void Descend(Pointer ptr);
|
||||
/// Adjust the iterators to account for the fact that the specified slot is now leading.
|
||||
void Lead(Pointer ptr);
|
||||
/// Adjust the iterators to account for the fact that the specified slot is now tailing.
|
||||
void Tail(Pointer ptr);
|
||||
/// Adjust the iterators to finish the execution abruptly.
|
||||
void Finish();
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SizeType m_Used; // The number of stored slots that are valid.
|
||||
SizeType m_Size; // The size of the memory allocated for slots.
|
||||
Pointer m_Slots; // Pointer to the memory containing the slots.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Scope * m_Scope; // Current execution state.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
String m_Name; // The name that identifies this signal.
|
||||
LightObj m_Data; // User data associated with this instance.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ValueType m_SMB[SMB_SIZE]{}; // Small buffer optimization.
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a string.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & ToString() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the associated user data.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj & GetData()
|
||||
{
|
||||
return m_Data;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the associated user data.
|
||||
*/
|
||||
void SetData(LightObj & data)
|
||||
{
|
||||
m_Data = data;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* The number of slots connected to the signal.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetUsed() const
|
||||
{
|
||||
return static_cast< SQInteger >(m_Used);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all slots connected to the signal.
|
||||
*/
|
||||
void ClearSlots();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if there are any slots connected.
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsEmpty() const
|
||||
{
|
||||
return (m_Used == 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Connect the specified slot to the signal.
|
||||
*/
|
||||
SQInteger Connect(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Connect the specified slot but not before disconnecting all other occurrences.
|
||||
*/
|
||||
SQInteger ConnectOnce(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Disconnect all occurrences of the specified slot from the signal.
|
||||
*/
|
||||
SQInteger Disconnect(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if the specified slot is connected to the signal.
|
||||
*/
|
||||
SQInteger Exists(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if the specified slot environment is connected to the signal.
|
||||
*/
|
||||
SQInteger ExistsThis(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if the specified slot callback is connected to the signal.
|
||||
*/
|
||||
SQInteger ExistsFunc(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Count all occurrences of the specified slot.
|
||||
*/
|
||||
SQInteger Count(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Count all occurrences of the specified slot environment.
|
||||
*/
|
||||
SQInteger CountThis(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Count all occurrences of the specified slot callback.
|
||||
*/
|
||||
SQInteger CountFunc(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move all occurrences of the specified slot to the front.
|
||||
*/
|
||||
SQInteger Lead(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move all occurrences of the specified slot environment to the front.
|
||||
*/
|
||||
SQInteger LeadThis(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move all occurrences of the specified slot callback to the front.
|
||||
*/
|
||||
SQInteger LeadFunc(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move all occurrences of the specified slot to the back.
|
||||
*/
|
||||
SQInteger Tail(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move all occurrences of the specified slot environment to the back.
|
||||
*/
|
||||
SQInteger TailThis(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move all occurrences of the specified slot callback to the back.
|
||||
*/
|
||||
SQInteger TailFunc(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Remove all occurrences of the specified slot.
|
||||
*/
|
||||
SQInteger Eliminate(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Remove all occurrences of the specified slot environment.
|
||||
*/
|
||||
SQInteger EliminateThis(SignalWrapper & w);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Remove all occurrences of the specified slot callback.
|
||||
*/
|
||||
SQInteger EliminateFunc(SignalWrapper & w);
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Connect` method of this class.
|
||||
*/
|
||||
static SQInteger SqConnect(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `ConnectOnce` method of this class.
|
||||
*/
|
||||
static SQInteger SqConnectOnce(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Exists` method of this class.
|
||||
*/
|
||||
static SQInteger SqExists(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Disconnect` method of this class.
|
||||
*/
|
||||
static SQInteger SqDisconnect(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `ExistsThis` method of this class.
|
||||
*/
|
||||
static SQInteger SqExistsThis(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `ExistsFunc` method of this class.
|
||||
*/
|
||||
static SQInteger SqExistsFunc(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Count` method of this class.
|
||||
*/
|
||||
static SQInteger SqCount(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `CountThis` method of this class.
|
||||
*/
|
||||
static SQInteger SqCountThis(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `CountFunc` method of this class.
|
||||
*/
|
||||
static SQInteger SqCountFunc(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Lead` method of this class.
|
||||
*/
|
||||
static SQInteger SqLead(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `LeadThis` method of this class.
|
||||
*/
|
||||
static SQInteger SqLeadThis(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `LeadFunc` method of this class.
|
||||
*/
|
||||
static SQInteger SqLeadFunc(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Tail` method of this class.
|
||||
*/
|
||||
static SQInteger SqTail(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `TailThis` method of this class.
|
||||
*/
|
||||
static SQInteger SqTailThis(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `TailFunc` method of this class.
|
||||
*/
|
||||
static SQInteger SqTailFunc(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Eliminate` method of this class.
|
||||
*/
|
||||
static SQInteger SqEliminate(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `EliminateThis` method of this class.
|
||||
*/
|
||||
static SQInteger SqEliminateThis(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `EliminateFunc` method of this class.
|
||||
*/
|
||||
static SQInteger SqEliminateFunc(HSQUIRRELVM vm);
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots.
|
||||
*/
|
||||
SQInteger Emit(HSQUIRRELVM vm, SQInteger top);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and collect returned values.
|
||||
*/
|
||||
SQInteger Query(HSQUIRRELVM vm, SQInteger top);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and see if they consume it.
|
||||
*/
|
||||
SQInteger Consume(HSQUIRRELVM vm, SQInteger top);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and see if they approve it.
|
||||
*/
|
||||
SQInteger Approve(HSQUIRRELVM vm, SQInteger top);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit the event to the connected slots and see if they return something.
|
||||
*/
|
||||
SQInteger Request(HSQUIRRELVM vm, SQInteger top);
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Emit` method of this class.
|
||||
*/
|
||||
static SQInteger SqEmit(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Query` method of this class.
|
||||
*/
|
||||
static SQInteger SqQuery(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Consume` method of this class.
|
||||
*/
|
||||
static SQInteger SqConsume(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Approve` method of this class.
|
||||
*/
|
||||
static SQInteger SqApprove(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Squirrel wrapper for the `Request` method of this class.
|
||||
*/
|
||||
static SQInteger SqRequest(HSQUIRRELVM vm);
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::pair< std::size_t, SignalPair > SignalElement;
|
||||
typedef std::vector< SignalElement > SignalPool;
|
||||
typedef std::vector< Signal * > FreeSignals;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static SignalPool s_Signals; // List of all created signals.
|
||||
static FreeSignals s_FreeSignals; // List of signals without a name.
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Specialization for when there are no arguments given.
|
||||
*/
|
||||
void PushParameters()
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Specialization for when there's only one argument given/remaining.
|
||||
*/
|
||||
template < typename T > void PushParameters(T v)
|
||||
{
|
||||
Var< T >::push(SqVM(), v);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Specialization for when there's more than one argument given.
|
||||
*/
|
||||
template < typename T, typename... Args > void PushParameters(T v, Args... args)
|
||||
{
|
||||
Var< T >::push(SqVM(), v);
|
||||
PushParameters(args...);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Terminate all signal instances and release any script resources.
|
||||
*/
|
||||
static void Terminate();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create a free signal without a specific name.
|
||||
*/
|
||||
SQMOD_NODISCARD static LightObj CreateFree();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create a new signal with the specified name.
|
||||
*/
|
||||
SQMOD_NODISCARD static LightObj Create(StackStrF & name);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Remove the signal with the specified name.
|
||||
*/
|
||||
static void Remove(StackStrF & name);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the signal with the specified name.
|
||||
*/
|
||||
SQMOD_NODISCARD static const LightObj & Fetch(StackStrF & name);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Emit a signal from the module.
|
||||
*/
|
||||
template < typename... Args > void operator () (Args&&... args)
|
||||
{
|
||||
// Are there any slots connected?
|
||||
if (!m_Used) return;
|
||||
// Enter a new execution scope
|
||||
Scope scope(m_Scope, m_Slots, m_Slots + m_Used);
|
||||
// Activate the current scope and create a guard to restore it
|
||||
const AutoAssign< Scope * > aa(m_Scope, scope.mParent, &scope);
|
||||
// Grab the default virtual machine
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Process the slots from this scope
|
||||
while (scope.mItr != scope.mEnd)
|
||||
{
|
||||
// Grab a reference to the current slot
|
||||
const Slot & slot = *(scope.mItr++);
|
||||
// Push the callback object
|
||||
sq_pushobject(vm, slot.mFuncRef);
|
||||
// Is there an explicit environment?
|
||||
if (slot.mThisHash == 0)
|
||||
{
|
||||
sq_pushroottable(vm);
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_pushobject(vm, slot.mThisRef);
|
||||
}
|
||||
// Push the given parameters on the stack
|
||||
PushParameters(args...);
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, 1 + sizeof...(Args), static_cast< SQBool >(false), static_cast< SQBool >(ErrorHandling::IsEnabled()));
|
||||
// Pop the callback object from the stack
|
||||
sq_pop(vm, 1);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
SQTHROW(vm, LastErrorString(vm)); // Stop emitting signals NOLINT(hicpp-exception-baseclass,cert-err60-cpp)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,521 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Tasks.hpp"
|
||||
#include "Core.hpp"
|
||||
#include "Library/Chrono.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstring>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(Typename, _SC("SqTask"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Tasks::Time Tasks::s_Last = 0;
|
||||
Tasks::Time Tasks::s_Prev = 0;
|
||||
Tasks::Interval Tasks::s_Intervals[SQMOD_MAX_TASKS];
|
||||
Tasks::Task Tasks::s_Tasks[SQMOD_MAX_TASKS];
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::Task::Init(HSQOBJECT & func, HSQOBJECT & inst, Interval intrv, Iterator itr, int32_t id, int32_t type)
|
||||
{
|
||||
// Initialize the callback hash
|
||||
mHash = 0;
|
||||
// Initialize the callback objects
|
||||
mFunc = LightObj(func);
|
||||
mInst = LightObj(inst);
|
||||
// Initialize the task options
|
||||
mIterations = itr;
|
||||
mInterval = intrv;
|
||||
// Initialize the entity information
|
||||
mEntity = ConvTo< int16_t >::From(id);
|
||||
mType = ConvTo< uint8_t >::From(type);
|
||||
// Grab the virtual machine once
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Is there a valid function?
|
||||
if (!mFunc.IsNull())
|
||||
{
|
||||
// Push the callback on the stack
|
||||
sq_pushobject(vm, mFunc);
|
||||
// Grab the hash of the callback object
|
||||
mHash = sq_gethash(vm, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::Task::Release()
|
||||
{
|
||||
mHash = 0;
|
||||
mTag.clear();
|
||||
mFunc.Release();
|
||||
mInst.Release();
|
||||
mData.Release();
|
||||
mIterations = 0;
|
||||
mInterval = 0;
|
||||
mEntity = -1;
|
||||
mType = 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Tasks::Interval Tasks::Task::Execute()
|
||||
{
|
||||
// Are we even a valid task?
|
||||
if (INVALID_ENTITY(mEntity))
|
||||
{
|
||||
return 0; // Dunno how we got here but it ends now
|
||||
}
|
||||
// Grab the virtual machine once
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Push the function on the stack
|
||||
sq_pushobject(vm, mFunc);
|
||||
// Push the environment on the stack
|
||||
sq_pushobject(vm, mSelf);
|
||||
// Push function parameters, if any
|
||||
for (uint32_t n = 0; n < mArgc; ++n)
|
||||
{
|
||||
sq_pushobject(vm, mArgv[n].mObj);
|
||||
}
|
||||
// Make the function call and store the result
|
||||
const SQRESULT res = sq_call(vm, mArgc + 1, static_cast< SQBool >(false), static_cast< SQBool >(ErrorHandling::IsEnabled()));
|
||||
// Pop the callback object from the stack
|
||||
sq_pop(vm, 1);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
Terminate(); // Destroy ourself on error
|
||||
}
|
||||
// Decrease the number of iterations if necessary
|
||||
if (mIterations && (--mIterations) == 0)
|
||||
{
|
||||
Terminate(); // This routine reached the end of it's life
|
||||
}
|
||||
// Return the current interval
|
||||
return mInterval;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::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 auto delta = int32_t((s_Last - s_Prev) / 1000L);
|
||||
// Process all active tasks
|
||||
for (Interval * itr = s_Intervals; itr != (s_Intervals + SQMOD_MAX_TASKS); ++itr)
|
||||
{
|
||||
// Is this task valid?
|
||||
if (*itr)
|
||||
{
|
||||
// Decrease the elapsed time
|
||||
(*itr) -= delta;
|
||||
// Have we completed the routine interval?
|
||||
if ((*itr) <= 0)
|
||||
{
|
||||
// Execute and reset the elapsed time
|
||||
(*itr) = s_Tasks[itr - s_Intervals].Execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::Initialize()
|
||||
{
|
||||
std::memset(s_Intervals, 0, sizeof(s_Intervals));
|
||||
// Transform all task instances to script objects
|
||||
for (auto & t : s_Tasks)
|
||||
{
|
||||
// This is fine because they'll always outlive the virtual machine
|
||||
t.mSelf = LightObj(&t);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::Register(HSQUIRRELVM vm)
|
||||
{
|
||||
RootTable(vm).Bind(Typename::Str,
|
||||
Class< Task, NoDestructor< Task > >(vm, Typename::Str)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Task::ToString)
|
||||
// Properties
|
||||
.Prop(_SC("Tag"), &Task::GetTag, &Task::SetTag)
|
||||
.Prop(_SC("Entity"), &Task::GetInst)
|
||||
.Prop(_SC("Func"), &Task::GetFunc, &Task::SetFunc)
|
||||
.Prop(_SC("Data"), &Task::GetData, &Task::SetData)
|
||||
.Prop(_SC("Interval"), &Task::GetInterval, &Task::SetInterval)
|
||||
.Prop(_SC("Iterations"), &Task::GetIterations, &Task::SetIterations)
|
||||
.Prop(_SC("Arguments"), &Task::GetArguments)
|
||||
.Prop(_SC("Inst"), &Task::GetInst)
|
||||
// Member Methods
|
||||
.FmtFunc(_SC("SetTag"), &Task::SetTag)
|
||||
.Func(_SC("Terminate"), &Task::Terminate)
|
||||
.Func(_SC("GetArgument"), &Task::GetArgument)
|
||||
// Static functions
|
||||
.StaticFunc(_SC("Used"), &Tasks::GetUsed)
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::Deinitialize()
|
||||
{
|
||||
// Release any script resources that the tasks might store
|
||||
for (auto & t : s_Tasks)
|
||||
{
|
||||
t.Terminate();
|
||||
t.mSelf.Release();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & Tasks::FindEntity(int32_t id, int32_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ENT_BLIP: return Core::Get().GetBlip(id).mObj;
|
||||
case ENT_CHECKPOINT: return Core::Get().GetCheckpoint(id).mObj;
|
||||
case ENT_KEYBIND: return Core::Get().GetKeyBind(id).mObj;
|
||||
case ENT_OBJECT: return Core::Get().GetObj(id).mObj;
|
||||
case ENT_PICKUP: return Core::Get().GetPickup(id).mObj;
|
||||
case ENT_PLAYER: return Core::Get().GetPlayer(id).mObj;
|
||||
case ENT_VEHICLE: return Core::Get().GetVehicle(id).mObj;
|
||||
default: return NullLightObj();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Tasks::FindUnused()
|
||||
{
|
||||
for (const auto & t : s_Tasks)
|
||||
{
|
||||
if (INVALID_ENTITY(t.mEntity))
|
||||
{
|
||||
return (&t - s_Tasks); // Return the index of this element
|
||||
}
|
||||
}
|
||||
// No available slot
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Tasks::Create(int32_t id, int32_t type, HSQUIRRELVM vm)
|
||||
{
|
||||
// Locate the identifier of a free slot
|
||||
const SQInteger slot = FindUnused();
|
||||
// See if we have where to store this task
|
||||
if (slot < 0)
|
||||
{
|
||||
return sq_throwerror(vm, "Reached the maximum number of tasks");
|
||||
}
|
||||
// Grab the top of the stack
|
||||
const SQInteger top = sq_gettop(vm);
|
||||
// See if too many arguments were specified
|
||||
if (top > 12) /* 4 base + 8 parameters = 12 */
|
||||
{
|
||||
return sq_throwerror(vm, "Too many parameters specified");
|
||||
}
|
||||
// Was there was a callback specified?
|
||||
else if (top <= 1)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing task callback");
|
||||
}
|
||||
// Validate the callback type
|
||||
else if (sq_gettype(vm, 2) != OT_CLOSURE && sq_gettype(vm, 2) != OT_NATIVECLOSURE)
|
||||
{
|
||||
return sq_throwerror(vm, "Invalid callback type");
|
||||
}
|
||||
// Prepare an entity instance object
|
||||
HSQOBJECT inst;
|
||||
// Attempt to retrieve the entity instance
|
||||
try
|
||||
{
|
||||
inst = FindEntity(id, type).GetObj();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Prepare the function object
|
||||
HSQOBJECT func;
|
||||
// Fetch the specified callback
|
||||
SQRESULT res = sq_getstackobj(vm, 2, &func);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
|
||||
// The number of iterations and interval to execute the task
|
||||
SQInteger intrv = 0, itr = 0;
|
||||
// Was there an interval specified?
|
||||
if (top > 2)
|
||||
{
|
||||
// Grab the interval from the stack
|
||||
res = sq_getinteger(vm, 3, &intrv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Was there a number of iterations specified?
|
||||
if (top > 3)
|
||||
{
|
||||
// Grab the iterations from the stack
|
||||
res = sq_getinteger(vm, 4, &itr);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we can grab a reference to our slot
|
||||
Task & task = s_Tasks[slot];
|
||||
// Were there any arguments specified?
|
||||
if (top > 4)
|
||||
{
|
||||
// Grab a pointer to the arguments array
|
||||
Argument * args = task.mArgv;
|
||||
// Reset the argument counter
|
||||
task.mArgc = 0;
|
||||
// Grab the specified arguments from the stack
|
||||
for (SQInteger i = 5; i <= top; ++i)
|
||||
{
|
||||
res = sq_getstackobj(vm, i, &(args[task.mArgc].mObj));
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
// Clear previous arguments
|
||||
task.Clear();
|
||||
// Propagate the error
|
||||
return res;
|
||||
}
|
||||
// Keep a strong reference to the argument
|
||||
sq_addref(vm, &(args[task.mArgc].mObj));
|
||||
// Increase the argument counter
|
||||
++task.mArgc;
|
||||
}
|
||||
}
|
||||
|
||||
// Alright, at this point we can initialize the slot
|
||||
task.Init(func, inst, intrv, static_cast< Iterator >(itr), id, type);
|
||||
// Now initialize the timer
|
||||
s_Intervals[slot] = intrv;
|
||||
// Push the tag instance on the stack
|
||||
sq_pushobject(vm, task.mSelf);
|
||||
// Specify that this function returns a value
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Tasks::Find(int32_t id, int32_t type, SQInteger & pos, HSQUIRRELVM vm)
|
||||
{
|
||||
// Grab the top of the stack
|
||||
const SQInteger top = sq_gettop(vm);
|
||||
// Was there a callback specified?
|
||||
if (top <= 1)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing task callback");
|
||||
}
|
||||
|
||||
SQRESULT res = SQ_OK;
|
||||
// Grab the hash of the callback object
|
||||
const SQHash chash = sq_gethash(vm, 2);
|
||||
// Should we include the iterations in the criteria?
|
||||
if (top > 3)
|
||||
{
|
||||
SQInteger intrv = 0;
|
||||
// Grab the interval from the stack
|
||||
res = sq_getinteger(vm, 3, &intrv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Attempt to find the requested task
|
||||
for (const auto & t : s_Tasks)
|
||||
{
|
||||
if (t.mHash == chash && t.mEntity == id && t.mType == type && t.mInterval == intrv)
|
||||
{
|
||||
pos = static_cast< SQInteger >(&t - s_Tasks); // Store the index of this element
|
||||
}
|
||||
}
|
||||
}
|
||||
// Should we include the interval in the criteria?
|
||||
else if (top > 2)
|
||||
{
|
||||
SQInteger intrv = 0, sqitr = 0;
|
||||
// Grab the interval from the stack
|
||||
res = sq_getinteger(vm, 3, &intrv);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Grab the iterations from the stack
|
||||
res = sq_getinteger(vm, 4, &sqitr);
|
||||
// Validate the result
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Cast iterations to the right type
|
||||
const Iterator itr = ConvTo< Iterator >::From(sqitr);
|
||||
// Attempt to find the requested task
|
||||
for (const auto & t : s_Tasks)
|
||||
{
|
||||
if (t.mHash == chash && t.mEntity == id && t.mType == type && t.mInterval == intrv && t.mIterations == itr)
|
||||
{
|
||||
pos = static_cast< SQInteger >(&t - s_Tasks); // Store the index of this element
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to find the requested task
|
||||
for (const auto & t : s_Tasks)
|
||||
{
|
||||
if (t.mHash == chash && t.mEntity == id && t.mType == type)
|
||||
{
|
||||
pos = static_cast< SQInteger >(&t - s_Tasks); // Store the index of this element
|
||||
}
|
||||
}
|
||||
}
|
||||
// We could not find such task
|
||||
return res;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Tasks::Remove(int32_t id, int32_t type, HSQUIRRELVM vm)
|
||||
{
|
||||
// Default to not found
|
||||
SQInteger pos = -1;
|
||||
// Perform a search
|
||||
SQRESULT res = Find(id, type, pos, vm);
|
||||
// Did the search failed?
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Did we find anything?
|
||||
else if (pos < 0)
|
||||
{
|
||||
return sq_throwerror(vm, "Unable to locate such task");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release task resources
|
||||
s_Tasks[pos].Terminate();
|
||||
// Reset the timer
|
||||
s_Intervals[pos] = 0;
|
||||
}
|
||||
// Specify that we don't return anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Tasks::Exists(int32_t id, int32_t type, HSQUIRRELVM vm)
|
||||
{
|
||||
// Default to not found
|
||||
SQInteger pos = -1;
|
||||
// Perform a search
|
||||
SQRESULT res = Find(id, type, pos, vm);
|
||||
// Did the search failed?
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
return res; // Propagate the error
|
||||
}
|
||||
// Push a boolean on whether this task was found
|
||||
sq_pushbool(vm, static_cast< SQBool >(pos >= 0));
|
||||
// Specify that we're returning a value
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Tasks::Task & Tasks::FindByTag(int32_t id, int32_t type, StackStrF & tag)
|
||||
{
|
||||
// Attempt to find the requested task
|
||||
for (const auto & t : s_Tasks)
|
||||
{
|
||||
if (t.mEntity == id && t.mType == type && t.mTag == tag.mPtr)
|
||||
{
|
||||
return t; // Return this task instance
|
||||
}
|
||||
}
|
||||
// Unable to find such task
|
||||
STHROWF("Unable to find a task with tag (%s)", tag.mPtr);
|
||||
// Should not reach this point but if it did, we have to return something
|
||||
SQ_UNREACHABLE
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tasks::Cleanup(int32_t id, int32_t type)
|
||||
{
|
||||
for (auto & t : s_Tasks)
|
||||
{
|
||||
if (t.mEntity == id && t.mType == type)
|
||||
{
|
||||
t.Terminate();
|
||||
// Also disable the timer
|
||||
s_Intervals[&t - s_Tasks] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to process tasks.
|
||||
*/
|
||||
void ProcessTasks()
|
||||
{
|
||||
Tasks::Process();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to initialize tasks.
|
||||
*/
|
||||
void InitializeTasks()
|
||||
{
|
||||
Tasks::Initialize();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to terminate tasks.
|
||||
*/
|
||||
void TerminateTasks()
|
||||
{
|
||||
Tasks::Deinitialize();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to cleanup certain tasks.
|
||||
*/
|
||||
void CleanupTasks(int32_t id, int32_t type)
|
||||
{
|
||||
Tasks::Cleanup(id, type);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Forward the call to register tasks.
|
||||
*/
|
||||
void Register_Tasks(HSQUIRRELVM vm)
|
||||
{
|
||||
Tasks::Register(vm);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,524 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Execute callbacks for specific entities after specific intervals of time.
|
||||
*/
|
||||
class Tasks
|
||||
{
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Simplify future changes to a single point of change.
|
||||
*/
|
||||
typedef int64_t Time;
|
||||
typedef SQInteger Interval;
|
||||
typedef uint32_t Iterator;
|
||||
typedef LightObj Argument;
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Structure that represents a task and keeps track of the task information.
|
||||
*/
|
||||
struct Task
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SQHash mHash; // The hash of the referenced function object.
|
||||
String mTag; // An arbitrary string which represents the tag.
|
||||
LightObj mSelf; // A reference to `this`as a script object.
|
||||
LightObj mFunc; // A reference to the managed function object.
|
||||
LightObj mInst; // A reference to the associated entity object.
|
||||
LightObj mData; // A reference to the arbitrary data associated with this instance.
|
||||
Iterator mIterations; // Number of iterations before self destruct.
|
||||
Interval mInterval; // Interval between task invocations.
|
||||
int16_t mEntity; // The identifier of the entity to which is belongs.
|
||||
uint8_t mType; // The type of the entity to which is belongs.
|
||||
uint8_t mArgc; // The number of arguments that the task must forward.
|
||||
Argument mArgv[8]; // The arguments that the task must forward.
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Task() noexcept
|
||||
: mHash(0)
|
||||
, mTag()
|
||||
, mSelf()
|
||||
, mFunc()
|
||||
, mInst()
|
||||
, mData()
|
||||
, mIterations(0)
|
||||
, mInterval(0)
|
||||
, mEntity(-1)
|
||||
, mType(0)
|
||||
, mArgc(0)
|
||||
, mArgv()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
Task(const Task & o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
Task(Task && o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Release managed script resources.
|
||||
*/
|
||||
~Task()
|
||||
{
|
||||
Terminate();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Task & operator = (const Task & o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
Task & operator = (Task && o) = delete;
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a string.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & ToString() const
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Initializes the task parameters. (assumes previous values are already released)
|
||||
*/
|
||||
void Init(HSQOBJECT & inst, HSQOBJECT & func, Interval intrv, Iterator itr, int32_t id, int32_t type);
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Release managed script resources.
|
||||
*/
|
||||
void Release();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Execute the managed task.
|
||||
*/
|
||||
Interval Execute();
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Clear the arguments.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
// Now release the arguments
|
||||
for (auto & a : mArgv)
|
||||
{
|
||||
a.Release();
|
||||
}
|
||||
// Reset the counter
|
||||
mArgc = 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Terminate the task.
|
||||
*/
|
||||
void Terminate()
|
||||
{
|
||||
Release();
|
||||
Clear();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the associated user tag.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & GetTag() const
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Modify the associated user tag.
|
||||
*/
|
||||
void SetTag(StackStrF & tag)
|
||||
{
|
||||
mTag.assign(tag.mPtr, static_cast< size_t >(ClampMin(tag.mLen, 0)));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the instance to entity instance.
|
||||
*/
|
||||
SQMOD_NODISCARD const LightObj & GetInst() const
|
||||
{
|
||||
return mInst;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the function object.
|
||||
*/
|
||||
SQMOD_NODISCARD const LightObj & GetFunc() const
|
||||
{
|
||||
return mFunc;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Modify the function object.
|
||||
*/
|
||||
void SetFunc(const Function & func)
|
||||
{
|
||||
// Validate the specified
|
||||
if (!sq_isclosure(func.GetFunc()) && !sq_isnativeclosure(func.GetFunc()))
|
||||
{
|
||||
STHROWF("Invalid callback type %s", SqTypeName(mFunc.GetType()));
|
||||
}
|
||||
// Grab the virtual machine once
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Remember the current stack size
|
||||
const StackGuard sg(vm);
|
||||
// Push the callback on the stack
|
||||
sq_pushobject(vm, func.GetFunc());
|
||||
// Grab the hash of the callback object
|
||||
mHash = sq_gethash(vm, -1);
|
||||
// Now store the function without the environment
|
||||
mFunc = LightObj(func.GetFunc());
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the arbitrary user data object.
|
||||
*/
|
||||
SQMOD_NODISCARD const LightObj & GetData() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Modify the arbitrary user data object.
|
||||
*/
|
||||
void SetData(const LightObj & data)
|
||||
{
|
||||
mData = data;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the execution interval.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetInterval() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(mInterval);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Modify the execution interval.
|
||||
*/
|
||||
void SetInterval(SQInteger itr)
|
||||
{
|
||||
mInterval = ClampMin(ConvTo< Interval >::From(itr), static_cast< Interval >(0));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the number of iterations.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetIterations() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(mIterations);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Modify the number of iterations.
|
||||
*/
|
||||
void SetIterations(SQInteger itr)
|
||||
{
|
||||
mIterations = ConvTo< Iterator >::From(itr);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve the number of arguments to be forwarded.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetArguments() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(mArgc);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Retrieve a certain argument.
|
||||
*/
|
||||
SQMOD_NODISCARD const Argument & GetArgument(SQInteger arg) const
|
||||
{
|
||||
constexpr uint32_t argvn = (sizeof(mArgv) / sizeof(mArgv[0]));
|
||||
// Cast the index to the proper value
|
||||
uint8_t idx = ConvTo< uint8_t >::From(arg);
|
||||
// Validate the specified index
|
||||
if (idx >= argvn)
|
||||
{
|
||||
STHROWF("The specified index is out of range: %u >= %u", idx, argvn);
|
||||
}
|
||||
// Return the requested argument
|
||||
return mArgv[idx];
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static Time s_Last; // Last time point.
|
||||
static Time s_Prev; // Previous time point.
|
||||
static Interval s_Intervals[SQMOD_MAX_TASKS]; // List of intervals to be processed.
|
||||
static Task s_Tasks[SQMOD_MAX_TASKS]; // List of tasks to be executed.
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
Tasks & operator = (const Tasks & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
Tasks & operator = (Tasks && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor. (disabled)
|
||||
*/
|
||||
Tasks() = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
Tasks(const Tasks & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
Tasks(Tasks && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor. (disabled)
|
||||
*/
|
||||
~Tasks() = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Process all active tasks and update elapsed time.
|
||||
*/
|
||||
static void Process();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Initialize all resources and prepare for startup.
|
||||
*/
|
||||
static void Initialize();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Register the task class.
|
||||
*/
|
||||
static void Register(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release all resources and prepare for shutdown.
|
||||
*/
|
||||
static void Deinitialize();
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the instance of the specified entity.
|
||||
*/
|
||||
static LightObj & FindEntity(int32_t id, int32_t type);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Find an unoccupied task slot.
|
||||
*/
|
||||
static SQInteger FindUnused();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Locate the first task with the specified parameters.
|
||||
*/
|
||||
static SQInteger Find(int32_t id, int32_t type, SQInteger & pos, HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to create a task with the specified parameters.
|
||||
*/
|
||||
static SQInteger Create(int32_t id, int32_t type, HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to remove the task with the specified parameters.
|
||||
*/
|
||||
static SQInteger Remove(int32_t id, int32_t type, HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if a task with the specified parameters exists.
|
||||
*/
|
||||
static SQInteger Exists(int32_t id, int32_t type, HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Cleanup all tasks associated with the specified entity.
|
||||
*/
|
||||
static const Task & FindByTag(int32_t id, int32_t type, StackStrF & tag);
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of used tasks slots.
|
||||
*/
|
||||
SQMOD_NODISCARD static SQInteger GetUsed()
|
||||
{
|
||||
SQInteger n = 0;
|
||||
// Iterate task list
|
||||
for (const auto & t : s_Tasks)
|
||||
{
|
||||
if (VALID_ENTITY(t.mEntity))
|
||||
{
|
||||
++n;
|
||||
}
|
||||
}
|
||||
// Return the final count
|
||||
return n;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Cleanup all tasks associated with the specified entity.
|
||||
*/
|
||||
static void Cleanup(int32_t id, int32_t type);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Forwards calls to create tasks.
|
||||
*/
|
||||
template < typename Entity, int32_t Type > static SQInteger MakeTask(HSQUIRRELVM vm)
|
||||
{
|
||||
// The entity instance
|
||||
const Entity * inst;
|
||||
// Attempt to extract the instance
|
||||
try
|
||||
{
|
||||
// Fetch the instance from the stack
|
||||
inst = Var< const Entity * >(vm, 1).value;
|
||||
// Do we have a valid instance?
|
||||
if (!inst)
|
||||
{
|
||||
STHROWF("Invalid entity instance");
|
||||
}
|
||||
// Validate the std::exception entity instance
|
||||
inst->Validate();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Forward the call and return the result
|
||||
return Create(inst->GetID(), Type, vm);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Forwards calls to remove tasks.
|
||||
*/
|
||||
template < typename Entity, int32_t Type > static SQInteger DropTask(HSQUIRRELVM vm)
|
||||
{
|
||||
// The entity instance
|
||||
const Entity * inst;
|
||||
// Attempt to extract the instance
|
||||
try
|
||||
{
|
||||
// Fetch the instance from the stack
|
||||
inst = Var< const Entity * >(vm, 1).value;
|
||||
// Do we have a valid instance?
|
||||
if (!inst)
|
||||
{
|
||||
STHROWF("Invalid entity instance");
|
||||
}
|
||||
// Validate the actual entity instance
|
||||
inst->Validate();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Forward the call and return the result
|
||||
return Remove(inst->GetID(), Type, vm);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Forwards calls to check tasks.
|
||||
*/
|
||||
template < typename Entity, int32_t Type > static SQInteger DoesTask(HSQUIRRELVM vm)
|
||||
{
|
||||
// The entity instance
|
||||
const Entity * inst;
|
||||
// Attempt to extract the instance
|
||||
try
|
||||
{
|
||||
// Fetch the instance from the stack
|
||||
inst = Var< const Entity * >(vm, 1).value;
|
||||
// Do we have a valid instance?
|
||||
if (!inst)
|
||||
{
|
||||
STHROWF("Invalid entity instance");
|
||||
}
|
||||
// Validate the actual entity instance
|
||||
inst->Validate();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Forward the call and return the result
|
||||
return Exists(inst->GetID(), Type, vm);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Forwards calls to find tasks.
|
||||
*/
|
||||
template < typename Entity, int32_t Type > static SQInteger FindTask(HSQUIRRELVM vm)
|
||||
{
|
||||
// Was the tag string specified?
|
||||
if (sq_gettop(vm) <= 1)
|
||||
{
|
||||
return sq_throwerror(vm, "Missing tag string");
|
||||
}
|
||||
// The entity instance
|
||||
const Entity * inst;
|
||||
// Attempt to extract the instance
|
||||
try
|
||||
{
|
||||
// Fetch the instance from the stack
|
||||
inst = Var< const Entity * >(vm, 1).value;
|
||||
// Do we have a valid instance?
|
||||
if (!inst)
|
||||
{
|
||||
STHROWF("Invalid entity instance");
|
||||
}
|
||||
// Validate the actual entity instance
|
||||
inst->Validate();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Attempt to generate the string value
|
||||
StackStrF tag(vm, 2);
|
||||
// Have we failed to retrieve the string?
|
||||
if (SQ_FAILED(tag.Proc(true)))
|
||||
{
|
||||
return tag.mRes; // Propagate the error!
|
||||
}
|
||||
// Attempt to find the specified task
|
||||
try
|
||||
{
|
||||
// Perform the search
|
||||
const Task & task = FindByTag(inst->GetID(), Type, tag);
|
||||
// Now push the instance on the stack
|
||||
sq_pushobject(vm, task.mSelf.mObj);
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
return sq_throwerror(vm, e.what());
|
||||
}
|
||||
// Specify that this function returns a value
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,423 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#ifdef SQMOD_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // SQMOD_OS_WINDOWS
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Really poor design decision if a multi-threaded situation ever occurs. Don't do this. Ever!
|
||||
*/
|
||||
static SQChar g_NumBuf[1024];
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< int8_t >::ToStr(int8_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%d", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
int8_t ConvNum< int8_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return ConvTo< int8_t >::From(std::strtol(s, nullptr, 10));
|
||||
}
|
||||
|
||||
int8_t ConvNum< int8_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return ConvTo< int8_t >::From(std::strtol(s, nullptr, base));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< uint8_t >::ToStr(uint8_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%u", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
uint8_t ConvNum< uint8_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return ConvTo< uint8_t >::From(std::strtoul(s, nullptr, 10));
|
||||
}
|
||||
|
||||
uint8_t ConvNum< uint8_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return ConvTo< uint8_t >::From(std::strtoul(s, nullptr, base));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< int16_t >::ToStr(int16_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%d", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
int16_t ConvNum< int16_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return ConvTo< int16_t >::From(std::strtol(s, nullptr, 10));
|
||||
}
|
||||
|
||||
int16_t ConvNum< int16_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return ConvTo< int16_t >::From(std::strtol(s, nullptr, base));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< uint16_t >::ToStr(uint16_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%u", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
uint16_t ConvNum< uint16_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return ConvTo< uint16_t >::From(std::strtoul(s, nullptr, 10));
|
||||
}
|
||||
|
||||
uint16_t ConvNum< uint16_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return ConvTo< uint16_t >::From(std::strtoul(s, nullptr, base));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< int32_t >::ToStr(int32_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%d", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
int32_t ConvNum< int32_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return ConvTo< int32_t >::From(std::strtol(s, nullptr, 10));
|
||||
}
|
||||
|
||||
int32_t ConvNum< int32_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return ConvTo< int32_t >::From(std::strtol(s, nullptr, base));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< uint32_t >::ToStr(uint32_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%u", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
uint32_t ConvNum< uint32_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return ConvTo< uint32_t >::From(std::strtoul(s, nullptr, 10));
|
||||
}
|
||||
|
||||
uint32_t ConvNum< uint32_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return ConvTo< uint32_t >::From(std::strtoul(s, nullptr, base));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< int64_t >::ToStr(int64_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%lld", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
int64_t ConvNum< int64_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strtoll(s, nullptr, 10);
|
||||
}
|
||||
|
||||
int64_t ConvNum< int64_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return std::strtoll(s, nullptr, base);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< uint64_t >::ToStr(uint64_t v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%llu", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
uint64_t ConvNum< uint64_t >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strtoull(s, nullptr, 10);
|
||||
}
|
||||
|
||||
uint64_t ConvNum< uint64_t >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return std::strtoull(s, nullptr, base);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< long >::ToStr(long v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%ld", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
long ConvNum< long >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strtol(s, nullptr, 10);
|
||||
}
|
||||
|
||||
long ConvNum< long >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return std::strtol(s, nullptr, base);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< unsigned long >::ToStr(unsigned long v)
|
||||
{
|
||||
// Write the numeric value to the buffer
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%lu", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the beginning of the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
unsigned long ConvNum< unsigned long >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strtoul(s, nullptr, 10);
|
||||
}
|
||||
|
||||
unsigned long ConvNum< unsigned long >::FromStr(const SQChar * s, int32_t base)
|
||||
{
|
||||
return std::strtoul(s, nullptr, base);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< float >::ToStr(float v)
|
||||
{
|
||||
// Attempt to convert the value to a string
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%f", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the data from the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
float ConvNum< float >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strtof(s, nullptr);
|
||||
}
|
||||
|
||||
float ConvNum< float >::FromStr(const SQChar * s, int32_t /*base*/)
|
||||
{
|
||||
return std::strtof(s, nullptr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< double >::ToStr(double v)
|
||||
{
|
||||
// Attempt to convert the value to a string
|
||||
if (std::snprintf(g_NumBuf, sizeof(g_NumBuf), "%f", v) < 0)
|
||||
{
|
||||
g_NumBuf[0] = '\0';
|
||||
}
|
||||
// Return the data from the buffer
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
double ConvNum< double >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strtod(s, nullptr);
|
||||
}
|
||||
|
||||
double ConvNum< double >::FromStr(const SQChar * s, int32_t /*base*/)
|
||||
{
|
||||
return std::strtod(s, nullptr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const SQChar * ConvNum< bool >::ToStr(bool v)
|
||||
{
|
||||
if (v)
|
||||
{
|
||||
g_NumBuf[0] = 't';
|
||||
g_NumBuf[1] = 'r';
|
||||
g_NumBuf[2] = 'u';
|
||||
g_NumBuf[3] = 'e';
|
||||
g_NumBuf[4] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
g_NumBuf[0] = 'f';
|
||||
g_NumBuf[1] = 'a';
|
||||
g_NumBuf[2] = 'l';
|
||||
g_NumBuf[3] = 's';
|
||||
g_NumBuf[4] = 'e';
|
||||
g_NumBuf[5] = '\0';
|
||||
}
|
||||
return g_NumBuf;
|
||||
}
|
||||
|
||||
bool ConvNum< bool >::FromStr(const SQChar * s)
|
||||
{
|
||||
return std::strcmp(s, "true") == 0;
|
||||
}
|
||||
|
||||
bool ConvNum< bool >::FromStr(const SQChar * s, int32_t /*base*/)
|
||||
{
|
||||
return std::strcmp(s, "true") == 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool NameFilterCheck(const SQChar * filter, const SQChar * name)
|
||||
{
|
||||
// If only one of them is null then they don't match
|
||||
if ((!filter && name) || (filter && !name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// If they're both null or the filter is empty then there's nothing to check for
|
||||
else if ((!filter && !name) || (*filter == '\0'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SQChar ch;
|
||||
// Start comparing the strings
|
||||
while (true)
|
||||
{
|
||||
// Grab the current character from filter
|
||||
ch = *(filter++);
|
||||
// See if the filter or name was completed
|
||||
if (ch == '\0' || *name == '\0')
|
||||
{
|
||||
break; // They matched so far
|
||||
}
|
||||
// Are we supposed to perform a wild-card search?
|
||||
else if (ch == '*')
|
||||
{
|
||||
// Grab the next character from filter
|
||||
ch = *(filter++);
|
||||
// Start comparing characters until the first match
|
||||
while (*name != '\0')
|
||||
{
|
||||
if (*(name++) == ch)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// See if the character matches doesn't have to match
|
||||
else if (ch != '?' && *name != ch)
|
||||
{
|
||||
return false; // The character had to match and failed
|
||||
}
|
||||
else
|
||||
{
|
||||
++name;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point the name satisfied the filter
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool NameFilterCheckInsensitive(const SQChar * filter, const SQChar * name)
|
||||
{
|
||||
// If only one of them is null then they don't match
|
||||
if ((!filter && name) || (filter && !name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// If they're both null or the filter is empty then there's nothing to check for
|
||||
else if ((!filter && !name) || (*filter == '\0'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SQChar ch;
|
||||
// Start comparing the strings
|
||||
while (true)
|
||||
{
|
||||
// Grab the current character from filter
|
||||
ch = static_cast< SQChar >(std::tolower(*(filter++)));
|
||||
// See if the filter or name was completed
|
||||
if (ch == '\0' || *name == '\0')
|
||||
{
|
||||
break; // They matched so far
|
||||
}
|
||||
// Are we supposed to perform a wild-card search?
|
||||
else if (ch == '*')
|
||||
{
|
||||
// Grab the next character from filter
|
||||
ch = static_cast< SQChar >(std::tolower(*(filter++)));
|
||||
// Start comparing characters until the first match
|
||||
while (*name != '\0')
|
||||
{
|
||||
if (static_cast< SQChar >(std::tolower(*(name++))) == ch)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// See if the character matches doesn't have to match
|
||||
else if (ch != '?' && static_cast< SQChar >(std::tolower(*name)) != ch)
|
||||
{
|
||||
return false; // The character had to match and failed
|
||||
}
|
||||
else
|
||||
{
|
||||
++name;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point the name satisfied the filter
|
||||
return true;
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,345 +0,0 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::ClearContainer(EntityType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ENT_BLIP:
|
||||
{
|
||||
m_Blips.clear();
|
||||
} break;
|
||||
case ENT_CHECKPOINT:
|
||||
{
|
||||
m_Checkpoints.clear();
|
||||
} break;
|
||||
case ENT_KEYBIND:
|
||||
{
|
||||
m_Keybinds.clear();
|
||||
} break;
|
||||
case ENT_OBJECT:
|
||||
{
|
||||
m_Objects.clear();
|
||||
} break;
|
||||
case ENT_PICKUP:
|
||||
{
|
||||
m_Pickups.clear();
|
||||
} break;
|
||||
case ENT_PLAYER:
|
||||
{
|
||||
m_Players.clear();
|
||||
} break;
|
||||
case ENT_VEHICLE:
|
||||
{
|
||||
m_Vehicles.clear();
|
||||
} break;
|
||||
default: STHROWF("Cannot clear unknown entity type container");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::InitEvents()
|
||||
{
|
||||
// Ignore the call if already initialized
|
||||
if (!m_Events.IsNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Create a new table on the stack
|
||||
sq_newtableex(SqVM(), 128);
|
||||
// Grab the table object from the stack
|
||||
m_Events = LightObj(-1, SqVM());
|
||||
// Pop the table object from the stack
|
||||
sq_pop(SqVM(), 1);
|
||||
// Proceed to initializing the events
|
||||
InitSignalPair(mOnCustomEvent, m_Events, "CustomEvent");
|
||||
InitSignalPair(mOnBlipCreated, m_Events, "BlipCreated");
|
||||
InitSignalPair(mOnCheckpointCreated, m_Events, "CheckpointCreated");
|
||||
InitSignalPair(mOnKeybindCreated, m_Events, "KeybindCreated");
|
||||
InitSignalPair(mOnObjectCreated, m_Events, "ObjectCreated");
|
||||
InitSignalPair(mOnPickupCreated, m_Events, "PickupCreated");
|
||||
InitSignalPair(mOnPlayerCreated, m_Events, "PlayerCreated");
|
||||
InitSignalPair(mOnVehicleCreated, m_Events, "VehicleCreated");
|
||||
InitSignalPair(mOnBlipDestroyed, m_Events, "BlipDestroyed");
|
||||
InitSignalPair(mOnCheckpointDestroyed, m_Events, "CheckpointDestroyed");
|
||||
InitSignalPair(mOnKeybindDestroyed, m_Events, "KeybindDestroyed");
|
||||
InitSignalPair(mOnObjectDestroyed, m_Events, "ObjectDestroyed");
|
||||
InitSignalPair(mOnPickupDestroyed, m_Events, "PickupDestroyed");
|
||||
InitSignalPair(mOnPlayerDestroyed, m_Events, "PlayerDestroyed");
|
||||
InitSignalPair(mOnVehicleDestroyed, m_Events, "VehicleDestroyed");
|
||||
InitSignalPair(mOnBlipCustom, m_Events, "BlipCustom");
|
||||
InitSignalPair(mOnCheckpointCustom, m_Events, "CheckpointCustom");
|
||||
InitSignalPair(mOnKeybindCustom, m_Events, "KeybindCustom");
|
||||
InitSignalPair(mOnObjectCustom, m_Events, "ObjectCustom");
|
||||
InitSignalPair(mOnPickupCustom, m_Events, "PickupCustom");
|
||||
InitSignalPair(mOnPlayerCustom, m_Events, "PlayerCustom");
|
||||
InitSignalPair(mOnVehicleCustom, m_Events, "VehicleCustom");
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
InitSignalPair(mOnCheckpointStream, m_Events, "CheckpointStream");
|
||||
InitSignalPair(mOnObjectStream, m_Events, "ObjectStream");
|
||||
InitSignalPair(mOnPickupStream, m_Events, "PickupStream");
|
||||
InitSignalPair(mOnPlayerStream, m_Events, "PlayerStream");
|
||||
InitSignalPair(mOnVehicleStream, m_Events, "VehicleStream");
|
||||
#endif
|
||||
InitSignalPair(mOnServerStartup, m_Events, "ServerStartup");
|
||||
InitSignalPair(mOnServerShutdown, m_Events, "ServerShutdown");
|
||||
InitSignalPair(mOnServerFrame, m_Events, "ServerFrame");
|
||||
InitSignalPair(mOnIncomingConnection, m_Events, "IncomingConnection");
|
||||
InitSignalPair(mOnPlayerRequestClass, m_Events, "PlayerRequestClass");
|
||||
InitSignalPair(mOnPlayerRequestSpawn, m_Events, "PlayerRequestSpawn");
|
||||
InitSignalPair(mOnPlayerSpawn, m_Events, "PlayerSpawn");
|
||||
InitSignalPair(mOnPlayerWasted, m_Events, "PlayerWasted");
|
||||
InitSignalPair(mOnPlayerKilled, m_Events, "PlayerKilled");
|
||||
InitSignalPair(mOnPlayerEmbarking, m_Events, "PlayerEmbarking");
|
||||
InitSignalPair(mOnPlayerEmbarked, m_Events, "PlayerEmbarked");
|
||||
InitSignalPair(mOnPlayerDisembark, m_Events, "PlayerDisembark");
|
||||
InitSignalPair(mOnPlayerRename, m_Events, "PlayerRename");
|
||||
InitSignalPair(mOnPlayerState, m_Events, "PlayerState");
|
||||
InitSignalPair(mOnStateNone, m_Events, "StateNone");
|
||||
InitSignalPair(mOnStateNormal, m_Events, "StateNormal");
|
||||
InitSignalPair(mOnStateAim, m_Events, "StateAim");
|
||||
InitSignalPair(mOnStateDriver, m_Events, "StateDriver");
|
||||
InitSignalPair(mOnStatePassenger, m_Events, "StatePassenger");
|
||||
InitSignalPair(mOnStateEnterDriver, m_Events, "StateEnterDriver");
|
||||
InitSignalPair(mOnStateEnterPassenger, m_Events, "StateEnterPassenger");
|
||||
InitSignalPair(mOnStateExit, m_Events, "StateExit");
|
||||
InitSignalPair(mOnStateUnspawned, m_Events, "StateUnspawned");
|
||||
InitSignalPair(mOnPlayerAction, m_Events, "PlayerAction");
|
||||
InitSignalPair(mOnActionNone, m_Events, "ActionNone");
|
||||
InitSignalPair(mOnActionNormal, m_Events, "ActionNormal");
|
||||
InitSignalPair(mOnActionAiming, m_Events, "ActionAiming");
|
||||
InitSignalPair(mOnActionShooting, m_Events, "ActionShooting");
|
||||
InitSignalPair(mOnActionJumping, m_Events, "ActionJumping");
|
||||
InitSignalPair(mOnActionLieDown, m_Events, "ActionLieDown");
|
||||
InitSignalPair(mOnActionGettingUp, m_Events, "ActionGettingUp");
|
||||
InitSignalPair(mOnActionJumpVehicle, m_Events, "ActionJumpVehicle");
|
||||
InitSignalPair(mOnActionDriving, m_Events, "ActionDriving");
|
||||
InitSignalPair(mOnActionDying, m_Events, "ActionDying");
|
||||
InitSignalPair(mOnActionWasted, m_Events, "ActionWasted");
|
||||
InitSignalPair(mOnActionEmbarking, m_Events, "ActionEmbarking");
|
||||
InitSignalPair(mOnActionDisembarking, m_Events, "ActionDisembarking");
|
||||
InitSignalPair(mOnPlayerBurning, m_Events, "PlayerBurning");
|
||||
InitSignalPair(mOnPlayerCrouching, m_Events, "PlayerCrouching");
|
||||
InitSignalPair(mOnPlayerGameKeys, m_Events, "PlayerGameKeys");
|
||||
InitSignalPair(mOnPlayerStartTyping, m_Events, "PlayerStartTyping");
|
||||
InitSignalPair(mOnPlayerStopTyping, m_Events, "PlayerStopTyping");
|
||||
InitSignalPair(mOnPlayerAway, m_Events, "PlayerAway");
|
||||
InitSignalPair(mOnPlayerMessage, m_Events, "PlayerMessage");
|
||||
InitSignalPair(mOnPlayerCommand, m_Events, "PlayerCommand");
|
||||
InitSignalPair(mOnPlayerPrivateMessage, m_Events, "PlayerPrivateMessage");
|
||||
InitSignalPair(mOnPlayerKeyPress, m_Events, "PlayerKeyPress");
|
||||
InitSignalPair(mOnPlayerKeyRelease, m_Events, "PlayerKeyRelease");
|
||||
InitSignalPair(mOnPlayerSpectate, m_Events, "PlayerSpectate");
|
||||
InitSignalPair(mOnPlayerUnspectate, m_Events, "PlayerUnspectate");
|
||||
InitSignalPair(mOnPlayerCrashreport, m_Events, "PlayerCrashreport");
|
||||
InitSignalPair(mOnPlayerModuleList, m_Events, "PlayerModuleList");
|
||||
InitSignalPair(mOnVehicleExplode, m_Events, "VehicleExplode");
|
||||
InitSignalPair(mOnVehicleRespawn, m_Events, "VehicleRespawn");
|
||||
InitSignalPair(mOnObjectShot, m_Events, "ObjectShot");
|
||||
InitSignalPair(mOnObjectTouched, m_Events, "ObjectTouched");
|
||||
InitSignalPair(mOnObjectWorld, m_Events, "ObjectWorld");
|
||||
InitSignalPair(mOnObjectAlpha, m_Events, "ObjectAlpha");
|
||||
InitSignalPair(mOnObjectReport, m_Events, "ObjectReport");
|
||||
InitSignalPair(mOnPickupClaimed, m_Events, "PickupClaimed");
|
||||
InitSignalPair(mOnPickupCollected, m_Events, "PickupCollected");
|
||||
InitSignalPair(mOnPickupRespawn, m_Events, "PickupRespawn");
|
||||
InitSignalPair(mOnPickupWorld, m_Events, "PickupWorld");
|
||||
InitSignalPair(mOnPickupAlpha, m_Events, "PickupAlpha");
|
||||
InitSignalPair(mOnPickupAutomatic, m_Events, "PickupAutomatic");
|
||||
InitSignalPair(mOnPickupAutoTimer, m_Events, "PickupAutoTimer");
|
||||
InitSignalPair(mOnPickupOption, m_Events, "PickupOption");
|
||||
InitSignalPair(mOnCheckpointEntered, m_Events, "CheckpointEntered");
|
||||
InitSignalPair(mOnCheckpointExited, m_Events, "CheckpointExited");
|
||||
InitSignalPair(mOnCheckpointWorld, m_Events, "CheckpointWorld");
|
||||
InitSignalPair(mOnCheckpointRadius, m_Events, "CheckpointRadius");
|
||||
InitSignalPair(mOnEntityPool, m_Events, "EntityPool");
|
||||
InitSignalPair(mOnClientScriptData, m_Events, "ClientScriptData");
|
||||
InitSignalPair(mOnPlayerUpdate, m_Events, "PlayerUpdate");
|
||||
InitSignalPair(mOnVehicleUpdate, m_Events, "VehicleUpdate");
|
||||
InitSignalPair(mOnPlayerHealth, m_Events, "PlayerHealth");
|
||||
InitSignalPair(mOnPlayerArmour, m_Events, "PlayerArmour");
|
||||
InitSignalPair(mOnPlayerWeapon, m_Events, "PlayerWeapon");
|
||||
InitSignalPair(mOnPlayerHeading, m_Events, "PlayerHeading");
|
||||
InitSignalPair(mOnPlayerPosition, m_Events, "PlayerPosition");
|
||||
InitSignalPair(mOnPlayerOption, m_Events, "PlayerOption");
|
||||
InitSignalPair(mOnPlayerAdmin, m_Events, "PlayerAdmin");
|
||||
InitSignalPair(mOnPlayerWorld, m_Events, "PlayerWorld");
|
||||
InitSignalPair(mOnPlayerTeam, m_Events, "PlayerTeam");
|
||||
InitSignalPair(mOnPlayerSkin, m_Events, "PlayerSkin");
|
||||
InitSignalPair(mOnPlayerMoney, m_Events, "PlayerMoney");
|
||||
InitSignalPair(mOnPlayerScore, m_Events, "PlayerScore");
|
||||
InitSignalPair(mOnPlayerWantedLevel, m_Events, "PlayerWantedLevel");
|
||||
InitSignalPair(mOnPlayerImmunity, m_Events, "PlayerImmunity");
|
||||
InitSignalPair(mOnPlayerAlpha, m_Events, "PlayerAlpha");
|
||||
InitSignalPair(mOnPlayerEnterArea, m_Events, "PlayerEnterArea");
|
||||
InitSignalPair(mOnPlayerLeaveArea, m_Events, "PlayerLeaveArea");
|
||||
InitSignalPair(mOnVehicleColor, m_Events, "VehicleColor");
|
||||
InitSignalPair(mOnVehicleHealth, m_Events, "VehicleHealth");
|
||||
InitSignalPair(mOnVehiclePosition, m_Events, "VehiclePosition");
|
||||
InitSignalPair(mOnVehicleRotation, m_Events, "VehicleRotation");
|
||||
InitSignalPair(mOnVehicleOption, m_Events, "VehicleOption");
|
||||
InitSignalPair(mOnVehicleWorld, m_Events, "VehicleWorld");
|
||||
InitSignalPair(mOnVehicleImmunity, m_Events, "VehicleImmunity");
|
||||
InitSignalPair(mOnVehiclePartStatus, m_Events, "VehiclePartStatus");
|
||||
InitSignalPair(mOnVehicleTyreStatus, m_Events, "VehicleTyreStatus");
|
||||
InitSignalPair(mOnVehicleDamageData, m_Events, "VehicleDamageData");
|
||||
InitSignalPair(mOnVehicleRadio, m_Events, "VehicleRadio");
|
||||
InitSignalPair(mOnVehicleHandlingRule, m_Events, "VehicleHandlingRule");
|
||||
InitSignalPair(mOnVehicleEnterArea, m_Events, "VehicleEnterArea");
|
||||
InitSignalPair(mOnVehicleLeaveArea, m_Events, "VehicleLeaveArea");
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
InitSignalPair(mOnEntityStream, m_Events, "EntityStream");
|
||||
#endif
|
||||
InitSignalPair(mOnServerOption, m_Events, "ServerOption");
|
||||
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
|
||||
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::DropEvents()
|
||||
{
|
||||
ResetSignalPair(mOnCustomEvent);
|
||||
ResetSignalPair(mOnBlipCreated);
|
||||
ResetSignalPair(mOnCheckpointCreated);
|
||||
ResetSignalPair(mOnKeybindCreated);
|
||||
ResetSignalPair(mOnObjectCreated);
|
||||
ResetSignalPair(mOnPickupCreated);
|
||||
ResetSignalPair(mOnPlayerCreated);
|
||||
ResetSignalPair(mOnVehicleCreated);
|
||||
ResetSignalPair(mOnBlipDestroyed);
|
||||
ResetSignalPair(mOnCheckpointDestroyed);
|
||||
ResetSignalPair(mOnKeybindDestroyed);
|
||||
ResetSignalPair(mOnObjectDestroyed);
|
||||
ResetSignalPair(mOnPickupDestroyed);
|
||||
ResetSignalPair(mOnPlayerDestroyed);
|
||||
ResetSignalPair(mOnVehicleDestroyed);
|
||||
ResetSignalPair(mOnBlipCustom);
|
||||
ResetSignalPair(mOnCheckpointCustom);
|
||||
ResetSignalPair(mOnKeybindCustom);
|
||||
ResetSignalPair(mOnObjectCustom);
|
||||
ResetSignalPair(mOnPickupCustom);
|
||||
ResetSignalPair(mOnPlayerCustom);
|
||||
ResetSignalPair(mOnVehicleCustom);
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
ResetSignalPair(mOnCheckpointStream);
|
||||
ResetSignalPair(mOnObjectStream);
|
||||
ResetSignalPair(mOnPickupStream);
|
||||
ResetSignalPair(mOnPlayerStream);
|
||||
ResetSignalPair(mOnVehicleStream);
|
||||
#endif
|
||||
ResetSignalPair(mOnServerStartup);
|
||||
ResetSignalPair(mOnServerShutdown);
|
||||
ResetSignalPair(mOnServerFrame);
|
||||
ResetSignalPair(mOnIncomingConnection);
|
||||
ResetSignalPair(mOnPlayerRequestClass);
|
||||
ResetSignalPair(mOnPlayerRequestSpawn);
|
||||
ResetSignalPair(mOnPlayerSpawn);
|
||||
ResetSignalPair(mOnPlayerWasted);
|
||||
ResetSignalPair(mOnPlayerKilled);
|
||||
ResetSignalPair(mOnPlayerEmbarking);
|
||||
ResetSignalPair(mOnPlayerEmbarked);
|
||||
ResetSignalPair(mOnPlayerDisembark);
|
||||
ResetSignalPair(mOnPlayerRename);
|
||||
ResetSignalPair(mOnPlayerState);
|
||||
ResetSignalPair(mOnStateNone);
|
||||
ResetSignalPair(mOnStateNormal);
|
||||
ResetSignalPair(mOnStateAim);
|
||||
ResetSignalPair(mOnStateDriver);
|
||||
ResetSignalPair(mOnStatePassenger);
|
||||
ResetSignalPair(mOnStateEnterDriver);
|
||||
ResetSignalPair(mOnStateEnterPassenger);
|
||||
ResetSignalPair(mOnStateExit);
|
||||
ResetSignalPair(mOnStateUnspawned);
|
||||
ResetSignalPair(mOnPlayerAction);
|
||||
ResetSignalPair(mOnActionNone);
|
||||
ResetSignalPair(mOnActionNormal);
|
||||
ResetSignalPair(mOnActionAiming);
|
||||
ResetSignalPair(mOnActionShooting);
|
||||
ResetSignalPair(mOnActionJumping);
|
||||
ResetSignalPair(mOnActionLieDown);
|
||||
ResetSignalPair(mOnActionGettingUp);
|
||||
ResetSignalPair(mOnActionJumpVehicle);
|
||||
ResetSignalPair(mOnActionDriving);
|
||||
ResetSignalPair(mOnActionDying);
|
||||
ResetSignalPair(mOnActionWasted);
|
||||
ResetSignalPair(mOnActionEmbarking);
|
||||
ResetSignalPair(mOnActionDisembarking);
|
||||
ResetSignalPair(mOnPlayerBurning);
|
||||
ResetSignalPair(mOnPlayerCrouching);
|
||||
ResetSignalPair(mOnPlayerGameKeys);
|
||||
ResetSignalPair(mOnPlayerStartTyping);
|
||||
ResetSignalPair(mOnPlayerStopTyping);
|
||||
ResetSignalPair(mOnPlayerAway);
|
||||
ResetSignalPair(mOnPlayerMessage);
|
||||
ResetSignalPair(mOnPlayerCommand);
|
||||
ResetSignalPair(mOnPlayerPrivateMessage);
|
||||
ResetSignalPair(mOnPlayerKeyPress);
|
||||
ResetSignalPair(mOnPlayerKeyRelease);
|
||||
ResetSignalPair(mOnPlayerSpectate);
|
||||
ResetSignalPair(mOnPlayerUnspectate);
|
||||
ResetSignalPair(mOnPlayerCrashreport);
|
||||
ResetSignalPair(mOnPlayerModuleList);
|
||||
ResetSignalPair(mOnVehicleExplode);
|
||||
ResetSignalPair(mOnVehicleRespawn);
|
||||
ResetSignalPair(mOnObjectShot);
|
||||
ResetSignalPair(mOnObjectTouched);
|
||||
ResetSignalPair(mOnObjectWorld);
|
||||
ResetSignalPair(mOnObjectAlpha);
|
||||
ResetSignalPair(mOnObjectReport);
|
||||
ResetSignalPair(mOnPickupClaimed);
|
||||
ResetSignalPair(mOnPickupCollected);
|
||||
ResetSignalPair(mOnPickupRespawn);
|
||||
ResetSignalPair(mOnPickupWorld);
|
||||
ResetSignalPair(mOnPickupAlpha);
|
||||
ResetSignalPair(mOnPickupAutomatic);
|
||||
ResetSignalPair(mOnPickupAutoTimer);
|
||||
ResetSignalPair(mOnPickupOption);
|
||||
ResetSignalPair(mOnCheckpointEntered);
|
||||
ResetSignalPair(mOnCheckpointExited);
|
||||
ResetSignalPair(mOnCheckpointWorld);
|
||||
ResetSignalPair(mOnCheckpointRadius);
|
||||
ResetSignalPair(mOnEntityPool);
|
||||
ResetSignalPair(mOnClientScriptData);
|
||||
ResetSignalPair(mOnPlayerUpdate);
|
||||
ResetSignalPair(mOnVehicleUpdate);
|
||||
ResetSignalPair(mOnPlayerHealth);
|
||||
ResetSignalPair(mOnPlayerArmour);
|
||||
ResetSignalPair(mOnPlayerWeapon);
|
||||
ResetSignalPair(mOnPlayerHeading);
|
||||
ResetSignalPair(mOnPlayerPosition);
|
||||
ResetSignalPair(mOnPlayerOption);
|
||||
ResetSignalPair(mOnPlayerAdmin);
|
||||
ResetSignalPair(mOnPlayerWorld);
|
||||
ResetSignalPair(mOnPlayerTeam);
|
||||
ResetSignalPair(mOnPlayerSkin);
|
||||
ResetSignalPair(mOnPlayerMoney);
|
||||
ResetSignalPair(mOnPlayerScore);
|
||||
ResetSignalPair(mOnPlayerWantedLevel);
|
||||
ResetSignalPair(mOnPlayerImmunity);
|
||||
ResetSignalPair(mOnPlayerAlpha);
|
||||
ResetSignalPair(mOnPlayerEnterArea);
|
||||
ResetSignalPair(mOnPlayerLeaveArea);
|
||||
ResetSignalPair(mOnVehicleColor);
|
||||
ResetSignalPair(mOnVehicleHealth);
|
||||
ResetSignalPair(mOnVehiclePosition);
|
||||
ResetSignalPair(mOnVehicleRotation);
|
||||
ResetSignalPair(mOnVehicleOption);
|
||||
ResetSignalPair(mOnVehicleWorld);
|
||||
ResetSignalPair(mOnVehicleImmunity);
|
||||
ResetSignalPair(mOnVehiclePartStatus);
|
||||
ResetSignalPair(mOnVehicleTyreStatus);
|
||||
ResetSignalPair(mOnVehicleDamageData);
|
||||
ResetSignalPair(mOnVehicleRadio);
|
||||
ResetSignalPair(mOnVehicleHandlingRule);
|
||||
ResetSignalPair(mOnVehicleEnterArea);
|
||||
ResetSignalPair(mOnVehicleLeaveArea);
|
||||
#if SQMOD_SDK_LEAST(2, 1)
|
||||
ResetSignalPair(mOnEntityStream);
|
||||
#endif
|
||||
ResetSignalPair(mOnServerOption);
|
||||
ResetSignalPair(mOnScriptReload);
|
||||
ResetSignalPair(mOnScriptLoaded);
|
||||
m_Events.Release();
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
Reference in New Issue
Block a user