Audit found 200+ direct bot stat reads on worker threads across
strategy files. Converted the highest-impact patterns:
- RestStrategy: NeedsFood/NeedsDrink/IsActive/UpdateBehavior now use
ai->GetCachedHealthPct() and ai->GetCachedManaPct() from snapshot
- GrindStrategy: Health/mana recovery check uses snapshot
- SoloStrategy: Rest trigger, recovery check, mana check use snapshot
- Strategy.cpp: ShouldFlee health check uses snapshot
- BotAI.h: Added DistanceTo/Distance2dTo helpers using snapshot position
All reads go through BotAI accessors which read from the PlayerSnapshot
populated every 100ms from the spatial grid's main thread update.
Replace the broken cache system (SnapshotBotState ran before
Player::Update so values were always stale) with the spatial grid's
PlayerSnapshot which is populated on the main thread every 100ms
with current data via the DoubleBufferedSpatialGrid.
BotAI now stores a PlayerSnapshot and refreshes it at the start of
each UpdateAI via RefreshFromSpatialGrid(). All accessors
(GetCurrentPosition, GetCachedHealthPct, GetCachedManaPct, etc.)
read from this snapshot. Worker threads get accurate, lock-free data.
Changes:
- BotAI: Replace 5 individual cache fields with single PlayerSnapshot
- BotAI: Add RefreshFromSpatialGrid() querying spatial grid by bot GUID
- BotAI: Add GetSnapshot(), GetCachedIsAlive(), GetCachedLevel() etc.
- RestStrategy: NeedsFood/NeedsDrink/IsActive use snapshot via ai->
- Remove BotSession::SnapshotBotState() entirely
- Remove SnapshotBotState call from BotWorldSessionMgr
- Remove MoveSpline.h dependency from BotAI and BotSession
The main thread SnapshotBotState runs in OnWorldUpdate BEFORE
Map::Update/Player::Update, so it captures pre-regen health values.
The cache showed 49.4% while actual health was 100%.
Worker thread reads of bot->GetHealthPct() return correct values
because Player::Update has already run by the time the worker executes.
Reverted to direct reads which are proven correct by the
RestStrategy::UpdateBehavior logs showing health=100%.