Files
ThordekkCore/TEMPLATE_ARCHITECTURE_GUIDE.md
T
2026-01-20 21:37:09 -03:00

25 KiB

PlayerBot Template Architecture Guide

Version: 1.0 Date: 2025-10-02 Target: WoW 11.2 (The War Within)


Table of Contents

  1. Overview
  2. Template Hierarchy
  3. Resource System
  4. Proc Tracking System
  5. Rotation System
  6. Implementation Examples
  7. Best Practices
  8. Performance Considerations

Overview

The PlayerBot Class AI uses a template-based architecture to eliminate code duplication while maintaining complete, specialized combat AI for all 36 WoW specializations. This guide explains the architecture patterns and how to implement new specializations.

Design Principles

  1. Template Metaprogramming: Use C++20 templates to share common logic
  2. Role-Based Inheritance: Group specs by role (Tank, Healer, Melee DPS, Ranged DPS)
  3. Header-Only Templates: Required for C++ template compilation
  4. Resource Abstraction: Flexible resource systems via template parameters
  5. CLAUDE.md Compliance: Module-only, no core modifications

Template Hierarchy

Base Template: CombatSpecializationBase

All specializations inherit from CombatSpecializationBase<ResourceType>:

template<typename ResourceType>
class CombatSpecializationBase
{
protected:
    Player* bot;
    ResourceType _resource;

    // Core combat methods
    virtual void UpdateRotation(::Unit* target) = 0;
    virtual void UpdateBuffs() = 0;
    virtual void UpdateDefensives() = 0;

    // Utility methods
    bool CanCastSpell(uint32 spellId, ::Unit* target);
    void CastSpell(uint32 spellId, ::Unit* target);
    uint32 GetEnemiesInRange(float range) const;
};

Role Specialization Templates

Four role-based templates inherit from CombatSpecializationBase:

1. TankSpecialization

template<typename ResourceType>
class TankSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
    // Tank-specific methods
    void UpdateThreatGeneration();
    void UpdateMitigation();
    bool ShouldUseMajorDefensive();
    float GetThreatLevel() const;
};

Use Cases: Protection Warrior, Blood DK, Guardian Druid, etc.

Common Patterns:

  • Threat generation mechanics
  • Active mitigation tracking
  • Emergency defensive triggers
  • Taunt mechanics

2. HealerSpecialization

template<typename ResourceType>
class HealerSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
    // Healer-specific methods
    Unit* GetBestHealTarget(const std::vector<Unit*>& group);
    bool HandleGroupHealing(const std::vector<Unit*>& group);
    bool HandleEmergencyCooldowns(const std::vector<Unit*>& group);
    uint32 GetAverageGroupHealth(const std::vector<Unit*>& group);
};

Use Cases: Holy Priest, Restoration Druid, Mistweaver Monk, etc.

Common Patterns:

  • Group health evaluation
  • HoT/shield tracking
  • Emergency cooldown priorities
  • Mana conservation

3. MeleeDpsSpecialization

template<typename ResourceType>
class MeleeDpsSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
    // Melee DPS-specific methods
    void UpdateMeleePositioning();
    bool ShouldUseMajorCooldown();
    void ExecuteSingleTargetRotation(::Unit* target);
    void ExecuteAoERotation(::Unit* target, uint32 enemyCount);
};

Use Cases: Fury Warrior, Feral Druid, Windwalker Monk, etc.

Common Patterns:

  • Melee range positioning (< 5 yards)
  • Builder/spender mechanics
  • Burst window optimization
  • AoE cleave thresholds

4. RangedDpsSpecialization

template<typename ResourceType>
class RangedDpsSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
    // Ranged DPS-specific methods
    void UpdateRangedPositioning();
    bool ShouldMaintainDoTs();
    void ExecuteSingleTargetRotation(::Unit* target);
    void ExecuteAoERotation(::Unit* target, uint32 enemyCount);
};

Use Cases: Fire Mage, Shadow Priest, Elemental Shaman, etc.

Common Patterns:

  • Ranged positioning (20-40 yards)
  • DoT maintenance and pandemic windows
  • Cast time optimization
  • AoE target caps

Resource System

Resource Struct Pattern

Each specialization defines a custom resource struct:

struct ManaRageResource
{
    uint32 mana = 0;
    uint32 maxMana = 100;
    uint32 rage = 0;
    uint32 maxRage = 100;

