@@ -0,0 +1,393 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#include <math.h>
#include "DetourCommon.h"

//////////////////////////////////////////////////////////////////////////////////////////

float dtSqrt(float x)
{
return sqrtf(x);
}

void dtClosestPtPointTriangle(float* closest, const float* p,
const float* a, const float* b, const float* c)
{
// Check if P in vertex region outside A
float ab[3], ac[3], ap[3];
dtVsub(ab, b, a);
dtVsub(ac, c, a);
dtVsub(ap, p, a);
float d1 = dtVdot(ab, ap);
float d2 = dtVdot(ac, ap);
if (d1 <= 0.0f && d2 <= 0.0f)
{
// barycentric coordinates (1,0,0)
dtVcopy(closest, a);
return;
}

// Check if P in vertex region outside B
float bp[3];
dtVsub(bp, p, b);
float d3 = dtVdot(ab, bp);
float d4 = dtVdot(ac, bp);
if (d3 >= 0.0f && d4 <= d3)
{
// barycentric coordinates (0,1,0)
dtVcopy(closest, b);
return;
}

// Check if P in edge region of AB, if so return projection of P onto AB
float vc = d1*d4 - d3*d2;
if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f)
{
// barycentric coordinates (1-v,v,0)
float v = d1 / (d1 - d3);
closest[0] = a[0] + v * ab[0];
closest[1] = a[1] + v * ab[1];
closest[2] = a[2] + v * ab[2];
return;
}

// Check if P in vertex region outside C
float cp[3];
dtVsub(cp, p, c);
float d5 = dtVdot(ab, cp);
float d6 = dtVdot(ac, cp);
if (d6 >= 0.0f && d5 <= d6)
{
// barycentric coordinates (0,0,1)
dtVcopy(closest, c);
return;
}

// Check if P in edge region of AC, if so return projection of P onto AC
float vb = d5*d2 - d1*d6;
if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f)
{
// barycentric coordinates (1-w,0,w)
float w = d2 / (d2 - d6);
closest[0] = a[0] + w * ac[0];
closest[1] = a[1] + w * ac[1];
closest[2] = a[2] + w * ac[2];
return;
}

// Check if P in edge region of BC, if so return projection of P onto BC
float va = d3*d6 - d5*d4;
if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f)
{
// barycentric coordinates (0,1-w,w)
float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
closest[0] = b[0] + w * (c[0] - b[0]);
closest[1] = b[1] + w * (c[1] - b[1]);
closest[2] = b[2] + w * (c[2] - b[2]);
return;
}

// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
float denom = 1.0f / (va + vb + vc);
float v = vb * denom;
float w = vc * denom;
closest[0] = a[0] + ab[0] * v + ac[0] * w;
closest[1] = a[1] + ab[1] * v + ac[1] * w;
closest[2] = a[2] + ab[2] * v + ac[2] * w;
}

bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
const float* verts, int nverts,
float& tmin, float& tmax,
int& segMin, int& segMax)
{
static const float EPS = 0.00000001f;

tmin = 0;
tmax = 1;
segMin = -1;
segMax = -1;

float dir[3];
dtVsub(dir, p1, p0);

for (int i = 0, j = nverts-1; i < nverts; j=i++)
{
float edge[3], diff[3];
dtVsub(edge, &verts[i*3], &verts[j*3]);
dtVsub(diff, p0, &verts[j*3]);
const float n = dtVperp2D(edge, diff);
const float d = dtVperp2D(dir, edge);
if (fabsf(d) < EPS)
{
// S is nearly parallel to this edge
if (n < 0)
return false;
else
continue;
}
const float t = n / d;
if (d < 0)
{
// segment S is entering across this edge
if (t > tmin)
{
tmin = t;
segMin = j;
// S enters after leaving polygon
if (tmin > tmax)
return false;
}
}
else
{
// segment S is leaving across this edge
if (t < tmax)
{
tmax = t;
segMax = j;
// S leaves before entering polygon
if (tmax < tmin)
return false;
}
}
}

return true;
}

float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t)
{
float pqx = q[0] - p[0];
float pqz = q[2] - p[2];
float dx = pt[0] - p[0];
float dz = pt[2] - p[2];
float d = pqx*pqx + pqz*pqz;
t = pqx*dx + pqz*dz;
if (d > 0) t /= d;
if (t < 0) t = 0;
else if (t > 1) t = 1;
dx = p[0] + t*pqx - pt[0];
dz = p[2] + t*pqz - pt[2];
return dx*dx + dz*dz;
}

void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts)
{
tc[0] = 0.0f;
tc[1] = 0.0f;
tc[2] = 0.0f;
for (int j = 0; j < nidx; ++j)
{
const float* v = &verts[idx[j]*3];
tc[0] += v[0];
tc[1] += v[1];
tc[2] += v[2];
}
const float s = 1.0f / nidx;
tc[0] *= s;
tc[1] *= s;
tc[2] *= s;
}

bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h)
{
float v0[3], v1[3], v2[3];
dtVsub(v0, c,a);
dtVsub(v1, b,a);
dtVsub(v2, p,a);

const float dot00 = dtVdot2D(v0, v0);
const float dot01 = dtVdot2D(v0, v1);
const float dot02 = dtVdot2D(v0, v2);
const float dot11 = dtVdot2D(v1, v1);
const float dot12 = dtVdot2D(v1, v2);

// Compute barycentric coordinates
const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
const float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
const float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

// The (sloppy) epsilon is needed to allow to get height of points which
// are interpolated along the edges of the triangles.
static const float EPS = 1e-4f;

// If point lies inside the triangle, return interpolated ycoord.
if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS)
{
h = a[1] + v0[1]*u + v1[1]*v;
return true;
}

return false;
}

/// @par
///
/// All points are projected onto the xz-plane, so the y-values are ignored.
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
{
// TODO: Replace pnpoly with triArea2D tests?
int i, j;
bool c = false;
for (i = 0, j = nverts-1; i < nverts; j = i++)
{
const float* vi = &verts[i*3];
const float* vj = &verts[j*3];
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
c = !c;
}
return c;
}

bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
float* ed, float* et)
{
// TODO: Replace pnpoly with triArea2D tests?
int i, j;
bool c = false;
for (i = 0, j = nverts-1; i < nverts; j = i++)
{
const float* vi = &verts[i*3];
const float* vj = &verts[j*3];
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
c = !c;
ed[j] = dtDistancePtSegSqr2D(pt, vj, vi, et[j]);
}
return c;
}

static void projectPoly(const float* axis, const float* poly, const int npoly,
float& rmin, float& rmax)
{
rmin = rmax = dtVdot2D(axis, &poly[0]);
for (int i = 1; i < npoly; ++i)
{
const float d = dtVdot2D(axis, &poly[i*3]);
rmin = dtMin(rmin, d);
rmax = dtMax(rmax, d);
}
}

inline bool overlapRange(const float amin, const float amax,
const float bmin, const float bmax,
const float eps)
{
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
}

/// @par
///
/// All vertices are projected onto the xz-plane, so the y-values are ignored.
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
const float* polyb, const int npolyb)
{
const float eps = 1e-4f;

for (int i = 0, j = npolya-1; i < npolya; j=i++)
{
const float* va = &polya[j*3];
const float* vb = &polya[i*3];
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
float amin,amax,bmin,bmax;
projectPoly(n, polya, npolya, amin,amax);
projectPoly(n, polyb, npolyb, bmin,bmax);
if (!overlapRange(amin,amax, bmin,bmax, eps))
{
// Found separating axis
return false;
}
}
for (int i = 0, j = npolyb-1; i < npolyb; j=i++)
{
const float* va = &polyb[j*3];
const float* vb = &polyb[i*3];
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
float amin,amax,bmin,bmax;
projectPoly(n, polya, npolya, amin,amax);
projectPoly(n, polyb, npolyb, bmin,bmax);
if (!overlapRange(amin,amax, bmin,bmax, eps))
{
// Found separating axis
return false;
}
}
return true;
}

// Returns a random point in a convex polygon.
// Adapted from Graphics Gems article.
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
const float s, const float t, float* out)
{
// Calc triangle araes
float areasum = 0.0f;
for (int i = 2; i < npts; i++) {
areas[i] = dtTriArea2D(&pts[0], &pts[(i-1)*3], &pts[i*3]);
areasum += dtMax(0.001f, areas[i]);
}
// Find sub triangle weighted by area.
const float thr = s*areasum;
float acc = 0.0f;
float u = 0.0f;
int tri = 0;
for (int i = 2; i < npts; i++) {
const float dacc = areas[i];
if (thr >= acc && thr < (acc+dacc))
{
u = (thr - acc) / dacc;
tri = i;
break;
}
acc += dacc;
}

float v = dtSqrt(t);

const float a = 1 - v;
const float b = (1 - u) * v;
const float c = u * v;
const float* pa = &pts[0];
const float* pb = &pts[(tri-1)*3];
const float* pc = &pts[tri*3];

out[0] = a*pa[0] + b*pb[0] + c*pc[0];
out[1] = a*pa[1] + b*pb[1] + c*pc[1];
out[2] = a*pa[2] + b*pb[2] + c*pc[2];
}

inline float vperpXZ(const float* a, const float* b) { return a[0]*b[2] - a[2]*b[0]; }

bool dtIntersectSegSeg2D(const float* ap, const float* aq,
const float* bp, const float* bq,
float& s, float& t)
{
float u[3], v[3], w[3];
dtVsub(u,aq,ap);
dtVsub(v,bq,bp);
dtVsub(w,ap,bp);
float d = vperpXZ(u,v);
if (fabsf(d) < 1e-6f) return false;
s = vperpXZ(v,w) / d;
t = vperpXZ(u,w) / d;
return true;
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,148 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#ifndef DETOURNAVMESHBUILDER_H
#define DETOURNAVMESHBUILDER_H

#include "DetourAlloc.h"

/// Represents the source data used to build an navigation mesh tile.
/// @ingroup detour
struct dtNavMeshCreateParams
{

/// @name Polygon Mesh Attributes
/// Used to create the base navigation graph.
/// See #rcPolyMesh for details related to these attributes.
/// @{

const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3]
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3]

/// @}
/// @name Height Detail Attributes (Optional)
/// See #rcPolyMeshDetail for details related to these attributes.
/// @{

const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount]
const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
int detailVertsCount; ///< The number of vertices in the detail mesh.
const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount]
int detailTriCount; ///< The number of triangles in the detail mesh.

/// @}
/// @name Off-Mesh Connections Attributes (Optional)
/// Used to define a custom point-to-point edge within the navigation graph, an
/// off-mesh connection is a user defined traversable connection made up to two vertices,
/// at least one of which resides within a navigation mesh polygon.
/// @{

/// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
const float* offMeshConVerts;
/// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
const float* offMeshConRad;
/// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
const unsigned short* offMeshConFlags;
/// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
const unsigned char* offMeshConAreas;
/// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
///
/// 0 = Travel only from endpoint A to endpoint B.<br/>
/// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
const unsigned char* offMeshConDir;
/// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
const unsigned int* offMeshConUserID;
/// The number of off-mesh connections. [Limit: >= 0]
int offMeshConCount;

/// @}
/// @name Tile Attributes
/// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
/// @{

unsigned int userId; ///< The user defined id of the tile.
int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]

/// @}
/// @name General Configuration Attributes
/// @{

float walkableHeight; ///< The agent height. [Unit: wu]
float walkableRadius; ///< The agent radius. [Unit: wu]
float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]

/// True if a bounding volume tree should be built for the tile.
/// @note The BVTree is not normally needed for layered navigation meshes.
bool buildBvTree;

/// @}
};

/// Builds navigation mesh tile data from the provided tile creation data.
/// @ingroup detour
/// @param[in] params Tile creation data.
/// @param[out] outData The resulting tile data.
/// @param[out] outDataSize The size of the tile data array.
/// @return True if the tile data was successfully created.
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);

/// Swaps the endianess of the tile data's header (#dtMeshHeader).
/// @param[in,out] data The tile data array.
/// @param[in] dataSize The size of the data array.
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);

/// Swaps endianess of the tile data.
/// @param[in,out] data The tile data array.
/// @param[in] dataSize The size of the data array.
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);

#endif // DETOURNAVMESHBUILDER_H

// This section contains detailed documentation for members that don't have
// a source file. It reduces clutter in the main section of the header.

/**
@struct dtNavMeshCreateParams
@par
This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
are all based on the values of #cs and #ch.
The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
to a navigation mesh using either the dtNavMesh single tile <tt>init()</tt> function or the dtNavMesh::addTile()
function.
@see dtCreateNavMeshData
*/

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,165 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#include "DetourNode.h"
#include "DetourAlloc.h"
#include "DetourAssert.h"
#include "DetourCommon.h"
#include <string.h>

inline unsigned int dtHashRef(dtPolyRef a)
{
// Edited by TC
a = (~a) + (a << 18);
a = a ^ (a >> 31);
a = a * 21;
a = a ^ (a >> 11);
a = a + (a << 6);
a = a ^ (a >> 22);
return (unsigned int)a;
}

//////////////////////////////////////////////////////////////////////////////////////////
dtNodePool::dtNodePool(int maxNodes, int hashSize) :
m_nodes(0),
m_first(0),
m_next(0),
m_maxNodes(maxNodes),
m_hashSize(hashSize),
m_nodeCount(0)
{
dtAssert(dtNextPow2(m_hashSize) == (unsigned int)m_hashSize);
dtAssert(m_maxNodes > 0);

m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM);
m_next = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*m_maxNodes, DT_ALLOC_PERM);
m_first = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*hashSize, DT_ALLOC_PERM);

dtAssert(m_nodes);
dtAssert(m_next);
dtAssert(m_first);

memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
memset(m_next, 0xff, sizeof(dtNodeIndex)*m_maxNodes);
}

dtNodePool::~dtNodePool()
{
dtFree(m_nodes);
dtFree(m_next);
dtFree(m_first);
}

void dtNodePool::clear()
{
memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize);
m_nodeCount = 0;
}

dtNode* dtNodePool::findNode(dtPolyRef id)
{
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
dtNodeIndex i = m_first[bucket];
while (i != DT_NULL_IDX)
{
if (m_nodes[i].id == id)
return &m_nodes[i];
i = m_next[i];
}
return 0;
}

dtNode* dtNodePool::getNode(dtPolyRef id)
{
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
dtNodeIndex i = m_first[bucket];
dtNode* node = 0;
while (i != DT_NULL_IDX)
{
if (m_nodes[i].id == id)
return &m_nodes[i];
i = m_next[i];
}

if (m_nodeCount >= m_maxNodes)
return 0;

i = (dtNodeIndex)m_nodeCount;
m_nodeCount++;

// Init node
node = &m_nodes[i];
node->pidx = 0;
node->cost = 0;
node->total = 0;
node->id = id;
node->flags = 0;

m_next[i] = m_first[bucket];
m_first[bucket] = i;

return node;
}


//////////////////////////////////////////////////////////////////////////////////////////
dtNodeQueue::dtNodeQueue(int n) :
m_heap(0),
m_capacity(n),
m_size(0)
{
dtAssert(m_capacity > 0);

m_heap = (dtNode**)dtAlloc(sizeof(dtNode*)*(m_capacity+1), DT_ALLOC_PERM);
dtAssert(m_heap);
}

dtNodeQueue::~dtNodeQueue()
{
dtFree(m_heap);
}

void dtNodeQueue::bubbleUp(int i, dtNode* node)
{
int parent = (i-1)/2;
// note: (index > 0) means there is a parent
while ((i > 0) && (m_heap[parent]->total > node->total))
{
m_heap[i] = m_heap[parent];
i = parent;
parent = (i-1)/2;
}
m_heap[i] = node;
}

void dtNodeQueue::trickleDown(int i, dtNode* node)
{
int child = (i*2)+1;
while (child < m_size)
{
if (((child+1) < m_size) &&
(m_heap[child]->total > m_heap[child+1]->total))
{
child++;
}
m_heap[i] = m_heap[child];
i = child;
child = (i*2)+1;
}
bubbleUp(i, node);
}
@@ -0,0 +1,159 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#ifndef DETOURNODE_H
#define DETOURNODE_H

#include "DetourNavMesh.h"

enum dtNodeFlags
{
DT_NODE_OPEN = 0x01,
DT_NODE_CLOSED = 0x02,
};

typedef unsigned short dtNodeIndex;
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;

struct dtNode
{
float pos[3]; ///< Position of the node.
float cost; ///< Cost from previous node to current node.
float total; ///< Cost up to the node.
unsigned int pidx : 30; ///< Index to parent node.
unsigned int flags : 2; ///< Node flags 0/open/closed.
dtPolyRef id; ///< Polygon ref the node corresponds to.
};


class dtNodePool
{
public:
dtNodePool(int maxNodes, int hashSize);
~dtNodePool();
inline void operator=(const dtNodePool&) {}
void clear();
dtNode* getNode(dtPolyRef id);
dtNode* findNode(dtPolyRef id);

inline unsigned int getNodeIdx(const dtNode* node) const
{
if (!node) return 0;
return (unsigned int)(node - m_nodes)+1;
}

inline dtNode* getNodeAtIdx(unsigned int idx)
{
if (!idx) return 0;
return &m_nodes[idx-1];
}

inline const dtNode* getNodeAtIdx(unsigned int idx) const
{
if (!idx) return 0;
return &m_nodes[idx-1];
}

inline int getMemUsed() const
{
return sizeof(*this) +
sizeof(dtNode)*m_maxNodes +
sizeof(dtNodeIndex)*m_maxNodes +
sizeof(dtNodeIndex)*m_hashSize;
}

inline int getMaxNodes() const { return m_maxNodes; }

inline int getHashSize() const { return m_hashSize; }
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
inline dtNodeIndex getNext(int i) const { return m_next[i]; }

private:

dtNode* m_nodes;
dtNodeIndex* m_first;
dtNodeIndex* m_next;
const int m_maxNodes;
const int m_hashSize;
int m_nodeCount;
};

class dtNodeQueue
{
public:
dtNodeQueue(int n);
~dtNodeQueue();
inline void operator=(dtNodeQueue&) {}

inline void clear()
{
m_size = 0;
}

inline dtNode* top()
{
return m_heap[0];
}

inline dtNode* pop()
{
dtNode* result = m_heap[0];
m_size--;
trickleDown(0, m_heap[m_size]);
return result;
}

inline void push(dtNode* node)
{
m_size++;
bubbleUp(m_size-1, node);
}

inline void modify(dtNode* node)
{
for (int i = 0; i < m_size; ++i)
{
if (m_heap[i] == node)
{
bubbleUp(i, node);
return;
}
}
}

inline bool empty() const { return m_size == 0; }

inline int getMemUsed() const
{
return sizeof(*this) +
sizeof(dtNode*)*(m_capacity+1);
}

inline int getCapacity() const { return m_capacity; }

private:
void bubbleUp(int i, dtNode* node);
void trickleDown(int i, dtNode* node);

dtNode** m_heap;
const int m_capacity;
int m_size;
};


#endif // DETOURNODE_H

Large diffs are not rendered by default.

@@ -0,0 +1,148 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#ifndef DETOUROBSTACLEAVOIDANCE_H
#define DETOUROBSTACLEAVOIDANCE_H

struct dtObstacleCircle
{
float p[3]; // Position of the obstacle
float vel[3]; // Velocity of the obstacle
float dvel[3]; // Velocity of the obstacle
float rad; // Radius of the obstacle
float dp[3], np[3]; // Use for side selection during sampling.
};

struct dtObstacleSegment
{
float p[3], q[3]; // End points of the obstacle segment
bool touch;
};

static const int RVO_SAMPLE_RAD = 15;
static const int MAX_RVO_SAMPLES = (RVO_SAMPLE_RAD*2+1)*(RVO_SAMPLE_RAD*2+1) + 100;

class dtObstacleAvoidanceDebugData
{
public:
dtObstacleAvoidanceDebugData();
~dtObstacleAvoidanceDebugData();

bool init(const int maxSamples);
void reset();
void addSample(const float* vel, const float ssize, const float pen,
const float vpen, const float vcpen, const float spen, const float tpen);

void normalizeSamples();

inline int getSampleCount() const { return m_nsamples; }
inline const float* getSampleVelocity(const int i) const { return &m_vel[i*3]; }
inline float getSampleSize(const int i) const { return m_ssize[i]; }
inline float getSamplePenalty(const int i) const { return m_pen[i]; }
inline float getSampleDesiredVelocityPenalty(const int i) const { return m_vpen[i]; }
inline float getSampleCurrentVelocityPenalty(const int i) const { return m_vcpen[i]; }
inline float getSamplePreferredSidePenalty(const int i) const { return m_spen[i]; }
inline float getSampleCollisionTimePenalty(const int i) const { return m_tpen[i]; }

private:
int m_nsamples;
int m_maxSamples;
float* m_vel;
float* m_ssize;
float* m_pen;
float* m_vpen;
float* m_vcpen;
float* m_spen;
float* m_tpen;
};

dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData();
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr);


class dtObstacleAvoidanceQuery
{
public:
dtObstacleAvoidanceQuery();
~dtObstacleAvoidanceQuery();

bool init(const int maxCircles, const int maxSegments);

void reset();

void addCircle(const float* pos, const float rad,
const float* vel, const float* dvel);

void addSegment(const float* p, const float* q);

inline void setVelocitySelectionBias(float v) { m_velBias = v; }
inline void setDesiredVelocityWeight(float w) { m_weightDesVel = w; }
inline void setCurrentVelocityWeight(float w) { m_weightCurVel = w; }
inline void setPreferredSideWeight(float w) { m_weightSide = w; }
inline void setCollisionTimeWeight(float w) { m_weightToi = w; }
inline void setTimeHorizon(float t) { m_horizTime = t; }

void sampleVelocityGrid(const float* pos, const float rad, const float vmax,
const float* vel, const float* dvel, float* nvel,
const int gsize,
dtObstacleAvoidanceDebugData* debug = 0);

void sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
const float* vel, const float* dvel, float* nvel,
const int ndivs, const int nrings, const int depth,
dtObstacleAvoidanceDebugData* debug = 0);

inline int getObstacleCircleCount() const { return m_ncircles; }
const dtObstacleCircle* getObstacleCircle(const int i) { return &m_circles[i]; }

inline int getObstacleSegmentCount() const { return m_nsegments; }
const dtObstacleSegment* getObstacleSegment(const int i) { return &m_segments[i]; }

private:

void prepare(const float* pos, const float* dvel);

float processSample(const float* vcand, const float cs,
const float* pos, const float rad,
const float vmax, const float* vel, const float* dvel,
dtObstacleAvoidanceDebugData* debug);

dtObstacleCircle* insertCircle(const float dist);
dtObstacleSegment* insertSegment(const float dist);

float m_velBias;
float m_weightDesVel;
float m_weightCurVel;
float m_weightSide;
float m_weightToi;
float m_horizTime;

int m_maxCircles;
dtObstacleCircle* m_circles;
int m_ncircles;

int m_maxSegments;
dtObstacleSegment* m_segments;
int m_nsegments;
};

dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery();
void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr);


#endif // DETOUROBSTACLEAVOIDANCE_H
@@ -0,0 +1,64 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#ifndef DETOURSTATUS_H
#define DETOURSTATUS_H

typedef unsigned int dtStatus;

// High level status.
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.

// Detail information for status.
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.


// Returns true of status is success.
inline bool dtStatusSucceed(dtStatus status)
{
return (status & DT_SUCCESS) != 0;
}

// Returns true of status is failure.
inline bool dtStatusFailed(dtStatus status)
{
return (status & DT_FAILURE) != 0;
}

// Returns true of status is in progress.
inline bool dtStatusInProgress(dtStatus status)
{
return (status & DT_IN_PROGRESS) != 0;
}

// Returns true if specific detail is set.
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
{
return (status & detail) != 0;
}

#endif // DETOURSTATUS_H
@@ -0,0 +1,18 @@
Copyright (c) 2009 Mikko Mononen memon@inside.org

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@@ -0,0 +1,120 @@

Recast & Detour Version 1.4


Recast

Recast is state of the art navigation mesh construction toolset for games.

* It is automatic, which means that you can throw any level geometry
at it and you will get robust mesh out
* It is fast which means swift turnaround times for level designers
* It is open source so it comes with full source and you can
customize it to your hearts content.

The Recast process starts with constructing a voxel mold from a level geometry
and then casting a navigation mesh over it. The process consists of three steps,
building the voxel mold, partitioning the mold into simple regions, peeling off
the regions as simple polygons.

1. The voxel mold is build from the input triangle mesh by rasterizing
the triangles into a multi-layer heightfield. Some simple filters are
then applied to the mold to prune out locations where the character
would not be able to move.
2. The walkable areas described by the mold are divided into simple
overlayed 2D regions. The resulting regions have only one non-overlapping
contour, which simplifies the final step of the process tremendously.
3. The navigation polygons are peeled off from the regions by first tracing
the boundaries and then simplifying them. The resulting polygons are
finally converted to convex polygons which makes them perfect for
pathfinding and spatial reasoning about the level.

The toolset code is located in the Recast folder and demo application using the Recast
toolset is located in the RecastDemo folder.

The project files with this distribution can be compiled with Microsoft Visual C++ 2008
(you can download it for free) and XCode 3.1.


Detour

Recast is accompanied with Detour, path-finding and spatial reasoning toolkit. You can use any navigation mesh with Detour, but of course the data generated with Recast fits perfectly.

