9.0 KiB
Phase 2D Analysis: GroupCombatTrigger.cpp ObjectAccessor Migration
File: src/modules/Playerbot/AI/Combat/GroupCombatTrigger.cpp
Total ObjectAccessor Calls: 5
Priority: HIGH (combat initiation, group coordination)
Complexity: Low
Pattern: All 5 calls are leader lookups using same GUID
Executive Summary
GroupCombatTrigger.cpp contains 5 ObjectAccessor calls, all following the same pattern: looking up the group leader using group->GetLeaderGUID(). This repetitive pattern offers excellent optimization potential.
Key Findings:
- 100% leader lookups: All 5 calls use
group->GetLeaderGUID() - Repetitive pattern: Same leader looked up multiple times
- Optimization opportunity: Cache leader snapshot, reuse across functions
- Expected reduction: 5 → 1-2 calls (60-80% reduction)
Detailed Call Analysis
Call Inventory
| Line | Function | Pattern | Optimization Potential |
|---|---|---|---|
| 124 | GetUrgency() | FindPlayer(leader) → check combat/health | ✅ HIGH - Use snapshot |
| 287 | SelectGroupTarget() | FindPlayer(leader) | ✅ HIGH - Use snapshot |
| 288 | SelectGroupTarget() | GetUnit(leader, target) | ⚠️ MEDIUM - Need Unit* |
| 299 | GetLeaderTarget() | FindPlayer(leader) | ✅ HIGH - Use snapshot |
| 524 | CalculateTargetPriority() | FindPlayer(leader) | ✅ HIGH - Use snapshot |
Pattern Breakdown
Pattern 1: Leader Combat/Health Check (Line 124)
Current Code:
// Increase urgency if leader is in combat
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (leader && leader != bot && leader->IsInCombat())
{
urgency += 0.2f;
// Even higher if leader is low health
if (leader->GetHealthPct() < 50.0f)
urgency = 0.95f;
}
Analysis:
- Need: Leader combat status and health percentage
- Snapshot has:
isInCombat,health,maxHealthfields - Can optimize: 100% snapshot-based validation
Optimized:
// PHASE 2D: Use snapshot for leader combat/health check
auto leaderSnapshot = SpatialGridQueryHelpers::FindPlayerByGuid(nullptr, group->GetLeaderGUID());
if (leaderSnapshot && leaderSnapshot->guid != bot->GetGUID() && leaderSnapshot->isInCombat)
{
urgency += 0.2f;
// Even higher if leader is low health
float healthPct = (leaderSnapshot->health / static_cast<float>(leaderSnapshot->maxHealth)) * 100.0f;
if (healthPct < 50.0f)
urgency = 0.95f;
}
Pattern 2: Leader Target Lookup (Lines 287-288)
Current Code:
if (!bestTargetGuid.IsEmpty())
{
if (Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
return ObjectAccessor::GetUnit(*leader, bestTargetGuid);
}
Analysis:
- First call: Validate leader exists
- Second call: Get Unit* for target (return value)
- Can partially optimize: Use snapshot for leader validation, keep GetUnit for return
Optimized:
if (!bestTargetGuid.IsEmpty())
{
// PHASE 2D: Validate leader with snapshot first
auto leaderSnapshot = SpatialGridQueryHelpers::FindPlayerByGuid(nullptr, group->GetLeaderGUID());
if (leaderSnapshot && leaderSnapshot->isAlive)
{
// ONLY get Player* when snapshot confirms leader exists
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (leader)
return ObjectAccessor::GetUnit(*leader, bestTargetGuid);
}
}
Note: Second call (GetUnit) is necessary - function returns Unit*.
Pattern 3: Leader Victim Lookup (Line 299)
Current Code:
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (!leader || !leader->IsInCombat())
return nullptr;
return leader->GetVictim();
Analysis:
- Need: Leader combat status + GetVictim() (requires Player*)
- Can partially optimize: Snapshot for combat check, ObjectAccessor for GetVictim()
Optimized:
// PHASE 2D: Validate leader combat with snapshot first
auto leaderSnapshot = SpatialGridQueryHelpers::FindPlayerByGuid(nullptr, group->GetLeaderGUID());
if (!leaderSnapshot || !leaderSnapshot->isInCombat)
return nullptr;
// ONLY get Player* when snapshot confirms leader is in combat
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (!leader)
return nullptr;
return leader->GetVictim();
Pattern 4: Leader Victim Priority Check (Line 524)
Current Code:
// Leader's target gets bonus priority
if (Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
{
if (leader->GetVictim() == target)
priority += 20.0f;
}
Analysis:
- Need: Leader's GetVictim() to compare with target
- Can partially optimize: Snapshot validation first, ObjectAccessor for GetVictim()
Optimized:
// PHASE 2D: Leader's target gets bonus priority
auto leaderSnapshot = SpatialGridQueryHelpers::FindPlayerByGuid(nullptr, group->GetLeaderGUID());
if (leaderSnapshot && leaderSnapshot->isInCombat)
{
// ONLY get Player* when snapshot confirms leader is in combat
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (leader && leader->GetVictim() == target)
priority += 20.0f;
}
Optimization Strategy
Approach: Snapshot-First Validation
All 5 calls can benefit from snapshot-first validation:
Pattern:
// 1. Validate with snapshot (lock-free)
auto leaderSnapshot = SpatialGridQueryHelpers::FindPlayerByGuid(nullptr, group->GetLeaderGUID());
if (!leaderSnapshot || !leaderSnapshot->isAlive)
return; // Early exit
// 2. ONLY get Player* when snapshot confirms entity exists AND we need Player* API
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
Expected Results
Call Reduction Summary
| Function | Before | After | Reduction | Notes |
|---|---|---|---|---|
| GetUrgency() | 1 | 0 | 100% | Snapshot-only (combat/health) |
| SelectGroupTarget() | 2 | 2 | 0% | Need Player* and GetUnit (return value) |
| GetLeaderTarget() | 1 | 1 | 0% | Need GetVictim() (requires Player*) |
| CalculateTargetPriority() | 1 | 1 | 0% | Need GetVictim() (requires Player*) |
| TOTAL | 5 | 4 | 20% | vs. 80% roadmap estimate |
Wait - this doesn't match roadmap! Let me re-analyze...
Re-Analysis: Snapshot Fields Available
Looking at snapshot validation usage in other files:
isInCombatfield exists in PlayerSnapshothealthandmaxHealthfields exist- BUT: GetVictim() requires Player* - no snapshot field for current target
Revised Reduction:
- GetUrgency(): 1 → 0 (snapshot has combat/health)
- SelectGroupTarget(): 2 → 1-2 (validate with snapshot, still need GetUnit)
- GetLeaderTarget(): 1 → 1 (need GetVictim)
- CalculateTargetPriority(): 1 → 1 (need GetVictim)
Realistic Total: 5 → 3-4 calls (20-40% reduction)
Performance Impact
ObjectAccessor Call Frequency
Trigger Frequency: ~1-5 Hz (combat initiation checks)
Before: 5 calls per trigger × 3 Hz = 15 calls/sec After: 4 calls per trigger × 3 Hz = 12 calls/sec Reduction: 3 calls/sec eliminated (20%)
FPS Impact (100 bot scenario): <0.5% (low frequency path)
Recommended Action
Option A: Apply Optimizations
- Migrate GetUrgency() to snapshot-only (1 call eliminated)
- Add snapshot validation to other functions (reduce unnecessary lookups)
- Effort: 30 minutes
- Impact: 20% reduction, improved code clarity
Option B: Skip This File
- File has low call frequency (1-5 Hz)
- Low optimization potential (20% vs 80% estimated)
- Focus effort on higher-impact files
- Effort: 0 minutes
- Impact: Same performance
Recommendation: Option A - Quick optimization for completeness, demonstrates pattern.
Implementation Plan
Step 1: Migrate GetUrgency() (Line 124)
Current:
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (leader && leader != bot && leader->IsInCombat())
{
urgency += 0.2f;
if (leader->GetHealthPct() < 50.0f)
urgency = 0.95f;
}
After:
// PHASE 2D: Use snapshot for leader combat/health check (lock-free)
auto leaderSnapshot = SpatialGridQueryHelpers::FindPlayerByGuid(nullptr, group->GetLeaderGUID());
if (leaderSnapshot && leaderSnapshot->guid != bot->GetGUID() && leaderSnapshot->isInCombat)
{
urgency += 0.2f;
// Calculate health percentage from snapshot
float healthPct = (leaderSnapshot->health / static_cast<float>(leaderSnapshot->maxHealth)) * 100.0f;
if (healthPct < 50.0f)
urgency = 0.95f;
}
Step 2: Add Snapshot Validation to Remaining Functions
Add early validation to reduce unnecessary ObjectAccessor calls when leader is dead/invalid.
Conclusion
GroupCombatTrigger.cpp has limited optimization potential (20% vs 80% estimated) because most calls require Player* for GetVictim() API. However, the GetUrgency() function can be fully migrated to snapshots, demonstrating the pattern.
Recommendation: Apply optimizations for code quality and completeness, but don't expect significant performance gains.
End of Analysis