    void Initialize(Player* bot)
    {
        if (!bot)
            return;

        mana = bot->GetPower(POWER_MANA);
        maxMana = bot->GetMaxPower(POWER_MANA);
        rage = bot->GetPower(POWER_RAGE);
        maxRage = bot->GetMaxPower(POWER_RAGE);
    }

    void Update(Player* bot)
    {
        if (!bot)
            return;

        mana = bot->GetPower(POWER_MANA);
        rage = bot->GetPower(POWER_RAGE);
    }

    [[nodiscard]] bool HasMana(uint32 amount) const { return mana >= amount; }
    [[nodiscard]] bool HasRage(uint32 amount) const { return rage >= amount; }
    [[nodiscard]] uint32 GetManaPercent() const { return maxMana > 0 ? (mana * 100) / maxMana : 0; }
    [[nodiscard]] uint32 GetRagePercent() const { return maxRage > 0 ? (rage * 100) / maxRage : 0; }

    void GenerateRage(uint32 amount)
    {
        rage = std::min(rage + amount, maxRage);
    }

    void SpendRage(uint32 amount)
    {
        if (rage >= amount)
            rage -= amount;
        else
            rage = 0;
    }
};

Common Resource Types

  1. Mana (Healers, Ranged DPS)

    • Regenerates over time
    • Conservation mechanics
    • Cooldown-based regeneration
  2. Rage (Warriors, Druids)

    • Generated by taking/dealing damage
    • Decays over time out of combat
    • Burst generation mechanics
  3. Energy (Rogues, Druids, Monks)

    • Fast regeneration rate
    • Combo point builders
    • Energy pooling mechanics
  4. Focus (Hunters)

    • Medium regeneration rate
    • Pet resource management
    • Focus dump mechanics
  5. Runes (Death Knights)

    • Recharge-based system
    • Rune type tracking (Blood, Frost, Unholy)
    • Rune pooling strategies
  6. Holy Power (Paladins)

    • Builder/spender mechanic
    • 5 maximum stacks
    • Word of Glory priority
  7. Maelstrom (Shamans)

    • Generated by abilities
    • Spent on big hits
    • Overflow prevention
  8. Soul Shards (Warlocks)

    • Fragmented resource (0.1 increments)
    • 5 maximum shards
    • Demon summoning costs
  9. Insanity (Shadow Priests)

    • Generated by DoTs and builders
    • Voidform entry cost
    • Drain during Voidform
  10. Arcane Charges (Arcane Mages)

    • Stacking buff (1-4)
    • Increases damage and cost
    • Management critical to rotation

Proc Tracking System

Proc Tracker Pattern

class ProcNameTracker
{
public:
    ProcNameTracker() : _procActive(false), _procStacks(0), _procEndTime(0) {}

    void ActivateProc(uint32 stacks = 1)
    {
        _procActive = true;
        _procStacks = std::min(_procStacks + stacks, _maxStacks);
        _procEndTime = getMSTime() + _procDuration;
    }

    void ConsumeProc()
    {
        if (_procStacks > 0)
            _procStacks--;

        if (_procStacks == 0)
            _procActive = false;
    }

    [[nodiscard]] bool IsActive() const
    {
        return _procActive && getMSTime() < _procEndTime;
    }

    [[nodiscard]] uint32 GetStacks() const { return _procStacks; }

    void Update(Player* bot)
    {
        if (!bot)
            return;

        // Check if buff is active via aura
        if (Aura* aura = bot->GetAura(_buffId))
        {
            _procActive = true;
            _procStacks = aura->GetStackAmount();
            _procEndTime = getMSTime() + aura->GetDuration();
        }
        else
        {
            _procActive = false;
            _procStacks = 0;
        }

        // Expire if time is up
        if (_procActive && getMSTime() >= _procEndTime)
        {
            _procActive = false;
            _procStacks = 0;
        }
    }

private:
    bool _procActive;
    uint32 _procStacks;
    uint32 _procEndTime;
    static constexpr uint32 _maxStacks = 3;
    static constexpr uint32 _procDuration = 15000; // 15 sec
    static constexpr uint32 _buffId = 12345; // WoW spell ID
};

