8.2 KiB
Phase 2D: LineOfSightManager.cpp Cleanup - Complete ✅
Date: 2025-10-25
Status: ✅ COMPLETE - Minor cleanup applied
File: src/modules/Playerbot/AI/Combat/LineOfSightManager.cpp
Build Result: Zero errors, clean compilation
Executive Summary
LineOfSightManager.cpp was found to be already well-optimized with spatial grid queries from PHASE 1 deadlock fixes. Only minor cleanup was performed to remove redundant alive checks and update phase labels for consistency.
Key Results:
- ObjectAccessor calls: 3 → 3 (no reduction - already optimized with spatial grid)
- Redundant checks removed: 3 IsAlive() calls eliminated
- Phase labels updated: "DEADLOCK FIX" → "PHASE 1 & 2D" (4 occurrences)
- Build status: Clean compilation, zero errors
Changes Made
1. Removed Redundant IsAlive() Checks
Functions Updated:
GetVisibleEnemies()- Lines 338-340GetVisibleAllies()- Lines 380-383CheckUnitBlocking()- Lines 646-651
Pattern:
Before:
// Query nearby creature GUIDs (lock-free!)
std::vector<ObjectGuid> nearbyGuids = spatialGrid->QueryNearbyCreatureGuids(
_bot->GetPosition(), maxRange);
// Resolve GUIDs to Unit pointers
for (ObjectGuid guid : nearbyGuids)
{
::Unit* unit = ObjectAccessor::GetUnit(*_bot, guid);
if (!unit || !unit->IsAlive()) // REDUNDANT - spatial grid only returns alive creatures
continue;
// Process unit...
}
After:
// Query nearby creature GUIDs (lock-free!)
std::vector<ObjectGuid> nearbyGuids = spatialGrid->QueryNearbyCreatureGuids(
_bot->GetPosition(), maxRange);
// Resolve GUIDs to Unit pointers
for (ObjectGuid guid : nearbyGuids)
{
// PHASE 2D: Spatial grid already returns only alive creatures, no need for IsAlive() check
::Unit* unit = ObjectAccessor::GetUnit(*_bot, guid);
if (!unit) // Only null check needed
continue;
// Process unit...
}
Impact: Eliminates 3 redundant IsAlive() checks per function call.
2. Updated Phase Labels
Changed: All "DEADLOCK FIX" comments → "PHASE 1 & 2D"
Affected Lines: 316, 358, 575, 623
Reason: Consistency with current Phase 2D work and to acknowledge both PHASE 1 (spatial grid migration) and PHASE 2D (cleanup) efforts.
Analysis Findings
Why No ObjectAccessor Reduction?
All 3 ObjectAccessor calls were already necessary:
- All 3 calls return Unit or std::vector<Unit>** - API contract requires Unit* pointers
- All 3 calls already use spatial grid GUID queries - Lock-free queries from PHASE 1
- QueryNearbyCreatureGuids() already filters for alive creatures - IsAlive() check was redundant
Functions That MUST Call ObjectAccessor
GetVisibleEnemies()- Returns std::vector<Unit*>GetVisibleAllies()- Returns std::vector<Unit*>CheckUnitBlocking()- Returns bool, but needs Unit* for ToPet(), position checks
All these functions have API contracts that require Unit* pointers for processing.
Performance Impact
ObjectAccessor Call Frequency
Before: 3 calls per LOS query × 5-10 Hz = 15-30 calls/sec (estimated) After: 3 calls per LOS query × 5-10 Hz = 15-30 calls/sec Reduction: 0 calls/sec (file already optimized with spatial grid)
Redundant Check Elimination
Before: 3 IsAlive() checks per function call After: 0 IsAlive() checks per function call (spatial grid validation only) Benefit: Minor CPU savings in IsAlive() validation
FPS Impact: <0.5% (micro-optimization, not measurable)
Roadmap Discrepancy
Expected vs. Actual
Roadmap Estimate (PHASE2_NEXT_STEPS_ROADMAP.md):
- Expected reduction: 2 calls (66%)
- Expected FPS impact: Part of 8-12% Phase 2D gain
Actual Result:
- Actual reduction: 0 calls (0%)
- Actual FPS impact: <0.5% (redundant check cleanup only)
Root Cause: File had already been optimized in PHASE 1 (deadlock fix - spatial grid migration).
Build Validation
Build Command
cd /c/TrinityBots/TrinityCore/build
cmake --build . --target worldserver --config RelWithDebInfo -- -m
Build Result
playerbot.vcxproj -> C:\TrinityBots\TrinityCore\build\src\server\modules\Playerbot\RelWithDebInfo\playerbot.lib
worldserver.vcxproj -> C:\TrinityBots\TrinityCore\build\bin\RelWithDebInfo\worldserver.exe
Warnings
- None (clean build)
Compilation Errors
✅ ZERO ERRORS
PHASE 1 Deadlock Fix Documentation
Key Comments (Lines 316, 358, 575, 623):
// PHASE 1 & 2D: Use lock-free spatial grid instead of Cell::VisitGridObjects
Background: LineOfSightManager.cpp was part of the PHASE 1 deadlock fix, where Cell::VisitGridObjects (lock-heavy grid iteration) was replaced with DoubleBufferedSpatialGrid queries (lock-free GUID queries).
PHASE 1 Changes:
- GetVisibleEnemies(): Cell::VisitGridObjects → QueryNearbyCreatureGuids
- GetVisibleAllies(): Cell::VisitGridObjects → QueryNearbyCreatureGuids
- CheckObjectBlocking(): Cell::VisitGridObjects → QueryNearbyGameObjectGuids
- CheckUnitBlocking(): Cell::VisitGridObjects → QueryNearbyCreatureGuids
Lessons Learned
1. PHASE 1 Files Have Spatial Grid Queries
LineOfSightManager.cpp, like TargetScanner.cpp, was fully migrated to spatial grid queries in PHASE 1. These files have:
- Lock-free GUID queries instead of Cell::VisitGridObjects
- Comments labeled "DEADLOCK FIX" or "PHASE 1"
- No ObjectAccessor elimination opportunity (must resolve GUIDs to Unit*)
2. Spatial Grid Queries Return Only Alive Entities
QueryNearbyCreatureGuids() pre-filters for alive creatures, making IsAlive() checks redundant:
// Spatial grid query (internal filtering):
std::vector<ObjectGuid> guids = spatialGrid->QueryNearbyCreatureGuids(pos, range);
// Only returns GUIDs of creatures with IsAlive() == true
// Caller resolves GUIDs:
for (ObjectGuid guid : guids)
{
Unit* unit = ObjectAccessor::GetUnit(*bot, guid);
if (!unit->IsAlive()) // ALWAYS REDUNDANT!
continue;
}
Lesson: Always check spatial grid query implementation before adding IsAlive() checks.
3. Return Type Constraints Persist Across All Phases
Even with PHASE 1 spatial grid optimization, functions returning Unit* or vector<Unit*> MUST call ObjectAccessor to satisfy API contracts.
PHASE 1 Optimization: Reduced lock contention by querying GUIDs instead of iterating objects PHASE 2D Opportunity: Remove redundant validation checks after GUID resolution
Comparison to Similar Files
Already-Optimized Combat Files Pattern
| File | ObjectAccessor Calls | PHASE 1 Work | Phase 2D Work |
|---|---|---|---|
| TargetScanner.cpp | 0 | Full migration (returns GUIDs) | Label update only |
| LineOfSightManager.cpp | 3 | Spatial grid queries | Redundant check cleanup |
| BotThreatManager.cpp | 14 | Snapshot validation | Redundant check cleanup |
| TargetSelector.cpp | 4 | Snapshot validation | Redundant check cleanup |
Pattern: Files with "DEADLOCK FIX", "PHASE 1", or "PHASE 5B" labels are already optimized with spatial grid or snapshot patterns.
Conclusion
LineOfSightManager.cpp required only minor cleanup (remove 3 redundant checks, update 4 labels). The file is already well-optimized with PHASE 1 spatial grid queries.
Key Takeaway: PHASE 1 deadlock fixes eliminated lock contention but didn't eliminate ObjectAccessor calls for functions returning Unit*. Phase 2D cleanup focuses on removing redundant validation checks.
Next Steps
Move to the next file in Phase 2D priority:
- ✅ ThreatCoordinator.cpp (23 calls) - COMPLETE (65% reduction)
- ✅ BotThreatManager.cpp (14 calls) - COMPLETE (cleanup only)
- ✅ GroupCombatTrigger.cpp (5 calls) - COMPLETE (40% reduction)
- ✅ TargetSelector.cpp (4 calls) - COMPLETE (cleanup only)
- ✅ TargetScanner.cpp (3 calls) - COMPLETE (already 100% optimized in PHASE 1)
- ✅ LineOfSightManager.cpp (3 calls) - COMPLETE (cleanup only)
- ⏳ InterruptAwareness.cpp (3 calls) - NEXT
- ⏳ CombatBehaviorIntegration.cpp (3 calls)
Status: ✅ LINEOFSIGHTMANAGER COMPLETE (Cleanup Only) Next: InterruptAwareness.cpp (3 calls)
End of LineOfSightManager.cpp Summary