bot: switch look/body angles updates to thread worker

build: msvc projects now again targets msvc by default
This commit is contained in:
jeefo 2023-06-28 19:48:51 +03:00
commit 5ce2032acd
No known key found for this signature in database
GPG key ID: 927BCA0779BEA8ED
8 changed files with 59 additions and 35 deletions

View file

@ -416,23 +416,23 @@ CR_DECLARE_SCOPED_ENUM (FrustumSide,
) )
// some hard-coded desire defines used to override calculated ones // some hard-coded desire defines used to override calculated ones
struct TaskPri { namespace TaskPri {
static constexpr auto Normal { 35.0f }; constexpr auto Normal { 35.0f };
static constexpr auto Pause { 36.0f }; constexpr auto Pause { 36.0f };
static constexpr auto Camp { 37.0f }; constexpr auto Camp { 37.0f };
static constexpr auto Spraypaint { 38.0f }; constexpr auto Spraypaint { 38.0f };
static constexpr auto FollowUser { 39.0f }; constexpr auto FollowUser { 39.0f };
static constexpr auto MoveToPosition { 50.0f }; constexpr auto MoveToPosition { 50.0f };
static constexpr auto DefuseBomb { 89.0f }; constexpr auto DefuseBomb { 89.0f };
static constexpr auto PlantBomb { 89.0f }; constexpr auto PlantBomb { 89.0f };
static constexpr auto Attack { 90.0f }; constexpr auto Attack { 90.0f };
static constexpr auto SeekCover { 91.0f }; constexpr auto SeekCover { 91.0f };
static constexpr auto Hide { 92.0f }; constexpr auto Hide { 92.0f };
static constexpr auto Throw { 99.0f }; constexpr auto Throw { 99.0f };
static constexpr auto DoubleJump { 99.0f }; constexpr auto DoubleJump { 99.0f };
static constexpr auto Blind { 100.0f }; constexpr auto Blind { 100.0f };
static constexpr auto ShootBreakable { 100.0f }; constexpr auto ShootBreakable { 100.0f };
static constexpr auto EscapeFromBomb { 100.0f }; constexpr auto EscapeFromBomb { 100.0f };
}; };
constexpr auto kInfiniteDistance = 9999999.0f; constexpr auto kInfiniteDistance = 9999999.0f;
@ -441,6 +441,7 @@ constexpr auto kGrenadeCheckTime = 0.6f;
constexpr auto kSprayDistance = 260.0f; constexpr auto kSprayDistance = 260.0f;
constexpr auto kDoubleSprayDistance = kSprayDistance * 2; constexpr auto kDoubleSprayDistance = kSprayDistance * 2;
constexpr auto kMaxChatterRepeatInterval = 99.0f; constexpr auto kMaxChatterRepeatInterval = 99.0f;
constexpr auto kViewFrameUpdate = 1.0f / 30.0f;
constexpr auto kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance); constexpr auto kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance);
constexpr auto kMaxWeapons = 32; constexpr auto kMaxWeapons = 32;

View file

@ -225,6 +225,7 @@ public:
private: private:
mutable Mutex m_pathFindLock {}; mutable Mutex m_pathFindLock {};
mutable Mutex m_predictLock {}; mutable Mutex m_predictLock {};
mutable Mutex m_lookAnglesLock {};
private: private:
uint32_t m_states {}; // sensing bitstates uint32_t m_states {}; // sensing bitstates
@ -471,6 +472,7 @@ private:
void checkBurstMode (float distance); void checkBurstMode (float distance);
void checkSilencer (); void checkSilencer ();
void updateAimDir (); void updateAimDir ();
void syncUpdateLookAngles ();
void updateLookAngles (); void updateLookAngles ();
void updateBodyAngles (); void updateBodyAngles ();
void updateLookAnglesNewbie (const Vector &direction, float delta); 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 // need to wait until all threads will finish it's work before terminating bot object
~Bot () { ~Bot () {
MutexScopedLock lock (m_pathFindLock); MutexScopedLock lock1 (m_pathFindLock);
MutexScopedLock lock2 (m_lookAnglesLock);
} }
public: public:

View file

@ -82,7 +82,7 @@ void Bot::avoidGrenades () {
if (!bots.hasActiveGrenades ()) { if (!bots.hasActiveGrenades ()) {
return; return;
} }
auto &activeGrenades = bots.getActiveGrenades (); const auto &activeGrenades = bots.getActiveGrenades ();
// find all grenades on the map // find all grenades on the map
for (auto pent : activeGrenades) { for (auto pent : activeGrenades) {
@ -524,7 +524,7 @@ void Bot::updatePickups () {
allowPickup = false; allowPickup = false;
if (!m_defendHostage && m_personality != Personality::Rusher && m_difficulty >= Difficulty::Normal && rg.chance (15) && m_timeCamping + 15.0f < game.time ()) { 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::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 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) { if (!m_defendedBomb) {
m_defendedBomb = true; m_defendedBomb = true;
int index = findDefendNode (origin); const int index = findDefendNode (origin);
const Path &path = graph[index]; const Path &path = graph[index];
float bombTimer = mp_c4timer.float_ (); const 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 timeMidBlowup = bots.getTimeBombPlanted () + (bombTimer * 0.5f + bombTimer * 0.25f) - graph.calculateTravelTime (pev->maxspeed, pev->origin, path.origin);
if (timeMidBlowup > game.time ()) { if (timeMidBlowup > game.time ()) {
clearTask (Task::MoveToPosition); // remove any move tasks clearTask (Task::MoveToPosition); // remove any move tasks
@ -618,10 +618,10 @@ void Bot::updatePickups () {
if (!m_defendedBomb && !allowPickup) { if (!m_defendedBomb && !allowPickup) {
m_defendedBomb = true; m_defendedBomb = true;
int index = findDefendNode (origin); const int index = findDefendNode (origin);
const auto &path = graph[index]; 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 clearTask (Task::MoveToPosition); // remove any move tasks
@ -648,7 +648,7 @@ void Bot::updatePickups () {
allowPickup = false; allowPickup = false;
if (!m_defendedBomb && m_difficulty >= Difficulty::Normal && rg.chance (75) && m_healthValue < 60) { 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::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 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; 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)) { if (graph.exists (dangerIndex)) {
return graph[dangerIndex].origin; return graph[dangerIndex].origin;

View file

@ -2300,7 +2300,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
} }
// perform DFS instead of floyd-warshall, this shit speedup this process in a bit // perform DFS instead of floyd-warshall, this shit speedup this process in a bit
auto length = cr::min (static_cast <size_t> (kMaxNodes), m_paths.length ()); const auto length = cr::min (static_cast <size_t> (kMaxNodes), m_paths.length ());
// ensure valid capacity // ensure valid capacity
assert (length > 8 && length < static_cast <size_t> (kMaxNodes)); assert (length > 8 && length < static_cast <size_t> (kMaxNodes));

View file

@ -2153,9 +2153,6 @@ bool Bot::selectBestNextNode () {
// this function does a realtime post processing of nodes return from the // this function does a realtime post processing of nodes return from the
// pathfinder, to vary paths and find the best node on our way // 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 nextNodeIndex = m_pathWalk.next ();
const auto currentNodeIndex = m_pathWalk.first (); const auto currentNodeIndex = m_pathWalk.first ();
const auto prevNodeIndex = m_currentNodeIndex; const auto prevNodeIndex = m_currentNodeIndex;

View file

@ -412,7 +412,9 @@ void BotSupport::updateClients () {
} }
int BotSupport::getPingBitmask (edict_t *ent, int loss, int ping) { 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) { const auto emit = [] (int s0, int s1, int s2) {
return (s0 & (cr::bit (s1) - 1)) << s2; return (s0 & (cr::bit (s1) - 1)) << s2;
@ -443,6 +445,16 @@ void BotSupport::syncCalculatePings () {
int ping, loss; int ping, loss;
engfuncs.pfnGetPlayerStats (client.ent, &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 // store normal client ping
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg.get (8, 16)); // getting player ping sometimes fails client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping : rg.get (8, 16)); // getting player ping sometimes fails
++numHumans; ++numHumans;

View file

@ -337,7 +337,18 @@ void Bot::updateBodyAngles () {
} }
void Bot::updateLookAngles () { 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 <Mutex> unlock (m_lookAnglesLock);
const float delta = cr::clamp (game.time () - m_lookUpdateTime, cr::kFloatEqualEpsilon, kViewFrameUpdate);
m_lookUpdateTime = game.time (); m_lookUpdateTime = game.time ();
// adjust all body and view angles to face an absolute vector // adjust all body and view angles to face an absolute vector

View file

@ -122,7 +122,7 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>ClangCL</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<EnableASAN>false</EnableASAN> <EnableASAN>false</EnableASAN>
@ -137,7 +137,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<PlatformToolset>ClangCL</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<EnableASAN>false</EnableASAN> <EnableASAN>false</EnableASAN>
</PropertyGroup> </PropertyGroup>