mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Initial implementation of the area system.
This commit is contained in:
parent
6504f196bb
commit
2fb58f9fbf
@ -450,6 +450,8 @@
|
||||
<Unit filename="../shared/Base/Buffer.hpp" />
|
||||
<Unit filename="../shared/Base/Plugin.cpp" />
|
||||
<Unit filename="../shared/Base/Utility.hpp" />
|
||||
<Unit filename="../source/Areas.cpp" />
|
||||
<Unit filename="../source/Areas.hpp" />
|
||||
<Unit filename="../source/Base/AABB.cpp" />
|
||||
<Unit filename="../source/Base/AABB.hpp" />
|
||||
<Unit filename="../source/Base/Algo.cpp" />
|
||||
|
449
source/Areas.cpp
Normal file
449
source/Areas.cpp
Normal file
@ -0,0 +1,449 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Areas.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <algorithm>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMODE_DECL_TYPENAME(AreaTypename, _SC("SqArea"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AreaManager AreaManager::s_Inst;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Area::AddArray(const Sqrat::Array &)
|
||||
{
|
||||
//todo...
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Area::Manage()
|
||||
{
|
||||
// Are we connected to any cells?
|
||||
if (!mCells.empty())
|
||||
{
|
||||
STHROWF("The area is already managed");
|
||||
}
|
||||
// Is there something to be managed?
|
||||
else if (mPoints.size() < 3)
|
||||
{
|
||||
STHROWF("Areas need at least 3 points to be 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, DefaultVM::Get());
|
||||
// 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 i = 0, n = static_cast< Uint32 >(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 (fabs(dx) < 0.000001f)
|
||||
{
|
||||
k = 0xffffffff;
|
||||
}
|
||||
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)
|
||||
: 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 (int y = 0; y < GRIDN; ++y)
|
||||
{
|
||||
for (int x = 0; x < GRIDN; ++x)
|
||||
{
|
||||
// Grab a reference to the cell
|
||||
AreaCell & c = m_Grid[y][x];
|
||||
// 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
|
||||
AreaCell::Areas::iterator 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)
|
||||
Area::Cells::iterator 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 (Queue::iterator 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 (AreaCell (&row)[GRIDN] : m_Grid)
|
||||
for (int y = 0; y < GRIDN; ++y)
|
||||
{
|
||||
//for (AreaCell & c : row)
|
||||
for (int x = 0; x < GRIDN; ++x)
|
||||
{
|
||||
AreaCell & c = m_Grid[y][x];
|
||||
// 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 Vector2i(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 Vector2i(GRIDH+xc, GRIDH-yc);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPointEx(Object & env, Function & func, float x, float y)
|
||||
{
|
||||
// Is the function valid?
|
||||
if (func.IsNull())
|
||||
{
|
||||
STHROWF("Invalid callback object");
|
||||
}
|
||||
// Should we use a custom environment?
|
||||
else if (!env.IsNull())
|
||||
{
|
||||
func = Function(env.GetVM(), env, func.GetFunc());
|
||||
}
|
||||
// Begin testing
|
||||
AreaManager::Get().TestPoint([&func](AreaCell::Areas::reference ap) -> void {
|
||||
func.Execute(ap.second);
|
||||
}, x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPoint(Object & env, Function & func, const Vector2 & v)
|
||||
{
|
||||
Areas_TestPointEx(env, func, v.x, v.y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPointOnEx(Object & ctx, Object & env, Function & func, float x, float y)
|
||||
{
|
||||
// Is the function valid?
|
||||
if (func.IsNull())
|
||||
{
|
||||
STHROWF("Invalid callback object");
|
||||
}
|
||||
// Should we use a custom environment?
|
||||
else if (!env.IsNull())
|
||||
{
|
||||
func = Function(env.GetVM(), env, func.GetFunc());
|
||||
}
|
||||
// Begin testing
|
||||
AreaManager::Get().TestPoint([&ctx, &func](AreaCell::Areas::reference ap) -> void {
|
||||
func.Execute(ctx, ap.second);
|
||||
}, x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void Areas_TestPointOn(Object & ctx, Object & env, Function & func, const Vector2 & v)
|
||||
{
|
||||
Areas_TestPointOnEx(ctx, env, func, v.x, v.y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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()
|
||||
.FmtCtor()
|
||||
.FmtCtor< SQInteger >()
|
||||
.Ctor< const Vector2 &, const Vector2 &, const Vector2 & >()
|
||||
.FmtCtor< const Vector2 &, const Vector2 &, const Vector2 & >()
|
||||
.FmtCtor< const Vector2 &, const Vector2 &, const Vector2 &, SQInteger >()
|
||||
.Ctor< float, float, float, float, float, float >()
|
||||
.FmtCtor< float, float, float, float, float, float >()
|
||||
.FmtCtor< float, float, float, float, float, float, SQInteger >()
|
||||
// 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("BoundingBox"), &Area::GetBoundingBox)
|
||||
.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("Add"), &Area::AddPoint)
|
||||
.Func(_SC("AddEx"), &Area::AddPointEx)
|
||||
.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
|
670
source/Areas.hpp
Normal file
670
source/Areas.hpp
Normal file
@ -0,0 +1,670 @@
|
||||
#ifndef _AREAS_HPP_
|
||||
#define _AREAS_HPP_
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Base/Shared.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.
|
||||
*/
|
||||
Area(const StackStrF & name)
|
||||
: Area(16, name)
|
||||
{
|
||||
//...
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Area(SQInteger sz, const StackStrF & name)
|
||||
: mL(DEF_L), mB(DEF_B), mR(DEF_R), mT(DEF_T), mPoints(), mID(0), mCells()
|
||||
, mName(name.mPtr, 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())
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Vector2 constructor with name.
|
||||
*/
|
||||
Area(const Vector2 & a, const Vector2 & b, const Vector2 & c, const 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, const 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())
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Extended constructor with name.
|
||||
*/
|
||||
Area(float ax, float ay, float bx, float by, float cx, float cy, const 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, const StackStrF & name)
|
||||
: mL(DEF_L), mB(DEF_B), mR(DEF_R), mT(DEF_T), mPoints(), mID(0), mCells()
|
||||
, mName(name.mPtr, 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;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Area()
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* 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.
|
||||
*/
|
||||
const String & ToString() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Checks if the area is locked from changes and throws an exception if it is.
|
||||
*/
|
||||
void CheckLock()
|
||||
{
|
||||
// Are we connected to any cells?
|
||||
if (!mCells.empty())
|
||||
{
|
||||
STHROWF("The area cannot be modified while being managed");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the name of this area.
|
||||
*/
|
||||
const String & GetName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify the name of this area.
|
||||
*/
|
||||
void SetName(const 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(const StackStrF & name)
|
||||
{
|
||||
SetName(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the identifier of this area.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
bool IsLocked() const
|
||||
{
|
||||
return mCells.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the center of this area.
|
||||
*/
|
||||
Vector2 GetCenter() const
|
||||
{
|
||||
return Vector2((mL * 0.5f) + (mR * 0.5f), (mB * 0.5f) + (mT * 0.5f));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the bounding box of this area.
|
||||
*/
|
||||
Vector4 GetBoundingBox() const
|
||||
{
|
||||
return Vector4(mL, mB, mR, mT);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the area has no points.
|
||||
*/
|
||||
bool Empty() const
|
||||
{
|
||||
return mPoints.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of points in this area.
|
||||
*/
|
||||
SQInteger Size() const
|
||||
{
|
||||
return ConvTo< SQInteger >::From(mPoints.size());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of points this area has allocated for.
|
||||
*/
|
||||
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 an array of points to the point list.
|
||||
*/
|
||||
void AddArray(const Sqrat::Array & a);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* 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 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 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.
|
||||
*/
|
||||
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
|
||||
{
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
static AreaManager s_Inst; // Manager instance.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
AreaManager(size_t sz = 16);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
AreaManager(const AreaManager & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
AreaManager(AreaManager && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~AreaManager()
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
AreaManager & operator = (const AreaManager & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
AreaManager & operator = (AreaManager && o) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper used to make sure a cell is properly processed after leaving the scope.
|
||||
*/
|
||||
struct CellGuard
|
||||
{
|
||||
AreaCell & mCell;
|
||||
/* ----------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
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)
|
||||
: mCell(o.mCell), mArea(o.mArea), mObj(std::move(o.mObj))
|
||||
{
|
||||
// Take ownership
|
||||
o.mCell = nullptr;
|
||||
o.mArea = nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~QueueElement()
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
QueueElement & operator = (const QueueElement & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
QueueElement & operator = (QueueElement && o)
|
||||
{
|
||||
// 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:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the core instance.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
|
||||
#endif // _AREAS_HPP_
|
@ -37,6 +37,7 @@ extern bool RegisterAPI(HSQUIRRELVM vm);
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void InitializeTasks();
|
||||
extern void InitializeRoutines();
|
||||
extern void TerminateAreas();
|
||||
extern void TerminateTasks();
|
||||
extern void TerminateRoutines();
|
||||
extern void TerminateCommands();
|
||||
@ -146,6 +147,7 @@ Core::Core()
|
||||
, m_ReloadPayload()
|
||||
, m_IncomingNameBuffer(nullptr)
|
||||
, m_IncomingNameCapacity(0)
|
||||
, m_AreasEnabled(false)
|
||||
, m_Debugging(false)
|
||||
, m_Executed(false)
|
||||
, m_Shutdown(false)
|
||||
@ -480,6 +482,8 @@ void Core::Terminate(bool shutdown)
|
||||
TerminateCommands();
|
||||
// Release all resources from signals
|
||||
TerminateSignals();
|
||||
// Release all managed areas
|
||||
TerminateAreas();
|
||||
// In case there's a payload for reload
|
||||
m_ReloadPayload.Release();
|
||||
// Release null objects in case any reference to valid objects is stored in them
|
||||
|
@ -66,6 +66,9 @@ private:
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::vector< std::pair< Area *, LightObj > > AreaList; // List of colided areas.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Helper structure used to identify a blip entity instance on the server.
|
||||
*/
|
||||
@ -449,6 +452,9 @@ protected:
|
||||
CPlayer * mInst; // 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.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SQInteger mTrackPosition; // The number of times to track position changes.
|
||||
SQInteger mTrackHeading; // The number of times to track heading changes.
|
||||
@ -548,6 +554,8 @@ protected:
|
||||
SignalPair mOnWantedLevel;
|
||||
SignalPair mOnImmunity;
|
||||
SignalPair mOnAlpha;
|
||||
SignalPair mOnEnterArea;
|
||||
SignalPair mOnLeaveArea;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -600,6 +608,9 @@ protected:
|
||||
CVehicle * mInst; // 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.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
SQInteger mTrackPosition; // The number of times to track position changes.
|
||||
SQInteger mTrackRotation; // The number of times to track rotation changes.
|
||||
@ -637,6 +648,8 @@ protected:
|
||||
SignalPair mOnDamageData;
|
||||
SignalPair mOnRadio;
|
||||
SignalPair mOnHandlingRule;
|
||||
SignalPair mOnEnterArea;
|
||||
SignalPair mOnLeaveArea;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -688,6 +701,7 @@ private:
|
||||
size_t m_IncomingNameCapacity; // Incoming connection name size.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
bool m_AreasEnabled; // Whether area tracking is enabled.
|
||||
bool m_Debugging; // Enable debugging features, if any.
|
||||
bool m_Executed; // Whether the scripts were executed.
|
||||
bool m_Shutdown; // Whether the server currently shutting down.
|
||||
@ -695,7 +709,6 @@ private:
|
||||
bool m_LockPostLoadSignal; // Lock post load signal container.
|
||||
bool m_LockUnloadSignal; // Lock unload signal container.
|
||||
bool m_EmptyInit; // Whether to initialize without any scripts.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Int32 m_Verbosity; // Restrict the amount of outputted information.
|
||||
|
||||
@ -778,6 +791,22 @@ public:
|
||||
return m_Shutdown;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether area tracking should be enabled on newlly created entities.
|
||||
*/
|
||||
bool AreasEnabled() const
|
||||
{
|
||||
return m_AreasEnabled;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Toggle whether area tracking should be enabled on newlly created entities.
|
||||
*/
|
||||
void AreasEnabled(bool toggle)
|
||||
{
|
||||
m_AreasEnabled = toggle;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the value of the specified option.
|
||||
*/
|
||||
@ -1168,6 +1197,8 @@ public:
|
||||
void EmitPlayerWantedLevel(Int32 player_id, Int32 old_level, Int32 new_level);
|
||||
void EmitPlayerImmunity(Int32 player_id, Int32 old_immunity, Int32 new_immunity);
|
||||
void EmitPlayerAlpha(Int32 player_id, Int32 old_alpha, Int32 new_alpha, Int32 fade);
|
||||
void EmitPlayerEnterArea(Int32 player_id, LightObj & area_obj);
|
||||
void EmitPlayerLeaveArea(Int32 player_id, LightObj & area_obj);
|
||||
void EmitVehicleColor(Int32 vehicle_id, Int32 changed);
|
||||
void EmitVehicleHealth(Int32 vehicle_id, Float32 old_health, Float32 new_health);
|
||||
void EmitVehiclePosition(Int32 vehicle_id);
|
||||
@ -1180,6 +1211,8 @@ public:
|
||||
void EmitVehicleDamageData(Int32 vehicle_id, Uint32 old_data, Uint32 new_data);
|
||||
void EmitVehicleRadio(Int32 vehicle_id, Int32 old_radio, Int32 new_radio);
|
||||
void EmitVehicleHandlingRule(Int32 vehicle_id, Int32 rule, Float32 old_data, Float32 new_data);
|
||||
void EmitVehicleEnterArea(Int32 player_id, LightObj & area_obj);
|
||||
void EmitVehicleLeaveArea(Int32 player_id, LightObj & area_obj);
|
||||
void EmitServerOption(Int32 option, bool value, Int32 header, LightObj & payload);
|
||||
void EmitScriptReload(Int32 header, LightObj & payload);
|
||||
void EmitScriptLoaded();
|
||||
@ -1321,6 +1354,8 @@ public:
|
||||
SignalPair mOnPlayerWantedLevel;
|
||||
SignalPair mOnPlayerImmunity;
|
||||
SignalPair mOnPlayerAlpha;
|
||||
SignalPair mOnPlayerEnterArea;
|
||||
SignalPair mOnPlayerLeaveArea;
|
||||
SignalPair mOnVehicleColor;
|
||||
SignalPair mOnVehicleHealth;
|
||||
SignalPair mOnVehiclePosition;
|
||||
@ -1333,6 +1368,8 @@ public:
|
||||
SignalPair mOnVehicleDamageData;
|
||||
SignalPair mOnVehicleRadio;
|
||||
SignalPair mOnVehicleHandlingRule;
|
||||
SignalPair mOnVehicleEnterArea;
|
||||
SignalPair mOnVehicleLeaveArea;
|
||||
SignalPair mOnServerOption;
|
||||
SignalPair mOnScriptReload;
|
||||
SignalPair mOnScriptLoaded;
|
||||
|
@ -420,6 +420,11 @@ Core::VehicleInst & Core::AllocVehicle(Int32 id, bool owned, Int32 header, Light
|
||||
{
|
||||
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
|
||||
@ -795,6 +800,11 @@ void Core::ConnectPlayer(Int32 id, Int32 header, LightObj & payload)
|
||||
}
|
||||
// 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
|
||||
|
@ -1,5 +1,6 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core.hpp"
|
||||
#include "Areas.hpp"
|
||||
#include "Signal.hpp"
|
||||
#include "Base/Buffer.hpp"
|
||||
#include "Library/Utils/Buffer.hpp"
|
||||
@ -879,6 +880,22 @@ void Core::EmitPlayerAlpha(Int32 player_id, Int32 old_alpha, Int32 new_alpha, In
|
||||
(*mOnPlayerAlpha.first)(_player.mObj, old_alpha, new_alpha, fade);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitPlayerEnterArea(Int32 player_id, LightObj & area_obj)
|
||||
{
|
||||
PlayerInst & _player = m_Players.at(player_id);
|
||||
(*_player.mOnEnterArea.first)(area_obj);
|
||||
(*mOnPlayerEnterArea.first)(_player.mObj, area_obj);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitPlayerLeaveArea(Int32 player_id, LightObj & area_obj)
|
||||
{
|
||||
PlayerInst & _player = m_Players.at(player_id);
|
||||
(*_player.mOnLeaveArea.first)(area_obj);
|
||||
(*mOnPlayerLeaveArea.first)(_player.mObj, area_obj);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitVehicleColor(Int32 vehicle_id, Int32 changed)
|
||||
{
|
||||
@ -972,8 +989,24 @@ void Core::EmitVehicleRadio(Int32 vehicle_id, Int32 old_radio, Int32 new_radio)
|
||||
void Core::EmitVehicleHandlingRule(Int32 vehicle_id, Int32 rule, Float32 old_data, Float32 new_data)
|
||||
{
|
||||
VehicleInst & _vehicle = m_Vehicles.at(vehicle_id);
|
||||
(*mOnVehicleHandlingRule.first)(_vehicle.mObj, rule, old_data, new_data);
|
||||
(*_vehicle.mOnHandlingRule.first)(rule, old_data, new_data);
|
||||
(*mOnVehicleHandlingRule.first)(_vehicle.mObj, rule, old_data, new_data);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitVehicleEnterArea(Int32 vehicle_id, LightObj & area_obj)
|
||||
{
|
||||
VehicleInst & _vehicle = m_Vehicles.at(vehicle_id);
|
||||
(*_vehicle.mOnEnterArea.first)(area_obj);
|
||||
(*mOnVehicleEnterArea.first)(_vehicle.mObj, area_obj);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitVehicleLeaveArea(Int32 vehicle_id, LightObj & area_obj)
|
||||
{
|
||||
VehicleInst & _vehicle = m_Vehicles.at(vehicle_id);
|
||||
(*_vehicle.mOnLeaveArea.first)(area_obj);
|
||||
(*mOnVehicleLeaveArea.first)(_vehicle.mObj, area_obj);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -1150,6 +1183,39 @@ void Core::EmitPlayerUpdate(Int32 player_id, vcmpPlayerUpdate update_type)
|
||||
// Now emit the event
|
||||
EmitPlayerPosition(player_id);
|
||||
}
|
||||
// Should we check for area collision
|
||||
if (inst.mFlags & ENF_AREA_TRACK)
|
||||
{
|
||||
// Eliminate existing areas first, if the player is not in them anymore
|
||||
inst.mAreas.erase(std::remove_if(inst.mAreas.begin(), inst.mAreas.end(),
|
||||
[this, pos, player_id](AreaList::reference ap) -> bool {
|
||||
// Is this player still in this area?
|
||||
if (!ap.first->TestEx(pos.x, pos.y))
|
||||
{
|
||||
// Emit the script event
|
||||
this->EmitPlayerLeaveArea(player_id, ap.second);
|
||||
// Remove this area
|
||||
return true;
|
||||
}
|
||||
// Still in this area
|
||||
return false;
|
||||
}), inst.mAreas.end());
|
||||
// See if the player entered any new areas
|
||||
AreaManager::Get().TestPoint([this, &inst, player_id](AreaList::reference ap) -> void {
|
||||
// Was the player in this area before?
|
||||
if (std::find_if(inst.mAreas.begin(), inst.mAreas.end(),
|
||||
[a = ap.first](AreaList::reference ap) -> bool {
|
||||
return (a == ap.first);
|
||||
}) == inst.mAreas.end())
|
||||
{
|
||||
// The player just entered this area so emit the event
|
||||
this->EmitPlayerEnterArea(player_id, ap.second);
|
||||
// Now store this area so we know when the player leaves
|
||||
inst.mAreas.emplace_back(ap);
|
||||
}
|
||||
// The player was in this area before so ignore it
|
||||
}, pos.x, pos.y);
|
||||
}
|
||||
// Update the tracked value
|
||||
inst.mLastPosition = pos;
|
||||
}
|
||||
@ -1218,9 +1284,45 @@ void Core::EmitVehicleUpdate(Int32 vehicle_id, vcmpVehicleUpdate update_type)
|
||||
// Now emit the event
|
||||
EmitVehiclePosition(vehicle_id);
|
||||
}
|
||||
// New vehicle position
|
||||
Vector3 pos;
|
||||
// Retrieve the current vehicle position
|
||||
_Func->GetVehiclePosition(vehicle_id, &pos.x, &pos.y, &pos.z);
|
||||
// Should we check for area collision
|
||||
if (inst.mFlags & ENF_AREA_TRACK)
|
||||
{
|
||||
// Eliminate existing areas first, if the vehicle is not in them anymore
|
||||
inst.mAreas.erase(std::remove_if(inst.mAreas.begin(), inst.mAreas.end(),
|
||||
[this, pos, vehicle_id](AreaList::reference ap) -> bool {
|
||||
// Is this vehicle still in this area?
|
||||
if (!ap.first->TestEx(pos.x, pos.y))
|
||||
{
|
||||
// Emit the script event
|
||||
this->EmitVehicleLeaveArea(vehicle_id, ap.second);
|
||||
// Remove this area
|
||||
return true;
|
||||
}
|
||||
// Still in this area
|
||||
return false;
|
||||
}), inst.mAreas.end());
|
||||
// See if the vehicle entered any new areas
|
||||
AreaManager::Get().TestPoint([this, &inst, vehicle_id](AreaList::reference ap) -> void {
|
||||
// Was the vehicle in this area before?
|
||||
if (std::find_if(inst.mAreas.begin(), inst.mAreas.end(),
|
||||
[a = ap.first](AreaList::reference ap) -> bool {
|
||||
return (a == ap.first);
|
||||
}) == inst.mAreas.end())
|
||||
{
|
||||
// The vehicle just entered this area so emit the event
|
||||
this->EmitVehicleEnterArea(vehicle_id, ap.second);
|
||||
// Now store this area so we know when the vehicle leaves
|
||||
inst.mAreas.emplace_back(ap);
|
||||
}
|
||||
// The vehicle was in this area before so ignore it
|
||||
}, pos.x, pos.y);
|
||||
}
|
||||
// Update the tracked value
|
||||
_Func->GetVehiclePosition(vehicle_id, &inst.mLastPosition.x,
|
||||
&inst.mLastPosition.y, &inst.mLastPosition.z);
|
||||
inst.mLastPosition = pos;
|
||||
} break;
|
||||
case vcmpVehicleUpdateHealth:
|
||||
{
|
||||
|
@ -119,6 +119,18 @@ static void SetState(Int32 value)
|
||||
return Core::Get().SetState(value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool GetAreasEnabled()
|
||||
{
|
||||
return Core::Get().AreasEnabled();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SetAreasEnabled(bool toggle)
|
||||
{
|
||||
Core::Get().AreasEnabled(toggle);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static CSStr GetOption(CSStr name)
|
||||
{
|
||||
@ -306,6 +318,8 @@ void Register_Core(HSQUIRRELVM vm)
|
||||
.Func(_SC("GetReloadPayload"), &SqGetReloadPayload)
|
||||
.Func(_SC("GetState"), &GetState)
|
||||
.Func(_SC("SetState"), &SetState)
|
||||
.Func(_SC("AreasEnabled"), &GetAreasEnabled)
|
||||
.Func(_SC("SetAreasEnabled"), &SetAreasEnabled)
|
||||
.Func(_SC("GetOption"), &GetOption)
|
||||
.Func(_SC("GetOptionOr"), &GetOptionOr)
|
||||
.Func(_SC("SetOption"), &SetOption)
|
||||
|
@ -357,6 +357,7 @@ void Core::PlayerInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
mAreas.clear();
|
||||
mTrackPosition = 0;
|
||||
mTrackHeading = 0;
|
||||
mTrackPositionHeader = 0;
|
||||
@ -376,6 +377,7 @@ void Core::VehicleInst::ResetInstance()
|
||||
{
|
||||
mID = -1;
|
||||
mFlags = ENF_DEFAULT;
|
||||
mAreas.clear();
|
||||
mTrackPosition = 0;
|
||||
mTrackRotation = 0;
|
||||
mLastPrimaryColor = -1;
|
||||
@ -642,6 +644,8 @@ void Core::PlayerInst::InitEvents()
|
||||
InitSignalPair(mOnWantedLevel, mEvents, "WantedLevel");
|
||||
InitSignalPair(mOnImmunity, mEvents, "Immunity");
|
||||
InitSignalPair(mOnAlpha, mEvents, "Alpha");
|
||||
InitSignalPair(mOnEnterArea, mEvents, "EnterArea");
|
||||
InitSignalPair(mOnLeaveArea, mEvents, "LeaveArea");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -718,6 +722,8 @@ void Core::PlayerInst::DropEvents()
|
||||
ResetSignalPair(mOnWantedLevel);
|
||||
ResetSignalPair(mOnImmunity);
|
||||
ResetSignalPair(mOnAlpha);
|
||||
ResetSignalPair(mOnEnterArea);
|
||||
ResetSignalPair(mOnLeaveArea);
|
||||
mEvents.Release();
|
||||
}
|
||||
|
||||
@ -756,6 +762,8 @@ void Core::VehicleInst::InitEvents()
|
||||
InitSignalPair(mOnDamageData, mEvents, "DamageData");
|
||||
InitSignalPair(mOnRadio, mEvents, "Radio");
|
||||
InitSignalPair(mOnHandlingRule, mEvents, "HandlingRule");
|
||||
InitSignalPair(mOnEnterArea, mEvents, "EnterArea");
|
||||
InitSignalPair(mOnLeaveArea, mEvents, "LeaveArea");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -781,6 +789,8 @@ void Core::VehicleInst::DropEvents()
|
||||
ResetSignalPair(mOnDamageData);
|
||||
ResetSignalPair(mOnRadio);
|
||||
ResetSignalPair(mOnHandlingRule);
|
||||
ResetSignalPair(mOnEnterArea);
|
||||
ResetSignalPair(mOnLeaveArea);
|
||||
mEvents.Release();
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,8 @@ void Core::InitEvents()
|
||||
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");
|
||||
@ -177,6 +179,8 @@ void Core::InitEvents()
|
||||
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");
|
||||
InitSignalPair(mOnServerOption, m_Events, "ServerOption");
|
||||
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
|
||||
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
|
||||
@ -293,6 +297,8 @@ void Core::DropEvents()
|
||||
ResetSignalPair(mOnPlayerWantedLevel);
|
||||
ResetSignalPair(mOnPlayerImmunity);
|
||||
ResetSignalPair(mOnPlayerAlpha);
|
||||
ResetSignalPair(mOnPlayerEnterArea);
|
||||
ResetSignalPair(mOnPlayerLeaveArea);
|
||||
ResetSignalPair(mOnVehicleColor);
|
||||
ResetSignalPair(mOnVehicleHealth);
|
||||
ResetSignalPair(mOnVehiclePosition);
|
||||
@ -305,6 +311,8 @@ void Core::DropEvents()
|
||||
ResetSignalPair(mOnVehicleDamageData);
|
||||
ResetSignalPair(mOnVehicleRadio);
|
||||
ResetSignalPair(mOnVehicleHandlingRule);
|
||||
ResetSignalPair(mOnVehicleEnterArea);
|
||||
ResetSignalPair(mOnVehicleLeaveArea);
|
||||
ResetSignalPair(mOnServerOption);
|
||||
ResetSignalPair(mOnScriptReload);
|
||||
ResetSignalPair(mOnScriptLoaded);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Base/Vector3.hpp"
|
||||
#include "Library/Utils/Buffer.hpp"
|
||||
#include "Core.hpp"
|
||||
#include "Areas.hpp"
|
||||
#include "Tasks.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -1431,6 +1432,83 @@ LightObj & CPlayer::CreateCheckpoint(Int32 world, bool sphere, const Vector3 & p
|
||||
color.r, color.g, color.b, color.a, radius, header, payload);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool CPlayer::GetCollideAreas() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return (Core::Get().GetPlayer(m_ID).mFlags & ENF_AREA_TRACK);
|
||||
}
|
||||
|
||||
void CPlayer::SetCollideAreas(bool toggle) const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Perform the requested operation
|
||||
if (toggle)
|
||||
{
|
||||
Core::Get().GetPlayer(m_ID).mFlags |= ENF_AREA_TRACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Obtain the actual entity instance
|
||||
auto & inst = Core::Get().GetPlayer(m_ID);
|
||||
// Is this option even enabled?
|
||||
if (!(inst.mFlags & ENF_AREA_TRACK))
|
||||
{
|
||||
return; // Not enabled to begin with
|
||||
}
|
||||
// Disable the option
|
||||
inst.mFlags ^= ENF_AREA_TRACK;
|
||||
// Clear current areas
|
||||
inst.mAreas.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayer::SetAreasCollide(bool toggle) const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Perform the requested operation
|
||||
if (toggle)
|
||||
{
|
||||
Core::Get().GetPlayer(m_ID).mFlags |= ENF_AREA_TRACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Obtain the actual entity instance
|
||||
auto & inst = Core::Get().GetPlayer(m_ID);
|
||||
// Is this option even enabled?
|
||||
if (!(inst.mFlags & ENF_AREA_TRACK))
|
||||
{
|
||||
return; // Not enabled to begin with
|
||||
}
|
||||
// Disable the option
|
||||
inst.mFlags ^= ENF_AREA_TRACK;
|
||||
// Is the player currently in any areas?
|
||||
if (inst.mAreas.empty())
|
||||
{
|
||||
return; // Nothing to test
|
||||
}
|
||||
|
||||
Vector3 pos;
|
||||
// Obtain the current position of this instance
|
||||
_Func->GetPlayerPosition(m_ID, &pos.x, &pos.y, &pos.z);
|
||||
// Do a final check to see if the player left any area
|
||||
for (auto & ap : inst.mAreas)
|
||||
{
|
||||
// Is the player still in this area?
|
||||
if (!ap.first->TestEx(pos.x, pos.y))
|
||||
{
|
||||
Core::Get().EmitPlayerLeaveArea(m_ID, ap.second); // Emit the script event
|
||||
}
|
||||
}
|
||||
// Clear current areas
|
||||
inst.mAreas.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Int32 CPlayer::GetAuthority() const
|
||||
{
|
||||
@ -2423,6 +2501,7 @@ void Register_CPlayer(HSQUIRRELVM vm)
|
||||
.Prop(_SC("TouchedObject"), &CPlayer::StandingOnObject)
|
||||
.Prop(_SC("Away"), &CPlayer::IsAway)
|
||||
.Prop(_SC("Spec"), &CPlayer::GetSpectator, &CPlayer::SetSpectator)
|
||||
.Prop(_SC("CollideAreas"), &CPlayer::GetCollideAreas, &CPlayer::SetCollideAreas)
|
||||
.Prop(_SC("Authority"), &CPlayer::GetAuthority, &CPlayer::SetAuthority)
|
||||
.Prop(_SC("TrackPosition"), &CPlayer::GetTrackPosition, &CPlayer::SetTrackPosition)
|
||||
.Prop(_SC("TrackHeading"), &CPlayer::GetTrackHeading, &CPlayer::SetTrackHeading)
|
||||
@ -2472,6 +2551,7 @@ void Register_CPlayer(HSQUIRRELVM vm)
|
||||
.Func(_SC("Spectate"), &CPlayer::SetSpectator)
|
||||
.Func(_SC("Redirect"), &CPlayer::Redirect)
|
||||
.Func(_SC("PlaySound"), &CPlayer::PlaySound)
|
||||
.Func(_SC("AreasCollide"), &CPlayer::SetAreasCollide)
|
||||
.Func(_SC("GetMsgPrefix"), &CPlayer::GetMessagePrefix)
|
||||
.FmtFunc(_SC("SetMsgPrefix"), &CPlayer::SetMessagePrefix)
|
||||
.Func(_SC("SetTrackPosition"), &CPlayer::SetTrackPositionEx)
|
||||
|
@ -765,6 +765,21 @@ public:
|
||||
LightObj & CreateCheckpoint(Int32 world, bool sphere, const Vector3 & pos, const Color4 & color,
|
||||
Float32 radius, Int32 header, LightObj & payload) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the managed player entity collides with user defined areas.
|
||||
*/
|
||||
bool GetCollideAreas() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the managed player entity can collide with user defined areas.
|
||||
*/
|
||||
void SetCollideAreas(bool toggle) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the managed player entity can collide with user defined areas (with last test).
|
||||
*/
|
||||
void SetAreasCollide(bool toggle) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the authority level of the managed player entity.
|
||||
*/
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Base/Vector2.hpp"
|
||||
#include "Base/Vector3.hpp"
|
||||
#include "Core.hpp"
|
||||
#include "Areas.hpp"
|
||||
#include "Tasks.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -1119,6 +1120,83 @@ bool CVehicle::Embark(CPlayer & player, Int32 slot, bool allocate, bool warp) co
|
||||
!= vcmpErrorRequestDenied);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool CVehicle::GetCollideAreas() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return (Core::Get().GetVehicle(m_ID).mFlags & ENF_AREA_TRACK);
|
||||
}
|
||||
|
||||
void CVehicle::SetCollideAreas(bool toggle) const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Perform the requested operation
|
||||
if (toggle)
|
||||
{
|
||||
Core::Get().GetVehicle(m_ID).mFlags |= ENF_AREA_TRACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Obtain the actual entity instance
|
||||
auto & inst = Core::Get().GetVehicle(m_ID);
|
||||
// Is this option even enabled?
|
||||
if (!(inst.mFlags & ENF_AREA_TRACK))
|
||||
{
|
||||
return; // Not enabled to begin with
|
||||
}
|
||||
// Disable the option
|
||||
inst.mFlags ^= ENF_AREA_TRACK;
|
||||
// Clear current areas
|
||||
inst.mAreas.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CVehicle::SetAreasCollide(bool toggle) const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Perform the requested operation
|
||||
if (toggle)
|
||||
{
|
||||
Core::Get().GetVehicle(m_ID).mFlags |= ENF_AREA_TRACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Obtain the actual entity instance
|
||||
auto & inst = Core::Get().GetVehicle(m_ID);
|
||||
// Is this option even enabled?
|
||||
if (!(inst.mFlags & ENF_AREA_TRACK))
|
||||
{
|
||||
return; // Not enabled to begin with
|
||||
}
|
||||
// Disable the option
|
||||
inst.mFlags ^= ENF_AREA_TRACK;
|
||||
// Is the vehicle currently in any areas?
|
||||
if (inst.mAreas.empty())
|
||||
{
|
||||
return; // Nothing to test
|
||||
}
|
||||
|
||||
Vector3 pos;
|
||||
// Obtain the current position of this instance
|
||||
_Func->GetVehiclePosition(m_ID, &pos.x, &pos.y, &pos.z);
|
||||
// Do a final check to see if the vehicle left any area
|
||||
for (auto & ap : inst.mAreas)
|
||||
{
|
||||
// Is the vehicle still in this area?
|
||||
if (!ap.first->TestEx(pos.x, pos.y))
|
||||
{
|
||||
Core::Get().EmitVehicleLeaveArea(m_ID, ap.second); // Emit the script event
|
||||
}
|
||||
}
|
||||
// Clear current areas
|
||||
inst.mAreas.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger CVehicle::GetTrackPosition() const
|
||||
{
|
||||
@ -1820,6 +1898,7 @@ void Register_CVehicle(HSQUIRRELVM vm)
|
||||
.Prop(_SC("HorizontalTurretRotation"), &CVehicle::GetHorizontalTurretRotation)
|
||||
.Prop(_SC("VerTurretRotation"), &CVehicle::GetVerticalTurretRotation)
|
||||
.Prop(_SC("VerticalTurretRotation"), &CVehicle::GetVerticalTurretRotation)
|
||||
.Prop(_SC("CollideAreas"), &CVehicle::GetCollideAreas, &CVehicle::SetCollideAreas)
|
||||
.Prop(_SC("TrackPosition"), &CVehicle::GetTrackPosition, &CVehicle::SetTrackPosition)
|
||||
.Prop(_SC("TrackRotation"), &CVehicle::GetTrackRotation, &CVehicle::SetTrackRotation)
|
||||
.Prop(_SC("LastPrimaryColor"), &CVehicle::GetLastPrimaryColor)
|
||||
@ -1885,6 +1964,7 @@ void Register_CVehicle(HSQUIRRELVM vm)
|
||||
.Func(_SC("SetHandlingRule"), &CVehicle::SetHandlingRule)
|
||||
.Func(_SC("ResetHandlingRule"), &CVehicle::ResetHandlingRule)
|
||||
.Func(_SC("ResetHandlings"), &CVehicle::ResetHandlings)
|
||||
.Func(_SC("AreasCollide"), &CVehicle::SetAreasCollide)
|
||||
// Member Overloads
|
||||
.Overload< void (CVehicle::*)(const Vector3 &, bool) const >
|
||||
(_SC("SetPos"), &CVehicle::SetPositionEx)
|
||||
|
@ -612,6 +612,21 @@ public:
|
||||
*/
|
||||
bool Embark(CPlayer & player, Int32 slot, bool allocate, bool warp) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See whether the managed vehicle entity collides with user defined areas.
|
||||
*/
|
||||
bool GetCollideAreas() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the managed vehicle entity can collide with user defined areas.
|
||||
*/
|
||||
void SetCollideAreas(bool toggle) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set whether the managed vehicle entity can collide with user defined areas (with last test).
|
||||
*/
|
||||
void SetAreasCollide(bool toggle) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the amount of tracked position changes for the managed vehicle entity.
|
||||
*/
|
||||
|
@ -53,6 +53,7 @@ extern void RegisterTask(HSQUIRRELVM vm);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void Register_Misc(HSQUIRRELVM vm);
|
||||
extern void Register_Areas(HSQUIRRELVM vm);
|
||||
extern void Register_Signal(HSQUIRRELVM vm);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@ -95,6 +96,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
||||
RegisterTask(vm);
|
||||
|
||||
Register_Misc(vm);
|
||||
Register_Areas(vm);
|
||||
Register_Signal(vm);
|
||||
|
||||
return true;
|
||||
|
@ -243,6 +243,11 @@ class Core;
|
||||
class Logger;
|
||||
class Signal;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class AreaManager;
|
||||
struct AreaCell;
|
||||
struct Area;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class CmdManager;
|
||||
class CmdListener;
|
||||
|
Loading…
Reference in New Issue
Block a user