Files
ThordekkCore/CLASSAI_DUPLICATION_ANALYSIS.md
T

426 lines
11 KiB
Markdown
Raw Normal View History

2026-01-20 21:25:30 -03:00
# ClassAI Code Duplication Analysis
## Executive Summary
**Critical Code Duplication Detected:** 1,740 occurrences of common methods across 200 files.
### Impact
- **Maintenance Burden:** Bug fixes require changes in 13+ places
- **Linker Warnings:** Multiple definition warnings for identical methods
- **Memory Waste:** Duplicated code increases binary size unnecessarily
- **Inconsistency Risk:** Same bugs exist in multiple classes
## Duplicate Code Patterns Identified
### Pattern 1: Cooldown Management (EVERY SPECIALIZATION)
**Duplicated in:** 50+ files
```cpp
void UpdateCooldowns(uint32 diff)
{
for (auto& cooldown : _cooldowns)
if (cooldown.second > diff)
cooldown.second -= diff;
else
cooldown.second = 0;
}
```
### Pattern 2: Ability Validation (EVERY SPECIALIZATION)
**Duplicated in:** 50+ files
```cpp
bool CanUseAbility(uint32 spellId)
{
auto it = _cooldowns.find(spellId);
if (it != _cooldowns.end() && it->second > 0)
return false;
return HasEnoughResource(spellId);
}
```
### Pattern 3: Combat State Management (EVERY SPECIALIZATION)
**Duplicated in:** 50+ files
```cpp
void OnCombatStart(::Unit* target)
{
Player* bot = GetBot();
if (!bot)
return;
// Identical logic across all specs
}
void OnCombatEnd()
{
// Identical cleanup logic
}
```
### Pattern 4: Range Calculation (EVERY SPECIALIZATION)
**Duplicated in:** 50+ files
```cpp
float GetOptimalRange(::Unit* target)
{
// Melee: return 5.0f
// Ranged DPS: return 25.0f
// Healers: return 30.0f
// Only difference is the return value
}
```
### Pattern 5: Resource Management (MANY SPECIALIZATIONS)
**Duplicated in:** 30+ files
```cpp
bool HasEnoughResource(uint32 spellId)
{
// Check mana/rage/energy/etc
// Logic varies slightly by resource type
}
void ConsumeResource(uint32 spellId)
{
// Deduct resource cost
// Logic varies slightly by resource type
}
```
## Files with Duplicate Definitions (Linker Warnings)
### FrostSpecialization (Death Knight)
```
warning LNK4006: "GetOptimalRange" bereits definiert
warning LNK4006: "GetOptimalPosition" bereits definiert
warning LNK4006: "ConsumeResource" bereits definiert
warning LNK4006: "HasEnoughResource" bereits definiert
warning LNK4006: "OnCombatEnd" bereits definiert
warning LNK4006: "OnCombatStart" bereits definiert
warning LNK4006: "CanUseAbility" bereits definiert
warning LNK4006: "UpdateCooldowns" bereits definiert
warning LNK4006: "UpdateBuffs" bereits definiert
warning LNK4006: "UpdateRotation" bereits definiert
```
## Current Class Hierarchy
```
ClassAI (base)
├── DeathKnightAI
│ ├── BloodSpecialization (862 lines)
│ ├── FrostSpecialization
│ └── UnholySpecialization
├── PaladinAI
│ ├── HolySpecialization
│ ├── ProtectionSpecialization
│ └── RetributionSpecialization (433 lines)
├── WarriorAI
│ ├── ArmsSpecialization (620 lines)
│ ├── FurySpecialization
│ └── ProtectionSpecialization
├── MageAI
│ ├── ArcaneSpecialization
│ ├── FireSpecialization (622 lines)
│ └── FrostSpecialization
├── (9 more classes with 3+ specs each)
```
**Total Specs:** ~40 specializations
**Estimated Duplicated Code:** 60-70% of each spec is duplicated boilerplate
## Proposed Refactoring Strategy
### Phase 1: Create Base Template System
#### New Base Class: `CombatSpecializationBase`
```cpp
template<typename ResourceType>
class CombatSpecializationBase : public ClassAI
{
protected:
// ===== COMMON COOLDOWN MANAGEMENT =====
std::unordered_map<uint32, uint32> _cooldowns;
virtual void UpdateCooldowns(uint32 diff) final
{
for (auto& cooldown : _cooldowns)
if (cooldown.second > diff)
cooldown.second -= diff;
else
cooldown.second = 0;
}
bool IsCooldownReady(uint32 spellId) const
{
auto it = _cooldowns.find(spellId);
return it == _cooldowns.end() || it->second == 0;
}
void StartCooldown(uint32 spellId, uint32 duration)
{
_cooldowns[spellId] = duration;
}
// ===== COMMON RESOURCE MANAGEMENT =====
ResourceType _currentResource;
ResourceType _maxResource;
virtual bool HasEnoughResource(uint32 spellId)
{
ResourceType cost = GetResourceCost(spellId);
return _currentResource >= cost;
}
virtual void ConsumeResource(uint32 spellId)
{
ResourceType cost = GetResourceCost(spellId);
_currentResource -= cost;
}
// ===== COMMON ABILITY VALIDATION =====
virtual bool CanUseAbility(uint32 spellId) final
{
return IsCooldownReady(spellId) &&
HasEnoughResource(spellId) &&
IsSpellUsable(spellId);
}
// ===== COMMON COMBAT STATE =====
virtual void OnCombatStart(::Unit* target) override
{
_inCombat = true;
_combatTarget = target;
OnSpecializationCombatStart(target);
}
virtual void OnCombatEnd() override
{
_inCombat = false;
_combatTarget = nullptr;
OnSpecializationCombatEnd();
}
// ===== HOOKS FOR SPECIALIZATION-SPECIFIC LOGIC =====
virtual void OnSpecializationCombatStart(::Unit* target) {}
virtual void OnSpecializationCombatEnd() {}
virtual ResourceType GetResourceCost(uint32 spellId) = 0;
virtual void UpdateRotation(::Unit* target) = 0;
};
```
#### Specialized Resource Types
```cpp
// For Mana-based classes (Mage, Priest, Paladin, etc)
using ManaSpecialization = CombatSpecializationBase<uint32>;
// For Rage-based classes (Warrior)
using RageSpecialization = CombatSpecializationBase<uint32>;
// For Energy-based classes (Rogue, Monk)
using EnergySpecialization = CombatSpecializationBase<uint32>;
// For Rune-based classes (Death Knight)
struct RuneResource { /* complex rune management */ };
using RuneSpecialization = CombatSpecializationBase<RuneResource>;
```
#### Role-Based Templates
```cpp
// Melee DPS template
template<typename ResourceType>
class MeleeDpsSpecialization : public CombatSpecializationBase<ResourceType>
{
public:
float GetOptimalRange(::Unit* target) override { return 5.0f; }
protected:
bool IsInMeleeRange(::Unit* target) const
{
return GetBot()->GetDistance(target) <= 5.0f;
}
};
// Ranged DPS template
template<typename ResourceType>
class RangedDpsSpecialization : public CombatSpecializationBase<ResourceType>
{
public:
float GetOptimalRange(::Unit* target) override { return 25.0f; }
protected:
bool ShouldMaintainDistance(::Unit* target) const
{
return GetBot()->GetDistance(target) < 15.0f;
}
};
// Healer template
template<typename ResourceType>
class HealerSpecialization : public CombatSpecializationBase<ResourceType>
{
public:
float GetOptimalRange(::Unit* target) override { return 30.0f; }
protected:
::Unit* GetBestHealTarget()
{
// Common heal target selection logic
}
};
// Tank template
template<typename ResourceType>
class TankSpecialization : public CombatSpecializationBase<ResourceType>
{
public:
float GetOptimalRange(::Unit* target) override { return 5.0f; }
protected:
void ManageThreat(::Unit* target)
{
// Common threat management
}
};
```
### Phase 2: Refactor Each Specialization
#### Before (433 lines - RetributionSpecialization)
```cpp
class RetributionSpecialization : public PaladinSpecialization
{
public:
void UpdateCooldowns(uint32 diff) { /* 10 lines */ }
bool CanUseAbility(uint32 spellId) { /* 8 lines */ }
void OnCombatStart(::Unit* target) { /* 12 lines */ }
void OnCombatEnd() { /* 8 lines */ }
float GetOptimalRange(::Unit* target) { return 5.0f; }
// ... 390 more lines of actual rotation logic
};
```
#### After (~250 lines - 42% reduction)
```cpp
class RetributionSpecialization : public MeleeDpsSpecialization<uint32>
{
public:
RetributionSpecialization(Player* bot)
: MeleeDpsSpecialization(bot)
{
// Specialization-specific initialization
}
void UpdateRotation(::Unit* target) override
{
// ONLY the unique Retribution logic
if (ShouldCastTemplarsVerdict(target))
CastTemplarsVerdict(target);
else if (ShouldCastCrusaderStrike(target))
CastCrusaderStrike(target);
// ... only rotation logic, no boilerplate
}
protected:
uint32 GetResourceCost(uint32 spellId) override
{
// Mana cost calculation
}
private:
// ONLY Retribution-specific state
uint8 _holyPower;
bool _hasArtOfWar;
// ONLY Retribution-specific methods
bool ShouldCastTemplarsVerdict(::Unit* target);
void CastTemplarsVerdict(::Unit* target);
bool ShouldCastCrusaderStrike(::Unit* target);
void CastCrusaderStrike(::Unit* target);
};
```
## Expected Benefits
### Code Reduction
- **Before:** ~40 specs × 400 lines avg = 16,000 lines
- **After:** 40 specs × 200 lines avg = 8,000 lines
- **Reduction:** 50% less code to maintain
### Eliminated Duplication
- Remove 1,740 duplicate method implementations
- Eliminate all linker warnings
- Single source of truth for common logic
### Maintenance Improvements
- Fix bugs in ONE place instead of 40+
- Add features to base class, all specs benefit
- Consistent behavior across all classes
### Performance Improvements
- Smaller binary size
- Better CPU cache utilization
- Reduced memory footprint
## Implementation Plan
### Week 1: Foundation
- **Day 1-2:** Create `CombatSpecializationBase` template
- **Day 3:** Create role-based templates (Melee, Ranged, Healer, Tank)
- **Day 4:** Create resource-type specializations
- **Day 5:** Test compilation, ensure no regressions
### Week 2: First Wave (Simpler Classes)
- **Day 1:** Refactor Warriors (3 specs)
- **Day 2:** Refactor Paladins (3 specs)
- **Day 3:** Refactor Hunters (3 specs)
- **Day 4:** Refactor Rogues (3 specs)
- **Day 5:** Test all 12 specs in combat
### Week 3: Second Wave (Complex Classes)
- **Day 1:** Refactor Death Knights (3 specs)
- **Day 2:** Refactor Mages (3 specs)
- **Day 3:** Refactor Priests (3 specs)
- **Day 4:** Refactor Druids (4 specs)
- **Day 5:** Test all 13 specs in combat
### Week 4: Final Wave + Testing
- **Day 1:** Refactor Warlocks (3 specs)
- **Day 2:** Refactor Shamans (3 specs)
- **Day 3:** Refactor Monks (3 specs)
- **Day 4:** Refactor Demon Hunters + Evokers
- **Day 5:** Full regression testing with all 40 specs
## Risk Mitigation
### Backup Strategy
- Keep original files as `.cpp.backup`
- Branch: `refactor/classai-templates`
- Commit after each class refactored
### Testing Strategy
- Test EACH class after refactoring
- Verify combat works for all 3 specs
- Check memory usage hasn't increased
- Confirm no new crashes
### Rollback Plan
If refactoring causes issues:
1. Revert to backup files
2. Cherry-pick working classes
3. Leave problematic classes unreffactored temporarily
## Success Criteria
✅ All linker warnings eliminated
✅ 50%+ code reduction
✅ All 40 specs compile cleanly
✅ All specs function in combat
✅ No performance regression
✅ No memory increase
## Conclusion
This refactoring will:
- Cut maintenance burden in HALF
- Eliminate technical debt
- Make future features easier to add
- Improve code quality significantly
- Pay dividends for ALL future development
**Recommendation:** Proceed with refactoring immediately before adding more features.