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:
jeefo 2023-05-02 09:42:43 +03:00 committed by GitHub
commit e7712a551a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 3114 additions and 1722 deletions

View file

@ -39,10 +39,7 @@ void Game::precache () {
m_engineWrap.precacheSound ("weapons/xbow_hit1.wav"); // waypoint add
m_engineWrap.precacheSound ("weapons/mine_activate.wav"); // waypoint delete
m_engineWrap.precacheSound ("common/wpn_hudoff.wav"); // path add/delete start
m_engineWrap.precacheSound ("common/wpn_hudon.wav"); // path add/delete done
m_engineWrap.precacheSound ("common/wpn_moveselect.wav"); // path add/delete cancel
m_engineWrap.precacheSound ("common/wpn_denyselect.wav"); // path add/delete error
m_mapFlags = 0; // reset map type as worldspawn is the first entity spawned
@ -68,27 +65,27 @@ void Game::levelInitialize (edict_t *entities, int max) {
// update worldmodel
illum.resetWorldModel ();
// do level initialization stuff here...
graph.loadGraphData ();
// execute main config
conf.loadMainConfig ();
// load map-specific config
conf.loadMapSpecificConfig ();
// do level initialization stuff here...
graph.loadGraphData ();
// initialize quota management
bots.initQuota ();
// rebuild vistable if needed
graph.rebuildVisibility ();
// install the sendto hook to fake queries
util.installSendTo ();
// flush any print queue
ctrl.resetFlushTimestamp ();
// suspend any analyzer tasks
analyzer.suspend ();
// go thru the all entities on map, and do whatever we're want
for (int i = 0; i < max; ++i) {
auto ent = entities + i;
@ -413,11 +410,11 @@ void Game::playSound (edict_t *ent, const char *sound) {
}
void Game::setPlayerStartDrawModels () {
HashMap <String, String> models;
models["info_player_start"] = "models/player/urban/urban.mdl";
models["info_player_deathmatch"] = "models/player/terror/terror.mdl";
models["info_vip_start"] = "models/player/vip/vip.mdl";
static HashMap <String, String> models {
{"info_player_start", "models/player/urban/urban.mdl"},
{"info_player_deathmatch", "models/player/terror/terror.mdl"},
{"info_vip_start", "models/player/vip/vip.mdl"}
};
models.foreach ([&] (const String &key, const String &val) {
game.searchEntities ("classname", key, [&] (edict_t *ent) {
@ -620,6 +617,7 @@ void Game::addNewCvar (const char *name, const char *value, const char *info, bo
reg.reg.name = const_cast <char *> (name);
reg.reg.string = const_cast <char *> (value);
reg.name = name;
reg.missing = missingAction;
reg.init = value;
reg.info = info;
@ -654,6 +652,20 @@ void Game::addNewCvar (const char *name, const char *value, const char *info, bo
m_cvars.push (cr::move (reg));
}
void ConVar::revert () {
if (!ptr) {
return;
}
const auto &cvars = game.getCvars ();
for (const auto &var : cvars) {
if (var.name == ptr->name) {
set (var.initial);
break;
}
}
}
void Game::checkCvarsBounds () {
for (const auto &var : m_cvars) {
@ -669,14 +681,14 @@ void Game::checkCvarsBounds () {
continue;
}
auto value = var.self->float_ ();
auto str = var.self->str ();
auto str = String (var.self->str ());
// check the bounds and set default if out of bounds
if (value > var.max || value < var.min || (!strings.isEmpty (str) && isalpha (*str))) {
if (value > var.max || value < var.min || (!str.empty () && isalpha (str[0]))) {
var.self->set (var.initial);
// notify about that
ctrl.msg ("Bogus value for cvar '%s', min is '%.1f' and max is '%.1f', and we're got '%s', value reverted to default '%.1f'.", var.reg.name, var.min, var.max, str, var.initial);
ctrl.msg ("Bogus value for cvar '%s', min is '%.1f' and max is '%.1f', and we're got '%s', value reverted to default '%.1f'.", var.name, var.min, var.max, str, var.initial);
}
}
@ -741,19 +753,7 @@ bool Game::loadCSBinary () {
if (!modname) {
return false;
}
StringArray libs;
if (plat.win) {
libs.push ("mp.dll");
libs.push ("cs.dll");
}
else if (plat.nix) {
libs.push ("cs.so");
libs.push ("cs_i386.so");
}
else if (plat.osx) {
libs.push ("cs.dylib");
}
StringArray libs { "mp", "cs", "cs_i386" };
auto libCheck = [&] (StringRef mod, StringRef dll) {
// try to load gamedll
@ -771,7 +771,7 @@ bool Game::loadCSBinary () {
// search the libraries inside game dlls directory
for (const auto &lib : libs) {
auto path = strings.format ("%s/dlls/%s", modname, lib);
auto path = strings.format ("%s/dlls/%s.%s", modname, lib, DLL_SUFFIX);
// if we can't read file, skip it
if (!File::exists (path)) {
@ -834,7 +834,7 @@ bool Game::loadCSBinary () {
bool Game::postload () {
// register logger
logger.initialize (util.buildPath (BotFile::LogFile), [] (const char *msg) {
logger.initialize (bstor.buildPath (BotFile::LogFile), [] (const char *msg) {
game.print (msg);
});