mirror of
https://github.com/ENSL/NS.git
synced 2024-11-29 15:51:51 +00:00
58358d0927
* Initial bot commit * Added server commands and cvars for adding AI players to the game. * Added auto modes for automating the adding and removal of bots * Bots connect to the server and join teams correctly * Added round restart and new map detection for AI system Push before new project added for detour * Initial bot integration * Integrated all basic bot code for navigation and task performing * Added support for multi_managers to better understand how buttons and triggers affect doors * Improved bot understanding of door triggers and weldables * Reworked nav profiles Nav profiles for bots are now dynamically updated to take into account changing capabilities, such as picking up a welder * Improved bot door usage * Added weldable obstacles back into navigation Bots now understand how to get around weldable barriers * Replaced fixed arrays with vectors * Resource node and hive lists are now vectors. * Further improved bot weld behaviour * Added dynamic reachability calculations When barriers and doors are open/closed, new reachability calculations are done for structures and items so bots understand when items/structures become reachable or unreachable as the match progresses. * Added team-based reachability calculations Reachabilities for structures and items are now based on the team, so bots understand when they can't reach a structure from their spawn point. * Implemented long-range off-mesh connections and dynamic off-mesh connections * Implemented fully dynamic off-mesh connections Phase gates now use connections rather than custom path finding. Much more performant. * Replaced arrays with vectors for simpler code * Started Bot Swimming * Bots understand trigger_changetarget Bots can now navigate doors operated with a trigger_changetarget so they understand the sequence in which triggers must be activated to make it work * Push before trying to fix long-range connections * Implement new off-mesh connection system * Redid population of door triggers * Fixed trigger types and links to doors * Added lift and moving platform support * Lift improvements * Bots avoid getting crushed under a lift when summoning it * Bots are better at judging which stop a platform needs to be at * Tweak lift and welder usage * Fixed bug with multiple off-mesh connections close together * Finish lift movement * Fixed dodgy path finding * Improved skulk ladder usage and lerk lift usage * Fix crash with path finding * Re-implement commander AI * Commander improvements * Improve commander sieging * Commander scanning tweak * Reimplemented regular marine AI * Start reimplementing alien AI * Implement gorge building behaviours * Start alien tactical decisioning * Continuing alien building and other non-combat logic * More alien role work * Adjusted base node definitions * Iterate Capper Logic * Alien assault AI * Alien Combat * Fix grenade throwing, better combat * Marine combat AI improvements * Commander improvements * Commander + nav improvements * Drop mines * Improved bot stuck detection * Commander supply improvements * Bot fill timing config * Added nsbots.cfg to configure internal bots * Changed bot config file to "nsbots.cfg" * Bug fixing with navigation * Fix skulk movement on ladders * Improved commander placement and tactical refresh * Fixed bug with ladder climbing * Doors block off-mesh connections * Finished doors blocking connections * Marine and alien tactical bug fixes * Add commander beacon back in * Start combat mode stuff * First pass at combat mode * Bots attack turrets * Fix ladder and wall climbing * Commander chat request * Improved skulk ladders * Added nav meshes for new bot code * Added bot configuration to listen server menu * Added bot config file * Added default bot config to listenserver.cfg * Added default bot settings to server.cfg * Include VS filter for bot files * Crash fixes * Bot improvements * Bot stability and mine placement improvements * Fixed crash on new map start with bots * Reverted Svencoop fix * Fixed crash, added more cvars * Performance improvement * Commander building improvements * Stop bot spasming when waiting to take command * Fixed doors not blocking connections * Added bot disabled guard to round start * Commander improvements, movement improvements * Tweaked level load sequence * Performance improvements * Bot load spread * Fixed commander update * Refactor bot frame handling * Bug fixes + Pierow's dynamic load spread * Minor bug fixes * Fix door detection, prep for test * Fixed commander siege spam * linux compile test * fix hardcoded inlcudes * O1 compile flag for detour - fix linux server crash * Revert detour compile flags to original for windows * linux build update * remove x64 build configs * update bot nav meshes and configs * fix bot physics at high server fps, update navmeshes. from @RGreenlees --------- Co-authored-by: RGreenlees <RGreenlees@users.noreply.github.com> Co-authored-by: RichardGreenlees <richard.greenlees@forecast.global>
387 lines
9.6 KiB
C++
387 lines
9.6 KiB
C++
//
|
|
// 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 "DetourCommon.h"
|
|
#include "DetourMath.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
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)
|
|
{
|
|
const float EPS = 1e-6f;
|
|
float v0[3], v1[3], v2[3];
|
|
|
|
dtVsub(v0, c, a);
|
|
dtVsub(v1, b, a);
|
|
dtVsub(v2, p, a);
|
|
|
|
// Compute scaled barycentric coordinates
|
|
float denom = v0[0] * v1[2] - v0[2] * v1[0];
|
|
if (fabsf(denom) < EPS)
|
|
return false;
|
|
|
|
float u = v1[2] * v2[0] - v1[0] * v2[2];
|
|
float v = v0[0] * v2[2] - v0[2] * v2[0];
|
|
|
|
if (denom < 0) {
|
|
denom = -denom;
|
|
u = -u;
|
|
v = -v;
|
|
}
|
|
|
|
// If point lies inside the triangle, return interpolated ycoord.
|
|
if (u >= 0.0f && v >= 0.0f && (u + v) <= denom) {
|
|
h = a[1] + (v0[1] * u + v1[1] * v) / denom;
|
|
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 = 1.0f;
|
|
int tri = npts - 1;
|
|
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 = dtMathSqrtf(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;
|
|
}
|
|
|