chatlib: do not send chat messages to controlled bots

graph: first try more memory friendly bsp size check
build: restore ssse3 & ssse3 instructions (use nosmid version if needed)
Co-Authored-By: Max <161382234+dyspose@users.noreply.github.com>
This commit is contained in:
jeefo 2025-02-28 00:39:52 +03:00
commit 855fb903b6
No known key found for this signature in database
GPG key ID: D696786B81B667C8
13 changed files with 76 additions and 41 deletions

@ -1 +1 @@
Subproject commit 448e8341b8bba351c7b9e81ea9949588cedad10a
Subproject commit 399bcca8ec69dd5368f93124598fa07a4349a94e

View file

@ -281,7 +281,7 @@ public:
// bot async worker wrapper
class BotThreadWorker final : public Singleton <BotThreadWorker> {
private:
ThreadPool m_botWorker {};
UniquePtr <ThreadPool> m_pool {};
public:
explicit BotThreadWorker () = default;
@ -297,12 +297,12 @@ public:
fn (); // no threads, no fun, just run task in current thread
return;
}
m_botWorker.enqueue (cr::move (fn));
m_pool->enqueue (cr::move (fn));
}
public:
bool available () {
return m_botWorker.threadCount () > 0;
return m_pool && m_pool->threadCount () > 0;
}
};

View file

@ -57,6 +57,7 @@ private:
private:
int m_retries {};
ULZ *m_ulz {};
public:
BotStorage () = default;
@ -95,6 +96,11 @@ public:
void resetRetries () {
m_retries = 0;
}
// set the compressor instance
void setUlzInstance (ULZ *ulz) {
m_ulz = ulz;
}
};
#if !defined (BOT_STORAGE_EXPLICIT_INSTANTIATIONS)

View file

@ -188,9 +188,8 @@ public:
m_path[0] = 0;
}
void init (int32_t length) {
const auto allocSize = static_cast <uint32_t> (length);
m_path = cr::makeUnique <int32_t[]> (allocSize);
void init (size_t length) {
m_path = cr::makeUnique <int32_t[]> (length);
}
};
@ -320,7 +319,7 @@ private:
Fight m_fightStyle {}; // combat style to use
CollisionState m_collisionState {}; // collision State
FindPath m_pathType {}; // which pathfinder to use
uint8_t m_enemyParts {}; // visibility flags
int8_t m_enemyParts {}; // visibility flags
uint16_t m_modelMask {}; // model mask bits
UniquePtr <class AStarAlgo> m_planner {};

View file

@ -105,7 +105,9 @@ endif
# configure flags gcc and clang
if cxx == 'clang' or cxx == 'gcc'
cxxflags += [
'-fno-threadsafe-statics', '-pthread'
'-pipe',
'-fno-threadsafe-statics',
'-pthread'
]
if not opt_native and cpu != 'arm' and not cpu.startswith('ppc')
@ -119,7 +121,7 @@ if cxx == 'clang' or cxx == 'gcc'
elif cpu != 'arm' and not cpu.startswith('ppc')
if not opt_nosimd
cxxflags += [
'-msse', '-msse2', '-mfpmath=sse'
'-msse', '-msse2', '-msse3', '-msse3', '-mfpmath=sse'
]
endif
@ -131,6 +133,8 @@ if cxx == 'clang' or cxx == 'gcc'
cxxflags += '-march=i686'
endif
endif
cxx_version = compiler.version()
# setup optimization flags
if build_type == 'release'
@ -162,7 +166,7 @@ if cxx == 'clang' or cxx == 'gcc'
endif
# disable lto partitioning on gcc to get symver working
if os != 'darwin' and os != 'windows' and cxx == 'gcc'
if os != 'darwin' and os != 'windows' and cxx == 'gcc' and cxx_version.version_compare('<11.0')
ldflags += [
'-flto-partition=none'
]
@ -172,7 +176,7 @@ if cxx == 'clang' or cxx == 'gcc'
endif
# special script for mingw-64 builds
if os == 'windows' and cxx == 'gcc' and compiler.version().version_compare('<12.0')
if os == 'windows' and cxx == 'gcc' and cxx_version.version_compare('<12.0')
ldflags += [
'-Xlinker', '--script', '-Xlinker', meson.project_source_root() + '/ext/ldscripts/i386pe.lds'
]

View file