Detour offers simple static navigation mesh which is suitable for many simple cases, as well as tiled navigation mesh which allows you to plug in and out pieces of the mesh. The tiled mesh allows to create systems where you stream new navigation data in and out as the player progresses the level, or you may regenerate tiles as the world changes.


Latest code available at http://code.google.com/p/recastnavigation/


--

Release Notes

----------------
* Recast 1.4
Released August 24th, 2009

- Added detail height mesh generation (RecastDetailMesh.cpp) for single,
tiled statmeshes as well as tilemesh.
- Added feature to contour tracing which detects extra vertices along
tile edges which should be removed later.
- Changed the tiled stat mesh preprocess, so that it first generated
polymeshes per tile and finally combines them.
- Fixed bug in the GUI code where invisible buttons could be pressed.

----------------
* Recast 1.31
Released July 24th, 2009

- Better cost and heuristic functions.
- Fixed tile navmesh raycast on tile borders.

----------------
* Recast 1.3
Released July 14th, 2009

- Added dtTileNavMesh which allows to dynamically add and remove navmesh pieces at runtime.
- Renamed stat navmesh types to dtStat* (i.e. dtPoly is now dtStatPoly).
- Moved common code used by tile and stat navmesh to DetourNode.h/cpp and DetourCommon.h/cpp.
- Refactores the demo code.

----------------
* Recast 1.2
Released June 17th, 2009

- Added tiled mesh generation. The tiled generation allows to generate navigation for
much larger worlds, it removes some of the artifacts that comes from distance fields
in open areas, and allows later streaming and dynamic runtime generation
- Improved and added some debug draw modes
- API change: The helper function rcBuildNavMesh does not exists anymore,
had to change few internal things to cope with the tiled processing,
similar API functionality will be added later once the tiled process matures
- The demo is getting way too complicated, need to split demos
- Fixed several filtering functions so that the mesh is tighter to the geometry,
sometimes there could be up error up to tow voxel units close to walls,
now it should be just one.

----------------
* Recast 1.1
Released April 11th, 2009

This is the first release of Detour.

----------------
* Recast 1.0
Released March 29th, 2009

This is the first release of Recast.

The process is not always as robust as I would wish. The watershed phase sometimes swallows tiny islands
which are close to edges. These droppings are handled in rcBuildContours, but the code is not
particularly robust either.

Another non-robust case is when portal contours (contours shared between two regions) are always
assumed to be straight. That can lead to overlapping contours specially when the level has
large open areas.



Mikko Mononen
memon@inside.org
@@ -0,0 +1,33 @@
# Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

set(Recast_STAT_SRCS
Recast.cpp
RecastAlloc.cpp
RecastArea.cpp
RecastContour.cpp
RecastFilter.cpp
RecastLayers.cpp
RecastMesh.cpp
RecastMeshDetail.cpp
RecastRasterization.cpp
RecastRegion.cpp
)

if(WIN32)
include_directories(
${CMAKE_SOURCE_DIR}/dep/zlib
)
endif()

add_library(Recast STATIC ${Recast_STAT_SRCS})

target_link_libraries(Recast ${ZLIB_LIBRARIES})

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,88 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#include <stdlib.h>
#include <string.h>
#include "RecastAlloc.h"

static void *rcAllocDefault(int size, rcAllocHint)
{
return malloc(size);
}

static void rcFreeDefault(void *ptr)
{
free(ptr);
}

static rcAllocFunc* sRecastAllocFunc = rcAllocDefault;
static rcFreeFunc* sRecastFreeFunc = rcFreeDefault;

/// @see rcAlloc, rcFree
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc)
{
sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault;
sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault;
}

/// @see rcAllocSetCustom
void* rcAlloc(int size, rcAllocHint hint)
{
return sRecastAllocFunc(size, hint);
}

/// @par
///
/// @warning This function leaves the value of @p ptr unchanged. So it still
/// points to the same (now invalid) location, and not to null.
///
/// @see rcAllocSetCustom
void rcFree(void* ptr)
{
if (ptr)
sRecastFreeFunc(ptr);
}

/// @class rcIntArray
///
/// While it is possible to pre-allocate a specific array size during
/// construction or by using the #resize method, certain methods will
/// automatically resize the array as needed.
///
/// @warning The array memory is not initialized to zero when the size is
/// manually set during construction or when using #resize.

/// @par
///
/// Using this method ensures the array is at least large enough to hold
/// the specified number of elements. This can improve performance by
/// avoiding auto-resizing during use.
void rcIntArray::resize(int n)
{
if (n > m_cap)
{
if (!m_cap) m_cap = n;
while (m_cap < n) m_cap *= 2;
int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP);
if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int));
rcFree(m_data);
m_data = newData;
}
m_size = n;
}

@@ -0,0 +1,124 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#ifndef RECASTALLOC_H
#define RECASTALLOC_H

/// Provides hint values to the memory allocator on how long the
/// memory is expected to be used.
enum rcAllocHint
{
RC_ALLOC_PERM, ///< Memory will persist after a function call.
RC_ALLOC_TEMP ///< Memory used temporarily within a function.
};

/// A memory allocation function.
// @param[in] size The size, in bytes of memory, to allocate.
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
/// @see rcAllocSetCustom
typedef void* (rcAllocFunc)(int size, rcAllocHint hint);

/// A memory deallocation function.
/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc.
/// @see rcAllocSetCustom
typedef void (rcFreeFunc)(void* ptr);

/// Sets the base custom allocation functions to be used by Recast.
/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc
/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);

/// Allocates a memory block.
/// @param[in] size The size, in bytes of memory, to allocate.
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
/// @see rcFree
void* rcAlloc(int size, rcAllocHint hint);

/// Deallocates a memory block.
/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
/// @see rcAlloc
void rcFree(void* ptr);


/// A simple dynamic array of integers.
class rcIntArray
{
int* m_data;
int m_size, m_cap;
inline rcIntArray(const rcIntArray&);
inline rcIntArray& operator=(const rcIntArray&);
public:

/// Constructs an instance with an initial array size of zero.
inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {}

/// Constructs an instance initialized to the specified size.
/// @param[in] n The initial size of the integer array.
inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
inline ~rcIntArray() { rcFree(m_data); }

/// Specifies the new size of the integer array.
/// @param[in] n The new size of the integer array.
void resize(int n);

/// Push the specified integer onto the end of the array and increases the size by one.
/// @param[in] item The new value.
inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }

/// Returns the value at the end of the array and reduces the size by one.
/// @return The value at the end of the array.
inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; }

/// The value at the specified array index.
/// @warning Does not provide overflow protection.
/// @param[in] i The index of the value.
inline const int& operator[](int i) const { return m_data[i]; }

/// The value at the specified array index.
/// @warning Does not provide overflow protection.
/// @param[in] i The index of the value.
inline int& operator[](int i) { return m_data[i]; }

/// The current size of the integer array.
inline int size() const { return m_size; }
};

/// A simple helper class used to delete an array when it goes out of scope.
/// @note This class is rarely if ever used by the end user.
template<class T> class rcScopedDelete
{
T* ptr;
inline T* operator=(T* p);
public:

/// Constructs an instance with a null pointer.
inline rcScopedDelete() : ptr(0) {}

/// Constructs an instance with the specified pointer.
/// @param[in] p An pointer to an allocated array.
inline rcScopedDelete(T* p) : ptr(p) {}
inline ~rcScopedDelete() { rcFree(ptr); }

/// The root array pointer.
/// @return The root array pointer.
inline operator T*() { return ptr; }
};

#endif

Large diffs are not rendered by default.

@@ -0,0 +1,33 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#ifndef RECASTASSERT_H
#define RECASTASSERT_H

// Note: This header file's only purpose is to include define assert.
// Feel free to change the file and include your own implementation instead.

#ifdef NDEBUG
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
#else
# include <assert.h>
# define rcAssert assert
#endif

#endif // RECASTASSERT_H

Large diffs are not rendered by default.

@@ -0,0 +1,207 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include "Recast.h"
#include "RecastAssert.h"

/// @par
///
/// Allows the formation of walkable regions that will flow over low lying
/// objects such as curbs, and up structures such as stairways.
///
/// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
///
/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call
/// #rcFilterLedgeSpans after calling this filter.
///
/// @see rcHeightfield, rcConfig
void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_FILTER_LOW_OBSTACLES);

const int w = solid.width;
const int h = solid.height;

for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
rcSpan* ps = 0;
bool previousWalkable = false;
unsigned char previousArea = RC_NULL_AREA;

for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next)
{
const bool walkable = s->area != RC_NULL_AREA;
// If current span is not walkable, but there is walkable
// span just below it, mark the span above it walkable too.
if (!walkable && previousWalkable)
{
if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb)
s->area = previousArea;
}
// Copy walkable flag so that it cannot propagate
// past multiple non-walkable objects.
previousWalkable = walkable;
previousArea = s->area;
}
}
}

ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
}

/// @par
///
/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
/// from the current span's maximum.
/// This method removes the impact of the overestimation of conservative voxelization
/// so the resulting mesh will not have regions hanging in the air over ledges.
///
/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
///
/// @see rcHeightfield, rcConfig
void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb,
rcHeightfield& solid)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_FILTER_BORDER);

const int w = solid.width;
const int h = solid.height;
const int MAX_HEIGHT = 0xffff;

// Mark border spans.
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next)
{
// Skip non walkable spans.
if (s->area == RC_NULL_AREA)
continue;

const int bot = (int)(s->smax);
const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT;

// Find neighbours minimum height.
int minh = MAX_HEIGHT;

// Min and max height of accessible neighbours.
int asmin = s->smax;
int asmax = s->smax;

for (int dir = 0; dir < 4; ++dir)
{
int dx = x + rcGetDirOffsetX(dir);
int dy = y + rcGetDirOffsetY(dir);
// Skip neighbours which are out of bounds.
if (dx < 0 || dy < 0 || dx >= w || dy >= h)
{
minh = rcMin(minh, -walkableClimb - bot);
continue;
}

// From minus infinity to the first span.
rcSpan* ns = solid.spans[dx + dy*w];
int nbot = -walkableClimb;
int ntop = ns ? (int)ns->smin : MAX_HEIGHT;
// Skip neightbour if the gap between the spans is too small.
if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight)
minh = rcMin(minh, nbot - bot);

// Rest of the spans.
for (ns = solid.spans[dx + dy*w]; ns; ns = ns->next)
{
nbot = (int)ns->smax;
ntop = ns->next ? (int)ns->next->smin : MAX_HEIGHT;
// Skip neightbour if the gap between the spans is too small.
if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight)
{
minh = rcMin(minh, nbot - bot);

// Find min/max accessible neighbour height.
if (rcAbs(nbot - bot) <= walkableClimb)
{
if (nbot < asmin) asmin = nbot;
if (nbot > asmax) asmax = nbot;
}

}
}
}

// The current span is close to a ledge if the drop to any
// neighbour span is less than the walkableClimb.
if (minh < -walkableClimb)
s->area = RC_NULL_AREA;

// If the difference between all neighbours is too large,
// we are at steep slope, mark the span as ledge.
if ((asmax - asmin) > walkableClimb)
{
s->area = RC_NULL_AREA;
}
}
}
}

ctx->stopTimer(RC_TIMER_FILTER_BORDER);
}

/// @par
///
/// For this filter, the clearance above the span is the distance from the span's
/// maximum to the next higher span's minimum. (Same grid column.)
///
/// @see rcHeightfield, rcConfig
void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_FILTER_WALKABLE);

const int w = solid.width;
const int h = solid.height;
const int MAX_HEIGHT = 0xffff;

// Remove walkable flag from spans which do not have enough
// space above them for the agent to stand there.
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next)
{
const int bot = (int)(s->smax);
const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT;
if ((top - bot) <= walkableHeight)
s->area = RC_NULL_AREA;
}
}
}

ctx->stopTimer(RC_TIMER_FILTER_WALKABLE);
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,387 @@
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include "Recast.h"
#include "RecastAlloc.h"
#include "RecastAssert.h"

inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax)
{
bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
return overlap;
}

inline bool overlapInterval(unsigned short amin, unsigned short amax,
unsigned short bmin, unsigned short bmax)
{
if (amax < bmin) return false;
if (amin > bmax) return false;
return true;
}


static rcSpan* allocSpan(rcHeightfield& hf)
{
// If running out of memory, allocate new page and update the freelist.
if (!hf.freelist || !hf.freelist->next)
{
// Create new page.
// Allocate memory for the new pool.
rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
if (!pool) return 0;
pool->next = 0;
// Add the pool into the list of pools.
pool->next = hf.pools;
hf.pools = pool;
// Add new items to the free list.
rcSpan* freelist = hf.freelist;
rcSpan* head = &pool->items[0];
rcSpan* it = &pool->items[RC_SPANS_PER_POOL];
do
{
--it;
it->next = freelist;
freelist = it;
}
while (it != head);
hf.freelist = it;
}

// Pop item from in front of the free list.
rcSpan* it = hf.freelist;
hf.freelist = hf.freelist->next;
return it;
}

static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
{
if (!ptr) return;
// Add the node in front of the free list.
ptr->next = hf.freelist;
hf.freelist = ptr;
}

static void addSpan(rcHeightfield& hf, const int x, const int y,
const unsigned short smin, const unsigned short smax,
const unsigned char area, const int flagMergeThr)
{

int idx = x + y*hf.width;

rcSpan* s = allocSpan(hf);
s->smin = smin;
s->smax = smax;
s->area = area;
s->next = 0;

// Empty cell, add he first span.
if (!hf.spans[idx])
{
hf.spans[idx] = s;
return;
}
rcSpan* prev = 0;
rcSpan* cur = hf.spans[idx];

// Insert and merge spans.
while (cur)
{
if (cur->smin > s->smax)
{
// Current span is further than the new span, break.
break;
}
else if (cur->smax < s->smin)
{
// Current span is before the new span advance.
prev = cur;
cur = cur->next;
}
else
{
// Merge spans.
if (cur->smin < s->smin)
s->smin = cur->smin;
if (cur->smax > s->smax)
s->smax = cur->smax;

// Merge flags.
if (rcAbs((int)s->smax - (int)cur->smax) <= flagMergeThr)
s->area = rcMax(s->area, cur->area);

// Remove current span.
rcSpan* next = cur->next;
freeSpan(hf, cur);
if (prev)
prev->next = next;
else
hf.spans[idx] = next;
cur = next;
}
}

// Insert new span.
if (prev)
{
s->next = prev->next;
prev->next = s;
}
else
{
s->next = hf.spans[idx];
hf.spans[idx] = s;
}
}

/// @par
///
/// The span addition can be set to favor flags. If the span is merged to
/// another span and the new @p smax is within @p flagMergeThr units
/// from the existing span, the span flags are merged.
///
/// @see rcHeightfield, rcSpan.
void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
const unsigned short smin, const unsigned short smax,
const unsigned char area, const int flagMergeThr)
{
// rcAssert(ctx);
addSpan(hf, x,y, smin, smax, area, flagMergeThr);
}

static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
{
float d[12];
for (int i = 0; i < n; ++i)
d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;

int m = 0;
for (int i = 0, j = n-1; i < n; j=i, ++i)
{
bool ina = d[j] >= 0;
bool inb = d[i] >= 0;
if (ina != inb)
{
float s = d[j] / (d[j] - d[i]);
out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
m++;
}
if (inb)
{
out[m*3+0] = in[i*3+0];
out[m*3+1] = in[i*3+1];
out[m*3+2] = in[i*3+2];
m++;
}
}
return m;
}

static void rasterizeTri(const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& hf,
const float* bmin, const float* bmax,
const float cs, const float ics, const float ich,
const int flagMergeThr)
{
const int w = hf.width;
const int h = hf.height;
float tmin[3], tmax[3];
const float by = bmax[1] - bmin[1];

// Calculate the bounding box of the triangle.
rcVcopy(tmin, v0);
rcVcopy(tmax, v0);
rcVmin(tmin, v1);
rcVmin(tmin, v2);
rcVmax(tmax, v1);
rcVmax(tmax, v2);

// If the triangle does not touch the bbox of the heightfield, skip the triagle.
if (!overlapBounds(bmin, bmax, tmin, tmax))
return;

// Calculate the footpring of the triangle on the grid.
int x0 = (int)((tmin[0] - bmin[0])*ics);
int y0 = (int)((tmin[2] - bmin[2])*ics);
int x1 = (int)((tmax[0] - bmin[0])*ics);
int y1 = (int)((tmax[2] - bmin[2])*ics);
x0 = rcClamp(x0, 0, w-1);
y0 = rcClamp(y0, 0, h-1);
x1 = rcClamp(x1, 0, w-1);
y1 = rcClamp(y1, 0, h-1);

// Clip the triangle into all grid cells it touches.
float in[7*3], out[7*3], inrow[7*3];

for (int y = y0; y <= y1; ++y)
{
// Clip polygon to row.
rcVcopy(&in[0], v0);
rcVcopy(&in[1*3], v1);
rcVcopy(&in[2*3], v2);
int nvrow = 3;
const float cz = bmin[2] + y*cs;
nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
if (nvrow < 3) continue;
nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
if (nvrow < 3) continue;

for (int x = x0; x <= x1; ++x)
{
// Clip polygon to column.
int nv = nvrow;
const float cx = bmin[0] + x*cs;
nv = clipPoly(inrow, nv, out, 1, 0, -cx);
if (nv < 3) continue;
nv = clipPoly(out, nv, in, -1, 0, cx+cs);
if (nv < 3) continue;

// Calculate min and max of the span.
float smin = in[1], smax = in[1];
for (int i = 1; i < nv; ++i)
{
smin = rcMin(smin, in[i*3+1]);
smax = rcMax(smax, in[i*3+1]);
}
smin -= bmin[1];
smax -= bmin[1];
// Skip the span if it is outside the heightfield bbox
if (smax < 0.0f) continue;
if (smin > by) continue;
// Clamp the span to the heightfield bbox.
if (smin < 0.0f) smin = 0;
if (smax > by) smax = by;

// Snap the span to the heightfield height grid.
unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);

addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
}
}
}

