Fix submodules tf

This commit is contained in:
bencat07 2018-08-14 00:32:23 +02:00
parent 35e307e1af
commit fa0ba8d86b
22 changed files with 4 additions and 3532 deletions

4
.gitmodules vendored
View File

@ -20,5 +20,5 @@
path = include/TF2_NavFile_Reader
url = https://github.com/nullworks/TF2_NavFile_Reader.git
[submodule "external/MicroPather"]
path = src/MicroPather
url = https://github.com/leethomason/MicroPather.git
path = external/MicroPather
url = https://github.com/leethomason/MicroPather

1
external/MicroPather vendored Submodule

@ -0,0 +1 @@
Subproject commit 33a3b8403f1bc3937c9d364fe6c3977169bee3b5

View File

@ -1,113 +0,0 @@
#****************************************************************************
#
# Makefile for Micropather test.
# Lee Thomason
# www.grinninglizard.com
#
# This is a GNU make (gmake) makefile
#****************************************************************************
# DEBUG can be set to YES to include debugging info, or NO otherwise
DEBUG := NO
# PROFILE can be set to YES to include profiling info, or NO otherwise
PROFILE := NO
#****************************************************************************
CC := gcc
CXX := g++
LD := g++
AR := ar rc
RANLIB := ranlib
DEBUG_CFLAGS := -Wall -Wno-format -g -DDEBUG -std=c++11
RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-format -O3 -std=c++11
LIBS :=
DEBUG_CXXFLAGS := ${DEBUG_CFLAGS}
RELEASE_CXXFLAGS := ${RELEASE_CFLAGS}
DEBUG_LDFLAGS := -g
RELEASE_LDFLAGS :=
ifeq (YES, ${DEBUG})
CFLAGS := ${DEBUG_CFLAGS}
CXXFLAGS := ${DEBUG_CXXFLAGS}
LDFLAGS := ${DEBUG_LDFLAGS}
else
CFLAGS := ${RELEASE_CFLAGS}
CXXFLAGS := ${RELEASE_CXXFLAGS}
LDFLAGS := ${RELEASE_LDFLAGS}
endif
ifeq (YES, ${PROFILE})
CFLAGS := ${CFLAGS} -pg -O3
CXXFLAGS := ${CXXFLAGS} -pg -O3
LDFLAGS := ${LDFLAGS} -pg
endif
#****************************************************************************
# Preprocessor directives
#****************************************************************************
#****************************************************************************
# Include paths
#****************************************************************************
#INCS := -I/usr/include/g++-2 -I/usr/local/include
INCS :=
#****************************************************************************
# Makefile code common to all platforms
#****************************************************************************
CFLAGS := ${CFLAGS} ${DEFS}
CXXFLAGS := ${CXXFLAGS} ${DEFS}
#****************************************************************************
# Targets of the build
#****************************************************************************
OUTPUT := speed
all: ${OUTPUT}
#****************************************************************************
# Source files
#****************************************************************************
SRCS := micropather.cpp speed.cpp
# Add on the sources for libraries
SRCS := ${SRCS}
OBJS := $(addsuffix .o,$(basename ${SRCS}))
#****************************************************************************
# Output
#****************************************************************************
${OUTPUT}: ${OBJS}
${LD} -o $@ ${LDFLAGS} ${OBJS} ${LIBS} ${EXTRA_LIBS}
#****************************************************************************
# common rules
#****************************************************************************
# Rules for compiling source files to object files
%.o : %.cpp
${CXX} -c ${CXXFLAGS} ${INCS} $< -o $@
%.o : %.c
${CC} -c ${CFLAGS} ${INCS} $< -o $@
clean:
-rm -f core ${OBJS} ${OUTPUT}
micropather.o: micropather.h
speed.o: micropather.h

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,305 +0,0 @@
/*
Copyright (c) 2000-2012 Lee Thomason (www.grinninglizard.com)
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_PATHER
#include <ctype.h>
#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <vector>
#include <iostream>
#ifdef USE_PATHER
#include "micropather.h"
using namespace micropather;
#endif
const int MAPX = 30;
const int MAPY = 10;
const char gMap[MAPX*MAPY+1] =
//"012345678901234567890123456789"
" | | |"
" | |----+ | +"
"---+ +---DD-+ +--+--+ "
" | +-- +"
" +----+ +---+ "
"---+ + D D | "
" | | +----+ +----+ +--+"
" D | | | "
" | +-------+ +-+ |--+ "
"---+ | +";
class Dungeon
#ifdef USE_PATHER
: public Graph
#endif
{
private:
Dungeon( const Dungeon& );
void operator=( const Dungeon& );
int playerX, playerY;
MPVector<void*> path;
bool doorsOpen;
bool showConsidered;
MicroPather* pather;
public:
Dungeon() : playerX( 0 ), playerY( 0 ), doorsOpen( false ), showConsidered( false ), pather( 0 )
{
pather = new MicroPather( this, 20 ); // Use a very small memory block to stress the pather
}
virtual ~Dungeon() {
delete pather;
}
int X() { return playerX; }
int Y() { return playerY; }
void ClearPath()
{
#ifdef USE_PATHER
path.resize( 0 );
#endif
}
void ToggleTouched() { showConsidered = !showConsidered;
pather->Reset();
}
void ToggleDoor()
{
doorsOpen = !doorsOpen;
#ifdef USE_PATHER
pather->Reset();
#endif
}
int Passable( int nx, int ny )
{
if ( nx >= 0 && nx < MAPX
&& ny >= 0 && ny < MAPY )
{
int index = ny*MAPX+nx;
char c = gMap[ index ];
if ( c == ' ' )
return 1;
else if ( c == 'D' )
return 2;
}
return 0;
}
int SetPos( int nx, int ny )
{
int result = 0;
if ( Passable( nx, ny ) == 1 )
{
#ifdef USE_PATHER
float totalCost;
if ( showConsidered )
pather->Reset();
result = pather->Solve( XYToNode( playerX, playerY ), XYToNode( nx, ny ), &path, &totalCost );
if ( result == MicroPather::SOLVED ) {
playerX = nx;
playerY = ny;
}
printf( "Pather returned %d\n", result );
#else
playerX = nx;
playerY = ny;
#endif
}
return result;
}
void Print()
{
char buf[ MAPX+1 ];
MPVector< void* > stateVec;
if ( showConsidered )
pather->StatesInPool( &stateVec );
printf( " doors %s\n", doorsOpen ? "open" : "closed" );
printf( " 0 10 20\n" );
printf( " 012345678901234567890123456789\n" );
for( int j=0; j<MAPY; ++j ) {
// Copy in the line.
memcpy( buf, &gMap[MAPX*j], MAPX+1 );
buf[MAPX]=0;
#ifdef USE_PATHER
unsigned k;
// Wildly inefficient demo code.
unsigned size = path.size();
for( k=0; k<size; ++k ) {
int x, y;
NodeToXY( path[k], &x, &y );
if ( y == j )
buf[x] = '0' + k%10;
}
if ( showConsidered )
{
for( k=0; k<stateVec.size(); ++k ) {
int x, y;
NodeToXY( stateVec[k], &x, &y );
if ( y == j )
buf[x] = 'x';
}
}
#endif
// Insert the player
if ( j==playerY )
buf[playerX] = 'i';
printf( "%d%s\n", j%10, buf );
}
}
#ifdef USE_PATHER
void NodeToXY( void* node, int* x, int* y )
{
intptr_t index = (intptr_t)node;
*y = index / MAPX;
*x = index - *y * MAPX;
}
void* XYToNode( int x, int y )
{
return (void*) ( y*MAPX + x );
}
virtual float LeastCostEstimate( void* nodeStart, void* nodeEnd )
{
int xStart, yStart, xEnd, yEnd;
NodeToXY( nodeStart, &xStart, &yStart );
NodeToXY( nodeEnd, &xEnd, &yEnd );
/* Compute the minimum path cost using distance measurement. It is possible
to compute the exact minimum path using the fact that you can move only
on a straight line or on a diagonal, and this will yield a better result.
*/
int dx = xStart - xEnd;
int dy = yStart - yEnd;
return (float) sqrt( (double)(dx*dx) + (double)(dy*dy) );
}
virtual void AdjacentCost( void* node, micropather::MPVector< StateCost > *neighbors )
{
int x, y;
const int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
const int dy[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
const float cost[8] = { 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f };
NodeToXY( node, &x, &y );
for( int i=0; i<8; ++i ) {
int nx = x + dx[i];
int ny = y + dy[i];
int pass = Passable( nx, ny );
if ( pass > 0 ) {
if ( pass == 1 || doorsOpen )
{
// Normal floor
StateCost nodeCost = { XYToNode( nx, ny ), cost[i] };
neighbors->push_back( nodeCost );
}
else
{
// Normal floor
StateCost nodeCost = { XYToNode( nx, ny ), FLT_MAX };
neighbors->push_back( nodeCost );
}
}
}
}
virtual void PrintStateInfo( void* node )
{
int x, y;
NodeToXY( node, &x, &y );
printf( "(%d,%d)", x, y );
}
#endif
};
int main( int /*argc*/, const char** /*argv*/ )
{
Dungeon dungeon;
bool done = false;
char buf[ 256 ];
while ( !done ) {
dungeon.Print();
printf( "\n# # to move, q to quit, r to redraw, d to toggle doors, t for touched\n" );
//gets( buf );
//printf( "\n" );
std::cin.getline( buf, 256 );
if ( *buf )
{
if ( buf[0] == 'q' ) {
done = true;
}
else if ( buf[0] == 'd' ) {
dungeon.ToggleDoor();
dungeon.ClearPath();
}
else if ( buf[0] == 't' ) {
dungeon.ToggleTouched();
}
else if ( buf[0] == 'r' ) {
dungeon.ClearPath();
}
else if ( isdigit( buf[0] ) ) {
int x, y;
sscanf( buf, "%d %d", &x, &y ); // sleazy, I know
dungeon.SetPos( x, y );
}
}
else
{
dungeon.ClearPath();
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,509 +0,0 @@
/*
Copyright (c) 2000-2013 Lee Thomason (www.grinninglizard.com)
Micropather
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 GRINNINGLIZARD_MICROPATHER_INCLUDED
#define GRINNINGLIZARD_MICROPATHER_INCLUDED
/** @mainpage MicroPather
MicroPather is a path finder and A* solver (astar or a-star) written in platform independent
C++ that can be easily integrated into existing code. MicroPather focuses on being a path
finding engine for video games but is a generic A* solver. MicroPather is open source, with
a license suitable for open source or commercial use.
*/
// This probably works to remove, but isn't currently tested in STL mode.
#define GRINLIZ_NO_STL
#ifdef GRINLIZ_NO_STL
# define MP_VECTOR micropather::MPVector
#else
# include <vector>
# define MP_VECTOR std::vector
#endif
#include <float.h>
#ifdef _DEBUG
#ifndef DEBUG
#define DEBUG
#endif
#endif
#if defined(DEBUG)
# if defined(_MSC_VER)
# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
# define MPASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
# elif defined (ANDROID_NDK)
# include <android/log.h>
# define MPASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
# else
# include <assert.h>
# define MPASSERT assert
# endif
# else
# define MPASSERT( x ) {}
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
#include <stdlib.h>
typedef uintptr_t MP_UPTR;
#elif defined (__GNUC__) && (__GNUC__ >= 3 )
#include <stdint.h>
#include <stdlib.h>
typedef uintptr_t MP_UPTR;
#else
// Assume not 64 bit pointers. Get a new compiler.
typedef unsigned MP_UPTR;
#endif
namespace micropather
{
#ifdef GRINLIZ_NO_STL
/* WARNING: vector partial replacement. Does everything needed to replace std::vector
for micropather, but only works on Plain Old Data types. Doesn't call copy/construct/destruct
correctly for general use.
*/
template <typename T>
class MPVector {
public:
MPVector() : m_allocated( 0 ), m_size( 0 ), m_buf ( 0 ) {}
~MPVector() { delete [] m_buf; }
void clear() { m_size = 0; } // see warning above
void resize( unsigned s ) { capacity( s );
m_size = s;
}
T& operator[](unsigned i) { MPASSERT( i>=0 && i<m_size );
return m_buf[i];
}
const T& operator[](unsigned i) const { MPASSERT( i>=0 && i<m_size );
return m_buf[i];
}
void push_back( const T& t ) { capacity( m_size+1 );
m_buf[m_size++] = t;
}
unsigned size() const { return m_size; }
private:
void capacity( unsigned cap ) {
if ( m_allocated < cap ) {
unsigned newAllocated = cap * 3/2 + 16;
T* newBuf = new T[newAllocated];
MPASSERT( m_size <= m_allocated );
MPASSERT( m_size < newAllocated );
memcpy( newBuf, m_buf, sizeof(T)*m_size );
delete [] m_buf;
m_buf = newBuf;
m_allocated = newAllocated;
}
}
unsigned m_allocated;
unsigned m_size;
T* m_buf;
};
#endif
/**
Used to pass the cost of states from the cliet application to MicroPather. This
structure is copied in a vector.
@sa AdjacentCost
*/
struct StateCost
{
void* state; ///< The state as a void*
float cost; ///< The cost to the state. Use FLT_MAX for infinite cost.
};
/**
A pure abstract class used to define a set of callbacks.
The client application inherits from
this class, and the methods will be called when MicroPather::Solve() is invoked.
The notion of a "state" is very important. It must have the following properties:
- Unique
- Unchanging (unless MicroPather::Reset() is called)
If the client application represents states as objects, then the state is usually
just the object cast to a void*. If the client application sees states as numerical
values, (x,y) for example, then state is an encoding of these values. MicroPather
never interprets or modifies the value of state.
*/
class Graph
{
public:
virtual ~Graph() {}
/**
Return the least possible cost between 2 states. For example, if your pathfinding
is based on distance, this is simply the straight distance between 2 points on the
map. If you pathfinding is based on minimum time, it is the minimal travel time
between 2 points given the best possible terrain.
*/
virtual float LeastCostEstimate( void* stateStart, void* stateEnd ) = 0;
/**
Return the exact cost from the given state to all its neighboring states. This
may be called multiple times, or cached by the solver. It *must* return the same
exact values for every call to MicroPather::Solve(). It should generally be a simple,
fast function with no callbacks into the pather.
*/
virtual void AdjacentCost( void* state, MP_VECTOR< micropather::StateCost > *adjacent ) = 0;
/**
This function is only used in DEBUG mode - it dumps output to stdout. Since void*
aren't really human readable, normally you print out some concise info (like "(1,2)")
without an ending newline.
*/
virtual void PrintStateInfo( void* state ) = 0;
};
class PathNode;
struct NodeCost
{
PathNode* node;
float cost;
};
/*
Every state (void*) is represented by a PathNode in MicroPather. There
can only be one PathNode for a given state.
*/
class PathNode
{
public:
void Init( unsigned _frame,
void* _state,
float _costFromStart,
float _estToGoal,
PathNode* _parent );
void Clear();
void InitSentinel() {
Clear();
Init( 0, 0, FLT_MAX, FLT_MAX, 0 );
prev = next = this;
}
void *state; // the client state
float costFromStart; // exact
float estToGoal; // estimated
float totalCost; // could be a function, but save some math.
PathNode* parent; // the parent is used to reconstruct the path
unsigned frame; // unique id for this path, so the solver can distinguish
// correct from stale values
int numAdjacent; // -1 is unknown & needs to be queried
int cacheIndex; // position in cache
PathNode *child[2]; // Binary search in the hash table. [left, right]
PathNode *next, *prev; // used by open queue
bool inOpen;
bool inClosed;
void Unlink() {
next->prev = prev;
prev->next = next;
next = prev = 0;
}
void AddBefore( PathNode* addThis ) {
addThis->next = this;
addThis->prev = prev;
prev->next = addThis;
prev = addThis;
}
#ifdef DEBUG
void CheckList()
{
MPASSERT( totalCost == FLT_MAX );
for( PathNode* it = next; it != this; it=it->next ) {
MPASSERT( it->prev == this || it->totalCost >= it->prev->totalCost );
MPASSERT( it->totalCost <= it->next->totalCost );
}
}
#endif
void CalcTotalCost() {
if ( costFromStart < FLT_MAX && estToGoal < FLT_MAX )
totalCost = costFromStart + estToGoal;
else
totalCost = FLT_MAX;
}
private:
void operator=( const PathNode& );
};
/* Memory manager for the PathNodes. */
class PathNodePool
{
public:
PathNodePool( unsigned allocate, unsigned typicalAdjacent );
~PathNodePool();
// Free all the memory except the first block. Resets all memory.
void Clear();
// Essentially:
// pNode = Find();
// if ( !pNode )
// pNode = New();
//
// Get the PathNode associated with this state. If the PathNode already
// exists (allocated and is on the current frame), it will be returned.
// Else a new PathNode is allocated and returned. The returned object
// is always fully initialized.
//
// NOTE: if the pathNode exists (and is current) all the initialization
// parameters are ignored.
PathNode* GetPathNode( unsigned frame,
void* _state,
float _costFromStart,
float _estToGoal,
PathNode* _parent );
// Get a pathnode that is already in the pool.
PathNode* FetchPathNode( void* state );
// Store stuff in cache
bool PushCache( const NodeCost* nodes, int nNodes, int* start );
// Get neighbors from the cache
// Note - always access this with an offset. Can get re-allocated.
void GetCache( int start, int nNodes, NodeCost* nodes );
// Return all the allocated states. Useful for visuallizing what
// the pather is doing.
void AllStates( unsigned frame, MP_VECTOR< void* >* stateVec );
private:
struct Block
{
Block* nextBlock;
PathNode pathNode[1];
};
unsigned Hash( void* voidval );
unsigned HashSize() const { return 1<<hashShift; }
unsigned HashMask() const { return ((1<<hashShift)-1); }
void AddPathNode( unsigned key, PathNode* p );
Block* NewBlock();
PathNode* Alloc();
PathNode** hashTable;
Block* firstBlock;
Block* blocks;
NodeCost* cache;
int cacheCap;
int cacheSize;
PathNode freeMemSentinel;
unsigned allocate; // how big a block of pathnodes to allocate at once
unsigned nAllocated; // number of pathnodes allocated (from Alloc())
unsigned nAvailable; // number available for allocation
unsigned hashShift;
unsigned totalCollide;
};
/* Used to cache results of paths. Much, much faster
to return an existing solution than to calculate
a new one. A post on this is here: http://grinninglizard.com/altera/programming/a-path-caching-2/
*/
class PathCache
{
public:
struct Item {
// The key:
void* start;
void* end;
bool KeyEqual( const Item& item ) const { return start == item.start && end == item.end; }
bool Empty() const { return start == 0 && end == 0; }
// Data:
void* next;
float cost; // from 'start' to 'next'. FLT_MAX if unsolveable.
unsigned Hash() const {
const unsigned char *p = (const unsigned char *)(&start);
unsigned int h = 2166136261U;
for( unsigned i=0; i<sizeof(void*)*2; ++i, ++p ) {
h ^= *p;
h *= 16777619;
}
return h;
}
};
PathCache( int itemsToAllocate );
~PathCache();
void Reset();
void Add( const MP_VECTOR< void* >& path, const MP_VECTOR< float >& cost );
void AddNoSolution( void* end, void* states[], int count );
int Solve( void* startState, void* endState, MP_VECTOR< void* >* path, float* totalCost );
int AllocatedBytes() const { return allocated * sizeof(Item); }
int UsedBytes() const { return nItems * sizeof(Item); }
int hit;
int miss;
private:
void AddItem( const Item& item );
const Item* Find( void* start, void* end );
Item* mem;
int allocated;
int nItems;
};
struct CacheData {
CacheData() : nBytesAllocated(0), nBytesUsed(0), memoryFraction(0), hit(0), miss(0), hitFraction(0) {}
int nBytesAllocated;
int nBytesUsed;
float memoryFraction;
int hit;
int miss;
float hitFraction;
};
/**
Create a MicroPather object to solve for a best path. Detailed usage notes are
on the main page.
*/
class MicroPather
{
friend class micropather::PathNode;
public:
enum
{
SOLVED,
NO_SOLUTION,
START_END_SAME,
// internal
NOT_CACHED
};
/**
Construct the pather, passing a pointer to the object that implements
the Graph callbacks.
@param graph The "map" that implements the Graph callbacks.
@param allocate How many states should be internally allocated at a time. This
can be hard to get correct. The higher the value, the more memory
MicroPather will use.
- If you have a small map (a few thousand states?) it may make sense
to pass in the maximum value. This will cache everything, and MicroPather
will only need one main memory allocation. For a chess board, allocate
would be set to 8x8 (64)
- If your map is large, something like 1/4 the number of possible
states is good.
- If your state space is huge, use a multiple (5-10x) of the normal
path. "Occasionally" call Reset() to free unused memory.
@param typicalAdjacent Used to determine cache size. The typical number of adjacent states
to a given state. (On a chessboard, 8.) Higher values use a little
more memory.
@param cache Turn on path caching. Uses more memory (yet again) but at a huge speed
advantage if you may call the pather with the same path or sub-path, which
is common for pathing over maps in games.
*/
MicroPather( Graph* graph, unsigned allocate = 250, unsigned typicalAdjacent=6, bool cache=true );
~MicroPather();
/**
Solve for the path from start to end.
@param startState Input, the starting state for the path.
@param endState Input, the ending state for the path.
@param path Output, a vector of states that define the path. Empty if not found.
@param totalCost Output, the cost of the path, if found.
@return Success or failure, expressed as SOLVED, NO_SOLUTION, or START_END_SAME.
*/
int Solve( void* startState, void* endState, MP_VECTOR< void* >* path, float* totalCost );
/**
Find all the states within a given cost from startState.
@param startState Input, the starting state for the path.
@param near All the states within 'maxCost' of 'startState', and cost to that state.
@param maxCost Input, the maximum cost that will be returned. (Higher values return
larger 'near' sets and take more time to compute.)
@return Success or failure, expressed as SOLVED or NO_SOLUTION.
*/
int SolveForNearStates( void* startState, MP_VECTOR< StateCost >* near, float maxCost );
/** Should be called whenever the cost between states or the connection between states changes.
Also frees overhead memory used by MicroPather, and calling will free excess memory.
*/
void Reset();
// Debugging function to return all states that were used by the last "solve"
void StatesInPool( MP_VECTOR< void* >* stateVec );
void GetCacheData( CacheData* data );
private:
MicroPather( const MicroPather& ); // undefined and unsupported
void operator=( const MicroPather ); // undefined and unsupported
void GoalReached( PathNode* node, void* start, void* end, MP_VECTOR< void* > *path );
void GetNodeNeighbors( PathNode* node, MP_VECTOR< NodeCost >* neighborNode );
#ifdef DEBUG
//void DumpStats();
#endif
PathNodePool pathNodePool;
MP_VECTOR< StateCost > stateCostVec; // local to Solve, but put here to reduce memory allocation
MP_VECTOR< NodeCost > nodeCostVec; // local to Solve, but put here to reduce memory allocation
MP_VECTOR< float > costVec;
Graph* graph;
unsigned frame; // incremented with every solve, used to determine if cached data needs to be refreshed
PathCache* pathCache;
};
}; // namespace grinliz
#endif

View File

@ -1,181 +0,0 @@
MicroPather
===========
MicroPather is a path finder and A* solver (astar or a-star) written in platform
independent C++ that can be easily integrated into existing code. MicroPather
focuses on being a path finding engine for video games but is a generic A* solver.
MicroPather is open source, with a license suitable for open source or commercial
use.
The goals of MicroPather are:
* Easy integration into games and other software
* Easy to use and simple interface
* Fast enough
Demo
----
MicroPather comes with a demo application - dungeon.cpp - to show off pathing.
It's ASCII art dungeon exploring at its finest.
The demo shows an ASCII art dungeon. You can move around by typing a new location, and it will
print the path to that location. In the screen shot above, the path starts in
the upper left corner, and steps to the 'i' at about the middle of
the screen avoiding ASCII walls on the way. The numbers show the path from 0
to 9 then back to 0.
You can even open and close the doors to change possible paths. 'd' at the command prompt.
A Windows Visual C++ 2010 project file and a Linux Makefile are provided. Building it
for another environment is trivial: just compile dungeon.cpp, micropather.h, and
micropather.cpp to a command line app in your environment.
About A*
--------
In video games, the pathfinding problem comes up in many modern games. What
is the shortest distance from point A to point B? Humans are good at that problem
- you pathfind naturally almost every time you move - but tricky to express
as a computer algorithm. A* is the workhorse technique to solve pathing. It
is directed, meaning that it is optimized to find a solution quickly rather
than by brute force, but it will never fail to find a solution if there is one.
A* is much more universal that just pathfinding. A* and MicroPather could be
used to find the solution to general state problems, for example it could be
used to solve for a rubiks cube puzzle.
Terminology
-----------
The *Graph* is the search space. For the pathfinding problem,
this is your Map. It can be any kind of map: squares like the dungeon example,
polygonal, 3D, hexagons, etc.
In pathfinding, a *State* is just a position on the Map. In
the demo, the player starts at State (0,0). Adjacent states are very important,
as you might image. If something is at state (1,1) in the dungeon example,
it has 8 adjacent states (0,1), (2,1) etc. it can move to. Why State instead
of location or node? The terminology comes from the more general application.
The states of a cube puzzle aren't locations, for example.
States are separated by *Cost*. For simple pathfinding in
the dungeon, the *Cost* is simply distance. The cost from state
(0,0) to (1,0) is 1.0, and the cost from (0,0) to (1,1) is sqrt(2), about
1.4. *Cost* is challenging and interesting because it can be
distance, time, or difficulty.
* using distance as the cost will give the shortest length path
* using traversal time as the cost will give the fastest path
* using difficulty as the cost will give the easiest path
etc.
More info: http://www-cs-students.stanford.edu/~amitp/gameprog.html#paths
Integrating MicroPather Into Your Code
--------------------------------------
Nothing could by simpler! Or at least that's the goal. More importantly, none
of your game data structures need to change to use MicroPather. The steps, in
brief, are:
1. Include MicroPather files</p>
2. Implement the Graph interface</p>
3. Call the Solver</p>
*Include files*
There are only 2 files for micropather: micropather.cpp and micropather.h.
So there's no build, no make, just add the 2 files to your project. That's it.
They are standard C++ and don't require exceptions or RTTI. (I know, a bunch
of you like exceptions and RTTI. But it does make it less portable and slightly
slower to use them.)
Assuming you build a debug version of your project with _DEBUG or DEBUG (and
everyone does) MicroPather will run extra checking in these modes.
*Implement Graph Interface*
You have some class called Game, or Map, or World, that organizes and stores
your game map. This object (we'll call it Map) needs to inherit from the abstract
class Graph:
class Map : public Graph
Graph is pure abstract, so your map class won't be changed by it (except for
possibly gaining a vtable), or have strange conflicts.
Before getting to the methods of Graph, lets think states, as in:
void Foo( void* state )
The state pointer is provided by you, the game programmer. What it is? It is
a unique id for a state. For something like a 3D terrain map, like Lilith3D
uses, the states are pointers to a map structure, a 'QuadNode' in
this case. So the state would simply be:
void* state = (void*) quadNode;
On the other hand, the Dungeon example doesn't have an object per map location,
just an x and y. It then uses:
void* state = (void*)( y * MAPX + x );
The state can be anything you want, as long as it is unique and you can convert
to it and from it.
Now, the methods of Graph.
/**
Return the least possible cost between 2 states. For example, if your pathfinding
is based on distance, this is simply the straight distance between 2 points on the
map. If you pathfinding is based on minimum time, it is the minimal travel time
between 2 points given the best possible terrain.
*/
virtual float LeastCostEstimate( void* stateStart, void* stateEnd ) = 0;
/**
Return the exact cost from the given state to all its neighboring states. This
may be called multiple times, or cached by the solver. It *must* return the same
exact values for every call to MicroPather::Solve(). It should generally be a simple,
fast function with no callbacks into the pather.
*/
virtual void AdjacentCost( void* state, MP_VECTOR< micropather::StateCost > *adjacent ) = 0;
/**
This function is only used in DEBUG mode - it dumps output to stdout. Since void*
aren't really human readable, normally you print out some concise info (like "(1,2)")
without an ending newline.
*/
virtual void PrintStateInfo( void* state ) = 0;
*Call the Solver*
MicroPather* pather = new MicroPather( myGraph ); // Although you really should set the default params for your game.
micropather::MPVector< void* > path;
float totalCost = 0;
int result = pather->Solve( startState, endState, &path, &totalCost );
That's it. Given the start state and the end state, the sequence of states
from start to end will be written to the vector.
MicroPather does a lot of caching. You want to create one and keep in around.
It will cache lots of information about your graph, and get faster as it is
called. However, for caching to work, the connections between states and the
costs of those connections must stay the same. (Else the cache information will
be invalid.) If costs between connections does change, be sure to call Reset().
pather->Reset();
Reset() is a fast call if it doesn't need to do anything.
Future Improvements and Social Coding
-------------------------------------
I really like getting patches, improvements, and performance enhancements.
Some guidelines:
* Pull requests are the best way to send a change.
* The "ease of use" goal is important to this project. It can be sped up by
deeper integration into the client code (all states must subclass the State
object, for example) but that dramatically reduces usability.
Thanks for checking out MicroPather!
Lee Thomason

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,54 +0,0 @@
# Python program to set the version.
##############################################
def fileProcess( name, lineFunction ):
filestream = open( name, 'r' )
if filestream.closed:
print( "file " + name + " not open." )
return
output = ""
print( "--- Processing " + name + " ---------" )
while 1:
line = filestream.readline()
if not line: break
output += lineFunction( line )
filestream.close()
if not output: return # basic error checking
print( "Writing file " + name )
filestream = open( name, "w" );
filestream.write( output );
filestream.close()
def echoInput( line ):
return line
import sys
major = input( "Major: " )
minor = input( "Minor: " )
build = input( "Build: " )
print "Version: " + `major` + "." + `minor` + "." + `build`
#### Write the buildlilith #####
def buildlinuxRule( line ):
i = line.rfind( "_" )
if i >= 4 and line[i] == "_" and line[i-2] == "_" and line[i-4] == "_":
# This is ghetto. Should really use regular expressions.
i -= 4
print "buildmicro instance found"
return line[0:i] + "_" + `major` + "_" + `minor` + "_" + `build` + line[i+6:]
else:
return line
fileProcess( "buildmicro", buildlinuxRule )

View File

@ -1,339 +0,0 @@
/*
Copyright (c) 2000-2012 Lee Thomason (www.grinninglizard.com)
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 <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <vector>
#include <chrono>
#include "micropather.h"
using namespace micropather;
#ifdef _MSC_VER
#include <Windows.h>
// The std::chronos high resolution clocks are no where near accurate enough on Windows 10.
// Many calls come back at 0 time.
typedef uint64_t TimePoint;
inline uint64_t FastTime()
{
uint64_t t;
QueryPerformanceCounter((LARGE_INTEGER*)&t);
return t;
}
inline int64_t Nanoseconds(TimePoint start, TimePoint end)
{
uint64_t freq;
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
return (end - start) * 1000 * 1000 * 1000 / freq;
}
#else
typedef std::chrono::time_point<std::chrono::high_resolution_clock> TimePoint;
inline TimePoint FastTime()
{
return std::chrono::high_resolution_clock::now();
}
inline int64_t Nanoseconds(TimePoint start, TimePoint end)
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
}
#endif
const int MAPX = 90;
const int MAPY = 20;
const char gMap[MAPX*MAPY+1] =
//"012345678901234567890123456789"
" | | | | || | | | |"
" | |----+ | + | ||---+ | + | |----+ | +"
"---+ +--- -+ +--+--+ ---+ +--- -+| +--+--+ ---+ +--- -+ +--+--+ "
" | +-- + | || +-- + | +-- +"
" +----+ +---+ || +---+ +----+ +---+ "
"---+ + + + | ---+ + | 2---+ + + + | "
" | | +----+ +----+ +--+ | | || +----+ +--+322| | +----+ +----+ +--+"
" | | | | || | | 222232 | | | "
" | +-------+ +-+ |------------------+| +-+ |--+ 2223| +-------+ +-+ |--+ "
"---+ | || | 222+---+ | +"
" | | | || 22233| | | |"
" | |----+ ++ ||---+3333| 22+ | |----+ | +"
"---+ +--- -+ +--+-------------------||22223+--+--+ ---+ +--- -+ +--+--+ "
" | +-- + | 22223333 +-- + | +-- +"
" +----+ +---+ +---+| +---+ 222 +----+ +---+ "
"---+ + + + | ---+ + + +| |222---+ + + + | "
" | | +----+ +----+ +--+ | | +---+| 22+----+ +--+233|2| +----+ +----+ +--+"
" | | | | ||2222| | 2223333| | | "
" | +-------+ +-+ |--+ | +------++ +-+ |--+ |2+-------+ +-+ |--+ "
"---+ | +---+ || | +---+ | ";
class Dungeon : public Graph
{
public:
MPVector<void*> path;
MicroPather* aStar;
int maxDir;
Dungeon() {
aStar = new MicroPather( this, MAPX*MAPY, 6 );
maxDir = 4;
}
virtual ~Dungeon() {
delete aStar;
}
int Passable( int nx, int ny )
{
if ( nx >= 0 && nx < MAPX
&& ny >= 0 && ny < MAPY )
{
int index = ny*MAPX+nx;
char c = gMap[ index ];
if ( c == ' ' )
return 1;
else if ( c >= '1' && c <= '9' ) {
int val = c-'0';
MPASSERT( val > 0 );
return val;
}
}
return 0;
}
void NodeToXY( void* node, int* x, int* y )
{
int index = (int)((intptr_t)node);
*y = index / MAPX;
*x = index - *y * MAPX;
}
void* XYToNode( int x, int y )
{
return (void*) ( y*MAPX + x );
}
virtual float LeastCostEstimate( void* nodeStart, void* nodeEnd )
{
int xStart, yStart, xEnd, yEnd;
NodeToXY( nodeStart, &xStart, &yStart );
NodeToXY( nodeEnd, &xEnd, &yEnd );
int dx = xStart - xEnd;
int dy = yStart - yEnd;
return (float) sqrt( (double)(dx*dx) + (double)(dy*dy) );
}
virtual void AdjacentCost( void* node, MPVector< StateCost > *neighbors )
{
int x, y;
// E N W S NE NW SW SE
const int dx[8] = { 1, 0, -1, 0, 1, -1, -1, 1 };
const int dy[8] = { 0, -1, 0, 1, -1, -1, 1, 1 };
const float cost[8] = { 1.0f, 1.0f, 1.0f, 1.0f,
1.41f, 1.41f, 1.41f, 1.41f };
NodeToXY( node, &x, &y );
for( int i=0; i<maxDir; ++i ) {
int nx = x + dx[i];
int ny = y + dy[i];
int pass = Passable( nx, ny );
if ( pass > 0 ) {
// Normal floor
StateCost nodeCost = { XYToNode( nx, ny ), cost[i] * (float)(pass) };
neighbors->push_back( nodeCost );
}
}
}
virtual void PrintStateInfo( void* node )
{
int x, y;
NodeToXY( node, &x, &y );
printf( "(%2d,%2d)", x, y );
}
};
int main( int argc, const char* argv[] )
{
Dungeon dungeon;
const int NUM_TEST = 389;
int indexArray[ NUM_TEST ]; // a bunch of locations to go from-to
float costArray[ NUM_TEST ];
int64_t timeArray[ NUM_TEST ];
int resultArray[ NUM_TEST ];
bool useBinaryHash = false;
bool useList = false;
bool debug = false;
#ifdef DEBUG
debug = true;
#endif
#ifdef USE_BINARY_HASH
useBinaryHash = true;
#endif
#ifdef USE_LIST
useList = true;
#endif
printf( "SpeedTest binaryHash=%s list=%s debug=%s\n",
useBinaryHash ? "true" : "false",
useList ? "true" : "false",
debug ? "true" : "false" );
// Set up the test locations, making sure they
// are all valid.
for (int i = 0; i < NUM_TEST; ++i) {
indexArray[i] = (MAPX*MAPY) * i / NUM_TEST;
costArray[i] = 0.0f;
int y = indexArray[i] / MAPX;
int x = indexArray[i] - MAPX*y;
while (!dungeon.Passable(x, y)) {
indexArray[i] += 1;
y = indexArray[i] / MAPX;
x = indexArray[i] - MAPX*y;
}
}
// Randomize the locations.
for (int i = 0; i < NUM_TEST; ++i)
{
int swapWith = rand() % NUM_TEST;
int temp = indexArray[i];
indexArray[i] = indexArray[swapWith];
indexArray[swapWith] = temp;
}
int64_t compositeScore = 0;
for ( int numDir=4; numDir<=8; numDir+=4 )
{
dungeon.maxDir = numDir;
dungeon.aStar->Reset();
static const int SHORT_PATH = 0;
static const int MED_PATH = 1;
static const int LONG_PATH = 2;
static const int FAIL_SHORT = 3;
static const int FAIL_LONG = 4;
for( int reset=0; reset<=1; ++reset )
{
TimePoint clockStart = FastTime();
for( int i=0; i<NUM_TEST; ++i )
{
if ( reset )
dungeon.aStar->Reset();
int startState = indexArray[i];
int endState = indexArray[ (i==(NUM_TEST-1)) ? 0 : i+1];
TimePoint start = FastTime();
resultArray[i] = dungeon.aStar->Solve( (void*)startState, (void*)endState, &dungeon.path, &costArray[i] );
TimePoint end = FastTime();
timeArray[i] = Nanoseconds(start, end);
MPASSERT(timeArray[i]);
}
TimePoint clockEnd = FastTime();
#ifndef PROFILING_RUN
// -------- Results ------------ //
const float shortPath = (float)(MAPX / 4);
const float medPath = (float)(MAPX / 2 );
int count[5] = { 0 }; // short, med, long, fail short, fail long
int64_t time[5] = { 0 };
for(int i=0; i<NUM_TEST; ++i )
{
int idx = 0;
if ( resultArray[i] == MicroPather::SOLVED ) {
if ( costArray[i] < shortPath ) {
idx = SHORT_PATH;
}
else if ( costArray[i] < medPath ) {
idx = MED_PATH;
}
else {
idx = LONG_PATH;
}
}
else if ( resultArray[i] == MicroPather::NO_SOLUTION ) {
int startState = indexArray[i];
int endState = indexArray[ (i==(NUM_TEST-1)) ? 0 : i+1];
int startX, startY, endX, endY;
dungeon.NodeToXY( (void*)startState, &startX, &startY );
dungeon.NodeToXY( (void*)endState, &endX, &endY );
int distance = abs( startX - endX ) + abs( startY - endY );
if ( distance < shortPath ) {
idx = FAIL_SHORT;
}
else {
idx = FAIL_LONG;
}
}
count[idx] += 1;
time[idx] += timeArray[i];
}
printf( "Average of %d runs. Reset=%s. Dir=%d.\n",
NUM_TEST, reset ? "true" : "false", numDir );
printf( "short(%4d) = %7.2f\n", count[0], double(time[0]) / count[0] * 0.001 );
printf( "med (%4d) = %7.2f\n", count[1], double(time[1]) / count[1] * 0.001 );
printf( "long (%4d) = %7.2f\n", count[2], double(time[2]) / count[2] * 0.001 );
printf( "fail short (%4d) = %7.2f\n", count[3], double(time[3]) / count[3] * 0.001 );
printf( "fail long (%4d) = %7.2f\n", count[4], double(time[4]) / count[4] * 0.001 );
int64_t totalTime = 0;
int totalCount = 0;
for( int k=0; k<5; ++k ) {
totalTime += time[k];
totalCount += count[k];
}
printf( "Average = %7.2f\n", double(totalTime) / totalCount * 0.001 );
compositeScore += totalTime / totalCount;
#endif
}
}
printf( "Composite average = %7.2f\n", double(compositeScore) / 4 * 0.001);
return 0;
}

View File

@ -1,30 +0,0 @@
SpeedTest binaryHash=false list=false debug=false
Average of 389 runs. Reset=false. Dir=4.
short( 85, cutoff=22.0)= 31
med ( 119, cutoff=45.0)= 121
long ( 146) = 354
fail ( 13) short = 406
fail ( 26) long = 469
Average = 276
Average of 389 runs. Reset=true. Dir=4.
short( 85, cutoff=22.0)= 26
med ( 119, cutoff=45.0)= 102
long ( 146) = 325
fail ( 13) short = 432
fail ( 26) long = 495
Average = 276
Average of 389 runs. Reset=false. Dir=8.
short( 113, cutoff=22.0)= 27
med ( 124, cutoff=45.0)= 103
long ( 113) = 268
fail ( 13) short = 452
fail ( 26) long = 503
Average = 270
Average of 389 runs. Reset=true. Dir=8.
short( 113, cutoff=22.0)= 38
med ( 124, cutoff=45.0)= 157
long ( 113) = 430
fail ( 13) short = 675
fail ( 26) long = 688
Average = 397
Composite average = 305

View File

@ -1,26 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "micropather", "micropather.vcxproj", "{C36D6BFA-8F57-483C-83FB-5BBBDF3F4036}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speed", "speed.vcxproj", "{6E0FBADD-648B-4FAF-93DB-29830058D935}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C36D6BFA-8F57-483C-83FB-5BBBDF3F4036}.Debug|Win32.ActiveCfg = Debug|Win32
{C36D6BFA-8F57-483C-83FB-5BBBDF3F4036}.Debug|Win32.Build.0 = Debug|Win32
{C36D6BFA-8F57-483C-83FB-5BBBDF3F4036}.Release|Win32.ActiveCfg = Release|Win32
{C36D6BFA-8F57-483C-83FB-5BBBDF3F4036}.Release|Win32.Build.0 = Release|Win32
{6E0FBADD-648B-4FAF-93DB-29830058D935}.Debug|Win32.ActiveCfg = Debug|Win32
{6E0FBADD-648B-4FAF-93DB-29830058D935}.Debug|Win32.Build.0 = Debug|Win32
{6E0FBADD-648B-4FAF-93DB-29830058D935}.Release|Win32.ActiveCfg = Release|Win32
{6E0FBADD-648B-4FAF-93DB-29830058D935}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,140 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\dungeon.cpp" />
<ClCompile Include="..\micropather.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\micropather.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C36D6BFA-8F57-483C-83FB-5BBBDF3F4036}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/micropather.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/micropather.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
<ObjectFileName>.\Debug/</ObjectFileName>
<ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<OutputFile>.\Debug/micropather.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/micropather.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>.\Debug/micropather.bsc</OutputFile>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/micropather.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/micropather.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Release/</AssemblerListingLocation>
<ObjectFileName>.\Release/</ObjectFileName>
<ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<OutputFile>.\Release/micropather.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ProgramDatabaseFile>.\Release/micropather.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>.\Release/micropather.bsc</OutputFile>
</Bscmake>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,142 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\micropather.cpp" />
<ClCompile Include="..\speed.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\micropather.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{6E0FBADD-648B-4FAF-93DB-29830058D935}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\speed___Win32_Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\speed___Win32_Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\speed___Win32_Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\speed___Win32_Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\speed___Win32_Release/speed.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\speed___Win32_Release/speed.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\speed___Win32_Release/</AssemblerListingLocation>
<ObjectFileName>.\speed___Win32_Release/</ObjectFileName>
<ProgramDataBaseFileName>.\speed___Win32_Release/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<OutputFile>.\speed___Win32_Release/speed.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\speed___Win32_Release/speed.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>.\speed___Win32_Release/speed.bsc</OutputFile>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\speed___Win32_Debug/speed.tlb</TypeLibraryName>
<HeaderFileName>
</HeaderFileName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\speed___Win32_Debug/speed.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\speed___Win32_Debug/</AssemblerListingLocation>
<ObjectFileName>.\speed___Win32_Debug/</ObjectFileName>
<ProgramDataBaseFileName>.\speed___Win32_Debug/</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<OutputFile>.\speed___Win32_Debug/speed.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\speed___Win32_Debug/speed.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>.\speed___Win32_Debug/speed.bsc</OutputFile>
</Bscmake>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1 @@
Subproject commit d20b162b0f5803414b0229180441137e7abf7f4f

View File

@ -1,6 +0,0 @@
target_sources(cathook PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/astar.h"
"${CMAKE_CURRENT_LIST_DIR}/CNavFile.h"
"${CMAKE_CURRENT_LIST_DIR}/nav.h")
target_include_directories(cathook PRIVATE "${CMAKE_CURRENT_LIST_DIR}")

View File

@ -1,267 +0,0 @@
#pragma once
#include "nav.h"
#include <fstream>
class CNavFile
{
public:
// Intended to use with engine->GetLevelName() or mapname from server_spawn
// GameEvent Change it if you get the nav file from elsewhere
CNavFile(const char *szLevelname)
{
if (!szLevelname)
return;
m_mapName = std::string("tf/");
std::string map(szLevelname);
if (map.find("maps/") == std::string::npos)
m_mapName.append("maps/");
m_mapName.append(szLevelname);
int dotpos = m_mapName.find('.');
m_mapName = m_mapName.substr(0, dotpos);
m_mapName.append(".nav");
std::ifstream fs(m_mapName, std::ios::binary);
if (!fs.is_open())
{
//.nav file does not exist
return;
}
uint32_t magic;
fs.read((char *) &magic, sizeof(uint32_t));
if (magic != 0xFEEDFACE)
{
// Wrong magic number
return;
}
uint32_t version;
fs.read((char *) &version, sizeof(uint32_t));
if (version < 16) // 16 is latest for TF2
{
// Version is too old
return;
}
uint32_t subVersion;
fs.read((char *) &subVersion, sizeof(uint32_t));
if (subVersion != 2) // 2 for TF2
{
// Not TF2 nav file
return;
}
// We do not really need to check the size
uint32_t bspSize;
fs.read((char *) &bspSize, sizeof(uint32_t));
fs.read((char *) &m_isAnalized, sizeof(unsigned char));
uint16_t placeCount;
fs.read((char *) &placeCount, sizeof(uint16_t));
// TF2 does not use places, but in case they exist
uint16_t len;
for (int i = 0; i < placeCount; i++)
{
fs.read((char *) &len, sizeof(uint16_t));
CNavPlace place;
fs.read((char *) &place.m_name, len);
m_places.push_back(place);
}
fs.read((char *) &m_hasUnnamedAreas, sizeof(unsigned char));
uint32_t areaCount;
fs.read((char *) &areaCount, sizeof(uint32_t));
for (size_t i = 0; i < areaCount; i++)
{
CNavArea area;
fs.read((char *) &area.m_id, sizeof(uint32_t));
fs.read((char *) &area.m_attributeFlags, sizeof(uint32_t));
fs.read((char *) &area.m_nwCorner, sizeof(Vector));
fs.read((char *) &area.m_seCorner, sizeof(Vector));
fs.read((char *) &area.m_neY, sizeof(float));
fs.read((char *) &area.m_swY, sizeof(float));
area.m_center[0] = (area.m_nwCorner[0] + area.m_seCorner[0]) / 2.0f;
area.m_center[1] = (area.m_nwCorner[1] + area.m_seCorner[1]) / 2.0f;
area.m_center[2] = (area.m_nwCorner[2] + area.m_seCorner[2]) / 2.0f;
if ((area.m_seCorner.x - area.m_nwCorner.x) > 0.0f &&
(area.m_seCorner.y - area.m_nwCorner.y) > 0.0f)
{
area.m_invDxCorners =
1.0f / (area.m_seCorner.x - area.m_nwCorner.x);
area.m_invDzCorners =
1.0f / (area.m_seCorner.z - area.m_nwCorner.z);
}
else
area.m_invDxCorners = area.m_invDzCorners = 0.0f;
// Change the tolerance if you wish
area.m_minZ = min(area.m_seCorner.z, area.m_nwCorner.z) - 18.f;
area.m_maxZ = max(area.m_seCorner.z, area.m_nwCorner.z) + 18.f;
for (int dir = 0; dir < NUM_DIRECTIONS; dir++)
{
uint32_t connectionCount;
fs.read((char *) &connectionCount, sizeof(uint32_t));
for (size_t j = 0; j < connectionCount; j++)
{
NavConnect connect;
fs.read((char *) &connect.id, sizeof(uint32_t));
// Connection to the same area?
if (connect.id == area.m_id)
continue;
// Note: If connection directions matter to you, uncomment
// this
area.m_connections /*[dir]*/.push_back(connect);
}
}
uint8_t hidingSpotCount;
fs.read((char *) &hidingSpotCount, sizeof(uint8_t));
for (size_t j = 0; j < hidingSpotCount; j++)
{
HidingSpot spot;
fs.read((char *) &spot.m_id, sizeof(uint32_t));
fs.read((char *) &spot.m_pos, sizeof(Vector));
fs.read((char *) &spot.m_flags, sizeof(unsigned char));
area.m_hidingSpots.push_back(spot);
}
fs.read((char *) &area.m_encounterSpotCount, sizeof(uint32_t));
for (size_t j = 0; j < area.m_encounterSpotCount; j++)
{
SpotEncounter spot;
fs.read((char *) &spot.from.id, sizeof(uint32_t));
fs.read((char *) &spot.fromDir, sizeof(unsigned char));
fs.read((char *) &spot.to.id, sizeof(uint32_t));
fs.read((char *) &spot.toDir, sizeof(unsigned char));
unsigned char spotcount;
fs.read((char *) &spotcount, sizeof(unsigned char));
for (int s = 0; s < spotcount; ++s)
{
SpotOrder order;
fs.read((char *) &order.id, sizeof(uint32_t));
fs.read((char *) &order.t, sizeof(unsigned char));
spot.spots.push_back(order);
}
area.m_spotEncounters.push_back(spot);
}
fs.read((char *) &area.m_indexType, sizeof(uint16_t));
// TF2 does not use ladders either
for (int dir = 0; dir < NUM_LADDER_DIRECTIONS; dir++)
{
uint32_t laddercount;
fs.read((char *) &laddercount, sizeof(uint32_t));
for (size_t j = 0; j < laddercount; j++)
{
int temp;
fs.read((char *) &temp, sizeof(uint32_t));
}
}
for (int j = 0; j < MAX_NAV_TEAMS; j++)
fs.read((char *) &area.m_earliestOccupyTime[j], sizeof(float));
for (int j = 0; j < NUM_CORNERS; ++j)
fs.read((char *) &area.m_lightIntensity[j], sizeof(float));
fs.read((char *) &area.m_visibleAreaCount, sizeof(uint32_t));
for (size_t j = 0; j < area.m_visibleAreaCount; ++j)
{
AreaBindInfo info;
fs.read((char *) &info.id, sizeof(uint32_t));
fs.read((char *) &info.attributes, sizeof(unsigned char));
area.m_potentiallyVisibleAreas.push_back(info);
}
fs.read((char *) &area.m_inheritVisibilityFrom, sizeof(uint32_t));
// Unknown 4 bytes
uint32_t unk;
fs.read((char *) &unk, sizeof(uint32_t));
m_areas.push_back(area);
}
fs.close();
// Fill connection for every area with their area ptrs instead of IDs
// This will come in handy in path finding
for (auto it = m_areas.begin(); it != m_areas.end(); it++)
{
CNavArea &area = *it;
for (auto it2 = area.m_connections.begin();
it2 != area.m_connections.end(); it2++)
{
NavConnect &connection = *it2;
for (auto it3 = m_areas.begin(); it3 != m_areas.end(); it3++)
{
CNavArea &connectedarea = *it3;
if (connection.id == connectedarea.m_id)
{
connection.area = &connectedarea;
}
}
}
// Fill potentially visible areas as well
for (auto it2 = area.m_potentiallyVisibleAreas.begin();
it2 != area.m_potentiallyVisibleAreas.end(); it2++)
{
AreaBindInfo &bindinfo = *it2;
for (auto it3 = m_areas.begin(); it3 != m_areas.end(); it3++)
{
CNavArea &boundarea = *it3;
if (bindinfo.id == boundarea.m_id)
{
bindinfo.area = &boundarea;
}
}
}
}
m_isOK = true;
}
std::string m_mapName;
bool m_isAnalized;
std::vector<CNavPlace> m_places;
bool m_hasUnnamedAreas;
std::vector<CNavArea> m_areas;
bool m_isOK = false;
};

View File

@ -1,15 +0,0 @@
TF2 NavFile Reader
How to use:
1.) Include CNavFile.h
2.) Instantiate CNavFile, map name argument in
constructor is intended to work with level name from engine->GetLevelName() or with "mapname" string from "server_spawn" GameEvent
3.) Check if m_isOK -> no errors while reading
4.) Done!
License: http://www.wtfpl.net/txt/copying/
Credits: Source Engine SDK by Valve -> cool and good header files

View File

@ -1,53 +0,0 @@
#pragma once
#include "common.hpp"
#include <vector>
namespace nav {
struct singleNode {
typedef singleNode ThisClass;
int id{-1};
Vector pos;
std::vector<singleNode *> children;
inline void addChildren(singleNode *node) {
children.push_back(node);
}
inline std::vector<singleNode *> FindPath(singleNode *goal) {
std::vector<singleNode *> ret;
singleNode *node = nullptr;
singleNode *target = this;
for (int i = 0; i < 100; i++) {
float bestscr = 99999999.0f;
if (node) {
if (node->id == goal->id)
break;
ret.push_back(node);
}
for (auto child : target->children) {
bool rett = false;
for (auto sub : ret) {
if (sub->id == child->id) {
rett = true;
break;
}
}
if (rett)
continue;
if (child->id == goal->id) {
ret.push_back(child);
node = child;
target = child;
break;
}
if (child->pos.DistTo(goal->pos) < bestscr) {
bestscr = child->pos.DistTo(goal->pos);
node = child;
target = child;
}
}
}
return ret;
}
};
}

