backport: nodes flooder (analyzer) from cs-ebot
analyze: allow to disable goal marking analyze: add cvars descriptions and bounds nav: added optional post path smoothing for astar algorithm nav: now bots will use Dijkstra algo instead of floyd-warshall if memory usage too high (controlled via yb_path_floyd_memory_limit cvar) (fixes #434) nav: vistable are now calculated every frame to prevent game-freeze during loading the game (fixes #434) graph: pracrice reworked to hash table so memory footprint is as low as possible (at cost 5-10% performance loss on practice) (fixes #434) control: bots commands now is case-insensitive bot: major refactoring of bot's code nav: issue warnings about path fail only with debug practice: check for visibility when updating danger index analyzer: suspend any analyzing on change level control: add kickall_ct/kickall_t nav: increase blocked distance in stuck check
This commit is contained in:
parent
bb2e93a539
commit
e7712a551a
31 changed files with 3114 additions and 1722 deletions
79
inc/analyze.h
Normal file
79
inc/analyze.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// next code is based on cs-ebot implemntation, devised by EfeDursun125
|
||||
class GraphAnalyze : public Singleton <GraphAnalyze> {
|
||||
public:
|
||||
GraphAnalyze () = default;
|
||||
~GraphAnalyze () = default;
|
||||
|
||||
private:
|
||||
float m_updateInterval {}; // time to update analyzer
|
||||
|
||||
bool m_basicsCreated {}; // basics waypoints were created?
|
||||
bool m_isCrouch {}; // is node to be created as crouch ?
|
||||
bool m_isAnalyzing {}; // we're in analyzing ?
|
||||
bool m_isAnalyzed {}; // current waypoint is analyzed
|
||||
bool m_expandedNodes[kMaxNodes] {}; // all nodes expanded ?
|
||||
bool m_optimizedNodes[kMaxNodes] {}; // all nodes expanded ?
|
||||
|
||||
public:
|
||||
// start analyzation process
|
||||
void start ();
|
||||
|
||||
// update analyzation process
|
||||
void update ();
|
||||
|
||||
// suspend aanalyzing
|
||||
void suspend ();
|
||||
|
||||
private:
|
||||
// flood with nodes
|
||||
void flood (const Vector &pos, const Vector &next, float range);
|
||||
|
||||
// set update interval (keeps game from freezing)
|
||||
void setUpdateInterval ();
|
||||
|
||||
// mark waypoints as goals
|
||||
void markGoals ();
|
||||
|
||||
// terminate analyzation and save data
|
||||
void finish ();
|
||||
|
||||
// optimize nodes a little
|
||||
void optimize ();
|
||||
|
||||
// cleanup bad nodes
|
||||
void cleanup ();
|
||||
|
||||
public:
|
||||
|
||||
// node should be created as crouch
|
||||
bool isCrouch () const {
|
||||
return m_isCrouch;
|
||||
}
|
||||
|
||||
// is currently anaylyzing ?
|
||||
bool isAnalyzing () const {
|
||||
return m_isAnalyzing;
|
||||
}
|
||||
|
||||
// current graph is analyzed graph ?
|
||||
bool isAnalyzed () const {
|
||||
return m_isAnalyzed;
|
||||
}
|
||||
|
||||
// mark as optimized
|
||||
void markOptimized (const int index) {
|
||||
m_optimizedNodes[index] = true;
|
||||
}
|
||||
};
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (GraphAnalyze, analyzer);
|
||||
|
|
@ -216,7 +216,7 @@ public:
|
|||
m_args.clear ();
|
||||
|
||||
for (int i = 0; i < engfuncs.pfnCmd_Argc (); ++i) {
|
||||
m_args.emplace (engfuncs.pfnCmd_Argv (i));
|
||||
m_args.emplace (String (engfuncs.pfnCmd_Argv (i)).lowercase ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,5 +274,14 @@ template <typename ...Args> inline void BotControl::msg (const char *fmt, Args &
|
|||
}
|
||||
}
|
||||
|
||||
// graph heloer for sending message to correct channel
|
||||
template <typename ...Args> inline void BotGraph::msg (const char *fmt, Args &&...args) {
|
||||
if (m_silenceMessages) {
|
||||
return; // no messages while analyzing (too much spam)
|
||||
}
|
||||
BotControl::instance ().msg (strings.format (conf.translate (fmt), cr::forward <Args> (args)...));
|
||||
}
|
||||
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (BotControl, ctrl);
|
||||
|
|
|
|||
17
inc/engine.h
17
inc/engine.h
|
|
@ -71,6 +71,7 @@ struct ConVarReg {
|
|||
String info;
|
||||
String init;
|
||||
String regval;
|
||||
String name;
|
||||
class ConVar *self;
|
||||
float initial, min, max;
|
||||
bool missing;
|
||||
|
|
@ -420,6 +421,19 @@ public:
|
|||
Game::instance ().addNewCvar (name, initval, info, bounded, min, max, type, regMissing, regVal, this);
|
||||
}
|
||||
|
||||
template <typename U> constexpr U get () const {
|
||||
if constexpr (cr::is_same <U, float>::value) {
|
||||
return ptr->value;
|
||||
}
|
||||
else if constexpr (cr::is_same <U, bool>::value) {
|
||||
return ptr->value > 0.0f;
|
||||
}
|
||||
else if constexpr (cr::is_same <U, int>::value) {
|
||||
return static_cast <int> (ptr->value);
|
||||
}
|
||||
assert ("!Inavlid type requeted.");
|
||||
}
|
||||
|
||||
bool bool_ () const {
|
||||
return ptr->value > 0.0f;
|
||||
}
|
||||
|
|
@ -447,6 +461,9 @@ public:
|
|||
void set (const char *val) {
|
||||
engfuncs.pfnCvar_DirectSet (ptr, val);
|
||||
}
|
||||
|
||||
// revet cvar to default value
|
||||
void revert ();
|
||||
};
|
||||
|
||||
class MessageWriter final {
|
||||
|
|
|
|||
236
inc/graph.h
236
inc/graph.h
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
constexpr int kMaxNodes = 4096; // max nodes per graph
|
||||
constexpr int kMaxNodeLinks = 8; // max links for single node
|
||||
|
||||
// defines for nodes flags field (32 bits are available)
|
||||
CR_DECLARE_SCOPED_ENUM (NodeFlag,
|
||||
Lift = cr::bit (1), // wait for lift to be down before approaching this node
|
||||
|
|
@ -43,13 +46,6 @@ CR_DECLARE_SCOPED_ENUM (PathConnection,
|
|||
Bidirectional
|
||||
)
|
||||
|
||||
// a* route state
|
||||
CR_DECLARE_SCOPED_ENUM (RouteState,
|
||||
Open = 0,
|
||||
Closed,
|
||||
New
|
||||
)
|
||||
|
||||
// node edit states
|
||||
CR_DECLARE_SCOPED_ENUM (GraphEdit,
|
||||
On = cr::bit (1),
|
||||
|
|
@ -57,26 +53,6 @@ CR_DECLARE_SCOPED_ENUM (GraphEdit,
|
|||
Auto = cr::bit (3)
|
||||
)
|
||||
|
||||
// storage header options
|
||||
CR_DECLARE_SCOPED_ENUM (StorageOption,
|
||||
Practice = cr::bit (0), // this is practice (experience) file
|
||||
Matrix = cr::bit (1), // this is floyd warshal path & distance matrix
|
||||
Vistable = cr::bit (2), // this is vistable data
|
||||
Graph = cr::bit (3), // this is a node graph data
|
||||
Official = cr::bit (4), // this is additional flag for graph indicates graph are official
|
||||
Recovered = cr::bit (5), // this is additional flag indicates graph converted from podbot and was bad
|
||||
Exten = cr::bit (6) // this is additional flag indicates that there's extension info
|
||||
)
|
||||
|
||||
// storage header versions
|
||||
CR_DECLARE_SCOPED_ENUM (StorageVersion,
|
||||
Graph = 2,
|
||||
Practice = 1,
|
||||
Vistable = 2,
|
||||
Matrix = 1,
|
||||
Podbot = 7
|
||||
)
|
||||
|
||||
// lift usage states
|
||||
CR_DECLARE_SCOPED_ENUM (LiftState,
|
||||
None = 0,
|
||||
|
|
@ -103,29 +79,13 @@ CR_DECLARE_SCOPED_ENUM (NodeAddFlag,
|
|||
Goal = 100
|
||||
)
|
||||
|
||||
// a* route
|
||||
struct Route {
|
||||
float g, f;
|
||||
int parent;
|
||||
RouteState state;
|
||||
};
|
||||
CR_DECLARE_SCOPED_ENUM (NotifySound,
|
||||
Done = 0,
|
||||
Change = 1,
|
||||
Added = 2
|
||||
)
|
||||
|
||||
// general stprage header information structure
|
||||
struct StorageHeader {
|
||||
int32_t magic;
|
||||
int32_t version;
|
||||
int32_t options;
|
||||
int32_t length;
|
||||
int32_t compressed;
|
||||
int32_t uncompressed;
|
||||
};
|
||||
|
||||
// extension header for graph information
|
||||
struct ExtenHeader {
|
||||
char author[32]; // original author of graph
|
||||
int32_t mapSize; // bsp size for checksumming map consistency
|
||||
char modified[32]; // by whom modified
|
||||
};
|
||||
#include <vistable.h>
|
||||
|
||||
// general waypoint header information structure
|
||||
struct PODGraphHeader {
|
||||
|
|
@ -136,19 +96,6 @@ struct PODGraphHeader {
|
|||
char author[32];
|
||||
};
|
||||
|
||||
// floyd-warshall matrices
|
||||
struct Matrix {
|
||||
int16_t dist;
|
||||
int16_t index;
|
||||
};
|
||||
|
||||
// experience data hold in memory while playing
|
||||
struct Practice {
|
||||
int16_t damage[kGameTeamNum];
|
||||
int16_t index[kGameTeamNum];
|
||||
int16_t value[kGameTeamNum];
|
||||
};
|
||||
|
||||
// defines linked waypoints
|
||||
struct PathLink {
|
||||
Vector velocity;
|
||||
|
|
@ -157,11 +104,6 @@ struct PathLink {
|
|||
int16_t index;
|
||||
};
|
||||
|
||||
// defines visibility count
|
||||
struct PathVis {
|
||||
uint16_t stand, crouch;
|
||||
};
|
||||
|
||||
// define graph path structure for yapb
|
||||
struct Path {
|
||||
int32_t number, flags;
|
||||
|
|
@ -183,74 +125,21 @@ struct PODPath {
|
|||
PathVis vis;
|
||||
};
|
||||
|
||||
// this structure links nodes returned from pathfinder
|
||||
class PathWalk final : public DenyCopying {
|
||||
private:
|
||||
size_t m_cursor {};
|
||||
size_t m_length {};
|
||||
// general stprage header information structure
|
||||
struct StorageHeader {
|
||||
int32_t magic;
|
||||
int32_t version;
|
||||
int32_t options;
|
||||
int32_t length;
|
||||
int32_t compressed;
|
||||
int32_t uncompressed;
|
||||
};
|
||||
|
||||
UniquePtr <int32_t[]> m_path {};
|
||||
|
||||
public:
|
||||
explicit PathWalk () = default;
|
||||
~PathWalk () = default;
|
||||
|
||||
public:
|
||||
int32_t &next () {
|
||||
return at (1);
|
||||
}
|
||||
|
||||
int32_t &first () {
|
||||
return at (0);
|
||||
}
|
||||
|
||||
int32_t &last () {
|
||||
return at (length () - 1);
|
||||
}
|
||||
|
||||
int32_t &at (size_t index) {
|
||||
return m_path[m_cursor + index];
|
||||
}
|
||||
|
||||
void shift () {
|
||||
++m_cursor;
|
||||
}
|
||||
|
||||
void reverse () {
|
||||
for (size_t i = 0; i < m_length / 2; ++i) {
|
||||
cr::swap (m_path[i], m_path[m_length - 1 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t length () const {
|
||||
if (m_cursor >= m_length) {
|
||||
return 0;
|
||||
}
|
||||
return m_length - m_cursor;
|
||||
}
|
||||
|
||||
bool hasNext () const {
|
||||
return length () > m_cursor;
|
||||
}
|
||||
|
||||
bool empty () const {
|
||||
return !length ();
|
||||
}
|
||||
|
||||
void add (int32_t node) {
|
||||
m_path[m_length++] = node;
|
||||
}
|
||||
|
||||
void clear () {
|
||||
m_cursor = 0;
|
||||
m_length = 0;
|
||||
|
||||
m_path[0] = 0;
|
||||
}
|
||||
|
||||
void init (size_t length) {
|
||||
m_path = cr::makeUnique <int32_t []> (length);
|
||||
}
|
||||
// extension header for graph information
|
||||
struct ExtenHeader {
|
||||
char author[32]; // original author of graph
|
||||
int32_t mapSize; // bsp size for checksumming map consistency
|
||||
char modified[32]; // by whom modified
|
||||
};
|
||||
|
||||
// graph operation class
|
||||
|
|
@ -260,7 +149,6 @@ public:
|
|||
|
||||
private:
|
||||
int m_editFlags {};
|
||||
int m_loadAttempts {};
|
||||
int m_cacheNodeIndex {};
|
||||
int m_lastJumpNode {};
|
||||
int m_findWPIndex {};
|
||||
|
|
@ -277,8 +165,8 @@ private:
|
|||
bool m_endJumpPoint {};
|
||||
bool m_jumpLearnNode {};
|
||||
bool m_hasChanged {};
|
||||
bool m_needsVisRebuild {};
|
||||
bool m_narrowChecked {};
|
||||
bool m_silenceMessages {};
|
||||
|
||||
Vector m_learnVelocity {};
|
||||
Vector m_learnPosition {};
|
||||
|
|
@ -293,11 +181,8 @@ private:
|
|||
IntArray m_rescuePoints {};
|
||||
IntArray m_visitedGoals {};
|
||||
|
||||
SmallArray <Matrix> m_matrix {};
|
||||
SmallArray <Practice> m_practice {};
|
||||
public:
|
||||
SmallArray <Path> m_paths {};
|
||||
SmallArray <uint8_t> m_vistable {};
|
||||
|
||||
HashMap <int32_t, Array <int32_t>, EmptyHash <int32_t>> m_hashTable;
|
||||
|
||||
String m_graphAuthor {};
|
||||
|
|
@ -315,13 +200,10 @@ public:
|
|||
public:
|
||||
int getFacingIndex ();
|
||||
int getFarest (const Vector &origin, float maxDistance = 32.0);
|
||||
int getForAnalyzer (const Vector &origin, float maxDistance);
|
||||
int getNearest (const Vector &origin, float minDistance = kInfiniteDistance, int flags = -1);
|
||||
int getNearestNoBuckets (const Vector &origin, float minDistance = kInfiniteDistance, int flags = -1);
|
||||
int getEditorNearest ();
|
||||
int getDangerIndex (int team, int start, int goal);
|
||||
int getDangerValue (int team, int start, int goal);
|
||||
int getDangerDamage (int team, int start, int goal);
|
||||
int getPathDist (int srcIndex, int destIndex);
|
||||
int clearConnections (int index);
|
||||
int getBspSize ();
|
||||
int locateBucket (const Vector &pos);
|
||||
|
|
@ -329,30 +211,23 @@ public:
|
|||
float calculateTravelTime (float maxSpeed, const Vector &src, const Vector &origin);
|
||||
|
||||
bool convertOldFormat ();
|
||||
bool isVisible (int srcIndex, int destIndex);
|
||||
bool isStandVisible (int srcIndex, int destIndex);
|
||||
bool isDuckVisible (int srcIndex, int destIndex);
|
||||
bool isConnected (int a, int b);
|
||||
bool isConnected (int index);
|
||||
bool isNodeReacheableEx (const Vector &src, const Vector &destination, const float maxHeight);
|
||||
bool isNodeReacheable (const Vector &src, const Vector &destination);
|
||||
bool isNodeReacheableWithJump (const Vector &src, const Vector &destination);
|
||||
bool checkNodes (bool teleportPlayer);
|
||||
bool loadPathMatrix ();
|
||||
bool isVisited (int index);
|
||||
bool isAnalyzed () const;
|
||||
|
||||
bool saveGraphData ();
|
||||
bool loadGraphData ();
|
||||
bool canDownload ();
|
||||
|
||||
template <typename U> bool saveStorage (StringRef name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten);
|
||||
template <typename U> bool loadStorage (StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32_t *outOptions);
|
||||
template <typename ...Args> bool raiseLoadingError (bool isGraph, bool isDebug, MemFile &file, const char *fmt, Args &&...args);
|
||||
|
||||
void saveOldFormat ();
|
||||
void reset ();
|
||||
void frame ();
|
||||
void loadPractice ();
|
||||
void loadVisibility ();
|
||||
void initNodesTypes ();
|
||||
void populateNodes ();
|
||||
void initLightLevels ();
|
||||
void initNarrowPlaces ();
|
||||
void addPath (int addIndex, int pathIndex, float distance);
|
||||
|
|
@ -360,16 +235,11 @@ public:
|
|||
void erase (int target);
|
||||
void toggleFlags (int toggleFlag);
|
||||
void setRadius (int index, float radius);
|
||||
void rebuildVisibility ();
|
||||
void pathCreate (char dir);
|
||||
void erasePath ();
|
||||
void cachePoint (int index);
|
||||
void calculatePathRadius (int index);
|
||||
void savePractice ();
|
||||
void saveVisibility ();
|
||||
void addBasic ();
|
||||
void eraseFromDisk ();
|
||||
void savePathMatrix ();
|
||||
void setSearchIndex (int index);
|
||||
void startLearnJump ();
|
||||
void setVisited (int index);
|
||||
|
|
@ -378,16 +248,14 @@ public:
|
|||
void addToBucket (const Vector &pos, int index);
|
||||
void eraseFromBucket (const Vector &pos, int index);
|
||||
void setBombOrigin (bool reset = false, const Vector &pos = nullptr);
|
||||
void updateGlobalPractice ();
|
||||
void unassignPath (int from, int to);
|
||||
void setDangerValue (int team, int start, int goal, int value);
|
||||
void setDangerDamage (int team, int start, int goal, int value);
|
||||
void convertFromPOD (Path &path, const PODPath &pod);
|
||||
void convertToPOD (const Path &path, PODPath &pod);
|
||||
void convertCampDirection (Path &path);
|
||||
void setAutoPathDistance (const float distance);
|
||||
void showStats ();
|
||||
void showFileInfo ();
|
||||
void emitNotify (int32_t sound);
|
||||
|
||||
IntArray getNarestInRadius (float radius, const Vector &origin, int maxCount = -1);
|
||||
const IntArray &getNodesInBucket (const Vector &pos);
|
||||
|
|
@ -463,6 +331,25 @@ public:
|
|||
return m_editor;
|
||||
}
|
||||
|
||||
// slicence all graph messages or not
|
||||
void setMessageSilence (bool enable) {
|
||||
m_silenceMessages = enable;
|
||||
}
|
||||
|
||||
// set exten header from binary storage
|
||||
void setExtenHeader (ExtenHeader *hdr) {
|
||||
memcpy (&m_extenHeader, hdr, sizeof (ExtenHeader));
|
||||
}
|
||||
|
||||
// set graph header from binary storage
|
||||
void setGraphHeader (StorageHeader *hdr) {
|
||||
memcpy (&m_graphHeader, hdr, sizeof (StorageHeader));
|
||||
}
|
||||
|
||||
public:
|
||||
// graph heloer for sending message to correct channel
|
||||
template <typename ...Args> void msg (const char *fmt, Args &&...args);
|
||||
|
||||
public:
|
||||
Path *begin () {
|
||||
return m_paths.begin ();
|
||||
|
|
@ -481,29 +368,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// we're need `bots`
|
||||
#include <manager.h>
|
||||
|
||||
// helper for reporting load errors
|
||||
template <typename ...Args> bool BotGraph::raiseLoadingError (bool isGraph, bool isDebug, MemFile &file, const char *fmt, Args &&...args) {
|
||||
auto result = strings.format (fmt, cr::forward <Args> (args)...);
|
||||
|
||||
// display error only for graph file
|
||||
if (isGraph || isDebug) {
|
||||
logger.error (result);
|
||||
}
|
||||
|
||||
// if graph reset paths
|
||||
if (isGraph) {
|
||||
bots.kickEveryone (true);
|
||||
|
||||
m_graphAuthor = result;
|
||||
m_paths.clear ();
|
||||
}
|
||||
file.close ();
|
||||
|
||||
return false;
|
||||
}
|
||||
#include <practice.h>
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (BotGraph, graph);
|
||||
|
|
|
|||
277
inc/planner.h
Normal file
277
inc/planner.h
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
const float kInfiniteHeuristic = 65535.0f; // max out heuristic value
|
||||
|
||||
// a* route state
|
||||
CR_DECLARE_SCOPED_ENUM (RouteState,
|
||||
Open = 0,
|
||||
Closed,
|
||||
New
|
||||
)
|
||||
|
||||
// a * find path result
|
||||
CR_DECLARE_SCOPED_ENUM (AStarResult,
|
||||
Success = 0,
|
||||
Failed,
|
||||
InternalError,
|
||||
)
|
||||
|
||||
// node added
|
||||
using NodeAdderFn = Lambda <bool (int)>;
|
||||
|
||||
// route twin node
|
||||
template <typename HT> struct RouteTwin final {
|
||||
public:
|
||||
int32_t index {};
|
||||
HT heuristic {};
|
||||
|
||||
constexpr RouteTwin () = default;
|
||||
~RouteTwin () = default;
|
||||
|
||||
public:
|
||||
constexpr RouteTwin (const int32_t &ri, const HT &rh) : index (ri), heuristic (rh) {}
|
||||
|
||||
public:
|
||||
constexpr bool operator < (const RouteTwin &rhs) const {
|
||||
return heuristic < rhs.heuristic;
|
||||
}
|
||||
|
||||
constexpr bool operator > (const RouteTwin &rhs) const {
|
||||
return heuristic > rhs.heuristic;
|
||||
}
|
||||
};
|
||||
|
||||
// bot heuristic functions for astar planner
|
||||
class Heuristic final {
|
||||
public:
|
||||
using Func = Lambda <float (int, int, int)>;
|
||||
|
||||
public:
|
||||
// least kills and number of nodes to goal for a team
|
||||
static float gfunctionKillsDist (int team, int currentIndex, int parentIndex);;
|
||||
|
||||
// least kills and number of nodes to goal for a team (when with hostage)
|
||||
static float gfunctionKillsDistCTWithHostage (int team, int currentIndex, int parentIndex);;
|
||||
|
||||
// least kills to goal for a team
|
||||
static float gfunctionKills (int team, int currentIndex, int);;
|
||||
|
||||
// least kills to goal for a team (when with hostage)
|
||||
static auto gfunctionKillsCTWithHostage (int team, int currentIndex, int parentIndex) -> float;;
|
||||
|
||||
// least distance for a team
|
||||
static float gfunctionPathDist (int, int currentIndex, int parentIndex);;
|
||||
|
||||
// least distance for a team (when with hostage)
|
||||
static float gfunctionPathDistWithHostage (int, int currentIndex, int parentIndex);;
|
||||
|
||||
public:
|
||||
// square distance heuristic
|
||||
static float hfunctionPathDist (int index, int, int goalIndex);;
|
||||
|
||||
// square distance heuristic with hostages
|
||||
static float hfunctionPathDistWithHostage (int index, int, int goalIndex);;
|
||||
|
||||
// none heuristic
|
||||
static float hfunctionNone (int index, int, int goalIndex);;
|
||||
};
|
||||
|
||||
// A* algorithm for bots
|
||||
class AStarAlgo final {
|
||||
public:
|
||||
using HeuristicFn = Heuristic::Func;
|
||||
|
||||
public:
|
||||
struct Route {
|
||||
float g {}, f {};
|
||||
int parent { kInvalidNodeIndex };
|
||||
RouteState state { RouteState::New };
|
||||
};
|
||||
|
||||
private:
|
||||
BinaryHeap <RouteTwin <float>> m_routeQue {};
|
||||
Array <Route> m_routes {};
|
||||
|
||||
HeuristicFn m_hcalc;
|
||||
HeuristicFn m_gcalc;
|
||||
|
||||
int m_length {};
|
||||
|
||||
Array <int> m_constructedPath;
|
||||
Array <int> m_smoothedPath;
|
||||
|
||||
private:
|
||||
// cleares the currently built route
|
||||
void clearRoute ();
|
||||
|
||||
// can the node can be skipped?
|
||||
bool cantSkipNode (const int a, const int b);
|
||||
|
||||
// do a post-smoothing after a* finished constructing path
|
||||
void postSmooth (NodeAdderFn onAddedNode);
|
||||
|
||||
public:
|
||||
AStarAlgo () = default;
|
||||
~AStarAlgo () = default;
|
||||
|
||||
public:
|
||||
// do the pathfinding
|
||||
AStarResult find (int botTeam, int srcIndex, int destIndex, NodeAdderFn onAddedNode);
|
||||
|
||||
public:
|
||||
// initialize astar with valid path length
|
||||
void init (const int length) {
|
||||
m_length = length;
|
||||
clearRoute ();
|
||||
|
||||
m_constructedPath.reserve (getMaxLength ());
|
||||
m_smoothedPath.reserve (getMaxLength ());
|
||||
}
|
||||
|
||||
// set the g heuristic
|
||||
void setG (HeuristicFn fn) {
|
||||
m_gcalc = fn;
|
||||
}
|
||||
|
||||
// set the h heuristic
|
||||
void setH (HeuristicFn fn) {
|
||||
m_hcalc = fn;
|
||||
}
|
||||
|
||||
// get route max length, route length should not be larger than half of map nodes
|
||||
size_t getMaxLength () const {
|
||||
return m_length / 2;
|
||||
}
|
||||
};
|
||||
|
||||
// floyd-warshall shortest path algorithm
|
||||
class FloydWarshallAlgo final {
|
||||
private:
|
||||
int m_length {};
|
||||
|
||||
public:
|
||||
|
||||
// floyd-warshall matrices
|
||||
struct Matrix {
|
||||
int16_t index { kInvalidNodeIndex };
|
||||
int16_t dist { SHRT_MAX };
|
||||
|
||||
public:
|
||||
Matrix () = default;
|
||||
~Matrix () = default;
|
||||
|
||||
public:
|
||||
Matrix (const int index, const int dist) : index (static_cast <int16_t> (index)), dist (static_cast <int16_t> (dist)) {}
|
||||
};
|
||||
|
||||
private:
|
||||
SmallArray <Matrix> m_matrix {};
|
||||
|
||||
public:
|
||||
FloydWarshallAlgo () = default;
|
||||
~FloydWarshallAlgo () = default;
|
||||
|
||||
private:
|
||||
// create floyd matrics
|
||||
void rebuild ();
|
||||
|
||||
public:
|
||||
// load matrices from disk
|
||||
bool load ();
|
||||
|
||||
// flush matrices to disk, so we will not rebuild them on load same map
|
||||
void save ();
|
||||
|
||||
// do the pathfinding
|
||||
bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr);
|
||||
|
||||
public:
|
||||
// distance between two nodes with pathfinder
|
||||
int dist (int srcIndex, int destIndex) {
|
||||
return static_cast <int> ((m_matrix.data () + (srcIndex * m_length) + destIndex)->dist);
|
||||
}
|
||||
};
|
||||
|
||||
// dijkstra shortest path algorithm
|
||||
class DijkstraAlgo final {
|
||||
private:
|
||||
using Route = Twin <int, int>;
|
||||
|
||||
private:
|
||||
Array <int> m_distance {};
|
||||
Array <int> m_parent {};
|
||||
|
||||
BinaryHeap <Route> m_queue {};
|
||||
int m_length {};
|
||||
|
||||
public:
|
||||
DijkstraAlgo () = default;
|
||||
~DijkstraAlgo () = default;
|
||||
|
||||
|
||||
private:
|
||||
// reset pathfinder state to defaults
|
||||
void resetState ();
|
||||
|
||||
public:
|
||||
// initialize dijkstra with valid path length
|
||||
void init (const int length);
|
||||
|
||||
// do the pathfinding
|
||||
bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr);
|
||||
|
||||
// distance between two nodes with pathfinder
|
||||
int dist (int srcIndex, int destIndex);
|
||||
};
|
||||
|
||||
// the bot path planner
|
||||
class PathPlanner : public Singleton <PathPlanner> {
|
||||
private:
|
||||
UniquePtr <DijkstraAlgo> m_dijkstra;
|
||||
UniquePtr <FloydWarshallAlgo> m_floyd;
|
||||
UniquePtr <AStarAlgo > m_astar;
|
||||
bool m_memoryLimitHit {};
|
||||
|
||||
public:
|
||||
PathPlanner ();
|
||||
~PathPlanner () = default;
|
||||
|
||||
public:
|
||||
// initialize all planners
|
||||
void init ();
|
||||
|
||||
// has real path distance (instead of distance2d) ?
|
||||
bool hasRealPathDistance () const;
|
||||
|
||||
public:
|
||||
// get the dijkstra algo
|
||||
decltype (auto) getDijkstra () {
|
||||
return m_dijkstra.get ();
|
||||
}
|
||||
|
||||
// get the floyd algo
|
||||
decltype (auto) getFloydWarshall () {
|
||||
return m_floyd.get ();
|
||||
}
|
||||
|
||||
// get the floyd algo
|
||||
decltype (auto) getAStar () {
|
||||
return m_astar.get ();
|
||||
}
|
||||
|
||||
public:
|
||||
// do the pathfinding
|
||||
bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr);
|
||||
|
||||
// distance between two nodes with pathfinder
|
||||
int dist (int srcIndex, int destIndex);
|
||||
};
|
||||
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (PathPlanner, planner);
|
||||
121
inc/practice.h
Normal file
121
inc/practice.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// limits for storing practice data
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (PracticeLimit, int32_t,
|
||||
Goal = 2040,
|
||||
Damage = 2040
|
||||
);
|
||||
|
||||
// storage for from, to, team
|
||||
class DangerStorage final {
|
||||
protected:
|
||||
uint16_t data[3] {};
|
||||
|
||||
public:
|
||||
constexpr DangerStorage () = default;
|
||||
|
||||
public:
|
||||
constexpr DangerStorage (const int32_t &a, const int32_t &b, const int32_t &c) :
|
||||
data { static_cast <uint16_t> (a), static_cast <uint16_t> (b), static_cast <uint16_t> (c) } {}
|
||||
|
||||
public:
|
||||
constexpr bool operator == (const DangerStorage &rhs) const {
|
||||
return rhs.data[2] == data[2] && rhs.data[1] == data[1] && rhs.data[0] == data[0];
|
||||
}
|
||||
|
||||
constexpr bool operator != (const DangerStorage &rhs) const {
|
||||
return !operator == (rhs);
|
||||
}
|
||||
|
||||
public:
|
||||
// fnv1a for 3d vector hash
|
||||
constexpr uint32_t hash () const {
|
||||
constexpr uint32_t prime = 16777619u;
|
||||
constexpr uint32_t seed = 2166136261u;
|
||||
|
||||
uint32_t hash = seed;
|
||||
|
||||
for (const auto &key : data) {
|
||||
hash = (hash * prime) ^ key;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
// define hash function for hash map
|
||||
CR_NAMESPACE_BEGIN
|
||||
|
||||
template <> struct Hash <DangerStorage> {
|
||||
uint32_t operator () (const DangerStorage &key) const noexcept {
|
||||
return key.hash ();
|
||||
}
|
||||
};
|
||||
|
||||
CR_NAMESPACE_END
|
||||
|
||||
class BotPractice final : public Singleton <BotPractice> {
|
||||
public:
|
||||
// collected data
|
||||
struct PracticeData {
|
||||
int16_t damage {}, value {};
|
||||
int16_t index { kInvalidNodeIndex };
|
||||
};
|
||||
|
||||
// used to save-restore practice data
|
||||
struct DangerSaveRestore {
|
||||
DangerStorage danger {};
|
||||
PracticeData data {};
|
||||
|
||||
public:
|
||||
DangerSaveRestore () = default;
|
||||
|
||||
public:
|
||||
DangerSaveRestore (const DangerStorage &ds, const PracticeData &pd) : danger (ds), data (pd) {}
|
||||
};
|
||||
|
||||
HashMap <DangerStorage, PracticeData> m_data {};
|
||||
int32_t m_teamHighestDamage[kGameTeamNum] {};
|
||||
|
||||
public:
|
||||
BotPractice () = default;
|
||||
~BotPractice () = default;
|
||||
|
||||
private:
|
||||
inline bool exists (int32_t team, int32_t start, int32_t goal) const {
|
||||
return m_data.exists ({ start, goal, team });
|
||||
}
|
||||
|
||||
public:
|
||||
int32_t getIndex (int32_t team, int32_t start, int32_t goal);
|
||||
void setIndex (int32_t team, int32_t start, int32_t goal, int32_t value);
|
||||
|
||||
int32_t getValue (int32_t team, int32_t start, int32_t goal);
|
||||
void setValue (int32_t team, int32_t start, int32_t goal, int32_t value);
|
||||
|
||||
int32_t getDamage (int32_t team, int32_t start, int32_t goal);
|
||||
void setDamage (int32_t team, int32_t start, int32_t goal, int32_t value);
|
||||
|
||||
public:
|
||||
void update ();
|
||||
void load ();
|
||||
void save ();
|
||||
|
||||
public:
|
||||
int32_t getHighestDamageForTeam (int32_t team) const {
|
||||
return cr::max (1, m_teamHighestDamage[team]);
|
||||
}
|
||||
|
||||
void setHighestDamageForTeam (int32_t team, int32_t value) {
|
||||
m_teamHighestDamage[team] = value;
|
||||
}
|
||||
};
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (BotPractice, practice);
|
||||
103
inc/storage.h
Normal file
103
inc/storage.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// storage file magic (podbot)
|
||||
constexpr char kPodbotMagic[8] = "PODWAY!";
|
||||
|
||||
constexpr int32_t kStorageMagic = 0x59415042; // storage magic for yapb-data files
|
||||
constexpr int32_t kStorageMagicUB = 0x544f4255; //support also the fork format (merged back into yapb)
|
||||
|
||||
// storage header options
|
||||
CR_DECLARE_SCOPED_ENUM (StorageOption,
|
||||
Practice = cr::bit (0), // this is practice (experience) file
|
||||
Matrix = cr::bit (1), // this is floyd warshal path & distance matrix
|
||||
Vistable = cr::bit (2), // this is vistable data
|
||||
Graph = cr::bit (3), // this is a node graph data
|
||||
Official = cr::bit (4), // this is additional flag for graph indicates graph are official
|
||||
Recovered = cr::bit (5), // this is additional flag indicates graph converted from podbot and was bad
|
||||
Exten = cr::bit (6), // this is additional flag indicates that there's extension info
|
||||
Analyzed = cr::bit (7) // this graph has been analyzed
|
||||
)
|
||||
|
||||
// storage header versions
|
||||
CR_DECLARE_SCOPED_ENUM (StorageVersion,
|
||||
Graph = 2,
|
||||
Practice = 2,
|
||||
Vistable = 3,
|
||||
Matrix = 2,
|
||||
Podbot = 7
|
||||
)
|
||||
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (BotFile, uint32_t,
|
||||
Vistable = 0,
|
||||
LogFile = 1,
|
||||
Practice = 2,
|
||||
Graph = 3,
|
||||
Pathmatrix = 4,
|
||||
PodbotPWF = 5,
|
||||
EbotEWP = 6
|
||||
)
|
||||
|
||||
class BotStorage final : public Singleton <BotStorage> {
|
||||
private:
|
||||
struct SaveLoadData {
|
||||
String name {};
|
||||
int32_t option {};
|
||||
int32_t version {};
|
||||
|
||||
public:
|
||||
SaveLoadData (StringRef name, int32_t option, int32_t version) : name (name), option (option), version (version) {}
|
||||
};
|
||||
|
||||
private:
|
||||
int m_retries {};
|
||||
|
||||
public:
|
||||
BotStorage () = default;
|
||||
~BotStorage () = default;
|
||||
|
||||
public:
|
||||
// converts type to save/load options
|
||||
template <typename U> SaveLoadData guessType ();
|
||||
|
||||
// loads the data and decompress ulz
|
||||
template <typename U> bool load (SmallArray <U> &data, ExtenHeader *exten = nullptr, int32_t *outOptions = nullptr);
|
||||
|
||||
// saves the data and compress with ulz
|
||||
template <typename U> bool save (const SmallArray <U> &data, ExtenHeader *exten = nullptr, int32_t passOptions = 0);
|
||||
|
||||
// report fatail error loading stuff
|
||||
template <typename ...Args> bool error (bool isGraph, bool isDebug, MemFile &file, const char *fmt, Args &&...args);
|
||||
|
||||
// builds the filename to requested filename
|
||||
String buildPath (int32_t type, bool isMemoryLoad = false);
|
||||
|
||||
// converts storage option to stroage filename
|
||||
int32_t storageToBotFile (int32_t options);
|
||||
|
||||
// remove all bot related files frorm disk
|
||||
void unlinkFromDisk ();
|
||||
|
||||
public:
|
||||
// loading the graph may attemp to recurse loading, with converting or download, reset retry counter
|
||||
void resetRetries () {
|
||||
m_retries = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined (BOT_STORAGE_EXPLICIT_INSTANTIATIONS)
|
||||
# define BOT_STORAGE_EXPLICIT_INSTANTIATIONS
|
||||
# include "../src/storage.cpp"
|
||||
#endif
|
||||
|
||||
#undef BOT_STORAGE_EXPLICIT_INSTANTIATIONS
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (BotStorage, bstor);
|
||||
|
||||
|
|
@ -7,16 +7,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (BotFile, uint32_t,
|
||||
Vistable = 0,
|
||||
LogFile = 1,
|
||||
Practice = 2,
|
||||
Graph = 3,
|
||||
Pathmatrix = 4,
|
||||
PodbotPWF = 5,
|
||||
EbotEWP = 6
|
||||
)
|
||||
|
||||
class BotSupport final : public Singleton <BotSupport> {
|
||||
private:
|
||||
bool m_needToSendWelcome {};
|
||||
|
|
@ -106,12 +96,6 @@ public:
|
|||
// get the current date and time as string
|
||||
String getCurrentDateTime ();
|
||||
|
||||
// builds the filename to requested filename
|
||||
String buildPath (int32_t type, bool isMemoryLoad = false);
|
||||
|
||||
// converts storage option to stroage filename
|
||||
int32_t storageToBotFile (StorageOption options);
|
||||
|
||||
public:
|
||||
|
||||
// re-show welcome after changelevel ?
|
||||
|
|
|
|||
61
inc/vistable.h
Normal file
61
inc/vistable.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// limits for storing practice data
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (VisIndex, int32_t,
|
||||
None = 0,
|
||||
Stand = 1,
|
||||
Crouch = 2,
|
||||
Any = Stand | Crouch
|
||||
)
|
||||
|
||||
// defines visibility count
|
||||
struct PathVis {
|
||||
uint16_t stand, crouch;
|
||||
};
|
||||
|
||||
class GraphVistable final : public Singleton <GraphVistable> {
|
||||
public:
|
||||
using VisStorage = uint8_t;
|
||||
|
||||
private:
|
||||
SmallArray <VisStorage> m_vistable {};
|
||||
bool m_rebuild {};
|
||||
int m_length {};
|
||||
|
||||
int m_curIndex {};
|
||||
int m_sliceIndex {};
|
||||
|
||||
float m_notifyMsgTimestamp {};
|
||||
|
||||
public:
|
||||
GraphVistable () = default;
|
||||
~GraphVistable () = default;
|
||||
|
||||
public:
|
||||
bool visible (int srcIndex, int destIndex, VisIndex vis = VisIndex::Any);
|
||||
|
||||
void load ();
|
||||
void save ();
|
||||
void rebuild ();
|
||||
|
||||
public:
|
||||
|
||||
// triggers re-check for all the nodes
|
||||
void startRebuild ();
|
||||
|
||||
// ready to use ?
|
||||
bool isReady () const {
|
||||
return !m_rebuild;
|
||||
}
|
||||
};
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (GraphVistable, vistab);
|
||||
|
||||
103
inc/yapb.h
103
inc/yapb.h
|
|
@ -443,12 +443,6 @@ namespace TaskPri {
|
|||
static constexpr float EscapeFromBomb { 100.0f };
|
||||
}
|
||||
|
||||
// storage file magic
|
||||
constexpr char kPodbotMagic[8] = "PODWAY!";
|
||||
|
||||
constexpr int32_t kStorageMagic = 0x59415042; // storage magic for yapb-data files
|
||||
constexpr int32_t kStorageMagicUB = 0x544f4255; //support also the fork format (merged back into yapb)
|
||||
|
||||
constexpr float kInfiniteDistance = 9999999.0f;
|
||||
constexpr float kGrenadeCheckTime = 0.6f;
|
||||
constexpr float kSprayDistance = 260.0f;
|
||||
|
|
@ -456,10 +450,6 @@ constexpr float kDoubleSprayDistance = kSprayDistance * 2;
|
|||
constexpr float kMaxChatterRepeatInterval = 99.0f;
|
||||
|
||||
constexpr int kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance);
|
||||
constexpr int kMaxNodeLinks = 8;
|
||||
constexpr int kMaxPracticeDamageValue = 2040;
|
||||
constexpr int kMaxPracticeGoalValue = 2040;
|
||||
constexpr int kMaxNodes = 2048;
|
||||
constexpr int kMaxWeapons = 32;
|
||||
constexpr int kNumWeapons = 26;
|
||||
constexpr int kMaxCollideMoves = 3;
|
||||
|
|
@ -598,11 +588,78 @@ struct ChatCollection {
|
|||
// include bot graph stuff
|
||||
#include <graph.h>
|
||||
|
||||
// this structure links nodes returned from pathfinder
|
||||
class PathWalk final : public DenyCopying {
|
||||
private:
|
||||
size_t m_cursor {};
|
||||
size_t m_length {};
|
||||
|
||||
UniquePtr <int32_t[]> m_path {};
|
||||
|
||||
public:
|
||||
explicit PathWalk () = default;
|
||||
~PathWalk () = default;
|
||||
|
||||
public:
|
||||
int32_t &next () {
|
||||
return at (1);
|
||||
}
|
||||
|
||||
int32_t &first () {
|
||||
return at (0);
|
||||
}
|
||||
|
||||
int32_t &last () {
|
||||
return at (length () - 1);
|
||||
}
|
||||
|
||||
int32_t &at (size_t index) {
|
||||
return m_path[m_cursor + index];
|
||||
}
|
||||
|
||||
void shift () {
|
||||
++m_cursor;
|
||||
}
|
||||
|
||||
void reverse () {
|
||||
for (size_t i = 0; i < m_length / 2; ++i) {
|
||||
cr::swap (m_path[i], m_path[m_length - 1 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t length () const {
|
||||
if (m_cursor >= m_length) {
|
||||
return 0;
|
||||
}
|
||||
return m_length - m_cursor;
|
||||
}
|
||||
|
||||
bool hasNext () const {
|
||||
return length () > m_cursor;
|
||||
}
|
||||
|
||||
bool empty () const {
|
||||
return !length ();
|
||||
}
|
||||
|
||||
void add (int32_t node) {
|
||||
m_path[m_length++] = node;
|
||||
}
|
||||
|
||||
void clear () {
|
||||
m_cursor = 0;
|
||||
m_length = 0;
|
||||
|
||||
m_path[0] = 0;
|
||||
}
|
||||
|
||||
void init (size_t length) {
|
||||
m_path = cr::makeUnique <int32_t[]> (length);
|
||||
}
|
||||
};
|
||||
|
||||
// main bot class
|
||||
class Bot final {
|
||||
private:
|
||||
using RouteTwin = Twin <int, float>;
|
||||
|
||||
public:
|
||||
friend class BotManager;
|
||||
|
||||
|
|
@ -632,6 +689,7 @@ private:
|
|||
int m_tryOpenDoor {}; // attempt's to open the door
|
||||
int m_liftState {}; // state of lift handling
|
||||
int m_radioSelect {}; // radio entry
|
||||
int m_lastPredictIndex {}; // last predicted index
|
||||
|
||||
float m_headedTime {};
|
||||
float m_prevTime {}; // time previously checked movement speed
|
||||
|
|
@ -744,16 +802,14 @@ private:
|
|||
|
||||
Array <edict_t *> m_ignoredBreakable {}; // list of ignored breakables
|
||||
Array <edict_t *> m_hostages {}; // pointer to used hostage entities
|
||||
Array <Route> m_routes {}; // pointer
|
||||
Array <int32_t> m_nodeHistory {}; // history of selected goals
|
||||
|
||||
BinaryHeap <RouteTwin> m_routeQue {};
|
||||
Path *m_path {}; // pointer to the current path node
|
||||
String m_chatBuffer {}; // space for strings (say text...)
|
||||
FrustumPlane m_frustum[FrustumSide::Num] {};
|
||||
|
||||
private:
|
||||
int pickBestWeapon (int *vec, int count, int moneySave);
|
||||
int pickBestWeapon (Array <int> &vec, int moneySave);
|
||||
int getRandomCampDir ();
|
||||
int findAimingNode (const Vector &to, int &pathLength);
|
||||
int findNearestNode ();
|
||||
|
|
@ -863,9 +919,7 @@ private:
|
|||
void updatePracticeDamage (edict_t *attacker, int damage);
|
||||
void findShortestPath (int srcIndex, int destIndex);
|
||||
void calculateFrustum ();
|
||||
|
||||
void findPath (int srcIndex, int destIndex, FindPath pathType = FindPath::Fast);
|
||||
void clearRoute ();
|
||||
void debugMsgInternal (const char *str);
|
||||
void frame ();
|
||||
void resetCollision ();
|
||||
|
|
@ -950,6 +1004,13 @@ private:
|
|||
issueCommand ("drop");
|
||||
}
|
||||
|
||||
// ensures current node is ok
|
||||
void ensureCurrentNodeIndex () {
|
||||
if (m_currentNodeIndex == kInvalidNodeIndex) {
|
||||
changeNodeIndex (findNearestNode ());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
entvars_t *pev {};
|
||||
|
||||
|
|
@ -1189,6 +1250,9 @@ public:
|
|||
#include "engine.h"
|
||||
#include "manager.h"
|
||||
#include "control.h"
|
||||
#include "planner.h"
|
||||
#include "storage.h"
|
||||
#include "analyze.h"
|
||||
|
||||
// very global convars
|
||||
extern ConVar cv_jasonmode;
|
||||
|
|
@ -1211,7 +1275,10 @@ extern ConVar cv_debug_goal;
|
|||
extern ConVar cv_save_bots_names;
|
||||
extern ConVar cv_random_knife_attacks;
|
||||
extern ConVar cv_rotate_bots;
|
||||
extern ConVar cv_graph_url;
|
||||
extern ConVar cv_graph_url_upload;
|
||||
extern ConVar cv_graph_auto_save_count;
|
||||
extern ConVar cv_graph_analyze_max_jump_height;
|
||||
|
||||
extern ConVar mp_freezetime;
|
||||
extern ConVar mp_roundtime;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue