diff --git a/inc/constant.h b/inc/constant.h index 4f02753..874249b 100644 --- a/inc/constant.h +++ b/inc/constant.h @@ -416,23 +416,23 @@ CR_DECLARE_SCOPED_ENUM (FrustumSide, ) // some hard-coded desire defines used to override calculated ones -struct TaskPri { - static constexpr auto Normal { 35.0f }; - static constexpr auto Pause { 36.0f }; - static constexpr auto Camp { 37.0f }; - static constexpr auto Spraypaint { 38.0f }; - static constexpr auto FollowUser { 39.0f }; - static constexpr auto MoveToPosition { 50.0f }; - static constexpr auto DefuseBomb { 89.0f }; - static constexpr auto PlantBomb { 89.0f }; - static constexpr auto Attack { 90.0f }; - static constexpr auto SeekCover { 91.0f }; - static constexpr auto Hide { 92.0f }; - static constexpr auto Throw { 99.0f }; - static constexpr auto DoubleJump { 99.0f }; - static constexpr auto Blind { 100.0f }; - static constexpr auto ShootBreakable { 100.0f }; - static constexpr auto EscapeFromBomb { 100.0f }; +namespace TaskPri { + constexpr auto Normal { 35.0f }; + constexpr auto Pause { 36.0f }; + constexpr auto Camp { 37.0f }; + constexpr auto Spraypaint { 38.0f }; + constexpr auto FollowUser { 39.0f }; + constexpr auto MoveToPosition { 50.0f }; + constexpr auto DefuseBomb { 89.0f }; + constexpr auto PlantBomb { 89.0f }; + constexpr auto Attack { 90.0f }; + constexpr auto SeekCover { 91.0f }; + constexpr auto Hide { 92.0f }; + constexpr auto Throw { 99.0f }; + constexpr auto DoubleJump { 99.0f }; + constexpr auto Blind { 100.0f }; + constexpr auto ShootBreakable { 100.0f }; + constexpr auto EscapeFromBomb { 100.0f }; }; constexpr auto kInfiniteDistance = 9999999.0f; @@ -441,6 +441,7 @@ constexpr auto kGrenadeCheckTime = 0.6f; constexpr auto kSprayDistance = 260.0f; constexpr auto kDoubleSprayDistance = kSprayDistance * 2; constexpr auto kMaxChatterRepeatInterval = 99.0f; +constexpr auto kViewFrameUpdate = 1.0f / 30.0f; constexpr auto kInfiniteDistanceLong = static_cast (kInfiniteDistance); constexpr auto kMaxWeapons = 32; diff --git a/inc/yapb.h b/inc/yapb.h index 48e8377..c97d8cd 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -225,6 +225,7 @@ public: private: mutable Mutex m_pathFindLock {}; mutable Mutex m_predictLock {}; + mutable Mutex m_lookAnglesLock {}; private: uint32_t m_states {}; // sensing bitstates @@ -471,6 +472,7 @@ private: void checkBurstMode (float distance); void checkSilencer (); void updateAimDir (); + void syncUpdateLookAngles (); void updateLookAngles (); void updateBodyAngles (); void updateLookAnglesNewbie (const Vector &direction, float delta); @@ -701,7 +703,8 @@ public: // need to wait until all threads will finish it's work before terminating bot object ~Bot () { - MutexScopedLock lock (m_pathFindLock); + MutexScopedLock lock1 (m_pathFindLock); + MutexScopedLock lock2 (m_lookAnglesLock); } public: diff --git a/src/botlib.cpp b/src/botlib.cpp index 3cf0d1a..39f7c76 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -82,7 +82,7 @@ void Bot::avoidGrenades () { if (!bots.hasActiveGrenades ()) { return; } - auto &activeGrenades = bots.getActiveGrenades (); + const auto &activeGrenades = bots.getActiveGrenades (); // find all grenades on the map for (auto pent : activeGrenades) { @@ -524,7 +524,7 @@ void Bot::updatePickups () { allowPickup = false; if (!m_defendHostage && m_personality != Personality::Rusher && m_difficulty >= Difficulty::Normal && rg.chance (15) && m_timeCamping + 15.0f < game.time ()) { - int index = findDefendNode (origin); + const int index = findDefendNode (origin); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 60.0f), true); // push camp task on to stack startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (3.0f, 6.0f), true); // push move command @@ -543,11 +543,11 @@ void Bot::updatePickups () { if (!m_defendedBomb) { m_defendedBomb = true; - int index = findDefendNode (origin); + const int index = findDefendNode (origin); const Path &path = graph[index]; - float bombTimer = mp_c4timer.float_ (); - float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); + const float bombTimer = mp_c4timer.float_ (); + const float timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); if (timeMidBlowup > game.time ()) { clearTask (Task::MoveToPosition); // remove any move tasks @@ -618,10 +618,10 @@ void Bot::updatePickups () { if (!m_defendedBomb && !allowPickup) { m_defendedBomb = true; - int index = findDefendNode (origin); + const int index = findDefendNode (origin); const auto &path = graph[index]; - float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.float_ () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); + const float timeToExplode = bots.getTimeBombPlanted () + mp_c4timer.float_ () - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin); clearTask (Task::MoveToPosition); // remove any move tasks @@ -648,7 +648,7 @@ void Bot::updatePickups () { allowPickup = false; if (!m_defendedBomb && m_difficulty >= Difficulty::Normal && rg.chance (75) && m_healthValue < 60) { - int index = findDefendNode (origin); + const int index = findDefendNode (origin); startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.get (30.0f, 70.0f), true); // push camp task on to stack startTask (Task::MoveToPosition, TaskPri::MoveToPosition, index, game.time () + rg.get (10.0f, 30.0f), true); // push move command @@ -778,7 +778,7 @@ Vector Bot::getCampDirection (const Vector &dest) { return graph[lookAtNode].origin; } } - auto dangerIndex = practice.getIndex (m_team, m_currentNodeIndex, m_currentNodeIndex); + const auto dangerIndex = practice.getIndex (m_team, m_currentNodeIndex, m_currentNodeIndex); if (graph.exists (dangerIndex)) { return graph[dangerIndex].origin; diff --git a/src/graph.cpp b/src/graph.cpp index 8e12129..24605fd 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -2300,7 +2300,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) { } // perform DFS instead of floyd-warshall, this shit speedup this process in a bit - auto length = cr::min (static_cast (kMaxNodes), m_paths.length ()); + const auto length = cr::min (static_cast (kMaxNodes), m_paths.length ()); // ensure valid capacity assert (length > 8 && length < static_cast (kMaxNodes)); diff --git a/src/navigate.cpp b/src/navigate.cpp index 61957f7..93cec76 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -2153,9 +2153,6 @@ bool Bot::selectBestNextNode () { // this function does a realtime post processing of nodes return from the // pathfinder, to vary paths and find the best node on our way - assert (!m_pathWalk.empty ()); - assert (m_pathWalk.hasNext ()); - const auto nextNodeIndex = m_pathWalk.next (); const auto currentNodeIndex = m_pathWalk.first (); const auto prevNodeIndex = m_currentNodeIndex; diff --git a/src/support.cpp b/src/support.cpp index 344600e..f74483b 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -412,7 +412,9 @@ void BotSupport::updateClients () { } int BotSupport::getPingBitmask (edict_t *ent, int loss, int ping) { - // this function generats bitmask for SVC_PINGS engine message. See SV_EmitPings from engine for details + // this function generates bitmask for SVC_PINGS engine message + // see: + // https://github.com/dreamstalker/rehlds/blob/a680f18ee1e7eb8c39fbdc45682163ca9477d783/rehlds/engine/sv_main.cpp#L4590 const auto emit = [] (int s0, int s1, int s2) { return (s0 & (cr::bit (s1) - 1)) << s2; @@ -443,6 +445,16 @@ void BotSupport::syncCalculatePings () { int ping, loss; engfuncs.pfnGetPlayerStats (client.ent, &ping, &loss); + // @note: for those who asking on a email, we CAN call pfnGetPlayerStats hl-engine function in a separate thread + // since the function doesn't modify anything inside engine, so race-condition and crash isn't viable situation + // it's just fills ping and loss from engine structures, the only way to cause crash in separate thread + // is to call it with a invalid ``client`` pointer (on goldsrc), thus causing Con_Printf which is not compatible with + // multi-threaded environment + // + // see: + // https://github.com/dreamstalker/rehlds/blob/a680f18ee1e7eb8c39fbdc45682163ca9477d783/rehlds/engine/pr_cmds.cpp#L2735C15-L2735C32 + // https://github.com/fwgs/xash3d-fwgs/blob/f5b9826fd9bbbdc5293c1ff522de11ce28d3c9f2/engine/server/sv_game.c#L4443 + // store normal client ping client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg.get (8, 16)); // getting player ping sometimes fails ++numHumans; diff --git a/src/vision.cpp b/src/vision.cpp index baa5010..58aecd7 100644 --- a/src/vision.cpp +++ b/src/vision.cpp @@ -337,7 +337,18 @@ void Bot::updateBodyAngles () { } void Bot::updateLookAngles () { - const float delta = cr::clamp (game.time () - m_lookUpdateTime, cr::kFloatEqualEpsilon, 1.0f / 30.0f); + worker.enqueue ([this] () { + syncUpdateLookAngles (); + }); +} + +void Bot::syncUpdateLookAngles () { + if (!m_lookAnglesLock.tryLock ()) { + return; // allow only single instance of syncUpdateLookAngles per-bot + } + ScopedUnlock unlock (m_lookAnglesLock); + + const float delta = cr::clamp (game.time () - m_lookUpdateTime, cr::kFloatEqualEpsilon, kViewFrameUpdate); m_lookUpdateTime = game.time (); // adjust all body and view angles to face an absolute vector diff --git a/vc/yapb.vcxproj b/vc/yapb.vcxproj index 6684ca8..80bd7e1 100644 --- a/vc/yapb.vcxproj +++ b/vc/yapb.vcxproj @@ -122,7 +122,7 @@ DynamicLibrary - ClangCL + v143 false true false @@ -137,7 +137,7 @@ DynamicLibrary false - ClangCL + v143 false false