/// @par
///
/// No spans will be added if the triangle does not overlap the heightfield grid.
///
/// @see rcHeightfield
void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& solid,
const int flagMergeThr)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);

const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);

ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
}

/// @par
///
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
const int* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);

const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
// Rasterize triangles.
for (int i = 0; i < nt; ++i)
{
const float* v0 = &verts[tris[i*3+0]*3];
const float* v1 = &verts[tris[i*3+1]*3];
const float* v2 = &verts[tris[i*3+2]*3];
// Rasterize.
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
}

ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
}

/// @par
///
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
const unsigned short* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);

const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
// Rasterize triangles.
for (int i = 0; i < nt; ++i)
{
const float* v0 = &verts[tris[i*3+0]*3];
const float* v1 = &verts[tris[i*3+1]*3];
const float* v2 = &verts[tris[i*3+2]*3];
// Rasterize.
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
}

ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
}

/// @par
///
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr)
{
rcAssert(ctx);

ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);

const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
// Rasterize triangles.
for (int i = 0; i < nt; ++i)
{
const float* v0 = &verts[(i*3+0)*3];
const float* v1 = &verts[(i*3+1)*3];
const float* v2 = &verts[(i*3+2)*3];
// Rasterize.
rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
}

ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
}

Large diffs are not rendered by default.

@@ -0,0 +1,20 @@
TODO/Roadmap

Summer/Autumn 2009

- Off mesh links (jump links)
- Area annotations
- Embed extra data per polygon
- Height conforming navmesh


Autumn/Winter 2009/2010

- Detour path following
- More dynamic example with tile navmesh
- Faster small tile process


More info at http://digestingduck.blogspot.com/2009/07/recast-and-detour-roadmap.html

-
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _TRINITY_AUTO_PTR_H
#define _TRINITY_AUTO_PTR_H

#include <ace/Bound_Ptr.h>

namespace Trinity
{

template <class Pointer, class Lock>
class AutoPtr : public ACE_Strong_Bound_Ptr<Pointer, Lock>
{
typedef ACE_Strong_Bound_Ptr<Pointer, Lock> Base;

public:
AutoPtr()
: Base()
{ }

AutoPtr(Pointer* x)
: Base(x)
{ }

operator bool() const
{
return !Base::null();
}

bool operator !() const
{
return Base::null();
}
};

} // namespace Trinity

#endif
@@ -1,7 +1,5 @@
# Copyright (C) 2010-2017 Project SkyFire <https://www.projectskyfire.org/>
# Copyright (C) 2010-2017 Oregon <http://www.oregoncore.com/>
# Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
# Copyright (C) 2005-2017 MaNGOS <http://www.getmangos.com/>
# Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
@@ -11,7 +9,7 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

if (USE_COREPCH)
if( USE_COREPCH )
include_directories(${CMAKE_CURRENT_BINARY_DIR})
endif()

@@ -24,18 +22,32 @@ file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h)
file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h)
file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h)
file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h)

file(GLOB sources_localdir *.cpp *.h)

source_group(CMake FILES CMakeLists.txt)
source_group(Configuration FILES ${sources_Configuration})
source_group(Cryptography FILES ${sources_Cryptography})
source_group(Database FILES ${sources_Database})
source_group(DataStores FILES ${sources_DataStores})
source_group(Dynamic FILES ${sources_Dynamic})
source_group(Logging FILES ${sources_Logging})
source_group(Packets FILES ${sources_Packets})
source_group(Threading FILES ${sources_Threading})
source_group(Utilities FILES ${sources_Utilities})
source_group(localdir FILES ${sources_localdir})

# Manually set sources for Debugging directory as we don't want to include WheatyExceptionReport in shared project
# It needs to be included both in authserver and worldserver for the static global variable to be properly initialized
# and to handle crash logs on windows
set(sources_Debugging Debugging/Errors.cpp Debugging/Errors.h)

#
# Build shared sourcelist
#

if (USE_COREPCH AND MSVC)
set(shared_STAT_SRCS
PrecompiledHeaders/SharedPCH.cpp
PrecompiledHeaders/SharedPCH.h
)
if (USE_COREPCH)
set(shared_STAT_PCH_HDR PrecompiledHeaders/sharedPCH.h)
set(shared_STAT_PCH_SRC PrecompiledHeaders/sharedPCH.cpp)
endif()

set(shared_STAT_SRCS
@@ -44,28 +56,22 @@ set(shared_STAT_SRCS
${sources_Cryptography}
${sources_Database}
${sources_DataStores}
${sources_Debugging}
${sources_Dynamic}
${sources_Logging}
${sources_Packets}
${sources_Threading}
${sources_Utilities}
${sources_localdir}
Debugging/Errors.h
)

include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/mersennetwister
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/utf8cpp
${CMAKE_SOURCE_DIR}/src/server
#${CMAKE_SOURCE_DIR}/src/server/game/World
#${CMAKE_SOURCE_DIR}/src/server/game/Addons
#${CMAKE_SOURCE_DIR}/src/server/game/Server
#${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol
#${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous
#${CMAKE_SOURCE_DIR}/src/server/game/Warden
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Configuration
${CMAKE_CURRENT_SOURCE_DIR}/Cryptography
@@ -77,23 +83,22 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Packets
${CMAKE_CURRENT_SOURCE_DIR}/Threading
${CMAKE_CURRENT_SOURCE_DIR}/Utilities
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object
${ACE_INCLUDE_DIR}
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
)

add_library(shared STATIC ${shared_STAT_SRCS})
add_library(shared STATIC
${shared_STAT_SRCS}
${shared_STAT_PCH_SRC}
)

target_link_libraries(shared
${ACE_LIBRARY}
)