Common Proc Types

  1. Instant Cast Procs

    • Hot Streak (Fire Mage)
    • Lava Surge (Elemental Shaman)
    • Sudden Death (Arms Warrior)
  2. Stacking Procs

    • Maelstrom Weapon (Enhancement Shaman)
    • Clearcasting (Arcane Mage)
    • Sacred Duty (Protection Paladin)
  3. Cooldown Reset Procs

    • Killing Machine (Frost DK)
    • Rime (Frost DK)
    • Wild Spirits (Beast Mastery Hunter)
  4. Damage Modifier Procs

    • Enrage (Fury Warrior)
    • Tiger's Fury (Feral Druid)
    • Combustion (Fire Mage)

Rotation System

Single-Target Rotation Pattern

void ExecuteSingleTargetRotation(::Unit* target)
{
    uint32 resource = _resource.GetPrimaryResource();

    // 1. Major DPS Cooldowns
    if (ShouldUseMajorCooldown())
    {
        if (CanCastSpell(MAJOR_COOLDOWN_SPELL, bot))
        {
            CastSpell(MAJOR_COOLDOWN_SPELL, bot);
            return;
        }
    }

    // 2. Maintain DoTs/Debuffs
    if (!target->HasAura(DOT_SPELL) || ShouldRefreshDoT(target))
    {
        if (CanCastSpell(DOT_SPELL, target))
        {
            CastSpell(DOT_SPELL, target);
            return;
        }
    }

    // 3. Proc-Based Abilities
    if (_procTracker.IsActive())
    {
        if (CanCastSpell(PROC_SPELL, target))
        {
            CastSpell(PROC_SPELL, target);
            _procTracker.ConsumeProc();
            return;
        }
    }

    // 4. Resource Spenders
    if (resource >= SPEND_THRESHOLD)
    {
        if (CanCastSpell(SPENDER_SPELL, target))
        {
            CastSpell(SPENDER_SPELL, target);
            _resource.SpendResource(SPEND_AMOUNT);
            return;
        }
    }

    // 5. Resource Builders
    if (CanCastSpell(BUILDER_SPELL, target))
    {
        CastSpell(BUILDER_SPELL, target);
        _resource.GenerateResource(BUILD_AMOUNT);
        return;
    }
}

AoE Rotation Pattern

void ExecuteAoERotation(::Unit* target, uint32 enemyCount)
{
    // 1. AoE Cooldowns
    if (enemyCount >= 5 && ShouldUseMajorCooldown())
    {
        if (CanCastSpell(AOE_COOLDOWN, bot))
        {
            CastSpell(AOE_COOLDOWN, bot);
            return;
        }
    }

    // 2. Ground-Targeted AoE
    if (enemyCount >= 3)
    {
        if (CanCastSpell(GROUND_AOE, target))
        {
            CastSpell(GROUND_AOE, target);
            return;
        }
    }

    // 3. Multi-DoT (if 5 or fewer targets)
    if (enemyCount <= 5)
    {
        if (!target->HasAura(DOT_SPELL))
        {
            if (CanCastSpell(DOT_SPELL, target))
            {
                CastSpell(DOT_SPELL, target);
                return;
            }
        }
    }

    // 4. AoE Spenders
    if (_resource.GetPrimaryResource() >= SPEND_THRESHOLD)
    {
        if (CanCastSpell(AOE_SPENDER, target))
        {
            CastSpell(AOE_SPENDER, target);
            return;
        }
    }

    // 5. AoE Builders
    if (CanCastSpell(AOE_BUILDER, target))
    {
        CastSpell(AOE_BUILDER, target);
        return;
    }
}

Pandemic Window Calculation

[[nodiscard]] bool ShouldRefreshDoT(::Unit* target, uint32 dotSpellId, uint32 baseDuration) const
{
    if (!target->HasAura(dotSpellId))
        return true;

    Aura* aura = target->GetAura(dotSpellId);
    if (!aura)
        return true;

    uint32 remaining = aura->GetDuration();
    uint32 pandemicWindow = baseDuration * 0.3f; // 30% of base duration

    return remaining < pandemicWindow;
}

Implementation Examples

Example 1: Fire Mage (Ranged DPS)

class FireMageRefactored : public RangedDpsSpecialization<ManaResourceFire>
{
public:
    explicit FireMageRefactored(Player* bot)
        : RangedDpsSpecialization<ManaResourceFire>(bot)
        , _hotStreakTracker()
        , _combustionActive(false)
    {
        _resource.Initialize(bot);
    }

