# 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 class CombatSpecializationBase : public ClassAI { protected: // ===== COMMON COOLDOWN MANAGEMENT ===== std::unordered_map _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; // For Rage-based classes (Warrior) using RageSpecialization = CombatSpecializationBase; // For Energy-based classes (Rogue, Monk) using EnergySpecialization = CombatSpecializationBase; // For Rune-based classes (Death Knight) struct RuneResource { /* complex rune management */ }; using RuneSpecialization = CombatSpecializationBase; ``` #### Role-Based Templates ```cpp // Melee DPS template template class MeleeDpsSpecialization : public CombatSpecializationBase { 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 class RangedDpsSpecialization : public CombatSpecializationBase { public: float GetOptimalRange(::Unit* target) override { return 25.0f; } protected: bool ShouldMaintainDistance(::Unit* target) const { return GetBot()->GetDistance(target) < 15.0f; } }; // Healer template template class HealerSpecialization : public CombatSpecializationBase { public: float GetOptimalRange(::Unit* target) override { return 30.0f; } protected: ::Unit* GetBestHealTarget() { // Common heal target selection logic } }; // Tank template template class TankSpecialization : public CombatSpecializationBase { 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 { 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.