# Generate precompiled header
if (USE_COREPCH)
if (CMAKE_COMPILER_IS_GNUCXX)
add_precompiled_header(shared ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders/SharedPCH.h)
elseif(MSVC)
add_native_precompiled_header(shared ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders/SharedPCH)
endif()
endif()
add_cxx_pch(shared ${shared_STAT_PCH_HDR} ${shared_STAT_PCH_SRC})
endif ()
@@ -1,12 +1,11 @@
/*
* Copyright (C) 2010-2013 Project SkyFire <https://www.projectskyfire.org/>
* Copyright (C) 2010-2013 Oregon <http://www.oregoncore.com/>
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
@@ -29,7 +28,10 @@ char const* localeNames[TOTAL_LOCALES] = {
"zhTW",
"esES",
"esMX",
"ruRU"
"ruRU",
"itIT",
"ptBR",
"ptPT",
};

LocaleConstant GetLocaleByName(const std::string& name)
@@ -39,5 +41,4 @@ LocaleConstant GetLocaleByName(const std::string& name)
return LocaleConstant(i);

return LOCALE_enUS; // including enGB case
}

}
@@ -1,12 +1,11 @@
/*
* Copyright (C) 2010-2013 Project SkyFire <https://www.projectskyfire.org/>
* Copyright (C) 2010-2013 Oregon <http://www.oregoncore.com/>
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
@@ -18,16 +17,16 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SKYFIRE_COMMON_H
#define SKYFIRE_COMMON_H
#ifndef TRINITYCORE_COMMON_H
#define TRINITYCORE_COMMON_H

// config.h needs to be included 1st
// TODO this thingy looks like hack , but its not, need to
/// @todo this thingy looks like hack, but its not, need to
// make separate header however, because It makes mess here.
#ifdef HAVE_CONFIG_H
// Remove Some things that we will define
// This is in case including another config.h
// before Skyfire config.h
// before trinity config.h
#ifdef PACKAGE
#undef PACKAGE
#endif //PACKAGE
@@ -49,7 +48,9 @@
#ifdef VERSION
#undef VERSION
#endif //VERSION
# include "config.h"

# include "Config.h"

#undef PACKAGE
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
@@ -61,21 +62,6 @@

#include "Define.h"

#if COMPILER == COMPILER_MICROSOFT
# pragma warning(disable:4996) // 'function': was declared deprecated
#ifndef __SHOW_STUPID_WARNINGS__
# pragma warning(disable:4005) // 'identifier' : macro redefinition
# pragma warning(disable:4018) // 'expression' : signed/unsigned mismatch
# pragma warning(disable:4244) // 'argument' : conversion from 'type1' to 'type2', possible loss of data
# pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
# pragma warning(disable:4305) // 'identifier' : truncation from 'type1' to 'type2'
# pragma warning(disable:4311) // 'variable' : pointer truncation from 'type' to 'type'
# pragma warning(disable:4355) // 'this' : used in base member initializer list
# pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning)
# pragma warning(disable:4522) // warning when class has 2 constructors
#endif // __SHOW_STUPID_WARNINGS__
#endif // __GNUC__

#include "Dynamic/UnorderedMap.h"
#include <stdio.h>
#include <stdlib.h>
@@ -100,16 +86,16 @@
#include <sstream>
#include <algorithm>

#include "LockedQueue.h"
#include "Threading.h"
#include "Threading/LockedQueue.h"
#include "Threading/Threading.h"

#include <ace/Basic_Types.h>
#include <ace/Guard_T.h>
#include <ace/RW_Thread_Mutex.h>
#include <ace/Thread_Mutex.h>
#include <ace/OS_NS_time.h>

#if PLATFORM == PLATFORM_WINDOWS
# define FD_SETSIZE 4096
# include <ace/config-all.h>
// XP winver - needed to compile with standard leak check in MemoryLeaks.h
// uncomment later if needed
@@ -132,7 +118,7 @@
#define I32FMT "%08I32X"
#define I64FMT "%016I64X"
#define snprintf _snprintf
#define atoll __atoi64
#define atoll _atoi64
#define vsnprintf _vsnprintf
#define finite(X) _finite(X)
#define llabs _abs64
@@ -146,37 +132,20 @@

#endif

#define UI64FMTD ACE_UINT64_FORMAT_SPECIFIER
#define UI64LIT(N) ACE_UINT64_LITERAL(N)

#define SI64FMTD ACE_INT64_FORMAT_SPECIFIER
#define SI64LIT(N) ACE_INT64_LITERAL(N)

#define SIZEFMTD ACE_SIZE_T_FORMAT_SPECIFIER

inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; }

#define atol(a) strtoul( a, NULL, 10)

#define STRINGIZE(a) #a

// used for creating values for respawn for example
#define MAKE_PAIR64(l, h) uint64(uint32(l) | (uint64(h) << 32))
#define PAIR64_HIPART(x) (uint32)((uint64(x) >> 32) & UI64LIT(0x00000000FFFFFFFF))
#define PAIR64_LOPART(x) (uint32)(uint64(x) & UI64LIT(0x00000000FFFFFFFF))

#define MAKE_PAIR32(l, h) uint32(uint16(l) | (uint32(h) << 16))
#define PAIR32_HIPART(x) (uint16)((uint32(x) >> 16) & 0x0000FFFF)
#define PAIR32_LOPART(x) (uint16)(uint32(x) & 0x0000FFFF)

enum TimeConstants
{
MINUTE = 60,
HOUR = MINUTE*60,
DAY = HOUR*24,
WEEK = DAY*7,
MONTH = DAY*30,
YEAR = MONTH*12,
MINUTE = 60,
HOUR = MINUTE*60,
DAY = HOUR*24,
WEEK = DAY*7,
MONTH = DAY*30,
YEAR = MONTH*12,
IN_MILLISECONDS = 1000
};

@@ -191,23 +160,49 @@ enum AccountTypes

enum LocaleConstant
{
LOCALE_enUS = 0, // also enGB
LOCALE_enUS = 0,
LOCALE_koKR = 1,
LOCALE_frFR = 2,
LOCALE_deDE = 3,
LOCALE_zhCN = 4,
LOCALE_zhTW = 5,
LOCALE_esES = 6,
LOCALE_esMX = 7,
LOCALE_ruRU = 8
LOCALE_ruRU = 8,
LOCALE_itIT = 9,
LOCALE_ptBR = 10,
LOCALE_ptPT = 11
};

const uint8 TOTAL_LOCALES = 9;
const uint8 TOTAL_LOCALES = 12;
#define DEFAULT_LOCALE LOCALE_enUS

#define MAX_LOCALES 11
#define MAX_ACCOUNT_TUTORIAL_VALUES 8

extern char const* localeNames[TOTAL_LOCALES];

LocaleConstant GetLocaleByName(const std::string& name);

typedef std::vector<std::string> StringVector;

#if defined(__GNUC__)
#pragma pack(1)
#else
#pragma pack(push, 1)
#endif

struct LocalizedString
{
char const* Str[TOTAL_LOCALES];
};

#if defined(__GNUC__)
#pragma pack()
#else
#pragma pack(pop)
#endif

// we always use stdlibc++ std::max/std::min, undefine some not C++ standard defines (Win API and some other platforms)
#ifdef max
#undef max
@@ -218,20 +213,25 @@ LocaleConstant GetLocaleByName(const std::string& name);
#endif

#ifndef M_PI
#define M_PI 3.14159265358979323846
#define M_PI 3.14159265358979323846f
#endif

#define SKYFIRE_GUARD(MUTEX, LOCK) \
ACE_Guard< MUTEX > SKYFIRE_GUARD_OBJECT (LOCK); \
if (SKYFIRE_GUARD_OBJECT.locked() == 0) ASSERT(false);
#define MAX_QUERY_LEN 32*1024

# define SKYFIRE_WRITE_GUARD(MUTEX, LOCK) \
ACE_Write_Guard< MUTEX > SKYFIRE_GUARD_OBJECT (LOCK); \
if (SKYFIRE_GUARD_OBJECT.locked() == 0) ASSERT(false);
#define TRINITY_GUARD(MUTEX, LOCK) \
ACE_Guard< MUTEX > TRINITY_GUARD_OBJECT (LOCK); \
if (TRINITY_GUARD_OBJECT.locked() == 0) ASSERT(false);

# define SKYFIRE_READ_GUARD(MUTEX, LOCK) \
ACE_Read_Guard< MUTEX > SKYFIRE_GUARD_OBJECT (LOCK); \
if (SKYFIRE_GUARD_OBJECT.locked() == 0) ASSERT(false);
//! For proper implementation of multiple-read, single-write pattern, use
//! ACE_RW_Mutex as underlying @MUTEX
# define TRINITY_WRITE_GUARD(MUTEX, LOCK) \
ACE_Write_Guard< MUTEX > TRINITY_GUARD_OBJECT (LOCK); \
if (TRINITY_GUARD_OBJECT.locked() == 0) ASSERT(false);

#endif
//! For proper implementation of multiple-read, single-write pattern, use
//! ACE_RW_Mutex as underlying @MUTEX
# define TRINITY_READ_GUARD(MUTEX, LOCK) \
ACE_Read_Guard< MUTEX > TRINITY_GUARD_OBJECT (LOCK); \
if (TRINITY_GUARD_OBJECT.locked() == 0) ASSERT(false);

#endif
@@ -1,12 +1,11 @@
/*
* Copyright (C) 2010-2013 Project SkyFire <https://www.projectskyfire.org/>
* Copyright (C) 2010-2013 Oregon <http://www.oregoncore.com/>
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
@@ -18,15 +17,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SKYFIRE_COMPILERDEFS_H
#define SKYFIRE_COMPILERDEFS_H
#ifndef TRINITY_COMPILERDEFS_H
#define TRINITY_COMPILERDEFS_H

#define PLATFORM_WINDOWS 0
#define PLATFORM_UNIX 1
#define PLATFORM_APPLE 2
#define PLATFORM_INTEL 3

// must be first (win 64 also define WIN32)
// must be first (win 64 also define _WIN32)
#if defined( _WIN64 )
# define PLATFORM PLATFORM_WINDOWS
#elif defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
@@ -52,13 +51,21 @@
# define COMPILER COMPILER_INTEL
#elif defined( __GNUC__ )
# define COMPILER COMPILER_GNU
# define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
# pragma error "FATAL ERROR: Unknown compiler."
# error "FATAL ERROR: Unknown compiler."
#endif

#if COMPILER == COMPILER_MICROSOFT
# pragma warning( disable : 4267 ) // conversion from 'size_t' to 'int', possible loss of data
# pragma warning( disable : 4786 ) // identifier was truncated to '255' characters in the debug information
#if defined(__cplusplus) && __cplusplus == 201103L
# define COMPILER_HAS_CPP11_SUPPORT 1
#else
# define COMPILER_HAS_CPP11_SUPPORT 0
#endif

#if defined(__cplusplus) && __cplusplus == 201402L
# define COMPILER_HAS_CPP14_SUPPORT 1
#else
# define COMPILER_HAS_CPP14_SUPPORT 0
#endif

#endif
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2010-2013 Project SkyFire <https://www.projectskyfire.org/>
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
@@ -18,71 +18,79 @@
*/