View File

@ -1,272 +0,0 @@
#pragma once
#include "common.hpp"
struct SpotEncounter;
class CNavPlace
{
public:
char m_name[256];
};
enum NavDirType
{
NORTH = 0,
EAST = 1,
SOUTH = 2,
WEST = 3,
NUM_DIRECTIONS
};
enum
{
MAX_NAV_TEAMS = 2
};
/**
* A HidingSpot is a good place for a bot to crouch and wait for enemies
*/
class HidingSpot
{
public:
enum
{
IN_COVER = 0x01, // in a corner with good hard cover nearby
GOOD_SNIPER_SPOT = 0x02, // had at least one decent sniping corridor
IDEAL_SNIPER_SPOT =
0x04, // can see either very far, or a large area, or both
EXPOSED = 0x08 // spot in the open, usually on a ledge or cliff
};
bool HasGoodCover(void) const
{
return (m_flags & IN_COVER) ? true : false;
} // return true if hiding spot in in cover
bool IsGoodSniperSpot(void) const
{
return (m_flags & GOOD_SNIPER_SPOT) ? true : false;
}
bool IsIdealSniperSpot(void) const
{
return (m_flags & IDEAL_SNIPER_SPOT) ? true : false;
}
bool IsExposed(void) const
{
return (m_flags & EXPOSED) ? true : false;
}
Vector m_pos; // world coordinates of the spot
unsigned int m_id; // this spot's unique ID
unsigned char m_flags; // bit flags
};
class CNavArea;
struct SpotEncounter;
struct NavConnect;
struct AreaBindInfo
{
union {
CNavArea *area;
unsigned int id = 0;
};
unsigned char attributes; // VisibilityType
};
enum NavAttributeType
{
NAV_MESH_INVALID = 0,
NAV_MESH_CROUCH = 0x0000001, // must crouch to use this node/area
NAV_MESH_JUMP = 0x0000002, // must jump to traverse this area (only used
// during generation)
NAV_MESH_PRECISE =
0x0000004, // do not adjust for obstacles, just move along area
NAV_MESH_NO_JUMP = 0x0000008, // inhibit discontinuity jumping
NAV_MESH_STOP = 0x0000010, // must stop when entering this area
NAV_MESH_RUN = 0x0000020, // must run to traverse this area
NAV_MESH_WALK = 0x0000040, // must walk to traverse this area
NAV_MESH_AVOID =
0x0000080, // avoid this area unless alternatives are too dangerous
NAV_MESH_TRANSIENT = 0x0000100, // area may become blocked, and should be
// periodically checked
NAV_MESH_DONT_HIDE =
0x0000200, // area should not be considered for hiding spot generation
NAV_MESH_STAND = 0x0000400, // bots hiding in this area should stand
NAV_MESH_NO_HOSTAGES = 0x0000800, // hostages shouldn't use this area
NAV_MESH_STAIRS = 0x0001000, // this area represents stairs, do not attempt
// to climb or jump them - just walk up
NAV_MESH_NO_MERGE = 0x0002000, // don't merge this area with adjacent areas
NAV_MESH_OBSTACLE_TOP =
0x0004000, // this nav area is the climb point on the tip of an obstacle
NAV_MESH_CLIFF = 0x0008000, // this nav area is adjacent to a drop of at
// least CliffHeight
NAV_MESH_FIRST_CUSTOM = 0x00010000, // apps may define custom app-specific
// bits starting with this value
NAV_MESH_LAST_CUSTOM =
0x04000000, // apps must not define custom app-specific bits higher than
// with this value
NAV_MESH_HAS_ELEVATOR = 0x40000000, // area is in an elevator's path
NAV_MESH_NAV_BLOCKER =
0x80000000, // area is blocked by nav blocker ( Alas, needed to hijack a
// bit in the attributes to get within a cache line
// [7/24/2008 tom])
};
enum NavTraverseType
{
// NOTE: First 4 directions MUST match NavDirType
GO_NORTH = 0,
GO_EAST,
GO_SOUTH,
GO_WEST,
GO_LADDER_UP,
GO_LADDER_DOWN,
GO_JUMP,
GO_ELEVATOR_UP,
GO_ELEVATOR_DOWN,
NUM_TRAVERSE_TYPES
};
enum NavCornerType
{
NORTH_WEST = 0,
NORTH_EAST = 1,
SOUTH_EAST = 2,
SOUTH_WEST = 3,
NUM_CORNERS
};
enum NavRelativeDirType
{
FORWARD = 0,
RIGHT,
BACKWARD,
LEFT,
UP,
DOWN,
NUM_RELATIVE_DIRECTIONS
};
enum LadderDirectionType
{
LADDER_UP = 0,
LADDER_DOWN,
NUM_LADDER_DIRECTIONS
};
class CNavArea
{
public:
uint32_t m_id;
int32_t m_attributeFlags;
Vector m_nwCorner;
Vector m_seCorner;
Vector m_center;
float m_invDzCorners;
float m_invDxCorners;
float m_neY;
float m_swY;
float m_minZ;
float m_maxZ;
std::vector<NavConnect> m_connections;
std::vector<HidingSpot> m_hidingSpots;
std::vector<SpotEncounter> m_spotEncounters;
uint32_t m_encounterSpotCount;
uint16_t m_indexType;
float m_earliestOccupyTime[MAX_NAV_TEAMS];
float m_lightIntensity[NUM_CORNERS];
uint32_t m_visibleAreaCount;
uint32_t m_inheritVisibilityFrom;
std::vector<AreaBindInfo> m_potentiallyVisibleAreas;
// Check if the given point is overlapping the area
// @return True if 'pos' is within 2D extents of area.
bool IsOverlapping(const Vector &vecPos, float flTolerance = 0)
{
if (vecPos.x + flTolerance < this->m_nwCorner.x)
return false;
if (vecPos.x - flTolerance > this->m_seCorner.x)
return false;
if (vecPos.y + flTolerance < this->m_nwCorner.y)
return false;
if (vecPos.y - flTolerance > this->m_seCorner.y)
return false;
return true;
}
// Check if the point is within the 3D bounds of this area
bool Contains(Vector &vecPoint)
{
if (!IsOverlapping(vecPoint))
return false;
if (vecPoint.z > m_maxZ)
return false;
if (vecPoint.z < m_minZ)
return false;
return true;
}
};
struct NavConnect
{
NavConnect()
{
id = 0;
length = -1;
}
union {
unsigned int id;
CNavArea *area;
};
mutable float length;
bool operator==(const NavConnect &other) const
{
return (area == other.area) ? true : false;
}
};
struct SpotOrder
{
float t; // parametric distance along ray where this spot first has LOS to
// our path
union {
HidingSpot *spot; // the spot to look at
unsigned int id; // spot ID for save/load
};
};
/**
* This struct stores possible path segments thru a CNavArea, and the dangerous
* spots to look at as we traverse that path segment.
*/
struct SpotEncounter
{
NavConnect from;
NavDirType fromDir;
NavConnect to;
NavDirType toDir;
// Ray path; // the path segment
std::vector<SpotOrder>
spots; // list of spots to look at, in order of occurrence
};