Files
ThordekkCore/PHASE2D_ANALYSIS_GROUPCOMBATTRIGGER.md
T
2026-01-20 21:33:16 -03:00

9.0 KiB
Raw Blame History

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:

  1. 100% leader lookups: All 5 calls use group->GetLeaderGUID()
  2. Repetitive pattern: Same leader looked up multiple times
  3. Optimization opportunity: Cache leader snapshot, reuse across functions
  4. 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, maxHealth fields
  • 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:

  • isInCombat field exists in PlayerSnapshot
  • health and maxHealth fields 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)


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