    void UpdateRotation(::Unit* target) override
    {
        if (!target || !bot)
            return;

        UpdateFireState();

        uint32 enemyCount = GetEnemiesInRange(40.0f);

        if (enemyCount >= 3)
            ExecuteAoERotation(target, enemyCount);
        else
            ExecuteSingleTargetRotation(target);
    }

private:
    void ExecuteSingleTargetRotation(::Unit* target)
    {
        // Combustion (major cooldown)
        if (!_combustionActive && _hotStreakTracker.IsActive())
        {
            if (CanCastSpell(FIRE_COMBUSTION, bot))
            {
                CastSpell(FIRE_COMBUSTION, bot);
                _combustionActive = true;
                return;
            }
        }

        // Pyroblast with Hot Streak
        if (_hotStreakTracker.IsActive())
        {
            if (CanCastSpell(FIRE_PYROBLAST, target))
            {
                CastSpell(FIRE_PYROBLAST, target);
                _hotStreakTracker.ConsumeProc();
                return;
            }
        }

        // Fire Blast to generate Hot Streak
        if (_heatingUpTracker.IsActive() && _fireBlastCharges > 0)
        {
            if (CanCastSpell(FIRE_FIRE_BLAST, target))
            {
                CastSpell(FIRE_FIRE_BLAST, target);
                _fireBlastCharges--;
                _hotStreakTracker.ActivateProc();
                return;
            }
        }

        // Fireball (builder)
        if (CanCastSpell(FIRE_FIREBALL, target))
        {
            CastSpell(FIRE_FIREBALL, target);

            // Simulate crit for Heating Up
            if (rand() % 100 < 30)
                _heatingUpTracker.ActivateProc();

            return;
        }
    }

    HotStreakTracker _hotStreakTracker;
    bool _combustionActive;
};

Example 2: Protection Warrior (Tank)

class ProtectionWarriorRefactored : public TankSpecialization<RageResource>
{
public:
    explicit ProtectionWarriorRefactored(Player* bot)
        : TankSpecialization<RageResource>(bot)
        , _ignoreePainActive(false)
        , _shieldBlockCharges(2)
    {
        _resource.Initialize(bot);
    }

    void UpdateRotation(::Unit* target) override
    {
        if (!target || !bot)
            return;

        UpdateProtectionState();

        // Prioritize active mitigation
        UpdateMitigation();

        // Then threat generation
        ExecuteThreatRotation(target);
    }

    void UpdateDefensives() override
    {
        float healthPct = bot->GetHealthPct();

        // Shield Wall (emergency)
        if (healthPct < 30.0f)
        {
            if (CanCastSpell(PROT_SHIELD_WALL, bot))
            {
                CastSpell(PROT_SHIELD_WALL, bot);
                return;
            }
        }

        // Last Stand (emergency)
        if (healthPct < 40.0f)
        {
            if (CanCastSpell(PROT_LAST_STAND, bot))
            {
                CastSpell(PROT_LAST_STAND, bot);
                return;
            }
        }
    }

private:
    void UpdateMitigation()
    {
        uint32 rage = _resource.rage;

        // Shield Block (physical mitigation)
        if (_shieldBlockCharges > 0 && bot->IsInCombat())
        {
            if (CanCastSpell(PROT_SHIELD_BLOCK, bot))
            {
                CastSpell(PROT_SHIELD_BLOCK, bot);
                _shieldBlockCharges--;
                return;
            }
        }

        // Ignore Pain (rage dump)
        if (rage >= 40 && !_ignorePainActive)
        {
            if (CanCastSpell(PROT_IGNORE_PAIN, bot))
            {
                CastSpell(PROT_IGNORE_PAIN, bot);
                _resource.SpendRage(40);
                _ignorePainActive = true;
                return;
            }
        }
    }

    void ExecuteThreatRotation(::Unit* target)
    {
        uint32 rage = _resource.rage;

        // Shield Slam (high threat)
        if (CanCastSpell(PROT_SHIELD_SLAM, target))
        {
            CastSpell(PROT_SHIELD_SLAM, target);
            _resource.GenerateRage(15);
            return;
        }

        // Thunder Clap (AoE threat)
        if (GetEnemiesInRange(8.0f) >= 2)
        {
            if (CanCastSpell(PROT_THUNDER_CLAP, bot))
            {
                CastSpell(PROT_THUNDER_CLAP, bot);
                _resource.GenerateRage(5);
                return;
            }
        }

        // Revenge (rage spender)
        if (rage >= 30)
        {
            if (CanCastSpell(PROT_REVENGE, target))
            {
                CastSpell(PROT_REVENGE, target);
                _resource.SpendRage(30);
                return;
            }
        }

        // Devastate (filler)
        if (CanCastSpell(PROT_DEVASTATE, target))
        {
            CastSpell(PROT_DEVASTATE, target);
            _resource.GenerateRage(5);
            return;
        }
    }