@ -410,6 +410,11 @@ void Bot::sendToChatLegacy (StringRef message, bool teamOnly) {
bool dedicatedSend = false;
auto sendChatMsg = [&] (const Client &client, String chatMsg) {
if (game.isDedicated () && !dedicatedSend) {
dedicatedSend = true;
game.print ("%s", chatMsg.trim ());
}
auto rcv = bots[client.ent];
if (rcv != nullptr) {
@ -418,6 +423,9 @@ void Bot::sendToChatLegacy (StringRef message, bool teamOnly) {
rcv->m_sayTextBuffer.sayText = message;
rcv->m_sayTextBuffer.timeNextChat = game.time () + rcv->m_sayTextBuffer.chatDelay;
}
else {
return; // do not send to controlled bots
}
if (((client.flags & ClientFlags::Alive) && m_isAlive)
|| (!(client.flags & ClientFlags::Alive) && m_isAlive)
@ -427,11 +435,6 @@ void Bot::sendToChatLegacy (StringRef message, bool teamOnly) {
.writeByte (m_index)
.writeString (chatMsg.chars ());
}
if (game.isDedicated () && !dedicatedSend) {
game.print ("%s", chatMsg.trim ());
}
dedicatedSend = true;
};
if (teamOnly) {

View file

@ -1159,7 +1159,12 @@ void Game::printBotVersion () {
}
if (is (GameFlags::Xash3D)) {
gameVersionStr.append (" @ Xash3D Engine");
if (is (GameFlags::Xash3DLegacy)) {
gameVersionStr.append (" @ Xash3D (Old)");
}
else {
gameVersionStr.append (" @ Xash3D FWGS");
}
if (is (GameFlags::Mobility)) {
gameVersionStr.append (" Mobile");
@ -1414,7 +1419,7 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
// compute the lightmap color at a particular point
for (int maps = 0; maps < MAX_LIGHTMAPS && surf->styles[maps] != 255; ++maps) {
const uint32_t scale = m_lightstyleValue[surf->styles[maps]];
const auto scale = static_cast <int32_t> (m_lightstyleValue[surf->styles[maps]]);
m_point.red += lightmap->r * scale;
m_point.green += lightmap->g * scale;

View file

@ -72,13 +72,16 @@ void BotFakePingManager::syncCalculate () {
}
for (auto &bot : bots) {
auto botPing = static_cast <int> (bot->m_pingBase + rg (averagePing - averagePing * 0.2f, averagePing + averagePing * 0.2f) + rg (bot->m_difficulty + 3, bot->m_difficulty + 6));
const auto diff = static_cast <int> (static_cast <float> (averagePing) * 0.2f);
if (botPing < 5) {
botPing = rg (10, 15);
// randomize bot ping
auto botPing = static_cast <float> (bot->m_pingBase + rg (averagePing - diff, averagePing + diff) + rg (bot->m_difficulty + 3, bot->m_difficulty + 6));
if (botPing < 5.0f) {
botPing = rg (10.0f, 15.0f);
}
else if (botPing > 100) {
botPing = rg (30, 40);
else if (botPing > 75.0f) {
botPing = rg (30.0f, 40.0f);
}
bot->m_ping = static_cast <int> (static_cast <float> (bot->entindex () % 2 == 0 ? botPing * 0.25f : botPing * 0.5f));
}

View file

@ -406,10 +406,13 @@ int BotGraph::clearConnections (int index) {
}
int BotGraph::getBspSize () {
MemFile file (strings.format ("maps/%s.bsp", game.getMapName ()));
if (File bsp { strings.joinPath (game.getRunningModName (), "maps", game.getMapName ()) + ".bsp", "rb" }) {
return static_cast <int> (bsp.length ());
}
if (file) {
return static_cast <int> (file.length ());
// worst case, load using engine (engfuncs.pfnGetFileSize isn't available on some legacy engines)
if (MemFile bsp { strings.joinPath (game.getRunningModName (), "maps", game.getMapName ()) + ".bsp" }) {
return static_cast <int> (bsp.length ());
}
return 0;
}
@ -1777,6 +1780,10 @@ bool BotGraph::loadGraphData () {
// re-initialize paths
reset ();
// initialize compression
ULZ ulz {};
bstor.setUlzInstance (&ulz);
// check if loaded
const bool dataLoaded = bstor.load <Path> (m_paths, &exten, &outOptions);
@ -1807,9 +1814,9 @@ bool BotGraph::loadGraphData () {
populateNodes ();
if (exten.mapSize > 0) {
int mapSize = getBspSize ();
const int mapSize = getBspSize ();
if (mapSize != exten.mapSize) {
if (mapSize > 0 && mapSize != exten.mapSize) {
msg ("Warning: Graph data is probably not for this map. Please check bots behaviour.");
}
}
@ -2377,7 +2384,7 @@ void BotGraph::frame () {
message.assignf (" %s node:\n"
" Node %d of %d, Radius: %.1f, Light: %s\n"
" Flags: %s\n"
" Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, p.radius, p.light == kInvalidLightLevel ? "Invalid" : strings.format ("%1.f", p.light), flags, p.origin.x, p.origin.y, p.origin.z);
" Origin: (%.1f, %.1f, %.1f)\n", type, node, m_paths.length () - 1, p.radius, cr::fequal (p.light, kInvalidLightLevel) ? "Invalid" : strings.format ("%1.f", p.light), flags, p.origin.x, p.origin.y, p.origin.z);
return message;
};

View file

@ -1225,7 +1225,6 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
// init path walker
m_pathWalk.init (m_planner->getMaxLength ());
// init player models parts enumerator
m_hitboxEnumerator = cr::makeUnique <PlayerHitboxEnumerator> ();
@ -1675,7 +1674,7 @@ void Bot::newRound () {
auto updateInterval = 1.0f / thinkFps;
auto commandInterval = 1.0f / 60.0f;
if (game.is (GameFlags::Xash3D | GameFlags::Xash3DLegacy)) {
if (game.is (GameFlags::Xash3D)) {
if (thinkFps < 50) {
updateInterval = 1.0f / 50.0f; // xash3d works acceptable at 50fps
}
@ -2172,7 +2171,10 @@ void BotThreadWorker::shutdown () {
return;
}
game.print ("Shutting down bot thread worker.");
m_botWorker.shutdown ();
m_pool->shutdown ();
// re-start pool completely
m_pool.release ();
}
void BotThreadWorker::startup (int workers) {
@ -2185,7 +2187,10 @@ void BotThreadWorker::startup (int workers) {
if (isLegacyGame || workers == 0 || (!disableWorkerEnv.empty () && disableWorkerEnv == "1")) {
return;
}
const auto count = m_botWorker.threadCount ();
m_pool = cr::makeUnique <ThreadPool> ();
// define worker threads
const auto count = m_pool->threadCount ();
if (count > 0) {
logger.error ("Tried to start thread pool with existing %d threads in pool.", count);
@ -2203,7 +2208,7 @@ void BotThreadWorker::startup (int workers) {
game.print ("Starting up bot thread worker with %d threads.", requestedThreads);
// start up the worker
m_botWorker.startup (static_cast <size_t> (requestedThreads));
m_pool->startup (static_cast <size_t> (requestedThreads));
}
bool BotManager::isLineBlockedBySmoke (const Vector &from, const Vector &to) {
@ -2325,5 +2330,5 @@ bool BotManager::isFrameSkipDisabled () {
if (game.is (GameFlags::Legacy)) {
return true;
}
return game.is (GameFlags::Xash3D | GameFlags::Xash3DLegacy) && cv_think_fps_disable;
return game.is (GameFlags::Xash3D) && cv_think_fps_disable;
}

View file

@ -149,9 +149,8 @@ template <typename U> bool BotStorage::load (SmallArray <U> &data, ExtenHeader *
// read compressed data
if (file.read (compressed.data (), sizeof (uint8_t), compressedSize) == compressedSize) {
// try to uncompress
if (ulz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast <uint8_t *> (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
if (m_ulz->uncompress (compressed.data (), hdr.compressed, reinterpret_cast <uint8_t *> (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
return error (isGraph, isDebug, file, "Unable to decompress ULZ data for %s (filename: '%s').", type.name, filename);
}
else {
@ -248,8 +247,12 @@ template <typename U> bool BotStorage::save (const SmallArray <U> &data, ExtenHe
const auto rawLength = data.length () * sizeof (U);
SmallArray <uint8_t> compressed (rawLength + sizeof (uint8_t) * ULZ::Excess);
// initialize compression
ULZ ulz {};
setUlzInstance (&ulz);
// try to compress
const auto compressedLength = static_cast <size_t> (ulz.compress (reinterpret_cast <uint8_t *> (data.data ()), static_cast <int32_t> (rawLength), reinterpret_cast <uint8_t *> (compressed.data ())));
const auto compressedLength = static_cast <size_t> (m_ulz->compress (reinterpret_cast <uint8_t *> (data.data ()), static_cast <int32_t> (rawLength), reinterpret_cast <uint8_t *> (compressed.data ())));
if (compressedLength > 0) {
StorageHeader hdr {};

View file

@ -428,7 +428,7 @@ void Bot::setAimDirection () {
}
// don't switch view right away after loosing focus with current enemy
if ((m_shootTime + 1.5f > game.time () || m_seeEnemyTime + 1.5 > game.time ())
if ((m_shootTime + 1.5f > game.time () || m_seeEnemyTime + 1.5f > game.time ())
&& m_forgetLastVictimTimer.elapsed ()
&& !m_lastEnemyOrigin.empty ()
&& util.isAlive (m_lastEnemy)

View file

@ -169,7 +169,7 @@ void GraphVistable::load () {
m_rebuild = false;
}
else {
m_vistable.resize (cr::sqrf (m_length));
m_vistable.resize (static_cast <size_t> (cr::sqrf (m_length)));
m_notifyMsgTimestamp = game.time ();
}
}