Skip to content

Fix improved hostages AI freezing after map change when bots are disabled#1162

Open
belomaxorka wants to merge 1 commit into
rehlds:masterfrom
belomaxorka:fix/hostage-ai-stale-nav-on-mapchange
Open

Fix improved hostages AI freezing after map change when bots are disabled#1162
belomaxorka wants to merge 1 commit into
rehlds:masterfrom
belomaxorka:fix/hostage-ai-stale-nav-on-mapchange

Conversation

@belomaxorka

@belomaxorka belomaxorka commented Jul 3, 2026

Copy link
Copy Markdown

Fixes #1161

Bug

With hostage_ai_enable 1 on a CS 1.6 server, the improved (CZ) hostages work fine on the first loaded map, but after any map change they completely freeze and stop responding to +use.

Root cause

LoadNavigationMap() (game_shared/bot/nav_file.cpp) returns early if TheNavAreaList is not empty, relying on the assumption that "the navigation map is destroyed on map change":

NavErrorType LoadNavigationMap()
{
	// since the navigation map is destroyed on map change,
	// if it exists it has already been loaded for this map
	if (!TheNavAreaList.empty())
		return NAV_OK;

However, the only place that actually destroys it on map change is CCSBotManager::LoadNavigationMap(), and it returns early when bots are not allowed (e.g. a dedicated CS 1.6 server without bot_enable 1):

bool CCSBotManager::LoadNavigationMap()
{
	if (m_isMapDataLoaded || !AreBotsAllowed())
		return false;
	...
	DestroyNavigationMap();

So with bots disabled the sequence is:

  1. First map (e.g. cs_office): TheNavAreaList is empty, the nav mesh loads correctly, CZ hostage AI works.
  2. map cs_italy: nobody destroys the old nav data. CHostageManager::ServerActivate() calls LoadNavigationMap(), which sees a non-empty list and silently keeps the mesh of the previous map.
  3. CHostage::IdleThink() still creates CHostageImprov (the list is not empty), but the improv cannot find any valid nav area beneath the hostage on the new map. The hostage freezes; +use is actually received, but the follow behavior cannot move without navigation.

This never reproduces in Condition Zero, because bots are always allowed there and the bot manager destroys and reloads the mesh on every map — which is exactly why only CS 1.6 with hostage_ai_enable is affected.

Fix

Destroy the stale navigation data in CHostageManager::ServerActivate() right before loading, but only when bots are not allowed. When bots are allowed, CCSBotManager::ServerActivate() has already destroyed and reloaded the mesh earlier in the same engine ServerActivate() call (see the order in client.cpp) and holds pointers into the fresh mesh (scenario zones), so it must not be destroyed again.

Both code paths are gated by the same AreBotsAllowed() flag (g_bAllowedCSBot, snapshotted once in Regamedll_Game_Init() after game_init.cfg is executed), so exactly one subsystem owns nav destruction for the entire server lifetime — no double-destroy and no ownerless state in any configuration.

Safety notes

  • The destroy runs inside ServerActivate before the first game frame: no bots exist (they are disallowed on this path), hostage improvs are not created yet (m_improv is only created in IdleThink), and CHostageManager is recreated per map with m_hostageCount already reset.
  • DestroyNavigationMap() also resets TheNavAreaGrid and the nav-edit statics (EditNavAreasReset() clears markedArea/lastSelectedArea); the A* open-list static is cleared by ClearSearchLists() at the start of every path search, so no stale pointer is ever dereferenced.
  • Destroying an empty/never-loaded state is a no-op (the very first LoadNavigationMap() call already does this internally).
  • CZ builds, non-REGAMEDLL_ADD builds and servers with bots enabled are bit-for-bit unaffected.
  • Side benefit: when changing to a map that has no .nav file, TheNavAreaList now correctly stays empty and hostages fall back to the classic CS 1.6 AI instead of freezing on the previous map's mesh.

Verified on a live server

Reproduced and verified on a dedicated ReHLDS server (Windows), CS 1.6, hostage_ai_enable "1", bots disabled, scenario cs_officemap cs_italy:

  • Official 5.30.0.814: hostages work on the first map; after the map change they play idle animations and flinch on +use, but never move — the follow behavior cannot path on the stale mesh. Enabling bots (bot_enable 1) makes the same build work across map changes, confirming that the bot manager's nav reload is exactly what masks the bug.
  • This patch: hostages respond to +use and follow normally after any number of map changes. A debug-instrumented build confirmed the expected internals on the second map: nav status NAV_OK with the correct area count after reload, hostages standing on valid nav areas, and successful path construction (no NavAreaBuildPath failures).

Notes for testers

  • The .nav files must be generated for the CS 1.6 map geometry (e.g. the zBot nav files). Nav files taken from CZ for maps that were remade in CZ (such as cs_assault) do not match the 1.6 geometry — hostages then cannot path on any map load, regardless of this fix.
  • The CZ hostage models (models/hostageA.mdl ... hostageD.mdl) must be present on the server, otherwise hostage_ai_enable silently resets to 0 at hostage precache and the classic (non-CZ) hostages are used.

How to test

  1. Dedicated ReHLDS server, CS 1.6, hostage_ai_enable "1" in game_init.cfg, bots disabled (no bot_enable 1).
  2. Start on cs_office — CZ hostages work (animations, pathfinding, +use).
  3. map cs_italy — before the fix the hostages freeze and ignore +use; with the fix they respond and follow normally. Repeated map changes (including back to cs_office) keep working.

@belomaxorka belomaxorka changed the title Fix improved hostages AI freezing after map change when bots are disabled WIP: Fix improved hostages AI freezing after map change when bots are disabled Jul 3, 2026
@belomaxorka belomaxorka changed the title WIP: Fix improved hostages AI freezing after map change when bots are disabled Fix improved hostages AI freezing after map change when bots are disabled Jul 3, 2026
…bled

When hostage_ai_enable is set in CS 1.6 but bots are not allowed
(dedicated server without bot_enable), CCSBotManager::LoadNavigationMap
returns early and never frees the navigation mesh of the previous map.
LoadNavigationMap() then sees a non-empty TheNavAreaList and keeps the
stale nav data, so on the next hostage map CHostageImprov is created
against the wrong navigation mesh: hostages freeze and stop responding
to +use.

Destroy the stale navigation data in CHostageManager::ServerActivate
before loading, but only when bots are not allowed - otherwise
CCSBotManager has already reloaded the nav mesh earlier in the same
ServerActivate and holds pointers into it.

Fixes rehlds#1161

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@belomaxorka belomaxorka force-pushed the fix/hostage-ai-stale-nav-on-mapchange branch from e35fd6c to 2fddd8c Compare July 3, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: hostage_entity completely freezes and ignores +use (E key) on map change when using Condition Zero Improved AI

1 participant