Files
ThordekkCore/PHASE2D_ANALYSIS_GROUPCOMBATTRIGGER.md
T

304 lines
9.0 KiB
Markdown
Raw Normal View History

2026-01-20 21:33:16 -03:00
# 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**:
```cpp
// 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**:
```cpp
// 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**:
```cpp
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**:
```cpp
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**:
```cpp
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**:
```cpp
// 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**:
```cpp
// 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**:
```cpp
// 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**:
```cpp
// 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)
---
## 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**:
```cpp
Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID());
if (leader && leader != bot && leader->IsInCombat())
{
urgency += 0.2f;
if (leader->GetHealthPct() < 50.0f)
urgency = 0.95f;
}
```
**After**:
```cpp
// 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**