#include "Config.h"
#include <ace/Auto_Ptr.h>
#include <ace/Configuration_Import_Export.h>
#include <ace/Thread_Mutex.h>
#include "Errors.h"

namespace ConfigMgr
// Defined here as it must not be exposed to end-users.
bool ConfigMgr::GetValueHelper(const char* name, ACE_TString &result)
{
namespace
{
typedef ACE_Thread_Mutex LockType;
typedef ACE_Guard<LockType> GuardType;

std::string _filename;
ACE_Auto_Ptr<ACE_Configuration_Heap> _config;
LockType m_configLock;

// Defined here as it must not be exposed to end-users.
bool GetValueHelper(const char* name, ACE_TString &result)
{
GuardType guard(m_configLock);

if (_config.get() == 0)
return false;
GuardType guard(_configLock);

ACE_TString section_name;
ACE_Configuration_Section_Key section_key;
const ACE_Configuration_Section_Key &root_key = _config->root_section();
if (_config.get() == 0)
return false;

int i = 0;
while (_config->enumerate_sections(root_key, i, section_name) == 0)
{
_config->open_section(root_key, section_name.c_str(), 0, section_key);
if (_config->get_string_value(section_key, name, result) == 0)
return true;
++i;
}
ACE_TString section_name;
ACE_Configuration_Section_Key section_key;
const ACE_Configuration_Section_Key &root_key = _config->root_section();

return false;
int i = 0;
while (_config->enumerate_sections(root_key, i, section_name) == 0)
{
_config->open_section(root_key, section_name.c_str(), 0, section_key);
if (_config->get_string_value(section_key, name, result) == 0)
return true;
++i;
}

return false;
}

bool Load(const char* file)
bool ConfigMgr::LoadInitial(char const* file)
{
GuardType guard(m_configLock);
ASSERT(file);

if (file)
_filename = file;
GuardType guard(_configLock);

_config.reset(new ACE_Configuration_Heap);
_filename = file;
_config.reset(new ACE_Configuration_Heap());
if (_config->open() == 0)
{
ACE_Ini_ImpExp config_importer(*_config.get());
if (config_importer.import_config(_filename.c_str()) == 0)
if (LoadData(_filename.c_str()))
return true;
}

_config.reset();
return false;
}

std::string GetStringDefault(const char* name, const std::string &def)
bool ConfigMgr::LoadMore(char const* file)
{
ASSERT(file);
ASSERT(_config);

GuardType guard(_configLock);

return LoadData(file);
}

bool ConfigMgr::Reload()
{
return LoadInitial(_filename.c_str());
}

bool ConfigMgr::LoadData(char const* file)
{
ACE_Ini_ImpExp config_importer(*_config.get());
if (config_importer.import_config(file) == 0)
return true;

return false;
}

std::string ConfigMgr::GetStringDefault(const char* name, const std::string &def)
{
ACE_TString val;
return GetValueHelper(name, val) ? val.c_str() : def;
};
}

bool GetBoolDefault(const char* name, bool def)
bool ConfigMgr::GetBoolDefault(const char* name, bool def)
{
ACE_TString val;

@@ -91,23 +99,54 @@ bool GetBoolDefault(const char* name, bool def)

return (val == "true" || val == "TRUE" || val == "yes" || val == "YES" ||
val == "1");
};
}

int GetIntDefault(const char* name, int def)
int ConfigMgr::GetIntDefault(const char* name, int def)
{
ACE_TString val;
return GetValueHelper(name, val) ? atoi(val.c_str()) : def;
};
}

float GetFloatDefault(const char* name, float def)
float ConfigMgr::GetFloatDefault(const char* name, float def)
{
ACE_TString val;
return GetValueHelper(name, val) ? (float)atof(val.c_str()) : def;
};
}

const std::string & GetFilename()
std::string const& ConfigMgr::GetFilename()
{
GuardType guard(m_configLock);
GuardType guard(_configLock);
return _filename;
}
} // namespace

std::list<std::string> ConfigMgr::GetKeysByString(std::string const& name)
{
GuardType guard(_configLock);

std::list<std::string> keys;
if (_config.get() == 0)
return keys;

ACE_TString section_name;
ACE_Configuration_Section_Key section_key;
const ACE_Configuration_Section_Key &root_key = _config->root_section();

int i = 0;
while (_config->enumerate_sections(root_key, i++, section_name) == 0)
{
_config->open_section(root_key, section_name.c_str(), 0, section_key);

ACE_TString key_name;
ACE_Configuration::VALUETYPE type;
int j = 0;
while (_config->enumerate_values(section_key, j++, key_name, type) == 0)
{
std::string temp = key_name.c_str();

if (!temp.find(name))
keys.push_back(temp);
}
}

return keys;
}
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2010-2013 Project SkyFire <https://www.projectskyfire.org/>
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
@@ -21,17 +21,59 @@
#define CONFIG_H

#include <string>
#include <list>
#include <ace/Singleton.h>
#include <ace/Configuration_Import_Export.h>
#include <ace/Thread_Mutex.h>
#include <AutoPtr.h>

namespace ConfigMgr
typedef Trinity::AutoPtr<ACE_Configuration_Heap, ACE_Null_Mutex> Config;

class ConfigMgr
{
bool Load(const char *file = NULL);
friend class ACE_Singleton<ConfigMgr, ACE_Null_Mutex>;
friend class ConfigLoader;

ConfigMgr() { }
~ConfigMgr() { }

public:
/// Method used only for loading main configuration files (authserver.conf and worldserver.conf)
bool LoadInitial(char const* file);

/**
* This method loads additional configuration files
* It is recommended to use this method in WorldScript::OnConfigLoad hooks
*
* @return true if loading was successful
*/
bool LoadMore(char const* file);

bool Reload();

std::string GetStringDefault(const char* name, const std::string& def);
bool GetBoolDefault(const char* name, bool def);
int GetIntDefault(const char* name, int def);
float GetFloatDefault(const char* name, float def);

const std::string & GetFilename();
}
std::string const& GetFilename();
std::list<std::string> GetKeysByString(std::string const& name);

private:
bool GetValueHelper(const char* name, ACE_TString &result);
bool LoadData(char const* file);

typedef ACE_Thread_Mutex LockType;
typedef ACE_Guard<LockType> GuardType;

std::string _filename;
Config _config;
LockType _configLock;

ConfigMgr(ConfigMgr const&);
ConfigMgr& operator=(ConfigMgr const&);
};

#define sConfigMgr ACE_Singleton<ConfigMgr, ACE_Null_Mutex>::instance()

#endif
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TRINITY_CONTAINERS_H
#define TRINITY_CONTAINERS_H

#include "Define.h"
#include <list>

//! Because circular includes are bad
extern uint32 urand(uint32 min, uint32 max);

namespace Trinity
{
namespace Containers
{
template<class T>
void RandomResizeList(std::list<T> &list, uint32 size)
{
size_t list_size = list.size();

while (list_size > size)
{
typename std::list<T>::iterator itr = list.begin();
std::advance(itr, urand(0, list_size - 1));
list.erase(itr);
--list_size;
}
}

template<class T, class Predicate>
void RandomResizeList(std::list<T> &list, Predicate& predicate, uint32 size)
{
//! First use predicate filter
std::list<T> listCopy;
for (typename std::list<T>::iterator itr = list.begin(); itr != list.end(); ++itr)
if (predicate(*itr))
listCopy.push_back(*itr);

if (size)
RandomResizeList(listCopy, size);

list = listCopy;
}

/* Select a random element from a container. Note: make sure you explicitly empty check the container */
template <class C> typename C::value_type const& SelectRandomContainerElement(C const& container)
{
typename C::const_iterator it = container.begin();
std::advance(it, urand(0, container.size() - 1));
return *it;
}
}
//! namespace Containers
}
//! namespace Trinity

#endif //! #ifdef TRINITY_CONTAINERS_H