From 50e5a0702e28eb350e1b966de20a04ca924e6925 Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Tue, 19 Mar 2024 17:46:09 +0000 Subject: [PATCH] Refactor bot frame handling --- main/source/mod/AIPlayers/AvHAIConstants.h | 6 + main/source/mod/AIPlayers/AvHAINavigation.cpp | 49 +++---- main/source/mod/AIPlayers/AvHAINavigation.h | 2 +- main/source/mod/AIPlayers/AvHAIPlayer.cpp | 39 +++++- .../mod/AIPlayers/AvHAIPlayerManager.cpp | 127 ++++++------------ .../source/mod/AIPlayers/AvHAIPlayerManager.h | 3 +- 6 files changed, 105 insertions(+), 121 deletions(-) diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index b2ddc76f..35f58ab4 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -794,6 +794,12 @@ typedef struct AVH_AI_PLAYER int ExperiencePointsAvailable = 0; // How much experience the bot has to spend AvHMessageID NextCombatModeUpgrade = MESSAGE_NULL; + float ThinkDelta = 0.0f; // How long since this bot last ran AIPlayerThink + float LastThinkTime = 0.0f; // When the bot last ran AIPlayerThink + + float ServerUpdateDelta = 0.0f; // How long since we last called RunPlayerMove + float LastServerUpdateTime = 0.0f; // When we last called RunPlayerMove + } AvHAIPlayer; diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index ac7e95ff..e554259e 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -1175,8 +1175,10 @@ void UTIL_PopulateBaseNavProfiles() BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f); BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f); BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL); - BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY); BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED); + BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY); + BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; @@ -1192,12 +1194,8 @@ void UTIL_PopulateBaseNavProfiles() BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f); BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL); BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED); - BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE); - BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE); - BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP); - BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD); - BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB); BaseNavProfiles[LERK_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; BaseNavProfiles[LERK_BASE_NAV_PROFILE].bFlyingProfile = true; @@ -1211,9 +1209,8 @@ void UTIL_PopulateBaseNavProfiles() BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f); BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL); BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED); - BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE); - BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE); - BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD); + BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD); + BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD); BaseNavProfiles[FADE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; BaseNavProfiles[FADE_BASE_NAV_PROFILE].bFlyingProfile = false; @@ -1228,10 +1225,8 @@ void UTIL_PopulateBaseNavProfiles() BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f); BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL); BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED); - BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE); - BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE); - BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD); - BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY); + BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY); + BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY); BaseNavProfiles[ONOS_BASE_NAV_PROFILE].NavMeshIndex = ONOS_NAV_MESH; BaseNavProfiles[ONOS_BASE_NAV_PROFILE].bFlyingProfile = false; @@ -1246,12 +1241,8 @@ void UTIL_PopulateBaseNavProfiles() BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f); BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL); BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED); - BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE); - BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE); - BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD); - BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_NOONOS); - BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY); + BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB | SAMPLE_POLYFLAGS_NOONOS); + BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB | SAMPLE_POLYFLAGS_NOONOS); BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].NavMeshIndex = BUILDING_NAV_MESH; BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL); @@ -3106,7 +3097,7 @@ DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, C return NearestTrigger; } -void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo) +void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo, unsigned int MovementFlags) { if (pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size()) { return; } @@ -3135,8 +3126,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom if (FNullEnt(BlockingBreakableEdict)) { - - BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, pBot->Edict->v.origin, CurrentPathNode.Location, SAMPLE_POLYAREA_GROUND, nullptr); + BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, &CurrentPathNode, nullptr); } if (FNullEnt(BlockingBreakableEdict)) @@ -3146,8 +3136,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom for (int i = (pBot->BotNavInfo.CurrentPathPoint + 1); i < pBot->BotNavInfo.CurrentPath.size(); i++) { bot_path_node ThisPathNode = pBot->BotNavInfo.CurrentPath[i]; - - BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, ThisPathNode.FromLocation, ThisPathNode.Location, SAMPLE_POLYAREA_GROUND, nullptr); + BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, &ThisPathNode, nullptr); NumIterations++; @@ -3172,7 +3161,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom { if (IsPlayerSkulk(pBot->Edict)) { - DesiredWeapon = (BlockingBreakableEdict->v.health <= 10) ? WEAPON_SKULK_PARASITE : WEAPON_SKULK_BITE; + DesiredWeapon = (BlockingBreakableEdict->v.health <= 30) ? WEAPON_SKULK_PARASITE : WEAPON_SKULK_BITE; } } @@ -3302,7 +3291,7 @@ void NewMove(AvHAIPlayer* pBot) } // While moving, check to make sure we're not obstructed by a func_breakable, e.g. vent or window. - CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo); + CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo, CurrentNavFlags); if (CurrentNavFlags != SAMPLE_POLYFLAGS_LIFT) { @@ -5579,12 +5568,12 @@ void UpdateBotStuck(AvHAIPlayer* pBot) } else { - pBot->BotNavInfo.StuckInfo.TotalStuckTime += fminf(AIMGR_GetBotDeltaTime(), 0.016f); + pBot->BotNavInfo.StuckInfo.TotalStuckTime += pBot->ThinkDelta; } } else { - pBot->BotNavInfo.StuckInfo.TotalStuckTime += fminf(AIMGR_GetBotDeltaTime(), 0.016f); + pBot->BotNavInfo.StuckInfo.TotalStuckTime += pBot->ThinkDelta; } if (pBot->BotNavInfo.StuckInfo.TotalStuckTime > 0.25f) @@ -6285,7 +6274,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot) pBot->desiredMovementDir = UTIL_GetForwardVector2D(pEdict->v.v_angle); - CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest); + CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest, SAMPLE_POLYFLAGS_WALK); CheckAndHandleDoorObstruction(pBot); diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index c8b62295..55723e3f 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -257,7 +257,7 @@ DoorTrigger* UTIL_GetDoorTriggerByEntity(edict_t* TriggerEntity); bool UTIL_TriggerHasBeenRecentlyActivated(edict_t* TriggerEntity); // Will check for any func_breakable which might be in the way (e.g. window, vent) and make the bot aim and attack it to break it. Marines will switch to knife to break it. -void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo); +void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo, unsigned int MovementFlags); void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot); diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index 1a432db2..fa39c819 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -1140,7 +1140,7 @@ void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot) // This simulates the fact that humans can't spin and lock their cross-hair exactly on the target, the further you have the spin, the more off your view will be first attempt if (fabsf(maxDelta) >= 45.0f) { - pBot->ViewInterpolationSpeed = 500.0f; + pBot->ViewInterpolationSpeed = 350.0f; if (!bIsMoveLook) { @@ -1169,7 +1169,7 @@ void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot) } else if (fabsf(maxDelta) >= 25.0f) { - pBot->ViewInterpolationSpeed = 250.0f; + pBot->ViewInterpolationSpeed = 175.0f; if (!bIsMoveLook) { @@ -1196,7 +1196,7 @@ void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot) } else if (fabsf(maxDelta) >= 5.0f) { - pBot->ViewInterpolationSpeed = 50.0f; + pBot->ViewInterpolationSpeed = 35.0f; if (!bIsMoveLook) { @@ -4966,6 +4966,39 @@ void AIPlayerDMThink(AvHAIPlayer* pBot) void AIPlayerThink(AvHAIPlayer* pBot) { + +#ifdef DEBUG + if (pBot == AIMGR_GetDebugAIPlayer()) + { + bool bBreak = true; // Add a break point here if you want to debug a specific bot + + AIDEBUG_DrawBotPath(pBot); + + if (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size()) + { + bot_path_node CurrentPathNode = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint]; + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, CurrentPathNode.FromLocation, 255, 0, 0); + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, CurrentPathNode.Location, 0, 128, 0); + } + + if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE) + { + if (!FNullEnt(pBot->CurrentTask->TaskTarget)) + { + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskTarget->v.origin, 255, 0, 0); + } + + if (!vIsZero(pBot->CurrentTask->TaskLocation)) + { + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskLocation, 255, 0, 0); + } + } + } +#endif + + pBot->ThinkDelta = fminf(gpGlobals->time - pBot->LastThinkTime, 0.1f); + pBot->LastThinkTime = gpGlobals->time; + bool bShouldThink = ShouldBotThink(pBot); if (bShouldThink) diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp index 8416e785..226e7dcf 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp @@ -13,7 +13,6 @@ #include double last_think_time = 0.0; -float BotDeltaTime = 0.01666667f; vector ActiveAIPlayers; @@ -544,19 +543,16 @@ void AIMGR_AddAIPlayerToTeam(int Team) } -byte BotThrottledMsec(AvHAIPlayer* inAIPlayer) +byte BotThrottledMsec(AvHAIPlayer* inAIPlayer, float CurrentTime) { // Thanks to The Storm (ePODBot) for this one, finally fixed the bot running speed! - int newmsec = (int)((gpGlobals->time - inAIPlayer->f_previous_command_time) * 1000); + int newmsec = (int)((CurrentTime - inAIPlayer->LastServerUpdateTime) * 1000); if (newmsec > 255) { newmsec = 255; } - // save the command time - inAIPlayer->f_previous_command_time = gpGlobals->time; - return (byte)newmsec; } @@ -595,8 +591,6 @@ void AIMGR_UpdateAIPlayers() static float PrevTime = 0.0f; static float CurrTime = 0.0f; - static float LastThinkTime = 0.0f; - static int CurrentBotSkill = 1; static int UpdateIndex = 0; @@ -609,13 +603,7 @@ void AIMGR_UpdateAIPlayers() PrevTime = 0.0f; } - if (CurrTime < LastThinkTime) - { - LastThinkTime = 0.0f; - } - float FrameDelta = CurrTime - PrevTime; - float ThinkDelta = CurrTime - LastThinkTime; int cvarBotSkill = clampi((int)avh_botskill.value, 0, 3); @@ -627,6 +615,31 @@ void AIMGR_UpdateAIPlayers() } bool bHasCommander = false; + + if (bHasRoundStarted) + { + AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber(); + AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber(); + + AvHTeam* TeamA = GetGameRules()->GetTeam(TeamANumber); + AvHTeam* TeamB = GetGameRules()->GetTeam(TeamBNumber); + + if (TeamA->GetTeamType() == AVH_CLASS_TYPE_MARINE) + { + if (TeamA->GetCommanderPlayer() && !(TeamA->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT)) + { + AIMGR_SetCommanderAllowedTime(TeamANumber, gpGlobals->time + 15.0f); + } + } + + if (TeamB->GetTeamType() == AVH_CLASS_TYPE_MARINE) + { + if (TeamB->GetCommanderPlayer() && !(TeamB->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT)) + { + AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f); + } + } + } for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();) { @@ -654,76 +667,18 @@ void AIMGR_UpdateAIPlayers() BotUpdateViewRotation(bot, FrameDelta); - if (IS_DEDICATED_SERVER() || ThinkDelta >= BOT_MIN_FRAME_TIME) + if (bHasRoundStarted) { - BotDeltaTime = ThinkDelta; - -#ifdef DEBUG - if (bot == AIMGR_GetDebugAIPlayer()) + if (IsPlayerCommander(bot->Edict)) { - bool bBreak = true; // Add a break point here if you want to debug a specific bot - - AIDEBUG_DrawBotPath(bot); - - if (bot->BotNavInfo.CurrentPath.size() > 0 && bot->BotNavInfo.CurrentPathPoint < bot->BotNavInfo.CurrentPath.size()) + if (UpdateIndex == FrameSpread) { - bot_path_node CurrentPathNode = bot->BotNavInfo.CurrentPath[bot->BotNavInfo.CurrentPathPoint]; - UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, CurrentPathNode.FromLocation, 255, 0, 0); - UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, CurrentPathNode.Location, 0, 128, 0); - } - - if (bot->CurrentTask && bot->CurrentTask->TaskType != TASK_NONE) - { - if (!FNullEnt(bot->CurrentTask->TaskTarget)) - { - UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->CurrentTask->TaskTarget->v.origin, 255, 0, 0); - } - - if (!vIsZero(bot->CurrentTask->TaskLocation)) - { - UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->CurrentTask->TaskLocation, 255, 0, 0); - } + AIPlayerThink(bot); } } -#endif - - if (bHasRoundStarted) + else { - AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber(); - AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber(); - - AvHTeam* TeamA = GetGameRules()->GetTeam(TeamANumber); - AvHTeam* TeamB = GetGameRules()->GetTeam(TeamBNumber); - - if (TeamA->GetTeamType() == AVH_CLASS_TYPE_MARINE) - { - if (TeamA->GetCommanderPlayer() && !(TeamA->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT)) - { - AIMGR_SetCommanderAllowedTime(TeamANumber, gpGlobals->time + 15.0f); - } - } - - if (TeamB->GetTeamType() == AVH_CLASS_TYPE_MARINE) - { - if (TeamB->GetCommanderPlayer() && !(TeamB->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT)) - { - AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f); - } - } - } - - UpdateBotChat(bot); - - if (bHasRoundStarted) - { - if (IsPlayerCommander(bot->Edict)) - { - if (UpdateIndex == FrameSpread) - { - AIPlayerThink(bot); - } - } - else + if (UpdateIndex != FrameSpread) { int BotModulo = BotIndex % FrameSpread; @@ -733,32 +688,34 @@ void AIMGR_UpdateAIPlayers() } } } + } + + if (IS_DEDICATED_SERVER() || (CurrTime - bot->LastServerUpdateTime) >= BOT_MIN_FRAME_TIME) + { + UpdateBotChat(bot); // Needed to correctly handle client prediction and physics calculations - byte adjustedmsec = BotThrottledMsec(bot); + byte adjustedmsec = BotThrottledMsec(bot, CurrTime); // Simulate PM_PlayerMove so client prediction and stuff can be executed correctly. RUN_AI_MOVE(bot->Edict, bot->Edict->v.v_angle, bot->ForwardMove, bot->SideMove, bot->UpMove, bot->Button, bot->Impulse, adjustedmsec); - LastThinkTime = gpGlobals->time; + bot->LastServerUpdateTime = CurrTime; } BotIt++; } - PrevTime = CurrTime; UpdateIndex++; if (UpdateIndex > FrameSpread || (!bHasCommander && UpdateIndex == FrameSpread)) { UpdateIndex = 0; } -} -float AIMGR_GetBotDeltaTime() -{ - return BotDeltaTime; + PrevTime = CurrTime; + } int AIMGR_GetNumAIPlayers() diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.h b/main/source/mod/AIPlayers/AvHAIPlayerManager.h index 3c178862..94a17c99 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.h +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.h @@ -28,8 +28,7 @@ void AIMGR_RemoveAIPlayerFromTeam(int Team); void AIMGR_UpdateAIPlayers(); // Kicks all bots in the ready room (used at round end when everyone is booted back to the ready room) void AIMGR_RemoveBotsInReadyRoom(); -// Delta between last bot frame and this one (default is 60hz = 0.0166666) -float AIMGR_GetBotDeltaTime(); + // Called every 0.2s to determine if bots need to be added/removed. Calls UpdateTeamBalance or UpdateFillTeams depending on auto-mode void AIMGR_UpdateAIPlayerCounts();