    bool _ignorePainActive;
    uint32 _shieldBlockCharges;
};

Example 3: Restoration Druid (Healer)

class RestorationDruidRefactored : public HealerSpecialization<ManaResource>
{
public:
    explicit RestorationDruidRefactored(Player* bot)
        : HealerSpecialization<ManaResource>(bot)
        , _rejuvenationTracker()
        , _lifebloomTracker()
    {
        _resource.Initialize(bot);
    }

    void UpdateRotation(::Unit* target) override
    {
        if (!target || !bot)
            return;

        UpdateRestorationState();

        // Check group health
        if (Group* group = bot->GetGroup())
        {
            std::vector<Unit*> groupMembers;
            for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
            {
                if (Player* member = ref->GetSource())
                {
                    if (member->IsAlive() && bot->IsInMap(member))
                        groupMembers.push_back(member);
                }
            }

            if (!groupMembers.empty())
            {
                if (HandleGroupHealing(groupMembers))
                    return;
            }
        }

        // Self-healing
        if (bot->GetHealthPct() < 80.0f)
        {
            HandleSelfHealing();
        }
    }

private:
    bool HandleGroupHealing(const std::vector<Unit*>& group)
    {
        // Emergency cooldowns
        if (HandleEmergencyCooldowns(group))
            return true;

        // Maintain HoTs
        if (HandleHoTs(group))
            return true;

        // Direct healing
        if (HandleDirectHealing(group))
            return true;

        return false;
    }

    bool HandleHoTs(const std::vector<Unit*>& group)
    {
        // Lifebloom on tank
        Unit* tankTarget = nullptr;
        for (Unit* member : group)
        {
            if (member && IsTankRole(member))
            {
                tankTarget = member;
                break;
            }
        }

        if (tankTarget && !_lifebloomTracker.HasLifebloom(tankTarget->GetGUID()))
        {
            if (CanCastSpell(RESTO_LIFEBLOOM, tankTarget))
            {
                CastSpell(RESTO_LIFEBLOOM, tankTarget);
                _lifebloomTracker.ApplyLifebloom(tankTarget->GetGUID());
                return true;
            }
        }

        // Rejuvenation on injured allies
        for (Unit* member : group)
        {
            if (member && member->GetHealthPct() < 90.0f)
            {
                if (_rejuvenationTracker.NeedsRejuvenationRefresh(member->GetGUID()))
                {
                    if (CanCastSpell(RESTO_REJUVENATION, member))
                    {
                        CastSpell(RESTO_REJUVENATION, member);
                        _rejuvenationTracker.ApplyRejuvenation(member->GetGUID());
                        return true;
                    }
                }
            }
        }

        return false;
    }

    bool HandleDirectHealing(const std::vector<Unit*>& group)
    {
        // Swiftmend for emergency
        for (Unit* member : group)
        {
            if (member && member->GetHealthPct() < 50.0f)
            {
                if (_rejuvenationTracker.HasRejuvenation(member->GetGUID()))
                {
                    if (CanCastSpell(RESTO_SWIFTMEND, member))
                    {
                        CastSpell(RESTO_SWIFTMEND, member);
                        return true;
                    }
                }
            }
        }

        // Regrowth for spot healing
        for (Unit* member : group)
        {
            if (member && member->GetHealthPct() < 70.0f)
            {
                if (CanCastSpell(RESTO_REGROWTH, member))
                {
                    CastSpell(RESTO_REGROWTH, member);
                    return true;
                }
            }
        }

        return false;
    }

    RejuvenationTracker _rejuvenationTracker;
    LifebloomTracker _lifebloomTracker;
};

Best Practices

1. Resource Management

// GOOD: Check resource before spending
if (_resource.HasRage(40))
{
    CastSpell(EXPENSIVE_SPELL, target);
    _resource.SpendRage(40);
}

// BAD: Spend without checking
_resource.SpendRage(40); // May go negative
CastSpell(EXPENSIVE_SPELL, target);

