bot: switch look/body angles updates to thread worker
build: msvc projects now again targets msvc by default
This commit is contained in:
parent
52bfac2b09
commit
5ce2032acd
8 changed files with 59 additions and 35 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue