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

304 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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**