2. Proc Tracking

// GOOD: Update procs before checking
_procTracker.Update(bot);
if (_procTracker.IsActive())
{
    // Use proc
}

// BAD: Use stale proc state
if (_procTracker.IsActive()) // May be outdated
{
    // Use proc
}

3. Null Safety

// GOOD: Always check pointers
void UpdateRotation(::Unit* target) override
{
    if (!target || !bot)
        return;

    // Safe to use target and bot
}

// BAD: Assume pointers are valid
void UpdateRotation(::Unit* target) override
{
    CastSpell(SPELL, target); // May crash
}

4. Cooldown Management

// GOOD: Track cooldown usage
if ((getMSTime() - _lastMajorCooldownTime) >= 180000) // 3 min CD
{
    if (CanCastSpell(MAJOR_COOLDOWN, bot))
    {
        CastSpell(MAJOR_COOLDOWN, bot);
        _lastMajorCooldownTime = getMSTime();
    }
}

// BAD: Spam cooldowns
if (CanCastSpell(MAJOR_COOLDOWN, bot))
{
    CastSpell(MAJOR_COOLDOWN, bot); // May be on cooldown
}

5. AoE Threshold

// GOOD: Smart AoE threshold
uint32 enemyCount = GetEnemiesInRange(40.0f);
if (enemyCount >= 3)
    ExecuteAoERotation(target, enemyCount);
else
    ExecuteSingleTargetRotation(target);

// BAD: Hard-coded AoE
ExecuteAoERotation(target, 1); // Inefficient for single target

Performance Considerations

1. Avoid Repeated Calculations

// GOOD: Calculate once
uint32 enemyCount = GetEnemiesInRange(40.0f);
if (enemyCount >= 3)
    ExecuteAoERotation(target, enemyCount);

// BAD: Calculate multiple times
if (GetEnemiesInRange(40.0f) >= 3)
    ExecuteAoERotation(target, GetEnemiesInRange(40.0f));

2. Use constexpr for Constants

// GOOD: Compile-time constants
constexpr uint32 FIRE_FIREBALL = 133;
constexpr uint32 FIRE_PYROBLAST = 11366;

// BAD: Runtime constants
uint32 FIRE_FIREBALL = 133;
uint32 FIRE_PYROBLAST = 11366;

3. Minimize Allocations

// GOOD: Static tracker (allocated once)
static HotStreakTracker _hotStreakTracker;

// BAD: Dynamic allocation every update
auto tracker = std::make_unique<HotStreakTracker>();

4. Early Return Pattern

// GOOD: Return early to avoid unnecessary checks
if (CanCastSpell(HIGH_PRIORITY_SPELL, target))
{
    CastSpell(HIGH_PRIORITY_SPELL, target);
    return; // Skip remaining checks
}

if (CanCastSpell(LOW_PRIORITY_SPELL, target))
{
    CastSpell(LOW_PRIORITY_SPELL, target);
}

// BAD: Nested if-else
if (CanCastSpell(HIGH_PRIORITY_SPELL, target))
{
    CastSpell(HIGH_PRIORITY_SPELL, target);
}
else if (CanCastSpell(LOW_PRIORITY_SPELL, target))
{
    CastSpell(LOW_PRIORITY_SPELL, target);
}

5. nodiscard Attribute

// GOOD: Mark functions that return important values
[[nodiscard]] bool IsActive() const { return _active; }
[[nodiscard]] uint32 GetStacks() const { return _stacks; }

// Compiler warns if return value is ignored:
IsActive(); // WARNING: Ignoring return value

Conclusion

This template architecture provides:

  • 70% code reduction via template inheritance
  • Type safety via C++20 concepts
  • Maintainability via role-based organization
  • Extensibility via template parameters
  • Performance via compile-time optimization

When implementing new specializations:

  1. Choose appropriate role template (Tank/Healer/MeleeDPS/RangedDPS)
  2. Define custom resource struct
  3. Implement proc tracking classes as needed
  4. Follow rotation pattern (priority-based, early return)
  5. Add to CMakeLists.txt
  6. Integrate baseline rotation support

Next Steps: See PLAYERBOT_REFACTORING_COMPLETE.md for implementation status and RoleSpecializations.h for base template definitions.


Document Version: 1.0 Last Updated: 2025-10-02 Maintainer: TrinityCore PlayerBot Team