WIP(refactoring): GameSystemsManager, CombatCoordinationIntegrator, and subsystem registry planning
Work-in-progress from recovery-refactoring-work branch including: - GameSystemsManager interface and implementation - CombatCoordinationIntegrator scaffolding - BotAI and BotMessage header updates - CMakeLists.txt updates for new files - Subsystem registry refactoring task spec and documentation Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: luis <[email protected]>
This commit is contained in:
committed by
luis
co-authored by
Claude Opus 4.6
parent
858235aec4
commit
04fbdf7242
@@ -0,0 +1,711 @@
|
||||
# Orchestration Architecture - Zenflow + Obsidian for TrinityCore
|
||||
|
||||
## System Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Zenflow Desktop (GUI) │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Project │ │ Workflow │ │ DAG │ │
|
||||
│ │ Dashboard │ │ Designer │ │ Visualizer │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │ │
|
||||
│ │ Orchestrates │
|
||||
│ ▼ │
|
||||
└───────────────────────────────────────────────────────────────-─┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ Claude Instance 1│ │ Claude Instance 2│ │ Claude Instance 3│
|
||||
│ (Analysis) │ │ (Implementation) │ │ (Review) │
|
||||
│ │ │ │ │ │
|
||||
│ Branch: │ │ Branch: │ │ Branch: │
|
||||
│ zenflow/agent-1/ │ │ zenflow/agent-2/ │ │ zenflow/agent-3/ │
|
||||
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
|
||||
│ │ │
|
||||
│ Shared Tasks │ Shared Memory │
|
||||
│ (via env var) │ (via MCP) │
|
||||
│ │ │
|
||||
└────────────────────┼────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────┐
|
||||
│ CLAUDE_CODE_TASK_LIST_ID │
|
||||
│ "trinitycore-playerbot-shared"│
|
||||
│ │
|
||||
│ Task Coordination Layer │
|
||||
│ • DAG dependencies │
|
||||
│ • Status updates │
|
||||
│ • Blocking relationships │
|
||||
└───────────────┬───────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────┐
|
||||
│ Obsidian Vault (MCP) │
|
||||
│ C:\...\PlayerBotProjectMemory│
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ Architecture/ │ │
|
||||
│ │ • System Overview.md │ │
|
||||
│ │ • Component Docs │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ Tasks/ │ │
|
||||
│ │ • Active Instances.md │ │
|
||||
│ │ • Task definitions │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ Refactorings/ │ │
|
||||
│ │ • DI Cleanup.md │ │
|
||||
│ │ • Sprint Plans │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ Sessions/ │ │
|
||||
│ │ • Implementation notes │ │
|
||||
│ │ • Build reports │ │
|
||||
│ │ • Handover docs │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ Gotchas/ │ │
|
||||
│ │ • Git Workflow rules │ │
|
||||
│ │ • Build system issues │ │
|
||||
│ └─────────────────────────┘ │
|
||||
└───────────────┬───────────────┘
|
||||
│
|
||||
│ All agents read/write
|
||||
│ Persistent memory
|
||||
│ Graph visualization
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────┐
|
||||
│ TrinityCore Repository │
|
||||
│ C:\TrinityBots\TrinityCore │
|
||||
│ │
|
||||
│ Branches: │
|
||||
│ • playerbot-dev (main) │
|
||||
│ • zenflow/agent-1/sprint-2 │
|
||||
│ • zenflow/agent-2/sprint-2 │
|
||||
│ • zenflow/agent-3/review │
|
||||
└───────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow Diagram
|
||||
|
||||
### Workflow Execution Flow
|
||||
|
||||
```
|
||||
User Action (Zenflow GUI)
|
||||
│
|
||||
│ Click "Run Workflow: DI Cleanup Sprint 2"
|
||||
│
|
||||
▼
|
||||
Zenflow Orchestrator
|
||||
│
|
||||
│ 1. Create workflow instance
|
||||
│ 2. Read DAG configuration
|
||||
│ 3. Identify first stage (Analysis)
|
||||
│
|
||||
▼
|
||||
Stage 1: Analysis Agent (Claude Opus 4.5)
|
||||
│
|
||||
│ Actions:
|
||||
│ • Create branch: zenflow/agent-1/sprint-2
|
||||
│ • Read Obsidian: "Refactorings/DI Cleanup.md"
|
||||
│ • Analyze dependencies
|
||||
│ • Write Obsidian: "Refactorings/Analysis Sprint 2.md"
|
||||
│ • Update task: Status = COMPLETE
|
||||
│
|
||||
▼
|
||||
Zenflow Orchestrator
|
||||
│
|
||||
│ Stage 1 complete ✅
|
||||
│ Check dependencies: Stage 2 unblocked
|
||||
│
|
||||
▼
|
||||
Stage 2: Specification Agent (Claude Opus 4.5)
|
||||
│
|
||||
│ Actions:
|
||||
│ • Create branch: zenflow/agent-2/sprint-2
|
||||
│ • Read Obsidian: "Refactorings/Analysis Sprint 2.md"
|
||||
│ • Generate technical spec
|
||||
│ • Write Obsidian: "Refactorings/Spec Sprint 2.md"
|
||||
│ • Update task: Status = COMPLETE
|
||||
│
|
||||
▼
|
||||
Zenflow Orchestrator
|
||||
│
|
||||
│ Stage 2 complete ✅
|
||||
│ Check dependencies: Stage 3 unblocked
|
||||
│
|
||||
▼
|
||||
Stage 3: Implementation Agent (Claude Sonnet 4.5)
|
||||
│
|
||||
│ Actions:
|
||||
│ • Create branch: zenflow/agent-3/sprint-2-impl
|
||||
│ • Read Obsidian: "Refactorings/Spec Sprint 2.md"
|
||||
│ • Check lock: .claude/locks/CMakeLists.txt.lock
|
||||
│ • Implement code changes
|
||||
│ • Update CMakeLists.txt
|
||||
│ • Commit changes
|
||||
│ • Write Obsidian: "Sessions/Implementation Sprint 2.md"
|
||||
│ • Update task: Status = COMPLETE
|
||||
│
|
||||
▼
|
||||
Zenflow Orchestrator
|
||||
│
|
||||
│ Stage 3 complete ✅
|
||||
│ Check dependencies: Stage 4 unblocked
|
||||
│
|
||||
▼
|
||||
Stage 4: Build Verification Agent (Claude Sonnet 4.5)
|
||||
│
|
||||
│ Actions:
|
||||
│ • Checkout impl branch
|
||||
│ • Run CMake configure
|
||||
│ • Build worldserver
|
||||
│ • Check for errors
|
||||
│ • Write Obsidian: "Sessions/Build Report Sprint 2.md"
|
||||
│ • Update task: Status = COMPLETE or FAILED
|
||||
│
|
||||
▼
|
||||
Zenflow Orchestrator
|
||||
│
|
||||
│ Stage 4 status check
|
||||
│ If FAILED: Alert user, stop workflow
|
||||
│ If COMPLETE: Continue to Stage 5
|
||||
│
|
||||
▼
|
||||
Stage 5: Review Agent (Claude Opus 4.5)
|
||||
│
|
||||
│ Actions:
|
||||
│ • Read all previous Obsidian notes
|
||||
│ • Review git diff
|
||||
│ • Check for issues:
|
||||
│ - Security vulnerabilities
|
||||
│ - Memory leaks
|
||||
│ - API misuse
|
||||
│ • Write Obsidian: "Sessions/Review Sprint 2.md"
|
||||
│ • Decision: APPROVE or REQUEST_CHANGES
|
||||
│ • Update task: Status = COMPLETE
|
||||
│
|
||||
▼
|
||||
Zenflow Orchestrator
|
||||
│
|
||||
│ Workflow complete ✅
|
||||
│ All stages passed
|
||||
│
|
||||
▼
|
||||
User Notification (Zenflow GUI)
|
||||
│
|
||||
│ "Sprint 2 workflow complete - Ready for merge"
|
||||
│
|
||||
▼
|
||||
User Reviews Obsidian Notes + Git Branches
|
||||
│
|
||||
│ Manually verify
|
||||
│ Merge when satisfied
|
||||
│
|
||||
▼
|
||||
Done ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Communication Patterns
|
||||
|
||||
### Pattern 1: Task Coordination (via Shared Task List)
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Instance 1 │ │ Instance 2 │
|
||||
│ (Terminal 1) │ │ (Terminal 2) │
|
||||
└────────┬────────┘ └────────┬────────┘
|
||||
│ │
|
||||
│ CLAUDE_CODE_TASK_LIST_ID │
|
||||
│ = "trinitycore-..." │
|
||||
│ │
|
||||
└─────────┬─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ Shared Task List │
|
||||
│ │
|
||||
│ 1. [COMPLETE] Stage1│
|
||||
│ 2. [IN_PROGRESS] S2 │◄─── Instance 1 updates
|
||||
│ 3. [PENDING] Stage3 │
|
||||
│ 4. [BLOCKED_BY: 3] │◄─── Instance 2 sees this
|
||||
└──────────────────────┘
|
||||
│
|
||||
│ Both instances
|
||||
│ read/write same list
|
||||
│
|
||||
┌─────────┴──────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
Instance 1 Instance 2
|
||||
Knows: S2 active Knows: Wait for S2
|
||||
```
|
||||
|
||||
### Pattern 2: Memory Sharing (via Obsidian MCP)
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Agent 1 │ │ Agent 2 │
|
||||
│ (Analysis) │ │ (Impl) │
|
||||
└────────┬────────┘ └────────┬────────┘
|
||||
│ │
|
||||
│ MCP: obsidian_write_note │ MCP: obsidian_read_note
|
||||
│ │
|
||||
└─────────┬─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────┐
|
||||
│ Obsidian Vault │
|
||||
│ │
|
||||
│ "Analysis Sprint 2.md" │
|
||||
│ ┌────────────────────────┐ │
|
||||
│ │ ## Dependencies Found │ │
|
||||
│ │ - File1 depends on File2│ │◄── Agent 1 writes
|
||||
│ │ - CMakeLists needs update│ │
|
||||
│ └────────────────────────┘ │
|
||||
│ │
|
||||
│ │◄── Agent 2 reads
|
||||
│ Agent 2 sees this │
|
||||
│ Uses it for implementation │
|
||||
└──────────────────────────────┘
|
||||
```
|
||||
|
||||
### Pattern 3: Conflict Prevention (via File Locks)
|
||||
|
||||
```
|
||||
Agent 1 wants to edit CMakeLists.txt
|
||||
│
|
||||
│ 1. Check Obsidian for lock file
|
||||
▼
|
||||
Obsidian: ".claude/locks/CMakeLists.txt.lock"
|
||||
│
|
||||
├─ EXISTS? ───────────────┐
|
||||
│ │
|
||||
YES NO
|
||||
│ │
|
||||
▼ ▼
|
||||
Read lock info Create lock file
|
||||
│ │
|
||||
├─ Expired? Write:
|
||||
│ • locked_at {
|
||||
NO • release_after "locked_by": "agent-1",
|
||||
│ "locked_at": "2026-02-06T10:00:00Z",
|
||||
▼ "release_after": "2026-02-06T12:00:00Z"
|
||||
⚠️ STOP }
|
||||
Report conflict │
|
||||
Exit │
|
||||
▼
|
||||
Edit CMakeLists.txt
|
||||
│
|
||||
▼
|
||||
Commit changes
|
||||
│
|
||||
▼
|
||||
Delete lock file
|
||||
│
|
||||
▼
|
||||
Done ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Management
|
||||
|
||||
### Workflow State Transitions
|
||||
|
||||
```
|
||||
PENDING ──────────────────────────────────┐
|
||||
│ │
|
||||
│ User triggers workflow │
|
||||
│ │
|
||||
▼ │
|
||||
IN_PROGRESS │
|
||||
│ │
|
||||
├─ Stage 1 ─→ RUNNING ─→ COMPLETE ───┤
|
||||
│ │
|
||||
├─ Stage 2 ─→ RUNNING ─→ COMPLETE ───┤
|
||||
│ │
|
||||
├─ Stage 3 ─→ RUNNING ─→ COMPLETE ───┤
|
||||
│ │
|
||||
├─ Stage 4 ─→ RUNNING ─→ FAILED ─────┼─→ WORKFLOW_FAILED
|
||||
│ │ │ │
|
||||
│ │ │ ▼
|
||||
│ │ │ Alert user
|
||||
│ │ │ Save logs to Obsidian
|
||||
│ └─ Retry? │ Stop execution
|
||||
│ │ │
|
||||
│ YES │
|
||||
│ │ │
|
||||
│ RUNNING ───┤
|
||||
│ │ │
|
||||
└──────────────────────────────┘ │
|
||||
│
|
||||
All stages COMPLETE ──────────────────────┘
|
||||
│
|
||||
▼
|
||||
WORKFLOW_COMPLETE ✅
|
||||
│
|
||||
│ Notification to Zenflow GUI
|
||||
│ Update Obsidian summary
|
||||
│ Mark all tasks COMPLETE
|
||||
│
|
||||
▼
|
||||
Ready for manual review & merge
|
||||
```
|
||||
|
||||
### Task State Transitions
|
||||
|
||||
```
|
||||
PENDING
|
||||
│
|
||||
│ Agent claims task
|
||||
▼
|
||||
IN_PROGRESS
|
||||
│
|
||||
├─ Work continues ───┐
|
||||
│ │
|
||||
│ ◄──────────────────┘
|
||||
│
|
||||
├─ Blocker encountered?
|
||||
│ YES ──→ BLOCKED
|
||||
│ │
|
||||
│ │ Blocker resolved
|
||||
│ ▼
|
||||
│ PENDING (restart)
|
||||
│
|
||||
├─ Work completes
|
||||
│ YES ──→ COMPLETE ✅
|
||||
│
|
||||
└─ Abandoned?
|
||||
YES ──→ DELETED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security & Isolation
|
||||
|
||||
### Branch Isolation Strategy
|
||||
|
||||
```
|
||||
Main Branch: playerbot-dev
|
||||
│
|
||||
│ Zenflow creates isolated branches per agent
|
||||
│
|
||||
├─ zenflow/agent-1/sprint-2
|
||||
│ └─ Changes: Analysis only
|
||||
│
|
||||
├─ zenflow/agent-2/sprint-2
|
||||
│ └─ Changes: Spec generation only
|
||||
│
|
||||
├─ zenflow/agent-3/sprint-2-impl
|
||||
│ └─ Changes: Implementation only
|
||||
│
|
||||
└─ zenflow/agent-4/sprint-2-build
|
||||
└─ Changes: Build fixes only
|
||||
|
||||
All isolated → Merge strategy:
|
||||
1. Review each branch independently
|
||||
2. Merge agent-1 first (analysis)
|
||||
3. Merge agent-2 second (spec)
|
||||
4. Merge agent-3 third (impl)
|
||||
5. Merge agent-4 last (fixes)
|
||||
|
||||
No cross-contamination ✅
|
||||
Clear audit trail ✅
|
||||
Easy rollback ✅
|
||||
```
|
||||
|
||||
### File Ownership Protection
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ Obsidian: File Ownership │
|
||||
│ │
|
||||
│ CMakeLists.txt │
|
||||
│ ├─ Owner: Agent 3 │
|
||||
│ ├─ Lock expires: 2026-02-06 12:00 │
|
||||
│ └─ Status: 🔒 LOCKED │
|
||||
│ │
|
||||
│ BattlegroundAI.cpp │
|
||||
│ ├─ Owner: Agent 5 │
|
||||
│ ├─ Lock expires: Never (completed) │
|
||||
│ └─ Status: ✅ AVAILABLE │
|
||||
│ │
|
||||
│ PlayerbotModule.cpp │
|
||||
│ ├─ Owner: None │
|
||||
│ ├─ Last modified: 2026-02-05 │
|
||||
│ └─ Status: ✅ AVAILABLE │
|
||||
└────────────────────────────────────────┘
|
||||
│
|
||||
│ Agent 2 tries to edit CMakeLists.txt
|
||||
▼
|
||||
Check ownership → LOCKED by Agent 3
|
||||
│
|
||||
▼
|
||||
⚠️ CONFLICT DETECTED
|
||||
│
|
||||
├─ Option 1: Wait for lock to expire
|
||||
├─ Option 2: Request unlock from Agent 3
|
||||
└─ Option 3: Choose different file
|
||||
|
||||
Conflict PREVENTED before it happens ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance & Scalability
|
||||
|
||||
### Parallel Execution Capacity
|
||||
|
||||
```
|
||||
Sequential (Before):
|
||||
Analysis → Spec → Impl → Build → Review
|
||||
│ │ │ │ │
|
||||
2h + 1h + 4h + 1h + 1h = 9 hours total
|
||||
|
||||
|
||||
Parallel (With Zenflow):
|
||||
Analysis (Agent 1) ──────────┐
|
||||
│ │
|
||||
▼ │
|
||||
Spec (Agent 2) ──────────┐ │
|
||||
│ │ │
|
||||
▼ │ │
|
||||
Impl (Agent 3) ───┐ │ │
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
Build + Review in parallel after impl
|
||||
│
|
||||
▼
|
||||
2h + 1h + 4h (max) + max(1h, 1h) = ~7 hours total
|
||||
|
||||
Savings: 22% time reduction
|
||||
Benefits:
|
||||
• Different models per stage (cost optimization)
|
||||
• Each agent specializes
|
||||
• Failures isolated to stage
|
||||
```
|
||||
|
||||
### Resource Usage
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────┐
|
||||
│ Resource Consumption │
|
||||
│ │
|
||||
│ Zenflow Desktop: │
|
||||
│ • CPU: ~5% (idle) / ~20% (active) │
|
||||
│ • RAM: ~200MB │
|
||||
│ • Disk: ~500MB │
|
||||
│ │
|
||||
│ Obsidian: │
|
||||
│ • CPU: ~2% (idle) / ~10% (indexing) │
|
||||
│ • RAM: ~100MB │
|
||||
│ • Disk: ~50MB (vault) + 500MB (plugins) │
|
||||
│ │
|
||||
│ MCP Server: │
|
||||
│ • CPU: ~1% (idle) / ~5% (requests) │
|
||||
│ • RAM: ~50MB │
|
||||
│ • Disk: Negligible │
|
||||
│ │
|
||||
│ Claude Code (per instance): │
|
||||
│ • CPU: ~10-30% (during execution) │
|
||||
│ • RAM: ~500MB │
|
||||
│ • Disk: Cache + logs (~1GB) │
|
||||
│ │
|
||||
│ Total System Impact: │
|
||||
│ • 3 Claude instances running: ~1.5GB RAM│
|
||||
│ • Acceptable on 16GB+ system │
|
||||
└───────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
### What Happens When Things Go Wrong
|
||||
|
||||
```
|
||||
Scenario: Agent 3 crashes during implementation
|
||||
|
||||
Before (No Orchestration):
|
||||
• All work lost
|
||||
• No record of progress
|
||||
• Must restart from scratch
|
||||
• Unknown what was attempted
|
||||
❌ Hours wasted
|
||||
|
||||
|
||||
After (With Zenflow + Obsidian):
|
||||
│
|
||||
│ Agent 3 crashes
|
||||
▼
|
||||
Zenflow detects failure
|
||||
│
|
||||
├─ Saves logs to Obsidian: "Sessions/Crash Sprint 2.md"
|
||||
├─ Marks task FAILED
|
||||
├─ Preserves git branch: zenflow/agent-3/sprint-2-impl
|
||||
├─ Updates Active Instances: Agent 3 = CRASHED
|
||||
└─ Alerts user
|
||||
|
||||
User can:
|
||||
│
|
||||
├─ Read crash logs in Obsidian
|
||||
├─ Review partial git branch
|
||||
├─ Understand what was attempted
|
||||
├─ Restart from last checkpoint
|
||||
└─ OR manually fix and continue
|
||||
|
||||
✅ Zero work lost
|
||||
✅ Full audit trail
|
||||
✅ Easy recovery
|
||||
```
|
||||
|
||||
### Rollback Procedure
|
||||
|
||||
```
|
||||
Problem: Sprint 2 implementation broke build
|
||||
|
||||
With Orchestration:
|
||||
│
|
||||
1. Check Obsidian: "Sessions/Build Report Sprint 2.md"
|
||||
└─ See exact error
|
||||
│
|
||||
2. Check git: zenflow/agent-3/sprint-2-impl
|
||||
└─ See all changes
|
||||
│
|
||||
3. Options:
|
||||
│
|
||||
├─ A. Rollback entire sprint
|
||||
│ git reset --hard HEAD~N
|
||||
│ Delete Obsidian notes (archive)
|
||||
│
|
||||
├─ B. Fix specific issue
|
||||
│ Read build logs
|
||||
│ Spawn new agent: "Fix build error X"
|
||||
│ Let agent fix specific problem
|
||||
│
|
||||
└─ C. Rollback to specific stage
|
||||
git checkout zenflow/agent-2/sprint-2 (spec was good)
|
||||
Re-run implementation stage with fixes
|
||||
|
||||
All options are safe ✅
|
||||
All changes are tracked ✅
|
||||
Easy to find root cause ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cost Analysis
|
||||
|
||||
### Setup Costs (One-Time)
|
||||
|
||||
```
|
||||
Time Investment:
|
||||
• Obsidian setup: 30 minutes
|
||||
• MCP server setup: 20 minutes
|
||||
• Zenflow setup: 20 minutes
|
||||
• Claude Code config: 15 minutes
|
||||
• First workflow: 30 minutes
|
||||
• Testing: 20 minutes
|
||||
─────────────────────────────────────
|
||||
Total: ~2-3 hours
|
||||
|
||||
Monetary Costs:
|
||||
• Obsidian: FREE
|
||||
• Zenflow: FREE (desktop version)
|
||||
• MCP server: FREE (open source)
|
||||
• Claude Code: INCLUDED (with Claude subscription)
|
||||
─────────────────────────────────────
|
||||
Total: $0 extra
|
||||
```
|
||||
|
||||
### Ongoing Costs
|
||||
|
||||
```
|
||||
Per Sprint/Workflow:
|
||||
• Zenflow desktop: FREE
|
||||
• Obsidian storage: ~50MB per sprint (negligible)
|
||||
• MCP overhead: Negligible CPU/RAM
|
||||
• Claude API calls: SAME (you're using Claude anyway)
|
||||
Actually LESS due to better coordination
|
||||
(no rework, no conflicts)
|
||||
|
||||
Time Savings Per Sprint:
|
||||
• Setup overhead: +5 minutes (create workflow)
|
||||
• Execution: -22% (parallel execution)
|
||||
• Debugging: -50% (clear logs, no conflicts)
|
||||
• Rework: -90% (spec-driven, no disasters)
|
||||
─────────────────────────────────────
|
||||
Net savings: ~2-3 hours per sprint
|
||||
|
||||
ROI: POSITIVE after first real sprint ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison with Alternatives
|
||||
|
||||
| Approach | Setup Time | Coordination | Memory | GUI | Cost | Best For |
|
||||
|----------|-----------|--------------|--------|-----|------|----------|
|
||||
| **No Orchestration** | 0 min | ❌ Manual | ❌ None | ❌ | $0 | Solo, simple tasks |
|
||||
| **Manual Git Branches** | 10 min | ⚠️ Manual | ❌ Docs only | ❌ | $0 | 2-3 instances max |
|
||||
| **Built-in Task Lists** | 5 min | ✅ Automatic | ❌ None | ❌ | $0 | Basic coordination |
|
||||
| **Zenflow + Obsidian** | 2-3 hrs | ✅ Automated | ✅ Full | ✅ | $0 | Complex projects |
|
||||
| **Claude-Flow** | 1 hr | ✅ Swarms | ✅ Shared | ⚠️ Minimal | $0 | AI-first teams |
|
||||
| **CrewAI** | 2 hrs | ✅ Crews | ✅ Shared | ✅ Visual | $0 | Multi-tool agents |
|
||||
| **Custom Solution** | 40+ hrs | ✅ Your design | ✅ Your design | ✅ Your design | Dev time | Specific needs |
|
||||
|
||||
**Recommended:** Zenflow + Obsidian for TrinityCore project ✅
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### How to Measure Success
|
||||
|
||||
```
|
||||
Metric: Git Conflicts
|
||||
Before: ~2-3 per week (manual coordination)
|
||||
After: ~0-1 per month (orchestrated)
|
||||
Target: 90% reduction ✅
|
||||
|
||||
Metric: Rework Rate
|
||||
Before: ~30% of code rewritten due to conflicts/misunderstandings
|
||||
After: ~5% (only genuine design changes)
|
||||
Target: 80% reduction ✅
|
||||
|
||||
Metric: Context Switching Time
|
||||
Before: 15-30 min to understand what others are doing
|
||||
After: 2-5 min (read Obsidian notes)
|
||||
Target: 75% reduction ✅
|
||||
|
||||
Metric: Disaster Recovery Time
|
||||
Before: 2-4 hours (recreate lost work)
|
||||
After: 10-15 min (restore from Obsidian + git)
|
||||
Target: 90% reduction ✅
|
||||
|
||||
Metric: Onboarding New Instance
|
||||
Before: 30-60 min (figure out state, conflicts)
|
||||
After: 5 min (read Obsidian "Active Instances")
|
||||
Target: 85% reduction ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Document Version:** 1.0
|
||||
**Last Updated:** 2026-02-06
|
||||
**Architecture Stability:** Stable
|
||||
**Recommended Review:** After completing 3 sprints
|
||||
@@ -0,0 +1,250 @@
|
||||
# Sprint 1: Code-Audit & Duplikat-Analyse - RESULTS
|
||||
|
||||
**Date:** 2026-02-06
|
||||
**Status:** COMPLETED
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The comprehensive audit of the Playerbot coordination systems revealed significant findings:
|
||||
|
||||
1. **~12,550 lines of code are NOT COMPILED** (dead code in Raid and Arena directories)
|
||||
2. **Two KitingManager classes exist** but are NOT duplicates - they serve different architectural layers
|
||||
3. **Event Bus infrastructure is active** but some domain buses need integration
|
||||
4. **Battleground coordination is fully active** with comprehensive BG script system
|
||||
|
||||
---
|
||||
|
||||
## Critical Finding: Orphaned Code Not In CMakeLists.txt
|
||||
|
||||
### Raid Coordination (AI/Coordination/Raid/)
|
||||
**Status: DEAD CODE - NOT COMPILED**
|
||||
**Files: 9 .cpp files + headers (~5,266 lines)**
|
||||
|
||||
| File | Lines | Description |
|
||||
|------|-------|-------------|
|
||||
| RaidCoordinator.cpp | ~788 | Main raid orchestrator |
|
||||
| RaidTankCoordinator.cpp | ~637 | Tank assignment/swap |
|
||||
| RaidHealCoordinator.cpp | ~636 | Healer assignment |
|
||||
| RaidCooldownRotation.cpp | ~310 | Bloodlust/defensive rotation |
|
||||
| RaidGroupManager.cpp | ~227 | Split raid mechanics |
|
||||
| RaidPositioningManager.cpp | ~213 | Position assignment |
|
||||
| RaidEncounterManager.cpp | ~309 | Boss phase tracking |
|
||||
| KitingManager.cpp | ~297 | Raid-level waypoint kiting |
|
||||
| AddManagementSystem.cpp | ~335 | Add priority/assignment |
|
||||
|
||||
**Root Cause:** Files exist but are not listed in CMakeLists.txt
|
||||
**Impact:** All raid coordination features are non-functional
|
||||
**Resolution:** Add to CMakeLists.txt in Sprint 5 (Raid Coordination)
|
||||
|
||||
### Arena Coordination (AI/Coordination/Arena/)
|
||||
**Status: DEAD CODE - NOT COMPILED**
|
||||
**Files: 6 .cpp files + headers (~7,284 lines)**
|
||||
|
||||
| File | Lines | Description |
|
||||
|------|-------|-------------|
|
||||
| ArenaCoordinator.cpp | ~1373 | Main arena orchestrator |
|
||||
| ArenaPositioning.cpp | ~1175 | Pillar/LOS management |
|
||||
| BurstCoordinator.cpp | ~686 | Offensive sync |
|
||||
| CCChainManager.cpp | ~849 | Crowd control chains |
|
||||
| DefensiveCoordinator.cpp | ~876 | Survivability management |
|
||||
| KillTargetManager.cpp | ~422 | Target selection |
|
||||
|
||||
**Root Cause:** Files exist but are not listed in CMakeLists.txt
|
||||
**Impact:** All arena coordination features are non-functional
|
||||
**Resolution:** Add to CMakeLists.txt in Sprint 6 (PvP Coordination)
|
||||
|
||||
---
|
||||
|
||||
## Kiting System Analysis
|
||||
|
||||
**Finding: NOT DUPLICATES - Different Architectural Layers**
|
||||
|
||||
### Combat KitingManager (AI/Combat/KitingManager)
|
||||
- **Purpose:** Single-bot dynamic kiting
|
||||
- **Architecture:** Real-time decision-based, 9 kiting patterns
|
||||
- **Status:** Orphaned (Phase 2 disabled in CombatAIIntegrator)
|
||||
- **Lines:** ~1,157
|
||||
|
||||
### Raid KitingManager (AI/Coordination/Raid/KitingManager)
|
||||
- **Purpose:** Raid-level waypoint coordination
|
||||
- **Architecture:** Path-based, pre-planned routes
|
||||
- **Status:** Active but not compiled (Raid/ not in CMakeLists)
|
||||
- **Lines:** ~297
|
||||
|
||||
**Recommendation:** Keep separate - they serve different purposes
|
||||
|
||||
---
|
||||
|
||||
## Dungeon Coordination Analysis
|
||||
|
||||
**Status: ACTIVE but PARTIAL**
|
||||
**Location:** AI/Coordination/Dungeon/
|
||||
**Files:** 6 (all in CMakeLists.txt)
|
||||
|
||||
### Active Components
|
||||
- ✅ **DungeonCoordinator** - Fully implemented, instantiated via DungeonAutonomyManager
|
||||
- ✅ **Event Bus Integration** - Subscribes to CombatEventRouter (6 event types)
|
||||
- ✅ **State Machine** - 8 states: IDLE → ENTERING → READY_CHECK → CLEARING_TRASH → PRE_BOSS → BOSS_COMBAT → POST_BOSS → COMPLETED
|
||||
- ✅ **Wipe Recovery** - Complete 6-phase recovery system
|
||||
|
||||
### Gaps Requiring Sprint 4 Work
|
||||
- ⚠️ **Boss Strategy Database** - `LoadBossStrategies()` is empty
|
||||
- ⚠️ **Trash Pack Pre-Loading** - Packs must be registered dynamically
|
||||
- ⚠️ **M+ Affix Handling** - Only 4/18 affixes active (Quaking, Explosive, Volcanic, Sanguine)
|
||||
- ⚠️ **Creature Forces DB** - Enemy forces not loaded from database
|
||||
- ⚠️ **Route Optimization** - Framework present but not implemented
|
||||
- ⚠️ **Marker Application** - Raid markers not actually set on targets
|
||||
|
||||
---
|
||||
|
||||
## Systems Status Matrix
|
||||
|
||||
| System | Location | CMake Status | Event Bus | Functional |
|
||||
|--------|----------|--------------|-----------|------------|
|
||||
| Dungeon Coordination | AI/Coordination/Dungeon/ | ✅ COMPILED | ✅ Active | ⚠️ PARTIAL |
|
||||
| Battleground Coordination | AI/Coordination/Battleground/ | ✅ COMPILED | ✅ Active | ✅ PRODUCTION-READY |
|
||||
| Raid Orchestrator | AI/Coordination/RaidOrchestrator | ✅ COMPILED | Limited | Partial |
|
||||
| Messaging (Sprint 2) | AI/Coordination/Messaging/ | ✅ COMPILED | ✅ Active | ✅ YES |
|
||||
| ContentContext (Sprint 2) | AI/Coordination/ContentContextManager | ✅ COMPILED | N/A | ✅ YES |
|
||||
| Raid Coordination | AI/Coordination/Raid/ | ❌ NOT COMPILED | N/A | ❌ NO |
|
||||
| Arena Coordination | AI/Coordination/Arena/ | ❌ NOT COMPILED | N/A | ❌ NO |
|
||||
|
||||
---
|
||||
|
||||
## Event Bus Infrastructure Status
|
||||
|
||||
### Event Bus Infrastructure Status
|
||||
|
||||
**ALL 12+ EVENT BUSES ARE ACTIVE** - Production-ready infrastructure
|
||||
|
||||
| Bus | Publishers | Processing | Status |
|
||||
|-----|------------|------------|--------|
|
||||
| CombatEventBus | 10 packet handlers | 50/cycle | ✅ ACTIVE |
|
||||
| GroupEventBus | 6 packet handlers | 100/cycle | ✅ ACTIVE |
|
||||
| LootEventBus | 9 packet handlers | 50/cycle | ✅ ACTIVE |
|
||||
| QuestEventBus | 13 packet handlers | 50/cycle | ✅ ACTIVE |
|
||||
| AuctionEventBus | 6 packet handlers | 20/cycle | ✅ ACTIVE |
|
||||
| ResourceEventBus | 3 packet handlers | 30/cycle | ✅ ACTIVE |
|
||||
| SocialEventBus | 6 packet handlers | 30/cycle | ✅ ACTIVE |
|
||||
| InstanceEventBus | 7 packet handlers | 20/cycle | ✅ ACTIVE |
|
||||
| NPCEventBus | 8 packet handlers | 30/cycle | ✅ ACTIVE |
|
||||
| AuraEventBus | 4 packet handlers | 30/cycle | ✅ ACTIVE |
|
||||
| ProfessionEventBus | Multi | 20/cycle | ✅ ACTIVE |
|
||||
| **CooldownEventBus** | **5 packet handlers** | **30/cycle** | ✅ **ACTIVE - GAP 1 WAS ALREADY RESOLVED** |
|
||||
|
||||
**GAP 1 Finding:** CooldownEventBus was **NOT dead** - it has 5 active packet handlers:
|
||||
- ParseTypedSpellCooldown() - SMSG_SPELL_COOLDOWN
|
||||
- ParseTypedCooldownEvent() - SMSG_COOLDOWN_EVENT
|
||||
- ParseTypedClearCooldown() - SMSG_CLEAR_COOLDOWN
|
||||
- ParseTypedClearCooldowns() - SMSG_CLEAR_COOLDOWNS
|
||||
- ParseTypedModifyCooldown() - SMSG_MODIFY_COOLDOWN
|
||||
|
||||
### Sprint 2 Infrastructure (Enhancements)
|
||||
- ✅ MajorCooldownTracker - Adds Major CD detection on top of working CooldownEventBus
|
||||
- ✅ BotMessageBus - Per-group message routing
|
||||
- ✅ ClaimResolver - First-Claim-Wins with priority override
|
||||
- ✅ ContentContextManager - Content type detection
|
||||
|
||||
---
|
||||
|
||||
## Recommendations
|
||||
|
||||
### Immediate Actions
|
||||
1. ✅ Merge conflicts resolved (CooldownEvents.h/cpp, PlayerbotModule.cpp)
|
||||
2. ⏳ Build validation for Sprint 2 changes
|
||||
|
||||
### Sprint 5 (Raid Coordination)
|
||||
- Add all Raid/ files to CMakeLists.txt
|
||||
- Wire RaidCoordinator instantiation
|
||||
- Integrate with event bus system
|
||||
|
||||
### Sprint 6 (PvP Coordination)
|
||||
- Add all Arena/ files to CMakeLists.txt
|
||||
- Wire ArenaCoordinator instantiation
|
||||
- Connect to existing ArenaAI/ArenaBotManager
|
||||
|
||||
### Low Priority
|
||||
- Consider extracting shared kiting utilities (optional ~150 lines dedup)
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Battleground Coordination Analysis
|
||||
|
||||
**Status: PRODUCTION-READY - FULLY IMPLEMENTED**
|
||||
**Location:** AI/Coordination/Battleground/
|
||||
**Total Code:** ~9,300 lines
|
||||
|
||||
The BG system is the **most complete coordination system** in the codebase:
|
||||
|
||||
| Component | Files | Status |
|
||||
|-----------|-------|--------|
|
||||
| Core Managers | 10/10 | ✅ ACTIVE |
|
||||
| Script System | 4/4 | ✅ ACTIVE |
|
||||
| BG Scripts | 21/21 | ✅ ACTIVE |
|
||||
| BG Coverage | 13/13 maps | ✅ COMPLETE |
|
||||
|
||||
### Key Features Implemented
|
||||
- **BattlegroundCoordinator** - Central orchestrator, instantiated per BG
|
||||
- **BGRoleManager** - 20+ role types with suitability scoring
|
||||
- **BGStrategyEngine** - 7 strategic options with momentum tracking
|
||||
- **FlagCarrierManager** - Complete CTF mechanics
|
||||
- **NodeController** - Domination node management
|
||||
- **BGSpatialQueryCache** - O(1) player lookups (~80x faster)
|
||||
- **21 BG Scripts** - All major battlegrounds covered
|
||||
|
||||
### Event Integration
|
||||
- Subscribes to CombatEventRouter (priority 35)
|
||||
- Script event system with 25+ event types
|
||||
|
||||
**This system requires NO additional work for Sprint 6 BG portion.**
|
||||
|
||||
---
|
||||
|
||||
## CombatBehaviors System Analysis
|
||||
|
||||
**Location:** AI/CombatBehaviors/
|
||||
**Status:** COMPILED but NOT INTEGRATED
|
||||
|
||||
All 5 CombatBehaviors managers are in CMakeLists.txt but have **zero external instantiation** - they exist but are never created in BotAI.
|
||||
|
||||
| File | Lines | Status | Gap Coverage |
|
||||
|------|-------|--------|--------------|
|
||||
| AoEDecisionManager | 800+ | ✅ Complete | Target clustering, DoT spread |
|
||||
| CooldownStackingOptimizer | 1500+ | ✅ Complete | 12-class cooldown DB |
|
||||
| DefensiveBehaviorManager | 200+ | ⚠️ Headers only | GAP 3 partial |
|
||||
| DispelCoordinator | 450+ | ✅ Complete | **GAP 2 READY** |
|
||||
| InterruptRotationManager | 420+ | ✅ Complete | Rotation queue |
|
||||
|
||||
### GAP 2 (Dispel Rotation) - READY FOR INTEGRATION
|
||||
- `DispelCoordinator` has full implementation with:
|
||||
- `DispelAssignment` struct for claim tracking
|
||||
- `IsBeingDispelled()` to prevent overlap
|
||||
- 6-tier priority system
|
||||
- 200+ debuff database
|
||||
|
||||
### GAP 3 (External Defensive CD) - PARTIAL
|
||||
- `DefensiveBehaviorManager` has architecture but procedural logic incomplete
|
||||
- External defensive request/response infrastructure exists
|
||||
- Needs procedural logic in .cpp
|
||||
|
||||
### Integration Required
|
||||
- Add member variables to BotAI.h
|
||||
- Create instantiation in BotAI constructor
|
||||
- Wire into BotAI::UpdateAI() flow
|
||||
- Connect CombatCoordinationIntegrator to bridge to BotMessageBus
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Sprint 1 audit reveals that the coordination infrastructure has significant code that needs activation:
|
||||
|
||||
1. **Dead Code (not compiled):** ~12,550 lines (Raid/ + Arena/)
|
||||
2. **Orphaned Code (compiled but not used):** ~3,500 lines (CombatBehaviors)
|
||||
|
||||
**Quality of Code:** Production-ready (not stubs)
|
||||
**Recovery Effort:**
|
||||
- Raid/Arena: Add to CMakeLists.txt + instantiation
|
||||
- CombatBehaviors: Wire into BotAI lifecycle
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,238 @@
|
||||
# Zenflow + Obsidian Setup - Quick Start Checklist
|
||||
|
||||
**Goal:** Get orchestration running in 2-3 hours
|
||||
|
||||
**Full Guide:** See `ZENFLOW_OBSIDIAN_SETUP_GUIDE.md` for detailed instructions
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Pre-Setup (15 minutes)
|
||||
|
||||
- [ ] **Download Obsidian** from https://obsidian.md/download
|
||||
- [ ] **Download Zenflow** from https://zencoder.ai/zenflow
|
||||
- [ ] **Check Node.js:** `node --version` (need v18+)
|
||||
- If not installed: https://nodejs.org/
|
||||
- [ ] **Find Anthropic API Key** (for Zenflow)
|
||||
- Dashboard: https://console.anthropic.com/
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Obsidian Setup (30 minutes)
|
||||
|
||||
- [ ] **Install Obsidian Desktop**
|
||||
- [ ] **Create new vault:**
|
||||
- Name: `TrinityCore-Playerbot-Memory`
|
||||
- Location: `C:\TrinityBots\PlayerBotProjectMemory`
|
||||
- [ ] **Enable Community Plugins:**
|
||||
- Settings → Community plugins → Turn off Restricted mode
|
||||
- [ ] **Install "Local REST API" plugin:**
|
||||
- Browse plugins → Search "Local REST API"
|
||||
- Install and enable
|
||||
- Copy API key from settings (SAVE THIS!)
|
||||
- [ ] **Install "Dataview" plugin** (optional but recommended)
|
||||
- [ ] **Create folder structure:**
|
||||
- `Architecture/`
|
||||
- `Refactorings/`
|
||||
- `Gotchas/`
|
||||
- `Tasks/`
|
||||
- `Sessions/`
|
||||
- `Decisions/`
|
||||
- [ ] **Create core files** (copy from setup guide):
|
||||
- `Architecture/System Overview.md`
|
||||
- `Gotchas/Git Workflow Gotchas.md`
|
||||
- `Refactorings/DI Cleanup.md`
|
||||
- `Tasks/Active Instances.md`
|
||||
- `Tasks/Task Template.md`
|
||||
|
||||
---
|
||||
|
||||
## ☑️ MCP Server Setup (20 minutes)
|
||||
|
||||
- [ ] **Clone repository:**
|
||||
```bash
|
||||
cd C:\TrinityBots
|
||||
git clone https://github.com/cyanheads/obsidian-mcp-server.git
|
||||
cd obsidian-mcp-server
|
||||
```
|
||||
- [ ] **Install dependencies:**
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
- [ ] **Build:**
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
- [ ] **Create config.json:**
|
||||
- Location: `C:\TrinityBots\obsidian-mcp-server\config.json`
|
||||
- Content: See setup guide Section 2.4
|
||||
- **IMPORTANT:** Use your Obsidian API key!
|
||||
- [ ] **Test server:**
|
||||
```bash
|
||||
node dist/index.js
|
||||
# Should start without errors
|
||||
# Ctrl+C to stop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Zenflow Setup (20 minutes)
|
||||
|
||||
- [ ] **Install Zenflow Desktop**
|
||||
- [ ] **Sign in / Create account**
|
||||
- [ ] **Create project:**
|
||||
- Name: `TrinityCore Playerbot`
|
||||
- Path: `C:\TrinityBots\TrinityCore`
|
||||
- Type: C++ / CMake
|
||||
- [ ] **Configure AI Provider:**
|
||||
- Settings → AI Providers → Add Anthropic
|
||||
- Enter API key
|
||||
- Select models: Opus 4.5, Sonnet 4.5, Haiku
|
||||
- [ ] **Connect Git:**
|
||||
- Project Settings → Version Control
|
||||
- Enable "Branch per agent" ✅
|
||||
- Prefix: `zenflow/agent-{agent-id}/`
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Claude Code Integration (15 minutes)
|
||||
|
||||
- [ ] **Edit MCP config:**
|
||||
- Location: `%APPDATA%\Roaming\claude-code\mcp.json`
|
||||
- Add `obsidian-memory` server (see setup guide 4.1)
|
||||
- [ ] **Set environment variable:**
|
||||
- Windows: Environment Variables → New
|
||||
- Name: `CLAUDE_CODE_TASK_LIST_ID`
|
||||
- Value: `trinitycore-playerbot-shared`
|
||||
- [ ] **Restart all terminals**
|
||||
- [ ] **Test MCP:**
|
||||
```bash
|
||||
claude-code
|
||||
> Can you list available MCP tools?
|
||||
# Should see obsidian_* tools
|
||||
```
|
||||
- [ ] **Test Obsidian read:**
|
||||
```bash
|
||||
> Read "Architecture/System Overview" from Obsidian vault
|
||||
# Should display content
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Create First Workflow (30 minutes)
|
||||
|
||||
- [ ] **Open Zenflow Desktop**
|
||||
- [ ] **New Workflow:**
|
||||
- Name: `DI Cleanup Refactoring`
|
||||
- Template: Spec-Driven Development
|
||||
- [ ] **Configure 5 stages:**
|
||||
1. Analyze Dependencies (Opus 4.5)
|
||||
2. Create Technical Spec (Opus 4.5)
|
||||
3. Implement Changes (Sonnet 4.5)
|
||||
4. Verify Build (Sonnet 4.5)
|
||||
5. Code Review (Opus 4.5)
|
||||
- [ ] **Set dependencies:**
|
||||
- Stage 2 depends on Stage 1
|
||||
- Stage 3 depends on Stage 2
|
||||
- Stage 4 depends on Stage 3
|
||||
- Stage 5 depends on Stage 4
|
||||
- [ ] **Configure agent settings:**
|
||||
- Enable "Isolated Branches" ✅
|
||||
- Enable "Shared Memory" → Obsidian ✅
|
||||
- Vault: `C:\TrinityBots\PlayerBotProjectMemory`
|
||||
- [ ] **Add instructions to each stage** (see setup guide 5.2)
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Run Test (20 minutes)
|
||||
|
||||
- [ ] **Create test task in Obsidian:**
|
||||
- File: `Tasks/TEST-2026-02-06-01 - Verify Setup.md`
|
||||
- Copy template from setup guide 6.1
|
||||
- [ ] **Start workflow in Zenflow:**
|
||||
- Run Workflow → DI Cleanup Refactoring
|
||||
- Sprint: `TEST`
|
||||
- Click Start
|
||||
- [ ] **Watch progress:**
|
||||
- Zenflow: See DAG visualization
|
||||
- Obsidian: Open Graph View (Ctrl+G)
|
||||
- Watch new notes appear in `Sessions/`
|
||||
- [ ] **Verify results:**
|
||||
- Check for 5 new markdown files in Obsidian
|
||||
- Check git branches: `git branch | grep zenflow`
|
||||
- Check task list: `claude-code` → `/tasks`
|
||||
- [ ] **Cleanup test:**
|
||||
```bash
|
||||
git branch -D zenflow/di-cleanup-sprint-TEST/*
|
||||
# Delete test notes in Obsidian
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ☑️ Verify Everything Works
|
||||
|
||||
- [ ] **Multiple instances can share tasks** ✅
|
||||
- Open 2 Claude Code terminals
|
||||
- Both should see same tasks: `/tasks`
|
||||
- [ ] **Obsidian memory is accessible** ✅
|
||||
- Claude can read notes: `> Read "Architecture/System Overview"`
|
||||
- Claude can write notes: `> Write a test note to Obsidian`
|
||||
- [ ] **Zenflow shows progress** ✅
|
||||
- GUI displays running workflows
|
||||
- Stage logs are visible
|
||||
- [ ] **No git conflicts** ✅
|
||||
- Each agent uses separate branch
|
||||
- Clean merge possible
|
||||
|
||||
---
|
||||
|
||||
## ✅ You're Done! What's Next?
|
||||
|
||||
### Immediate Next Steps:
|
||||
1. **Update Obsidian notes** with your TrinityCore-specific info
|
||||
2. **Run real refactoring sprint** (not TEST)
|
||||
3. **Monitor and refine** workflows based on experience
|
||||
|
||||
### Advanced Features to Explore:
|
||||
- File locking pattern (Section 7.1)
|
||||
- Session handover (Section 7.2)
|
||||
- Emergency stop (Section 7.3)
|
||||
- Cross-repository coordination (Section 7.5)
|
||||
|
||||
### Daily Workflow:
|
||||
See Section "Daily Workflow" in full guide for:
|
||||
- Morning startup checklist
|
||||
- Starting new tasks
|
||||
- Hourly checks
|
||||
- End of day routine
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Quick Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| MCP server won't start | Check Obsidian REST API plugin enabled, API key correct |
|
||||
| Zenflow can't find repo | Re-scan repository in project settings |
|
||||
| Tasks not shared | Set `CLAUDE_CODE_TASK_LIST_ID` env var, restart terminals |
|
||||
| Obsidian links don't show | Use `[[Note]]` syntax not `[Note](path)` |
|
||||
| Workflow hangs | Check logs in Zenflow, cancel and restart stage |
|
||||
|
||||
See "Troubleshooting" section in full guide for detailed fixes.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Resources
|
||||
|
||||
- **Full Setup Guide:** `.claude/ZENFLOW_OBSIDIAN_SETUP_GUIDE.md`
|
||||
- **Zenflow Docs:** https://zencoder.ai/docs
|
||||
- **Obsidian MCP Server:** https://github.com/cyanheads/obsidian-mcp-server
|
||||
- **Claude Code Docs:** https://code.claude.com/docs
|
||||
- **MCP Protocol:** https://modelcontextprotocol.io/
|
||||
|
||||
---
|
||||
|
||||
**Total Time:** ~2-3 hours for complete setup
|
||||
**Complexity:** Moderate (some terminal/config work)
|
||||
**Payoff:** Massive (prevents disasters, enables safe parallel work)
|
||||
|
||||
**Last Updated:** 2026-02-06
|
||||
@@ -0,0 +1,820 @@
|
||||
# Zenflow Workflow: TOK Lighthouse Battleground
|
||||
|
||||
**Complete workflow configuration for Temple of Kotmogu - 100% correct & fully dynamic**
|
||||
|
||||
---
|
||||
|
||||
## Workflow Metadata
|
||||
|
||||
**Workflow Name:** `TOK Lighthouse Battleground`
|
||||
|
||||
**Description:** Make Temple of Kotmogu the first 100% correct, fully dynamic battleground. This will serve as the template/blueprint for all 13 other battlegrounds.
|
||||
|
||||
**Branch Prefix:** `lighthouse-bg/tok/`
|
||||
|
||||
**Project:** TrinityCore Playerbot
|
||||
|
||||
**Agent:** Claude Code (for all automated stages)
|
||||
|
||||
---
|
||||
|
||||
## Stage 1: Research TOK Data
|
||||
|
||||
**Stage Name:** `Research TOK Data (DBC/DB2/SQL)`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** None (first stage)
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read from Obsidian: "Refactorings/TOK Lighthouse BG.md"
|
||||
|
||||
Research and verify:
|
||||
1. Orb GameObject entries (should be 212091-212094)
|
||||
- Query: SELECT * FROM gameobject WHERE id IN (212091,212092,212093,212094)
|
||||
- Verify spawn positions, display IDs, states
|
||||
|
||||
2. Orb aura IDs (should be 121175-121178)
|
||||
- Check spell data for each aura
|
||||
- Verify buff mechanics (1x, 2x, 3x, 4x multipliers)
|
||||
|
||||
3. Victory conditions
|
||||
- Confirm 1600 points to win
|
||||
- Score calculation formula
|
||||
- Center control multiplier (5x)
|
||||
|
||||
4. Map data
|
||||
- Zone ID for Temple of Kotmogu
|
||||
- Center area coordinates
|
||||
- Orb spawn positions (exact coordinates)
|
||||
|
||||
5. Current implementation analysis
|
||||
- Read: src/modules/Playerbot/PvP/BattlegroundAI.cpp (TOK functions)
|
||||
- Read: src/modules/Playerbot/AI/Coordination/Battleground/Scripts/Domination/TempleOfKotmoguScript.cpp
|
||||
- Identify all bugs and issues
|
||||
|
||||
Document findings:
|
||||
- Write to Obsidian: "Sessions/TOK Sprint 1 - Data Research.md"
|
||||
- Include: All GameObject data, aura data, current bugs found
|
||||
- List: What needs to be fixed vs what's already correct
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 2: Create Perfect Specification
|
||||
|
||||
**Stage Name:** `Create TOK Perfect Spec`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** Stage 1 ✓
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read from Obsidian:
|
||||
- "Sessions/TOK Sprint 1 - Data Research.md" (Stage 1 output)
|
||||
- "Refactorings/TOK Lighthouse BG.md" (requirements)
|
||||
|
||||
Create detailed technical specification covering:
|
||||
|
||||
1. GameObject Interaction Fix
|
||||
- Exact code changes needed for orb pickup
|
||||
- Correct GameObject::Use() parameters
|
||||
- State checks required
|
||||
- Error handling approach
|
||||
|
||||
2. Combat Engagement Implementation
|
||||
- Where to add Attack() calls
|
||||
- Target selection logic
|
||||
- Combat state management
|
||||
- Integration with existing combat system
|
||||
|
||||
3. Dynamic Strategy State Machine
|
||||
- State definitions (e.g., AGGRESSIVE, DEFENSIVE, BALANCED)
|
||||
- Transition triggers (score difference, orb count, time)
|
||||
- Actions per state
|
||||
- Role assignment per state
|
||||
|
||||
4. Center Control Logic
|
||||
- Detection of center area
|
||||
- Movement to center
|
||||
- 5x multiplier awareness
|
||||
- Risk/reward calculation
|
||||
|
||||
5. Edge Case Handling
|
||||
- Bot death with orb (orb drop behavior)
|
||||
- Orb respawn timing (30 seconds)
|
||||
- Multiple bots targeting same orb
|
||||
- Player disconnect/AFK
|
||||
- Uneven team sizes
|
||||
|
||||
6. Data Validation
|
||||
- Confirm all GameObject entries
|
||||
- Confirm all aura IDs
|
||||
- Confirm spawn positions
|
||||
- Confirm victory conditions
|
||||
|
||||
7. Testing Criteria
|
||||
- Success metrics (>95% orb pickup, 100% combat engagement)
|
||||
- Performance requirements (<0.1% CPU per bot)
|
||||
- Zero crashes requirement
|
||||
|
||||
Write specification to Obsidian: "Refactorings/TOK Lighthouse Spec.md"
|
||||
|
||||
Specification must be:
|
||||
- Complete (no TODOs or "to be determined")
|
||||
- Precise (exact line numbers, exact code changes)
|
||||
- Testable (clear acceptance criteria)
|
||||
- Reviewable (clear rationale for each decision)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 3: Fix GameObject & Combat
|
||||
|
||||
**Stage Name:** `Fix Orb Pickup & Combat Engagement`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** Stage 2 ✓
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read specification: "Refactorings/TOK Lighthouse Spec.md"
|
||||
|
||||
Implementation tasks:
|
||||
|
||||
1. Fix GameObject Orb Pickup
|
||||
File: src/modules/Playerbot/PvP/BattlegroundAI.cpp
|
||||
|
||||
- Locate PickupOrb() function (around line 1750)
|
||||
- Fix GameObject search to use correct entries:
|
||||
* 212091 (Orange Orb)
|
||||
* 212092 (Purple Orb)
|
||||
* 212093 (Green Orb)
|
||||
* 212094 (Blue Orb)
|
||||
- Add proper GameObject state checks (GAMEOBJECT_STATE_READY)
|
||||
- Add distance validation (must be within USE_RANGE)
|
||||
- Add proper error handling
|
||||
- Add detailed logging for debugging
|
||||
|
||||
2. Merge Combat Engagement Fix
|
||||
|
||||
- Check if fix exists in recovery-refactoring-work branch
|
||||
- If yes: Cherry-pick combat engagement commits
|
||||
- If no: Implement from scratch:
|
||||
* HuntEnemyOrbCarrier() - Add player->Attack(enemyCarrier, true)
|
||||
* DefendOrbCarrier() - Add player->Attack(enemy, true)
|
||||
- Ensure Attack() is called AFTER SetSelection()
|
||||
- Add combat state validation (IsAlive, IsHostileTo)
|
||||
- Add detailed logging
|
||||
|
||||
3. Add Center Control Awareness
|
||||
|
||||
- Define center area coordinates
|
||||
- Add IsInCenterArea() helper function
|
||||
- Modify movement logic to prioritize center when carrying orb
|
||||
- Add 5x multiplier awareness to decision making
|
||||
|
||||
4. Code Quality
|
||||
|
||||
- Remove all TODOs
|
||||
- Add comprehensive error handling
|
||||
- Add null pointer checks
|
||||
- Add bounds checking
|
||||
- Follow TrinityCore coding style
|
||||
|
||||
5. Testing Preparation
|
||||
|
||||
- Add detailed logging statements for:
|
||||
* Orb pickup attempts (success/failure with reason)
|
||||
* Combat engagements (target, result)
|
||||
* Center control decisions
|
||||
* State transitions
|
||||
|
||||
Write implementation notes to Obsidian: "Sessions/TOK Sprint 2 - GameObject & Combat Fix.md"
|
||||
|
||||
Include:
|
||||
- Exact changes made (file:line references)
|
||||
- Rationale for each change
|
||||
- Any deviations from spec (with justification)
|
||||
- Known limitations or edge cases not yet handled
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 4: Implement Dynamic Strategy
|
||||
|
||||
**Stage Name:** `Implement Dynamic Tactics & Strategy`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** Stage 3 ✓
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read from Obsidian:
|
||||
- "Refactorings/TOK Lighthouse Spec.md" (strategy design)
|
||||
- "Sessions/TOK Sprint 2 - GameObject & Combat Fix.md" (current state)
|
||||
|
||||
Implement dynamic strategy system:
|
||||
|
||||
1. Create Strategy State Machine
|
||||
File: src/modules/Playerbot/AI/Coordination/Battleground/Scripts/Domination/TempleOfKotmoguScript.cpp
|
||||
|
||||
States:
|
||||
- AGGRESSIVE: Ahead in score, hunt enemy carriers
|
||||
- DEFENSIVE: Behind in score, protect our carriers
|
||||
- BALANCED: Even score, standard play
|
||||
- DESPERATION: Far behind + time running out
|
||||
- PRESERVATION: Far ahead + time running out
|
||||
|
||||
Transitions:
|
||||
- Based on score difference (thresholds: 200, 400 points)
|
||||
- Based on orb distribution (who has more orbs)
|
||||
- Based on time remaining
|
||||
- Based on player count advantage
|
||||
|
||||
2. Implement Score-Based Tactics
|
||||
|
||||
- Add GetCurrentScore() for both teams
|
||||
- Add GetScoreDifference() helper
|
||||
- Add GetOrbDistribution() (count orbs per team)
|
||||
- Implement tactics per state:
|
||||
* AGGRESSIVE: Focus on enemy carriers, center control
|
||||
* DEFENSIVE: Protect carriers, avoid risky plays
|
||||
* BALANCED: Standard role distribution
|
||||
* DESPERATION: All-in aggressive, ignore defense
|
||||
* PRESERVATION: Avoid combat, run down clock
|
||||
|
||||
3. Implement Orb Distribution Analysis
|
||||
|
||||
- Track which team holds which orbs
|
||||
- Count total orbs per team
|
||||
- Identify priority targets (enemy with multiple orbs)
|
||||
- Adjust strategy based on orb count
|
||||
|
||||
4. Implement Role Reassignment
|
||||
File: src/modules/Playerbot/AI/Coordination/Battleground/BGRoleManager.cpp
|
||||
|
||||
- Dynamic role changes based on strategy state
|
||||
- Role distribution per state:
|
||||
* AGGRESSIVE: More hunters, fewer defenders
|
||||
* DEFENSIVE: More defenders/escorts, fewer hunters
|
||||
* BALANCED: Even distribution
|
||||
- Smooth role transitions (don't abandon mid-action)
|
||||
|
||||
5. Add Strategy Logging
|
||||
|
||||
- Log state transitions (old state → new state + reason)
|
||||
- Log strategy decisions (why choosing target X)
|
||||
- Log role reassignments
|
||||
- Performance metrics (state duration, effectiveness)
|
||||
|
||||
6. Integration with BGCoordinator
|
||||
File: src/modules/Playerbot/AI/Coordination/Battleground/BattlegroundCoordinator.cpp
|
||||
|
||||
- Connect strategy state to coordinator
|
||||
- Broadcast strategy changes to all bots
|
||||
- Coordinate multi-bot actions (synchronized attacks)
|
||||
|
||||
Write to Obsidian: "Sessions/TOK Sprint 3 - Dynamic Strategy.md"
|
||||
|
||||
Include:
|
||||
- State machine diagram (text-based)
|
||||
- Transition logic explanation
|
||||
- Role distribution tables
|
||||
- Example scenarios showing strategy adaptation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 5A: Build Verification & Test Prep
|
||||
|
||||
**Stage Name:** `Build & Prepare Tests`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** Stage 4 ✓
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read from Obsidian: "Refactorings/TOK Testing Plan.md"
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Build Verification
|
||||
|
||||
- Navigate to build directory
|
||||
- Run CMake configuration:
|
||||
cmake --build . --config RelWithDebInfo --target worldserver -- /maxcpucount:4
|
||||
- Check for compilation errors
|
||||
- Check for warnings (should be minimal)
|
||||
- Verify binary created successfully
|
||||
- Check binary size (compare to previous build)
|
||||
|
||||
2. Static Code Analysis
|
||||
|
||||
- Check all modified files for:
|
||||
* Null pointer dereferences
|
||||
* Uninitialized variables
|
||||
* Memory leaks (missing deletes)
|
||||
* Buffer overflows
|
||||
* Race conditions (missing locks)
|
||||
* Exception safety
|
||||
- Verify all TODOs removed
|
||||
- Verify all error paths handled
|
||||
- Check for code smells (duplicated code, long functions)
|
||||
|
||||
3. Generate bg.log Configuration
|
||||
|
||||
- Create snippet for worldserver.conf:
|
||||
Logger.BG.TOK=6,Console Server File
|
||||
Logger.BG.TOK.File=bg
|
||||
Logger.BG.TOK.TimeStamp=1
|
||||
Logger.playerbots.bg=6,Console Server File
|
||||
Logger.playerbots.bg.File=bg
|
||||
|
||||
4. Create Manual Test Checklist
|
||||
|
||||
Generate detailed test instructions in Obsidian: "Sessions/TOK Test Instructions.md"
|
||||
|
||||
Include:
|
||||
- Server startup instructions
|
||||
- How to add bg.log config
|
||||
- Exact test scenarios:
|
||||
* Test 1: Orange orb pickup (bot approaches, uses, confirms aura)
|
||||
* Test 2: Purple orb pickup
|
||||
* Test 3: Green orb pickup
|
||||
* Test 4: Blue orb pickup
|
||||
* Test 5: Combat engagement (bot attacks enemy carrier)
|
||||
* Test 6: Center control (bot moves to center with orb)
|
||||
* Test 7: Strategy switch (force score difference, observe behavior)
|
||||
* Test 8: Bot death with orb (verify orb drops)
|
||||
* Test 9: Orb respawn (verify 30 second timer)
|
||||
* Test 10: Full game (10v10, complete to victory condition)
|
||||
|
||||
- Metrics to track:
|
||||
* Orb pickup attempts vs successes (target: >95%)
|
||||
* Combat engagements vs failures to attack (target: 100%)
|
||||
* Crashes (target: ZERO)
|
||||
* Strategy transitions observed
|
||||
* Victory condition correctness
|
||||
|
||||
- Log collection instructions:
|
||||
* Where to find logs/bg.log
|
||||
* What log excerpts to copy
|
||||
* How to save to Obsidian
|
||||
|
||||
5. Create Test Results Template
|
||||
|
||||
Create file in Obsidian: "Sessions/TOK Manual Test Results.md"
|
||||
|
||||
Template with sections:
|
||||
- Test Environment (build hash, date, duration)
|
||||
- Orb Pickup Results (table with attempts/successes per orb)
|
||||
- Combat Engagement Results
|
||||
- Strategy Transition Observations
|
||||
- Crashes / Errors
|
||||
- Performance Notes
|
||||
- Log Excerpts
|
||||
- Overall Assessment
|
||||
|
||||
Write to Obsidian:
|
||||
- "Sessions/TOK Build Report.md" - Build results, warnings, binary info
|
||||
- "Sessions/TOK Code Analysis.md" - Static analysis findings
|
||||
- "Sessions/TOK Test Instructions.md" - Complete test checklist (ALREADY DESCRIBED ABOVE)
|
||||
|
||||
Output should be:
|
||||
- Build report: ✅ PASS or ❌ FAIL (if fail, stop workflow here)
|
||||
- Code analysis: List of issues found (if critical, stop workflow)
|
||||
- Test instructions: Complete, clear, ready for human tester
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 5B: MANUAL TESTING PAUSE
|
||||
|
||||
**Stage Name:** `⏸️ PAUSE: User Manual Testing`
|
||||
|
||||
**Agent:** None (Human Task)
|
||||
|
||||
**Depends On:** Stage 5A ✓
|
||||
|
||||
**Type:** Manual Pause Point
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
⏸️⏸️⏸️ WORKFLOW PAUSES HERE ⏸️⏸️⏸️
|
||||
|
||||
This is a manual testing phase. The workflow will resume after user completes testing.
|
||||
|
||||
USER TASKS:
|
||||
|
||||
1. Read Test Instructions
|
||||
- Open Obsidian: "Sessions/TOK Test Instructions.md"
|
||||
- Review all test scenarios
|
||||
- Understand success criteria
|
||||
|
||||
2. Configure Server
|
||||
- Add bg.log configuration to worldserver.conf (snippet provided in Stage 5A)
|
||||
- Ensure Playerbot module is enabled
|
||||
- Start worldserver
|
||||
|
||||
3. Execute Tests
|
||||
- Follow each test scenario in order
|
||||
- Track metrics for each test
|
||||
- Note any unexpected behavior
|
||||
- Collect screenshots if issues occur
|
||||
|
||||
4. Collect Logs
|
||||
- After testing, copy logs/bg.log
|
||||
- Extract relevant sections (orb pickup events, combat events, errors)
|
||||
- Save to a file for analysis
|
||||
|
||||
5. Fill Results Template
|
||||
- Open Obsidian: "Sessions/TOK Manual Test Results.md"
|
||||
- Fill in all sections:
|
||||
* Test environment details
|
||||
* Results for each test scenario
|
||||
* Metrics (success rates)
|
||||
* Crashes (if any)
|
||||
* Log excerpts (paste relevant logs)
|
||||
* Overall observations
|
||||
|
||||
6. Resume Workflow
|
||||
- After completing all tests and documenting results
|
||||
- Resume workflow to Stage 5C
|
||||
- Stage 5C will analyze your results
|
||||
|
||||
ESTIMATED TIME: 30-60 minutes
|
||||
|
||||
SUCCESS CRITERIA TO PROCEED:
|
||||
- ✅ All test scenarios executed
|
||||
- ✅ Results documented in Obsidian
|
||||
- ✅ Logs collected and excerpts saved
|
||||
- ✅ Ready for automated analysis
|
||||
|
||||
NOTE: If major issues found during testing:
|
||||
- Document them clearly
|
||||
- Stage 5C will identify them
|
||||
- Workflow may loop back to fix issues
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 5C: Log Analysis & Validation
|
||||
|
||||
**Stage Name:** `Analyze Test Results & Validate`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** Stage 5B ✓
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read from Obsidian:
|
||||
- "Sessions/TOK Manual Test Results.md" (user's test data)
|
||||
- "Refactorings/TOK Testing Plan.md" (success criteria)
|
||||
- Any attached log files referenced in test results
|
||||
|
||||
Analysis tasks:
|
||||
|
||||
1. Parse Test Results
|
||||
|
||||
- Extract metrics from user's results:
|
||||
* Orb pickup success rate (per orb and overall)
|
||||
* Combat engagement success rate
|
||||
* Crash count
|
||||
* Strategy transitions observed
|
||||
* Victory condition correctness
|
||||
- Compare against targets:
|
||||
* Orb pickup: >95% required
|
||||
* Combat: 100% required
|
||||
* Crashes: ZERO required
|
||||
|
||||
2. Log File Analysis
|
||||
|
||||
- Parse log excerpts for:
|
||||
* Error messages (ERROR, FATAL levels)
|
||||
* Warning messages (relevant to TOK)
|
||||
* Exception traces
|
||||
* Performance issues (long delays, timeouts)
|
||||
- Search for specific events:
|
||||
* "Orb pickup attempt" → success/failure reasons
|
||||
* "Combat engagement" → target acquired, attack started
|
||||
* "Strategy transition" → old state → new state
|
||||
* GameObject interaction failures
|
||||
* Null pointer accesses
|
||||
* Memory allocation failures
|
||||
|
||||
3. Performance Analysis
|
||||
|
||||
- Check for:
|
||||
* Excessive CPU usage indicators
|
||||
* Memory leaks (increasing allocations)
|
||||
* Slow operations (>100ms for simple actions)
|
||||
* Thread contention / deadlocks
|
||||
- Verify performance requirements met:
|
||||
* <0.1% CPU per bot
|
||||
* <10MB memory per bot
|
||||
* <50ms response time for decisions
|
||||
|
||||
4. Edge Case Verification
|
||||
|
||||
- Verify each edge case was tested:
|
||||
* Bot death with orb → orb dropped correctly
|
||||
* Orb respawn timing → 30 seconds confirmed
|
||||
* Multiple bots same orb → conflict resolution
|
||||
* Disconnect/AFK → system handled gracefully
|
||||
- Check if edge cases passed
|
||||
|
||||
5. Decision Matrix
|
||||
|
||||
Based on analysis, make decision:
|
||||
|
||||
✅ PASS - Proceed to Stage 6 if ALL true:
|
||||
- Orb pickup ≥95%
|
||||
- Combat engagement = 100%
|
||||
- Crashes = 0
|
||||
- No critical errors in logs
|
||||
- Performance acceptable
|
||||
- All edge cases handled
|
||||
|
||||
⚠️ NEEDS FIXES - Create fix tasks if:
|
||||
- Orb pickup <95% (identify failure reasons)
|
||||
- Combat engagement <100% (identify causes)
|
||||
- Crashes = 1-2 (not critical, but needs fixing)
|
||||
- Some errors in logs (non-critical)
|
||||
- Performance issues (but not blocking)
|
||||
|
||||
❌ FAIL - Recommend rollback if:
|
||||
- Crashes ≥3 (critical stability issue)
|
||||
- Critical errors in logs (data corruption, memory corruption)
|
||||
- Orb pickup <50% (fundamental design flaw)
|
||||
- Performance unacceptable (>1% CPU per bot, >50MB memory)
|
||||
|
||||
6. Fix Task Generation (if NEEDS FIXES)
|
||||
|
||||
- For each issue found, create task in Obsidian:
|
||||
* "Tasks/TOK-FIX-[NN] - [Issue Description].md"
|
||||
* Include: Root cause, proposed fix, affected files
|
||||
- Update "Refactorings/TOK Lighthouse BG.md" with fix status
|
||||
|
||||
Write comprehensive analysis to Obsidian: "Sessions/TOK Log Analysis Report.md"
|
||||
|
||||
Include:
|
||||
- Executive summary (PASS/NEEDS FIXES/FAIL + rationale)
|
||||
- Detailed metrics breakdown
|
||||
- Log analysis findings (errors, warnings, patterns)
|
||||
- Performance assessment
|
||||
- Edge case verification results
|
||||
- If NEEDS FIXES: List of issues + fix tasks created
|
||||
- If FAIL: Recommendations for next steps (rollback vs redesign)
|
||||
- If PASS: Confirmation to proceed to blueprint stage
|
||||
|
||||
WORKFLOW DECISION:
|
||||
- If PASS: Continue to Stage 6
|
||||
- If NEEDS FIXES: Pause workflow, alert user, wait for fixes
|
||||
- If FAIL: Stop workflow, alert user, recommend rollback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 6: Create Transfer Blueprint
|
||||
|
||||
**Stage Name:** `Create Transfer Blueprint for All BGs`
|
||||
|
||||
**Agent:** Claude Code
|
||||
|
||||
**Depends On:** Stage 5C ✓ (PASS status required)
|
||||
|
||||
**Instructions:**
|
||||
```
|
||||
Read from Obsidian:
|
||||
- "Refactorings/TOK Lighthouse BG.md" (original requirements)
|
||||
- "Refactorings/TOK Lighthouse Spec.md" (design decisions)
|
||||
- All session notes (Sprint 1-3, test results, analysis)
|
||||
- "Sessions/TOK Log Analysis Report.md" (validation confirmation)
|
||||
|
||||
Create comprehensive blueprint for transferring TOK patterns to all 13 other battlegrounds.
|
||||
|
||||
Blueprint document: "Architecture/Lighthouse BG Blueprint.md"
|
||||
|
||||
Structure:
|
||||
|
||||
1. Executive Summary
|
||||
- What makes TOK the lighthouse
|
||||
- Success metrics achieved
|
||||
- Key patterns to transfer
|
||||
- Estimated effort to apply to other BGs
|
||||
|
||||
2. Data Accuracy Pattern
|
||||
- How we researched TOK data (DBC/DB2/SQL queries)
|
||||
- GameObject verification process
|
||||
- Aura/spell verification process
|
||||
- Victory condition verification
|
||||
- Template queries for other BGs
|
||||
- Checklist for data validation
|
||||
|
||||
3. GameObject Interaction Pattern
|
||||
- The correct way to interact with BG objects
|
||||
- GameObject::Use() best practices
|
||||
- State checking requirements
|
||||
- Distance validation
|
||||
- Error handling pattern
|
||||
- Code template for object interaction
|
||||
|
||||
4. Combat Engagement Pattern
|
||||
- SetSelection() + Attack() sequence
|
||||
- Target validation (IsAlive, IsHostileTo)
|
||||
- Combat state management
|
||||
- Integration with existing combat system
|
||||
- Code template for combat engagement
|
||||
|
||||
5. Dynamic Strategy Pattern
|
||||
- State machine architecture
|
||||
- Transition logic design
|
||||
- How to define BG-specific states
|
||||
- How to define transition triggers
|
||||
- Role assignment integration
|
||||
- Code template for strategy system
|
||||
|
||||
6. Center Control / Objective Pattern
|
||||
- How to define objective areas
|
||||
- Priority calculation
|
||||
- Risk/reward analysis
|
||||
- Movement coordination
|
||||
- Code template for objective control
|
||||
|
||||
7. Edge Case Handling Pattern
|
||||
- Common edge cases across all BGs
|
||||
- BG-specific edge cases
|
||||
- Testing methodology
|
||||
- Code patterns for edge case handling
|
||||
|
||||
8. Coordination Pattern
|
||||
- BGCoordinator integration
|
||||
- Role manager usage
|
||||
- Multi-bot synchronization
|
||||
- Communication patterns
|
||||
- Code template for coordination
|
||||
|
||||
9. Logging & Debugging Pattern
|
||||
- What to log and why
|
||||
- Log levels for different events
|
||||
- Performance logging
|
||||
- Debugging tools used
|
||||
- Log configuration template
|
||||
|
||||
10. Testing Pattern
|
||||
- Build verification process
|
||||
- Static code analysis checklist
|
||||
- Manual testing scenarios template
|
||||
- Log analysis methodology
|
||||
- Success criteria definition
|
||||
- Metrics tracking template
|
||||
|
||||
11. Performance Pattern
|
||||
- CPU usage targets
|
||||
- Memory usage targets
|
||||
- Response time requirements
|
||||
- Performance profiling tools
|
||||
- Optimization techniques used
|
||||
|
||||
12. Code Quality Pattern
|
||||
- TrinityCore coding standards applied
|
||||
- Error handling requirements
|
||||
- Null safety practices
|
||||
- Resource management (RAII)
|
||||
- Code review checklist
|
||||
|
||||
13. Transfer Process
|
||||
- Step-by-step guide to apply patterns to new BG
|
||||
- Customization points (what's BG-specific vs generic)
|
||||
- Estimated time per BG
|
||||
- Dependency order (which BGs to do first)
|
||||
- Risk mitigation (testing, validation)
|
||||
|
||||
14. BG Priority Matrix
|
||||
- List all 13 other battlegrounds
|
||||
- Categorize by type:
|
||||
* CTF: Warsong Gulch, Twin Peaks
|
||||
* Domination: Arathi Basin, Battle for Gilneas, Eye of the Storm
|
||||
* Resource Race: Silvershard Mines, Deepwind Gorge
|
||||
* Siege: Alterac Valley, Isle of Conquest, Strand of the Ancients
|
||||
* Epic: Ashran
|
||||
- Recommend order of implementation
|
||||
- Complexity assessment per BG
|
||||
|
||||
15. Success Metrics for Transfer
|
||||
- How to measure if pattern was applied correctly
|
||||
- Validation checklist per BG
|
||||
- Testing requirements per BG
|
||||
- Sign-off criteria
|
||||
|
||||
16. Lessons Learned
|
||||
- What worked well in TOK development
|
||||
- What challenges were faced
|
||||
- What would be done differently
|
||||
- Tips for applying to other BGs
|
||||
|
||||
17. Code Appendix
|
||||
- Complete code templates (copy-paste ready)
|
||||
- Configuration snippets
|
||||
- SQL queries for data verification
|
||||
- Testing scripts
|
||||
|
||||
Write blueprint to Obsidian: "Architecture/Lighthouse BG Blueprint.md"
|
||||
|
||||
Also create quick reference:
|
||||
- "Architecture/BG Transfer Checklist.md" - Quick checklist for applying patterns
|
||||
|
||||
Update project documentation:
|
||||
- "Refactorings/TOK Lighthouse BG.md" - Mark as ✅ COMPLETE
|
||||
- "Tasks/Active Instances.md" - Update status
|
||||
|
||||
Blueprint should be:
|
||||
- Complete (covers all aspects)
|
||||
- Actionable (anyone can follow it)
|
||||
- Template-based (minimal customization per BG)
|
||||
- Validated (based on proven TOK implementation)
|
||||
- Maintainable (easy to update if patterns improve)
|
||||
|
||||
FINAL OUTPUT:
|
||||
- Blueprint document (50-100 pages equivalent)
|
||||
- Transfer checklist (2-3 pages)
|
||||
- Updated project status
|
||||
- Ready for application to next BG
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow Settings
|
||||
|
||||
**If Zenflow allows these configurations:**
|
||||
|
||||
- ✅ **Branch Strategy:** Create branch per stage
|
||||
- Format: `lighthouse-bg/tok/stage-{N}-{stage-name}`
|
||||
- Merge after validation
|
||||
|
||||
- ✅ **Shared Memory:** Obsidian Vault
|
||||
- Path: `C:\TrinityBots\PlayerBotProjectMemory\TrinityCore-Playerbot-Memory`
|
||||
- All stages read/write to Obsidian for coordination
|
||||
|
||||
- ✅ **Parallelization:** Sequential (not parallel)
|
||||
- Max parallel: 1
|
||||
- Stages must complete in order
|
||||
|
||||
- ✅ **Auto-commit:** After each stage
|
||||
- Commit message format: `[Zenflow] Stage {N}: {stage-name} - {brief summary}`
|
||||
|
||||
- ✅ **Failure Handling:**
|
||||
- On build failure (Stage 5A): Stop workflow, alert user
|
||||
- On test failure (Stage 5C): Pause workflow, create fix tasks
|
||||
- On any critical error: Stop workflow, alert user
|
||||
|
||||
- ✅ **Notifications:**
|
||||
- Stage complete: Update Obsidian "Tasks/Active Instances.md"
|
||||
- Workflow paused: Alert user with reason
|
||||
- Workflow complete: Summary report to Obsidian
|
||||
|
||||
---
|
||||
|
||||
## Expected Timeline
|
||||
|
||||
- **Stage 1 (Research):** ~30-45 minutes
|
||||
- **Stage 2 (Spec):** ~45-60 minutes
|
||||
- **Stage 3 (GameObject/Combat):** ~60-90 minutes
|
||||
- **Stage 4 (Dynamic Strategy):** ~90-120 minutes
|
||||
- **Stage 5A (Build & Prep):** ~15-30 minutes
|
||||
- **Stage 5B (Manual Testing):** ~30-60 minutes (USER)
|
||||
- **Stage 5C (Analysis):** ~20-30 minutes
|
||||
- **Stage 6 (Blueprint):** ~60-90 minutes
|
||||
|
||||
**Total Automated Time:** ~6-8 hours
|
||||
**Total Manual Time:** ~30-60 minutes (your testing)
|
||||
**Total Workflow Time:** ~7-9 hours
|
||||
|
||||
---
|
||||
|
||||
## Workflow Success Criteria
|
||||
|
||||
To consider the workflow successful:
|
||||
|
||||
- ✅ All stages complete without critical errors
|
||||
- ✅ Build passes (Stage 5A)
|
||||
- ✅ Manual tests pass (Stage 5B/5C):
|
||||
- Orb pickup ≥95%
|
||||
- Combat engagement = 100%
|
||||
- Zero crashes
|
||||
- ✅ Blueprint created (Stage 6)
|
||||
- ✅ Code merged to main branch
|
||||
- ✅ Documentation complete in Obsidian
|
||||
|
||||
**Result:** Temple of Kotmogu is production-ready and serves as the blueprint for all other battlegrounds.
|
||||
|
||||
---
|
||||
|
||||
**End of Workflow Definition**
|
||||
@@ -0,0 +1,503 @@
|
||||
# Task: PlayerbotModule Subsystem Registry Refactoring + Startup Log Harmonisierung
|
||||
|
||||
## Ziel
|
||||
|
||||
Refactoring der drei "God Functions" in `PlayerbotModule.cpp`:
|
||||
- `InitializeManagers()` (~300 Zeilen Boilerplate)
|
||||
- `OnWorldUpdate()` (~200 Zeilen mit manuellen Timer-Variablen t1–t17)
|
||||
- `Shutdown()` (~100 Zeilen Copy-Paste Shutdown-Calls)
|
||||
|
||||
Ersetze das manuelle, hart-codierte Subsystem-Management durch ein **SubsystemRegistry-Pattern**, das Init, Update und Shutdown automatisch verwaltet. Zusätzlich: **Harmonisierung und Verschlankung des Startup-Log-Outputs** für bessere Übersichtlichkeit.
|
||||
|
||||
---
|
||||
|
||||
## Kontext
|
||||
|
||||
### Projekt
|
||||
- **Pfad**: `C:\TrinityBots\TrinityCore`
|
||||
- **Modul**: `src/modules/Playerbot/`
|
||||
- **Sprache**: C++20, MSVC (Visual Studio 2025)
|
||||
- **Build**: `cmake --build build --config RelWithDebInfo -- /m`
|
||||
- **Branch**: `playerbot-dev`
|
||||
- **Codebasis**: ~636K LOC, ~1010 Dateien im Playerbot-Modul
|
||||
|
||||
### Wichtige Dateien
|
||||
- `src/modules/Playerbot/PlayerbotModule.h` — Hauptklasse (Header)
|
||||
- `src/modules/Playerbot/PlayerbotModule.cpp` — Hauptklasse (Implementation, ~600 Zeilen)
|
||||
- `src/modules/Playerbot/PlayerbotModuleAdapter.h/.cpp` — ModuleManager-Integration
|
||||
- `src/modules/Common/Update/ModuleUpdateManager.h/.cpp` — Bestehendes Update-Registry (NICHT ändern)
|
||||
- `src/modules/Playerbot/CMakeLists.txt` — Build-Konfiguration (Multi-Library Architektur)
|
||||
|
||||
### Bestehende Architektur
|
||||
`PlayerbotModuleAdapter` registriert sich beim `ModuleManager`. Bei jedem World-Tick wird `PlayerbotModuleAdapter::OnModuleUpdate()` → `PlayerbotModule::OnWorldUpdate()` aufgerufen. PlayerbotModule ruft dann manuell 17+ Manager-Update-Funktionen auf.
|
||||
|
||||
### Coding Standards (aus CLAUDE.md)
|
||||
- **Naming**: PascalCase Klassen, PascalCase Methoden, camelCase Variablen, `m_` Prefix für Members
|
||||
- **Threading**: `std::shared_mutex` für read-heavy, `std::mutex` für write-heavy
|
||||
- **Memory**: Smart Pointers bevorzugen
|
||||
- **Include Order**: Own header → Project headers → TrinityCore headers → External → STL
|
||||
- **Singletons**: Nutze `#define sXxxManager XxxManager::instance()` Pattern wie im restlichen TC-Code
|
||||
|
||||
---
|
||||
|
||||
## Problem-Analyse
|
||||
|
||||
### 1. OnWorldUpdate() — Manuelles Timing-Boilerplate
|
||||
|
||||
Aktuell sieht die Funktion so aus (gekürzt):
|
||||
|
||||
```cpp
|
||||
void PlayerbotModule::OnWorldUpdate(uint32 diff)
|
||||
{
|
||||
auto timeStart = std::chrono::high_resolution_clock::now();
|
||||
auto lastTime = timeStart;
|
||||
|
||||
sBotAccountMgr->Update(diff);
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
auto accountTime = std::chrono::duration_cast<std::chrono::microseconds>(t1 - lastTime).count();
|
||||
lastTime = t1;
|
||||
|
||||
Playerbot::sBotSpawner->Update(diff);
|
||||
auto t2 = std::chrono::high_resolution_clock::now();
|
||||
auto spawnerTime = std::chrono::duration_cast<std::chrono::microseconds>(t2 - lastTime).count();
|
||||
lastTime = t2;
|
||||
|
||||
// ... 15 weitere identische Blöcke mit t3–t17 ...
|
||||
|
||||
if (totalUpdateTime > 100000)
|
||||
{
|
||||
TC_LOG_WARN("module.playerbot.performance",
|
||||
"PERFORMANCE: OnWorldUpdate took {:.2f}ms - Account:{:.2f}ms, ...",
|
||||
totalUpdateTime / 1000.0f, accountTime / 1000.0f, ...); // 17 Parameter!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Probleme**: Massiver Code-Duplikat, jedes neue Subsystem erfordert Änderungen an 3 Stellen (Init, Update, Shutdown + neue Timer-Variable + Log-Format-String).
|
||||
|
||||
### 2. InitializeManagers() — Identisches Boilerplate × 25
|
||||
|
||||
```cpp
|
||||
TC_LOG_INFO("server.loading", "Initializing Bot Protection Registry...");
|
||||
if (!sBotProtectionRegistry->Initialize())
|
||||
{
|
||||
TC_LOG_WARN("server.loading", "Bot Protection Registry initialization failed...");
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_INFO("server.loading", "Bot Protection Registry initialized successfully");
|
||||
}
|
||||
```
|
||||
|
||||
Dieses Pattern wiederholt sich ~25 Mal mit minimalem Unterschied.
|
||||
|
||||
### 3. Shutdown() — Spiegelbildliches Boilerplate
|
||||
|
||||
```cpp
|
||||
TC_LOG_INFO("server.loading", "Shutting down Bot Protection Registry...");
|
||||
sBotProtectionRegistry->Shutdown();
|
||||
TC_LOG_INFO("server.loading", "Bot Protection Registry shutdown complete");
|
||||
```
|
||||
|
||||
~20 Mal wiederholt.
|
||||
|
||||
### 4. Startup-Logging — Unübersichtlich und inkonsistent
|
||||
|
||||
- Manche Subsysteme loggen auf `"server.loading"`, andere auf `"module.playerbot"`
|
||||
- Einige nutzen `TC_LOG_ERROR` für nicht-kritische Meldungen (z.B. `PlayerbotModuleAdapter::OnModuleStartup` loggt mit `TC_LOG_ERROR`)
|
||||
- Jedes Subsystem produziert 2-3 Zeilen (init start + init success/fail)
|
||||
- Bei 25+ Subsystemen sind das ~75 Log-Zeilen nur für Init
|
||||
- Kein visueller Überblick — alles sieht gleich aus
|
||||
|
||||
---
|
||||
|
||||
## Anforderungen
|
||||
|
||||
### A. Neues SubsystemRegistry-Interface
|
||||
|
||||
Erstelle ein `IPlayerbotSubsystem`-Interface und eine `PlayerbotSubsystemRegistry`:
|
||||
|
||||
```cpp
|
||||
// Core/PlayerbotSubsystem.h
|
||||
namespace Playerbot
|
||||
{
|
||||
|
||||
enum class SubsystemPriority : uint8
|
||||
{
|
||||
CRITICAL = 0, // Muss initialisiert werden, Fehler = Abort
|
||||
HIGH = 1, // Sollte initialisiert werden, Fehler = Warning
|
||||
NORMAL = 2, // Standard-Subsystem
|
||||
LOW = 3, // Optional, Fehler wird ignoriert
|
||||
};
|
||||
|
||||
struct SubsystemInfo
|
||||
{
|
||||
std::string name; // Display-Name für Logging
|
||||
SubsystemPriority priority; // Init-Priorität
|
||||
uint32 initOrder; // Init-Reihenfolge (niedrig = zuerst)
|
||||
uint32 updateOrder; // Update-Reihenfolge (niedrig = zuerst)
|
||||
uint32 shutdownOrder; // Shutdown-Reihenfolge (niedrig = zuerst)
|
||||
bool needsUpdate; // Ob dieses Subsystem per-tick updates braucht
|
||||
};
|
||||
|
||||
class IPlayerbotSubsystem
|
||||
{
|
||||
public:
|
||||
virtual ~IPlayerbotSubsystem() = default;
|
||||
|
||||
virtual SubsystemInfo GetInfo() const = 0;
|
||||
virtual bool Initialize() = 0;
|
||||
virtual void Update(uint32 diff) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
};
|
||||
|
||||
} // namespace Playerbot
|
||||
```
|
||||
|
||||
Die Registry:
|
||||
```cpp
|
||||
// Core/PlayerbotSubsystemRegistry.h
|
||||
namespace Playerbot
|
||||
{
|
||||
|
||||
class PlayerbotSubsystemRegistry
|
||||
{
|
||||
public:
|
||||
static PlayerbotSubsystemRegistry* instance();
|
||||
|
||||
// Registrierung
|
||||
void RegisterSubsystem(std::unique_ptr<IPlayerbotSubsystem> subsystem);
|
||||
|
||||
// Lifecycle
|
||||
bool InitializeAll(); // Ersetzt InitializeManagers()
|
||||
void UpdateAll(uint32 diff); // Ersetzt OnWorldUpdate()-Inhalt
|
||||
void ShutdownAll(); // Ersetzt Shutdown()-Inhalt
|
||||
|
||||
// Diagnostik
|
||||
struct SubsystemMetrics
|
||||
{
|
||||
std::string name;
|
||||
uint64 totalUpdateTimeUs = 0;
|
||||
uint64 lastUpdateTimeUs = 0;
|
||||
uint64 maxUpdateTimeUs = 0;
|
||||
uint32 updateCount = 0;
|
||||
};
|
||||
std::vector<SubsystemMetrics> GetMetrics() const;
|
||||
uint32 GetSubsystemCount() const;
|
||||
|
||||
private:
|
||||
PlayerbotSubsystemRegistry() = default;
|
||||
|
||||
struct SubsystemEntry
|
||||
{
|
||||
std::unique_ptr<IPlayerbotSubsystem> subsystem;
|
||||
SubsystemInfo info;
|
||||
SubsystemMetrics metrics;
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
std::vector<SubsystemEntry> m_subsystems;
|
||||
bool m_allInitialized = false;
|
||||
};
|
||||
|
||||
} // namespace Playerbot
|
||||
|
||||
#define sPlayerbotSubsystemRegistry Playerbot::PlayerbotSubsystemRegistry::instance()
|
||||
```
|
||||
|
||||
### B. Subsystem-Adapter für bestehende Manager
|
||||
|
||||
Da die bestehenden Singletons (sBotAccountMgr, sBotSpawner, etc.) NICHT geändert werden sollen, erstelle Thin-Wrapper-Adapter. Beispiel:
|
||||
|
||||
```cpp
|
||||
class BotAccountMgrSubsystem : public IPlayerbotSubsystem
|
||||
{
|
||||
public:
|
||||
SubsystemInfo GetInfo() const override
|
||||
{
|
||||
return { "BotAccountMgr", SubsystemPriority::CRITICAL,
|
||||
/*initOrder=*/100, /*updateOrder=*/100, /*shutdownOrder=*/900,
|
||||
/*needsUpdate=*/true };
|
||||
}
|
||||
bool Initialize() override { return sBotAccountMgr->Initialize(); }
|
||||
void Update(uint32 diff) override { sBotAccountMgr->Update(diff); }
|
||||
void Shutdown() override { sBotAccountMgr->Shutdown(); }
|
||||
};
|
||||
```
|
||||
|
||||
Erstelle Adapter für ALLE ~25 Subsysteme die aktuell in InitializeManagers/OnWorldUpdate/Shutdown manuell aufgerufen werden. Die Adapter können in einer einzigen Datei leben: `Core/SubsystemAdapters.cpp`.
|
||||
|
||||
**WICHTIG**: Analysiere die aktuelle Reihenfolge in PlayerbotModule.cpp sorgfältig und bilde sie exakt in den Order-Werten ab!
|
||||
|
||||
### C. Vereinfachte PlayerbotModule-Funktionen
|
||||
|
||||
Nach dem Refactoring sollte PlayerbotModule.cpp drastisch schrumpfen:
|
||||
|
||||
```cpp
|
||||
bool PlayerbotModule::InitializeManagers()
|
||||
{
|
||||
RegisterAllSubsystems();
|
||||
return sPlayerbotSubsystemRegistry->InitializeAll();
|
||||
}
|
||||
|
||||
void PlayerbotModule::OnWorldUpdate(uint32 diff)
|
||||
{
|
||||
if (!_enabled || !_initialized)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// One-time trigger to complete login for existing sessions
|
||||
static bool loginTriggered = false;
|
||||
static uint32 totalTime = 0;
|
||||
totalTime += diff;
|
||||
if (!loginTriggered && totalTime > 5000)
|
||||
{
|
||||
TriggerBotCharacterLogins();
|
||||
loginTriggered = true;
|
||||
}
|
||||
|
||||
sPlayerbotSubsystemRegistry->UpdateAll(diff);
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
TC_LOG_ERROR("module.playerbot", "CRITICAL EXCEPTION in OnWorldUpdate: {}", ex.what());
|
||||
_enabled = false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
TC_LOG_ERROR("module.playerbot", "CRITICAL UNKNOWN EXCEPTION in OnWorldUpdate");
|
||||
_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerbotModule::Shutdown()
|
||||
{
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
TC_LOG_INFO("module.playerbot", "Shutting down Playerbot Module...");
|
||||
sPlayerbotSubsystemRegistry->ShutdownAll();
|
||||
ShutdownDatabase();
|
||||
sPlayerbotCharDB->Shutdown();
|
||||
_initialized = false;
|
||||
_enabled = false;
|
||||
TC_LOG_INFO("module.playerbot", "Playerbot Module shutdown complete.");
|
||||
}
|
||||
```
|
||||
|
||||
### D. Automatisches Performance-Profiling in der Registry
|
||||
|
||||
Die Registry misst die Update-Zeit pro Subsystem automatisch. Bei Überschreitung von 100ms werden die **Top-5 langsamsten Subsysteme** geloggt (statt alle 17):
|
||||
|
||||
```
|
||||
PERFORMANCE: UpdateAll took 142.5ms - Top offenders:
|
||||
BotWorldSessionMgr: 68.3ms, BotSpawner: 32.1ms, DomainEventBus: 18.7ms, ...
|
||||
```
|
||||
|
||||
### E. Startup-Log Harmonisierung
|
||||
|
||||
**Ziel**: Kompakter, übersichtlicher Startup-Output statt ~75 Zeilen.
|
||||
|
||||
#### Format-Vorgabe:
|
||||
|
||||
```
|
||||
[module.playerbot] ═══════════════════════════════════════════════════════════════
|
||||
[module.playerbot] Playerbot Module v1.0.0 initializing...
|
||||
[module.playerbot] ───────────────────────────────────────────────────────────────
|
||||
[module.playerbot] Database : Connected (127.0.0.1:3306/characters)
|
||||
[module.playerbot] Migrations : 12 applied (schema v12)
|
||||
[module.playerbot] ───────────────────────────────────────────────────────────────
|
||||
[module.playerbot] Initializing 25 subsystems...
|
||||
[module.playerbot] ✓ BotAccountMgr [ 45ms]
|
||||
[module.playerbot] ✓ BotNameMgr [ 12ms]
|
||||
[module.playerbot] ✓ BotCharacterDistribution [ 89ms]
|
||||
[module.playerbot] ✓ BotWorldSessionMgr [ 23ms]
|
||||
[module.playerbot] ⚠ BotProtectionRegistry [ 3ms] (non-critical, continuing)
|
||||
[module.playerbot] ✓ QuestHubDatabase [ 234ms] (847 quest hubs)
|
||||
[module.playerbot] ... (weitere Subsysteme)
|
||||
[module.playerbot] ───────────────────────────────────────────────────────────────
|
||||
[module.playerbot] Result: 24/25 OK | 1 warning | 0 failed
|
||||
[module.playerbot] Total init time: 1,247ms
|
||||
[module.playerbot] ═══════════════════════════════════════════════════════════════
|
||||
[module.playerbot] Playerbot Module v1.0.0 ready.
|
||||
```
|
||||
|
||||
#### Regeln:
|
||||
1. **Einheitlicher Log-Channel**: Alles über `"module.playerbot"` (nicht `"server.loading"`)
|
||||
2. **Log-Level**: `TC_LOG_INFO` für normale Meldungen, `TC_LOG_WARN` für non-fatal, `TC_LOG_ERROR` nur für fatale Fehler
|
||||
3. **Kein doppeltes Logging**: Subsysteme selbst loggen NICHT mehr "Initializing..." / "...initialized". Die Registry macht das zentral.
|
||||
4. **Alle manuellen TC_LOG_INFO/WARN-Aufrufe** vor/nach Init-Calls in PlayerbotModule.cpp ENTFERNEN
|
||||
|
||||
#### PlayerbotModuleAdapter aufräumen:
|
||||
- `TC_LOG_ERROR("server.loading", "=== PlayerbotModuleAdapter::OnModuleStartup() CALLED ===")` → ENTFERNEN
|
||||
- `if (++logCounter % 100000 == 0)` periodic logging → ENTFERNEN
|
||||
- Alle verbleibenden Logs auf `"module.playerbot"` Channel umstellen
|
||||
|
||||
---
|
||||
|
||||
## Schritte
|
||||
|
||||
### Phase 1: Interface & Registry erstellen
|
||||
1. Erstelle `src/modules/Playerbot/Core/PlayerbotSubsystem.h` (Interface)
|
||||
2. Erstelle `src/modules/Playerbot/Core/PlayerbotSubsystemRegistry.h/.cpp` (Registry)
|
||||
3. Füge die neuen Dateien zum CMakeLists.txt hinzu (in `PLAYERBOT_CORE_SOURCES`)
|
||||
|
||||
### Phase 2: Subsystem-Adapter erstellen
|
||||
4. Erstelle `src/modules/Playerbot/Core/SubsystemAdapters.h/.cpp` — Thin-Wrapper für alle Manager
|
||||
5. Erstelle `RegisterAllSubsystems()` Funktion die alle Adapter registriert
|
||||
|
||||
**KRITISCH**: Die Reihenfolge der Registrierung (initOrder, updateOrder, shutdownOrder) muss die aktuelle Reihenfolge in PlayerbotModule.cpp exakt beibehalten! Analysiere die aktuelle Reihenfolge sorgfältig.
|
||||
|
||||
### Phase 3: PlayerbotModule.cpp refactorn
|
||||
6. `InitializeManagers()` → `RegisterAllSubsystems()` + `sPlayerbotSubsystemRegistry->InitializeAll()`
|
||||
7. `OnWorldUpdate()` → `sPlayerbotSubsystemRegistry->UpdateAll(diff)` (Login-Trigger und Exception-Safety beibehalten)
|
||||
8. `Shutdown()` → `sPlayerbotSubsystemRegistry->ShutdownAll()`
|
||||
9. Entferne ALLE manuellen Init/Shutdown-Log-Aufrufe
|
||||
|
||||
### Phase 4: Log-Harmonisierung
|
||||
10. Implementiere formatierte Startup-Ausgabe in `InitializeAll()`
|
||||
11. Implementiere Performance-Warning (Top-5) in `UpdateAll()`
|
||||
12. Räume `PlayerbotModuleAdapter.cpp` auf (Debug-Leftovers, Log-Channel)
|
||||
13. Stelle alle Playerbot-Logs in `PlayerbotModule.cpp` auf `"module.playerbot"` um
|
||||
14. Database-Init-Meldungen (`InitializeDatabase()`) ebenfalls harmonisieren
|
||||
|
||||
### Phase 5: Build & Verify
|
||||
15. Build: `cmake --build build --config RelWithDebInfo -- /m`
|
||||
16. Alle Compile-Fehler beheben
|
||||
17. Verifiziere: Keine funktionalen Änderungen — reines Refactoring
|
||||
|
||||
---
|
||||
|
||||
## Spezielle Anforderungen
|
||||
|
||||
### Was NICHT geändert werden darf
|
||||
- **Bestehende Singleton-Interfaces** (sBotAccountMgr, sBotSpawner, etc.) — nur Wrapper erstellen
|
||||
- **ModuleUpdateManager** in `src/modules/Common/` — fremder Code
|
||||
- **ModuleManager-Integration** — PlayerbotModuleAdapter bleibt Einstiegspunkt
|
||||
- **Die funktionale Reihenfolge** von Init, Update und Shutdown
|
||||
- **EventBus-Processing** in OnWorldUpdate() — als Subsystem wrappen
|
||||
- **Queue Health Monitoring** — als Teil des EventBus-Subsystems wrappen
|
||||
|
||||
### Was besonders beachtet werden muss
|
||||
- Die **Bot-Login-Trigger-Logik** (`static bool loginTriggered`) muss erhalten bleiben
|
||||
- **Dependency-Wiring** zwischen Subsystemen muss erhalten bleiben. Z.B.:
|
||||
```cpp
|
||||
sDemandCalculator->SetActivityTracker(sPlayerActivityTracker);
|
||||
sDemandCalculator->SetProtectionRegistry(sBotProtectionRegistry);
|
||||
sDemandCalculator->SetFlowPredictor(sBracketFlowPredictor);
|
||||
```
|
||||
Diese Calls gehören in den `Initialize()` des DemandCalculator-Adapters.
|
||||
- Die **BotRetirementManager** braucht ebenfalls Wiring: `sBotRetirementManager->SetProtectionRegistry(sBotProtectionRegistry)`
|
||||
- **Exception-Safety** in OnWorldUpdate() beibehalten (try-catch mit Module-Disable)
|
||||
- Das **NOTE über doppelte Updates** (ModuleUpdateManager vs ModuleManager) beachten
|
||||
|
||||
### Shutdown-Reihenfolge
|
||||
Die Shutdown-Reihenfolge ist NICHT einfach die umgekehrte Init-Reihenfolge. Die Registry braucht ein separates `shutdownOrder`-Feld. Analysiere die aktuelle Shutdown-Reihenfolge in `PlayerbotModule::Shutdown()` und bilde sie korrekt ab.
|
||||
|
||||
### Thread-Safety
|
||||
Die Registry wird NUR vom World Thread aufgerufen — kein Multi-Thread-Zugriff. Daher braucht die Registry selbst KEINE Mutex-Protection.
|
||||
|
||||
---
|
||||
|
||||
## Subsystem-Liste (aus aktueller PlayerbotModule.cpp extrahiert)
|
||||
|
||||
### InitializeManagers() Reihenfolge:
|
||||
1. BotAccountMgr (CRITICAL)
|
||||
2. BotNameMgr (CRITICAL)
|
||||
3. BotCharacterDistribution (CRITICAL)
|
||||
4. BotWorldSessionMgr (CRITICAL)
|
||||
5. BotPacketRelay
|
||||
6. BotChatCommandHandler
|
||||
7. ProfessionDatabase
|
||||
8. ProfessionEventBus (lazy init, evtl. kein Adapter nötig)
|
||||
9. ClassBehaviorTreeRegistry
|
||||
10. QuestHubDatabase
|
||||
11. PortalDatabase (non-fatal)
|
||||
12. BotGearFactory
|
||||
13. PlayerbotPacketSniffer
|
||||
14. BG/LFG Typed Packet Handlers
|
||||
15. MajorCooldownTracker
|
||||
16. BotActionManager
|
||||
17. BotProtectionRegistry (non-fatal)
|
||||
18. BotRetirementManager (non-fatal, braucht ProtectionRegistry)
|
||||
19. BracketFlowPredictor (non-fatal)
|
||||
20. PlayerActivityTracker (non-fatal)
|
||||
21. DemandCalculator (non-fatal, braucht ActivityTracker/ProtectionRegistry/FlowPredictor)
|
||||
22. PopulationLifecycleController (non-fatal)
|
||||
23. ContentRequirementDb (non-fatal)
|
||||
24. BotTemplateRepository (non-fatal)
|
||||
25. BotCloneEngine (non-fatal)
|
||||
26. BotPostLoginConfigurator (non-fatal)
|
||||
27. InstanceBotPool (non-fatal)
|
||||
28. JITBotFactory (non-fatal)
|
||||
29. QueueStatePoller (non-fatal)
|
||||
30. QueueShortageSubscriber (non-fatal)
|
||||
31. InstanceBotOrchestrator (non-fatal)
|
||||
32. InstanceBotHooks (non-fatal)
|
||||
33. BotOperationTracker
|
||||
|
||||
### OnWorldUpdate() Reihenfolge:
|
||||
1. BotAccountMgr
|
||||
2. BotSpawner
|
||||
3. BotWorldSessionMgr
|
||||
4. PlayerbotCharDB
|
||||
5. GroupEventBus
|
||||
6. Domain EventBuses (Combat, Loot, Quest, Aura, Cooldown, Resource, Social, Auction, NPC, Instance, Profession)
|
||||
7. Queue Health Monitoring (every 60s, kann Teil des EventBus-Subsystems sein)
|
||||
8. BotProtectionRegistry
|
||||
9. BotRetirementManager
|
||||
10. BracketFlowPredictor
|
||||
11. PlayerActivityTracker
|
||||
12. DemandCalculator
|
||||
13. PopulationLifecycleController
|
||||
14. InstanceBotPool
|
||||
15. InstanceBotOrchestrator
|
||||
16. JITBotFactory
|
||||
17. QueueStatePoller
|
||||
|
||||
### Shutdown() Reihenfolge (aktuell):
|
||||
1. BotActionManager
|
||||
2. PopulationLifecycleController
|
||||
3. InstanceBotHooks
|
||||
4. InstanceBotOrchestrator
|
||||
5. QueueShortageSubscriber
|
||||
6. QueueStatePoller
|
||||
7. JITBotFactory
|
||||
8. InstanceBotPool
|
||||
9. BotCloneEngine
|
||||
10. BotPostLoginConfigurator
|
||||
11. BotTemplateRepository
|
||||
12. BotOperationTracker (PrintStatus + Shutdown)
|
||||
13. DemandCalculator
|
||||
14. PlayerActivityTracker
|
||||
15. BracketFlowPredictor
|
||||
16. BotRetirementManager
|
||||
17. BotProtectionRegistry
|
||||
18. UnregisterHooks + UnregisterModule
|
||||
19. BotChatCommandHandler
|
||||
20. BotPacketRelay
|
||||
21. PlayerbotPacketSniffer
|
||||
22. BotWorldSessionMgr
|
||||
23. BotNameMgr
|
||||
24. BotAccountMgr
|
||||
25. PlayerbotDatabase (ShutdownDatabase)
|
||||
26. PlayerbotCharDB
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] Alle 3 God-Functions (Init/Update/Shutdown) sind auf je ~10-20 Zeilen geschrumpft
|
||||
- [ ] SubsystemRegistry existiert mit automatischem Performance-Profiling
|
||||
- [ ] Alle Subsysteme sind als Adapter registriert
|
||||
- [ ] Init/Update/Shutdown-Reihenfolge ist exakt wie vorher
|
||||
- [ ] Startup-Log ist kompakt und übersichtlich (gruppiert, mit Timing, mit Zusammenfassung)
|
||||
- [ ] Alle Logs nutzen einheitlich `"module.playerbot"` Channel
|
||||
- [ ] Keine `TC_LOG_ERROR` für informative Meldungen
|
||||
- [ ] Debug-Leftovers in PlayerbotModuleAdapter entfernt
|
||||
- [ ] Performance-Warning zeigt Top-5 langsamste Subsysteme
|
||||
- [ ] Build kompiliert fehlerfrei mit `RelWithDebInfo`
|
||||
- [ ] Keine funktionalen Änderungen — reines Refactoring
|
||||
- [ ] Dependency-Wiring zwischen Subsystemen funktioniert korrekt
|
||||
- [ ] Bot-Login-Trigger-Logik funktioniert weiterhin
|
||||
@@ -584,6 +584,63 @@ public:
|
||||
Events::EventDispatcher* GetEventDispatcher() { return _gameSystems ? _gameSystems->GetEventDispatcher() : nullptr; }
|
||||
Events::EventDispatcher const* GetEventDispatcher() const { return _gameSystems ? _gameSystems->GetEventDispatcher() : nullptr; }
|
||||
|
||||
// ========================================================================
|
||||
// SPRINT 3: COMBAT COORDINATION - Cross-bot coordination via claims
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Get Combat Coordination Integrator
|
||||
* Bridges existing combat managers with BotMessageBus claim system
|
||||
* @return Pointer to CombatCoordinationIntegrator, or nullptr if not initialized
|
||||
*/
|
||||
class CombatCoordinationIntegrator* GetCombatCoordinationIntegrator()
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetCombatCoordinationIntegrator() : nullptr;
|
||||
}
|
||||
class CombatCoordinationIntegrator const* GetCombatCoordinationIntegrator() const
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetCombatCoordinationIntegrator() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Dispel Coordinator for dispel rotation (GAP 2 fix)
|
||||
* @return Pointer to DispelCoordinator, or nullptr if not initialized
|
||||
*/
|
||||
class DispelCoordinator* GetDispelCoordinator()
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetDispelCoordinator() : nullptr;
|
||||
}
|
||||
class DispelCoordinator const* GetDispelCoordinator() const
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetDispelCoordinator() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Interrupt Rotation Manager
|
||||
* @return Pointer to InterruptRotationManager, or nullptr if not initialized
|
||||
*/
|
||||
class InterruptRotationManager* GetInterruptRotationManager()
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetInterruptRotationManager() : nullptr;
|
||||
}
|
||||
class InterruptRotationManager const* GetInterruptRotationManager() const
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetInterruptRotationManager() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Defensive Behavior Manager for external CD coordination (GAP 3 fix)
|
||||
* @return Pointer to DefensiveBehaviorManager, or nullptr if not initialized
|
||||
*/
|
||||
class DefensiveBehaviorManager* GetDefensiveBehaviorManager()
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetDefensiveBehaviorManager() : nullptr;
|
||||
}
|
||||
class DefensiveBehaviorManager const* GetDefensiveBehaviorManager() const
|
||||
{
|
||||
return _gameSystems ? _gameSystems->GetDefensiveBehaviorManager() : nullptr;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// ST-1: ADAPTIVE AI UPDATE THROTTLING - Performance optimization
|
||||
// ========================================================================
|
||||
|
||||
@@ -0,0 +1,800 @@
|
||||
/*
|
||||
* Copyright (C) 2024 TrinityCore <https://www.trinitycore.org/>
|
||||
*
|
||||
* Sprint 3: Combat Coordination Integration Layer Implementation
|
||||
*/
|
||||
|
||||
#include "CombatCoordinationIntegrator.h"
|
||||
#include "InterruptCoordinator.h"
|
||||
#include "AI/CombatBehaviors/DefensiveBehaviorManager.h"
|
||||
#include "CrowdControlManager.h"
|
||||
#include "AI/CombatBehaviors/DispelCoordinator.h"
|
||||
#include "AI/BotAI.h"
|
||||
#include "Group/GroupRoleEnums.h"
|
||||
#include "Player.h"
|
||||
#include "Group.h"
|
||||
#include "Unit.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace Playerbot
|
||||
{
|
||||
|
||||
// ============================================================================
|
||||
// EXTERNAL CD DATABASE
|
||||
// ============================================================================
|
||||
|
||||
static std::unordered_map<uint32, ExternalCDInfo> s_externalCDDatabase;
|
||||
static bool s_databaseInitialized = false;
|
||||
|
||||
const std::unordered_map<uint32, ExternalCDInfo>& ExternalCDInfo::GetDatabase()
|
||||
{
|
||||
if (!s_databaseInitialized)
|
||||
{
|
||||
// Major External CDs (single target, life-saving)
|
||||
s_externalCDDatabase[47788] = { 47788, ExternalCDTier::TIER_MAJOR, 180000, 10000, false, true }; // Guardian Spirit
|
||||
s_externalCDDatabase[33206] = { 33206, ExternalCDTier::TIER_MAJOR, 180000, 8000, false, true }; // Pain Suppression
|
||||
s_externalCDDatabase[102342] = { 102342, ExternalCDTier::TIER_MAJOR, 90000, 12000, false, true }; // Ironbark
|
||||
s_externalCDDatabase[116849] = { 116849, ExternalCDTier::TIER_MAJOR, 120000, 12000, false, true }; // Life Cocoon
|
||||
|
||||
// Moderate External CDs
|
||||
s_externalCDDatabase[6940] = { 6940, ExternalCDTier::TIER_MODERATE, 120000, 12000, false, true }; // Blessing of Sacrifice
|
||||
s_externalCDDatabase[114030] = { 114030, ExternalCDTier::TIER_MODERATE, 120000, 12000, false, true }; // Vigilance
|
||||
|
||||
// Minor/Group CDs
|
||||
s_externalCDDatabase[62618] = { 62618, ExternalCDTier::TIER_MINOR, 180000, 10000, true, false }; // Power Word: Barrier
|
||||
s_externalCDDatabase[196718] = { 196718, ExternalCDTier::TIER_MINOR, 180000, 8000, true, false }; // Darkness
|
||||
s_externalCDDatabase[51052] = { 51052, ExternalCDTier::TIER_MINOR, 120000, 10000, true, false }; // Anti-Magic Zone
|
||||
|
||||
// Raid CDs
|
||||
s_externalCDDatabase[97462] = { 97462, ExternalCDTier::TIER_RAID, 180000, 10000, true, false }; // Rallying Cry
|
||||
s_externalCDDatabase[98008] = { 98008, ExternalCDTier::TIER_RAID, 180000, 6000, true, false }; // Spirit Link Totem
|
||||
s_externalCDDatabase[31821] = { 31821, ExternalCDTier::TIER_RAID, 180000, 8000, true, false }; // Aura Mastery
|
||||
s_externalCDDatabase[108280] = { 108280, ExternalCDTier::TIER_RAID, 180000, 10000, true, false }; // Healing Tide Totem
|
||||
|
||||
s_databaseInitialized = true;
|
||||
}
|
||||
return s_externalCDDatabase;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CONSTRUCTOR / DESTRUCTOR
|
||||
// ============================================================================
|
||||
|
||||
CombatCoordinationIntegrator::CombatCoordinationIntegrator(BotAI* ai)
|
||||
: _ai(ai)
|
||||
, _bot(ai ? ai->GetBot() : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CombatCoordinationIntegrator::~CombatCoordinationIntegrator()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LIFECYCLE
|
||||
// ============================================================================
|
||||
|
||||
void CombatCoordinationIntegrator::Initialize(
|
||||
InterruptCoordinatorFixed* interruptCoord,
|
||||
DefensiveBehaviorManager* defensiveMgr,
|
||||
CrowdControlManager* ccMgr,
|
||||
DispelCoordinator* dispelCoord)
|
||||
{
|
||||
_interruptCoord = interruptCoord;
|
||||
_defensiveMgr = defensiveMgr;
|
||||
_ccMgr = ccMgr;
|
||||
_dispelCoord = dispelCoord;
|
||||
|
||||
// Ensure database is initialized
|
||||
ExternalCDInfo::GetDatabase();
|
||||
|
||||
// Get group GUID for message bus subscription
|
||||
if (_bot && _bot->GetGroup())
|
||||
{
|
||||
_groupGuid = _bot->GetGroup()->GetGUID();
|
||||
SubscribeToMessageBus();
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("playerbot.combat", "CombatCoordinationIntegrator::Initialize - Bot {} initialized",
|
||||
_bot ? _bot->GetGUID().ToString() : "null");
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::Shutdown()
|
||||
{
|
||||
UnsubscribeFromMessageBus();
|
||||
_activeClaims.clear();
|
||||
_protectionWindows.clear();
|
||||
|
||||
_interruptCoord = nullptr;
|
||||
_defensiveMgr = nullptr;
|
||||
_ccMgr = nullptr;
|
||||
_dispelCoord = nullptr;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::Update(uint32 diff)
|
||||
{
|
||||
if (!_bot || !_bot->IsAlive())
|
||||
return;
|
||||
|
||||
uint32 now = GameTime::GetGameTimeMS();
|
||||
if (now - _lastUpdate < UPDATE_INTERVAL_MS)
|
||||
return;
|
||||
_lastUpdate = now;
|
||||
|
||||
// Update protection windows (expire old ones)
|
||||
UpdateProtectionWindows();
|
||||
|
||||
// Check if group changed
|
||||
if (_bot->GetGroup())
|
||||
{
|
||||
ObjectGuid newGroupGuid = _bot->GetGroup()->GetGUID();
|
||||
if (newGroupGuid != _groupGuid)
|
||||
{
|
||||
UnsubscribeFromMessageBus();
|
||||
_groupGuid = newGroupGuid;
|
||||
SubscribeToMessageBus();
|
||||
}
|
||||
}
|
||||
|
||||
// Expire old claims
|
||||
auto claimIt = _activeClaims.begin();
|
||||
while (claimIt != _activeClaims.end())
|
||||
{
|
||||
auto elapsed = std::chrono::steady_clock::now() - claimIt->second.submitTime;
|
||||
if (elapsed > std::chrono::milliseconds(_config.claimTimeoutMs * 10)) // 10x timeout for cleanup
|
||||
{
|
||||
claimIt = _activeClaims.erase(claimIt);
|
||||
}
|
||||
else
|
||||
{
|
||||
++claimIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// INTERRUPT COORDINATION (S3.4)
|
||||
// ============================================================================
|
||||
|
||||
bool CombatCoordinationIntegrator::RequestInterrupt(ObjectGuid targetGuid, uint32 spellId, ClaimPriority priority)
|
||||
{
|
||||
if (!_config.enableInterruptClaims || !_bot || _groupGuid.IsEmpty())
|
||||
return false;
|
||||
|
||||
// Create interrupt claim message
|
||||
BotMessage msg = BotMessage::ClaimInterrupt(
|
||||
_bot->GetGUID(),
|
||||
_groupGuid,
|
||||
targetGuid,
|
||||
spellId,
|
||||
priority
|
||||
);
|
||||
|
||||
// Submit through BotMessageBus
|
||||
auto callback = [this](BotMessage const& m, ClaimStatus s) {
|
||||
OnClaimResolved(m, s);
|
||||
};
|
||||
|
||||
ClaimStatus status = BotMessageBus::Instance().SubmitClaim(msg, callback);
|
||||
|
||||
// Track the claim
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_INTERRUPT) << 56);
|
||||
ActiveClaim claim;
|
||||
claim.type = BotMessageType::CLAIM_INTERRUPT;
|
||||
claim.targetGuid = targetGuid;
|
||||
claim.spellOrAuraId = spellId;
|
||||
claim.status = status;
|
||||
claim.submitTime = std::chrono::steady_clock::now();
|
||||
_activeClaims[claimKey] = claim;
|
||||
|
||||
_metrics.interruptClaimsSubmitted++;
|
||||
|
||||
return status != ClaimStatus::REJECTED;
|
||||
}
|
||||
|
||||
bool CombatCoordinationIntegrator::ShouldInterrupt(ObjectGuid& targetGuid, uint32& spellId) const
|
||||
{
|
||||
// Find active interrupt claim that was accepted
|
||||
for (auto const& [key, claim] : _activeClaims)
|
||||
{
|
||||
if (claim.type == BotMessageType::CLAIM_INTERRUPT &&
|
||||
claim.status == ClaimStatus::ACCEPTED)
|
||||
{
|
||||
targetGuid = claim.targetGuid;
|
||||
spellId = GetInterruptSpell();
|
||||
return spellId != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::OnInterruptExecuted(ObjectGuid targetGuid, uint32 spellId, bool success)
|
||||
{
|
||||
// Remove the claim
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_INTERRUPT) << 56);
|
||||
_activeClaims.erase(claimKey);
|
||||
|
||||
// Announce via message bus
|
||||
if (_bot && !_groupGuid.IsEmpty())
|
||||
{
|
||||
BotMessage msg;
|
||||
msg.type = BotMessageType::ANNOUNCE_CD_USAGE;
|
||||
msg.senderGuid = _bot->GetGUID();
|
||||
msg.groupGuid = _groupGuid;
|
||||
msg.targetGuid = targetGuid;
|
||||
msg.spellId = spellId;
|
||||
msg.timestamp = std::chrono::steady_clock::now();
|
||||
|
||||
BotMessageBus::Instance().Publish(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// DISPEL COORDINATION (S3.2 - GAP 2 Fix)
|
||||
// ============================================================================
|
||||
|
||||
bool CombatCoordinationIntegrator::RequestDispel(ObjectGuid targetGuid, uint32 auraId, ClaimPriority priority)
|
||||
{
|
||||
if (!_config.enableDispelClaims || !_bot || _groupGuid.IsEmpty())
|
||||
return false;
|
||||
|
||||
BotMessage msg = BotMessage::ClaimDispel(
|
||||
_bot->GetGUID(),
|
||||
_groupGuid,
|
||||
targetGuid,
|
||||
auraId,
|
||||
priority
|
||||
);
|
||||
|
||||
auto callback = [this](BotMessage const& m, ClaimStatus s) {
|
||||
OnClaimResolved(m, s);
|
||||
};
|
||||
|
||||
ClaimStatus status = BotMessageBus::Instance().SubmitClaim(msg, callback);
|
||||
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_DISPEL) << 56) ^ auraId;
|
||||
ActiveClaim claim;
|
||||
claim.type = BotMessageType::CLAIM_DISPEL;
|
||||
claim.targetGuid = targetGuid;
|
||||
claim.spellOrAuraId = auraId;
|
||||
claim.status = status;
|
||||
claim.submitTime = std::chrono::steady_clock::now();
|
||||
_activeClaims[claimKey] = claim;
|
||||
|
||||
_metrics.dispelClaimsSubmitted++;
|
||||
|
||||
return status != ClaimStatus::REJECTED;
|
||||
}
|
||||
|
||||
bool CombatCoordinationIntegrator::ShouldDispel(ObjectGuid& targetGuid, uint32& auraId) const
|
||||
{
|
||||
for (auto const& [key, claim] : _activeClaims)
|
||||
{
|
||||
if (claim.type == BotMessageType::CLAIM_DISPEL &&
|
||||
claim.status == ClaimStatus::ACCEPTED)
|
||||
{
|
||||
targetGuid = claim.targetGuid;
|
||||
auraId = claim.spellOrAuraId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::OnDispelExecuted(ObjectGuid targetGuid, uint32 auraId, bool success)
|
||||
{
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_DISPEL) << 56) ^ auraId;
|
||||
_activeClaims.erase(claimKey);
|
||||
}
|
||||
|
||||
float CombatCoordinationIntegrator::CalculateDispelPriority(ObjectGuid targetGuid, uint32 auraId) const
|
||||
{
|
||||
if (!_bot)
|
||||
return 0.0f;
|
||||
|
||||
float priority = 0.0f;
|
||||
|
||||
// Base priority from aura danger
|
||||
if (_dispelCoord)
|
||||
{
|
||||
if (_dispelCoord->ShouldDispel(auraId))
|
||||
priority += 50.0f;
|
||||
}
|
||||
|
||||
// Can dispel type bonus (+100)
|
||||
SpellInfo const* auraSpell = sSpellMgr->GetSpellInfo(auraId, DIFFICULTY_NONE);
|
||||
if (auraSpell && CanDispelType(auraSpell->Dispel))
|
||||
priority += 100.0f;
|
||||
|
||||
// Distance bonus (+50 if in range)
|
||||
float distance = GetDistanceToTarget(targetGuid);
|
||||
if (distance < 40.0f)
|
||||
priority += 50.0f;
|
||||
|
||||
// CD available bonus (+200 if not on CD)
|
||||
// This would check dispel cooldown
|
||||
|
||||
// Healer bonus (+30)
|
||||
if (_bot && IsPlayerHealer(_bot))
|
||||
priority += 30.0f;
|
||||
|
||||
// GCD free bonus (+20)
|
||||
// Would check GCD state
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EXTERNAL DEFENSIVE CD COORDINATION (S3.3 - GAP 3 Fix)
|
||||
// ============================================================================
|
||||
|
||||
bool CombatCoordinationIntegrator::RequestExternalDefensive(ObjectGuid targetGuid, DangerLevel danger)
|
||||
{
|
||||
if (!_config.enableDefensiveClaims || !_bot || _groupGuid.IsEmpty())
|
||||
return false;
|
||||
|
||||
// Don't request if target is already protected
|
||||
if (IsTargetProtected(targetGuid))
|
||||
return false;
|
||||
|
||||
// Determine appropriate CD tier for danger level
|
||||
ExternalCDTier maxTier = GetAppropriateCDTier(danger);
|
||||
|
||||
// Get available CDs we can provide
|
||||
std::vector<uint32> availableCDs = GetAvailableExternalCDs(maxTier);
|
||||
if (availableCDs.empty())
|
||||
return false;
|
||||
|
||||
// Select best CD for the situation
|
||||
uint32 cdSpellId = availableCDs[0]; // Simple: use first available
|
||||
|
||||
ClaimPriority priority = ClaimPriority::MEDIUM;
|
||||
if (danger >= DangerLevel::CRITICAL)
|
||||
priority = ClaimPriority::CRITICAL;
|
||||
else if (danger >= DangerLevel::HIGH)
|
||||
priority = ClaimPriority::HIGH;
|
||||
|
||||
BotMessage msg = BotMessage::ClaimDefensiveCD(
|
||||
_bot->GetGUID(),
|
||||
_groupGuid,
|
||||
targetGuid,
|
||||
cdSpellId,
|
||||
priority
|
||||
);
|
||||
|
||||
auto callback = [this](BotMessage const& m, ClaimStatus s) {
|
||||
OnClaimResolved(m, s);
|
||||
};
|
||||
|
||||
ClaimStatus status = BotMessageBus::Instance().SubmitClaim(msg, callback);
|
||||
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_DEFENSIVE_CD) << 56);
|
||||
ActiveClaim claim;
|
||||
claim.type = BotMessageType::CLAIM_DEFENSIVE_CD;
|
||||
claim.targetGuid = targetGuid;
|
||||
claim.spellOrAuraId = cdSpellId;
|
||||
claim.status = status;
|
||||
claim.submitTime = std::chrono::steady_clock::now();
|
||||
_activeClaims[claimKey] = claim;
|
||||
|
||||
_metrics.defensiveClaimsSubmitted++;
|
||||
|
||||
return status != ClaimStatus::REJECTED;
|
||||
}
|
||||
|
||||
bool CombatCoordinationIntegrator::ShouldProvideExternalCD(ObjectGuid& targetGuid, uint32& spellId) const
|
||||
{
|
||||
for (auto const& [key, claim] : _activeClaims)
|
||||
{
|
||||
if (claim.type == BotMessageType::CLAIM_DEFENSIVE_CD &&
|
||||
claim.status == ClaimStatus::ACCEPTED)
|
||||
{
|
||||
targetGuid = claim.targetGuid;
|
||||
spellId = claim.spellOrAuraId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::OnExternalCDUsed(ObjectGuid targetGuid, uint32 spellId)
|
||||
{
|
||||
// Remove claim
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_DEFENSIVE_CD) << 56);
|
||||
_activeClaims.erase(claimKey);
|
||||
|
||||
// Create protection window (GAP 3 fix)
|
||||
auto& db = ExternalCDInfo::GetDatabase();
|
||||
auto it = db.find(spellId);
|
||||
|
||||
ProtectionWindow window;
|
||||
window.targetGuid = targetGuid;
|
||||
window.protectorGuid = _bot ? _bot->GetGUID() : ObjectGuid::Empty;
|
||||
window.spellId = spellId;
|
||||
window.tier = (it != db.end()) ? it->second.tier : ExternalCDTier::TIER_MINOR;
|
||||
window.startTime = std::chrono::steady_clock::now();
|
||||
window.endTime = window.startTime + std::chrono::milliseconds(_config.protectionWindowMs);
|
||||
|
||||
_protectionWindows.push_back(window);
|
||||
_metrics.protectionWindowsCreated++;
|
||||
|
||||
// Announce CD usage
|
||||
if (_bot && !_groupGuid.IsEmpty())
|
||||
{
|
||||
BotMessage msg;
|
||||
msg.type = BotMessageType::ANNOUNCE_CD_USAGE;
|
||||
msg.senderGuid = _bot->GetGUID();
|
||||
msg.groupGuid = _groupGuid;
|
||||
msg.targetGuid = targetGuid;
|
||||
msg.spellId = spellId;
|
||||
msg.timestamp = std::chrono::steady_clock::now();
|
||||
|
||||
BotMessageBus::Instance().Publish(msg);
|
||||
}
|
||||
}
|
||||
|
||||
bool CombatCoordinationIntegrator::IsTargetProtected(ObjectGuid targetGuid) const
|
||||
{
|
||||
for (auto const& window : _protectionWindows)
|
||||
{
|
||||
if (window.targetGuid == targetGuid && window.IsActive())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 CombatCoordinationIntegrator::GetProtectionRemaining(ObjectGuid targetGuid) const
|
||||
{
|
||||
for (auto const& window : _protectionWindows)
|
||||
{
|
||||
if (window.targetGuid == targetGuid && window.IsActive())
|
||||
return window.GetRemainingMs();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DangerLevel CombatCoordinationIntegrator::AssessDanger(ObjectGuid targetGuid) const
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*_bot, targetGuid);
|
||||
if (!target || !target->IsAlive())
|
||||
return DangerLevel::NONE;
|
||||
|
||||
float healthPct = target->GetHealthPct() / 100.0f;
|
||||
|
||||
if (healthPct < _config.dangerHealthCritical)
|
||||
return DangerLevel::CRITICAL;
|
||||
if (healthPct < _config.dangerHealthHigh)
|
||||
return DangerLevel::HIGH;
|
||||
if (healthPct < _config.dangerHealthModerate)
|
||||
return DangerLevel::MODERATE;
|
||||
|
||||
return DangerLevel::NONE;
|
||||
}
|
||||
|
||||
ExternalCDTier CombatCoordinationIntegrator::GetAppropriateCDTier(DangerLevel danger) const
|
||||
{
|
||||
// Per GAP 3: Don't waste major CDs on moderate danger
|
||||
switch (danger)
|
||||
{
|
||||
case DangerLevel::CRITICAL:
|
||||
case DangerLevel::PRE_DANGER:
|
||||
return ExternalCDTier::TIER_MAJOR;
|
||||
case DangerLevel::HIGH:
|
||||
return ExternalCDTier::TIER_MODERATE;
|
||||
case DangerLevel::MODERATE:
|
||||
return ExternalCDTier::TIER_MINOR;
|
||||
default:
|
||||
return ExternalCDTier::TIER_MINOR;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CC COORDINATION (S3.6)
|
||||
// ============================================================================
|
||||
|
||||
bool CombatCoordinationIntegrator::RequestCC(ObjectGuid targetGuid, uint32 spellId, ClaimPriority priority)
|
||||
{
|
||||
if (!_config.enableCCClaims || !_bot || _groupGuid.IsEmpty())
|
||||
return false;
|
||||
|
||||
BotMessage msg = BotMessage::ClaimCC(
|
||||
_bot->GetGUID(),
|
||||
_groupGuid,
|
||||
targetGuid,
|
||||
spellId,
|
||||
priority
|
||||
);
|
||||
|
||||
auto callback = [this](BotMessage const& m, ClaimStatus s) {
|
||||
OnClaimResolved(m, s);
|
||||
};
|
||||
|
||||
ClaimStatus status = BotMessageBus::Instance().SubmitClaim(msg, callback);
|
||||
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_CC) << 56);
|
||||
ActiveClaim claim;
|
||||
claim.type = BotMessageType::CLAIM_CC;
|
||||
claim.targetGuid = targetGuid;
|
||||
claim.spellOrAuraId = spellId;
|
||||
claim.status = status;
|
||||
claim.submitTime = std::chrono::steady_clock::now();
|
||||
_activeClaims[claimKey] = claim;
|
||||
|
||||
_metrics.ccClaimsSubmitted++;
|
||||
|
||||
return status != ClaimStatus::REJECTED;
|
||||
}
|
||||
|
||||
bool CombatCoordinationIntegrator::ShouldCC(ObjectGuid& targetGuid, uint32& spellId) const
|
||||
{
|
||||
for (auto const& [key, claim] : _activeClaims)
|
||||
{
|
||||
if (claim.type == BotMessageType::CLAIM_CC &&
|
||||
claim.status == ClaimStatus::ACCEPTED)
|
||||
{
|
||||
targetGuid = claim.targetGuid;
|
||||
spellId = claim.spellOrAuraId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::OnCCExecuted(ObjectGuid targetGuid, uint32 spellId, bool success)
|
||||
{
|
||||
uint64 claimKey = targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_CC) << 56);
|
||||
_activeClaims.erase(claimKey);
|
||||
|
||||
// Update CC manager's DR tracking
|
||||
if (_ccMgr && success)
|
||||
{
|
||||
_ccMgr->OnCCApplied(targetGuid, spellId);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CLAIM CALLBACKS
|
||||
// ============================================================================
|
||||
|
||||
void CombatCoordinationIntegrator::OnClaimResolved(BotMessage const& message, ClaimStatus status)
|
||||
{
|
||||
uint64 claimKey = 0;
|
||||
|
||||
switch (message.type)
|
||||
{
|
||||
case BotMessageType::CLAIM_INTERRUPT:
|
||||
claimKey = message.targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_INTERRUPT) << 56);
|
||||
if (status == ClaimStatus::ACCEPTED)
|
||||
_metrics.interruptClaimsWon++;
|
||||
else
|
||||
_metrics.interruptClaimsLost++;
|
||||
break;
|
||||
|
||||
case BotMessageType::CLAIM_DISPEL:
|
||||
claimKey = message.targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_DISPEL) << 56) ^ message.auraId;
|
||||
if (status == ClaimStatus::ACCEPTED)
|
||||
_metrics.dispelClaimsWon++;
|
||||
else
|
||||
_metrics.dispelClaimsLost++;
|
||||
break;
|
||||
|
||||
case BotMessageType::CLAIM_DEFENSIVE_CD:
|
||||
claimKey = message.targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_DEFENSIVE_CD) << 56);
|
||||
if (status == ClaimStatus::ACCEPTED)
|
||||
_metrics.defensiveClaimsWon++;
|
||||
else
|
||||
_metrics.defensiveClaimsLost++;
|
||||
break;
|
||||
|
||||
case BotMessageType::CLAIM_CC:
|
||||
claimKey = message.targetGuid.GetRawValue() ^ (static_cast<uint64>(BotMessageType::CLAIM_CC) << 56);
|
||||
if (status == ClaimStatus::ACCEPTED)
|
||||
_metrics.ccClaimsWon++;
|
||||
else
|
||||
_metrics.ccClaimsLost++;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Update claim status
|
||||
auto it = _activeClaims.find(claimKey);
|
||||
if (it != _activeClaims.end())
|
||||
{
|
||||
it->second.status = status;
|
||||
it->second.resolveTime = std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// INTERNAL METHODS
|
||||
// ============================================================================
|
||||
|
||||
void CombatCoordinationIntegrator::SubscribeToMessageBus()
|
||||
{
|
||||
if (_subscribed || _groupGuid.IsEmpty() || !_bot)
|
||||
return;
|
||||
|
||||
uint8 role = _ai ? _ai->GetRole() : 0;
|
||||
uint8 subgroup = 0;
|
||||
|
||||
if (_bot->GetGroup())
|
||||
{
|
||||
Group::MemberSlot const* slot = _bot->GetGroup()->GetMemberSlot(_bot->GetGUID());
|
||||
if (slot)
|
||||
subgroup = slot->group;
|
||||
}
|
||||
|
||||
_subscriptionId = BotMessageBus::Instance().Subscribe(
|
||||
_groupGuid,
|
||||
_bot->GetGUID(),
|
||||
role,
|
||||
subgroup,
|
||||
[this](BotMessage const& msg) { OnBotMessage(msg); }
|
||||
);
|
||||
|
||||
_subscribed = true;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::UnsubscribeFromMessageBus()
|
||||
{
|
||||
if (!_subscribed)
|
||||
return;
|
||||
|
||||
BotMessageBus::Instance().Unsubscribe(_groupGuid, _bot->GetGUID());
|
||||
_subscribed = false;
|
||||
_subscriptionId = 0;
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::OnBotMessage(BotMessage const& message)
|
||||
{
|
||||
// Handle incoming messages from other bots
|
||||
switch (message.type)
|
||||
{
|
||||
case BotMessageType::ANNOUNCE_CD_USAGE:
|
||||
// Track that another bot used a CD - could inform our CD planning
|
||||
break;
|
||||
|
||||
case BotMessageType::REQUEST_HEAL:
|
||||
// Could trigger external defensive if we have one
|
||||
break;
|
||||
|
||||
case BotMessageType::REQUEST_EXTERNAL_CD:
|
||||
// Another bot is requesting external CD
|
||||
{
|
||||
DangerLevel danger = AssessDanger(message.targetGuid);
|
||||
if (danger >= DangerLevel::HIGH)
|
||||
{
|
||||
RequestExternalDefensive(message.targetGuid, danger);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CombatCoordinationIntegrator::UpdateProtectionWindows()
|
||||
{
|
||||
auto it = _protectionWindows.begin();
|
||||
while (it != _protectionWindows.end())
|
||||
{
|
||||
if (!it->IsActive())
|
||||
{
|
||||
it = _protectionWindows.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32> CombatCoordinationIntegrator::GetAvailableExternalCDs(ExternalCDTier maxTier) const
|
||||
{
|
||||
std::vector<uint32> result;
|
||||
|
||||
if (!_bot)
|
||||
return result;
|
||||
|
||||
auto const& db = ExternalCDInfo::GetDatabase();
|
||||
for (auto const& [spellId, info] : db)
|
||||
{
|
||||
// Check tier
|
||||
if (static_cast<uint8>(info.tier) > static_cast<uint8>(maxTier))
|
||||
continue;
|
||||
|
||||
// Check if bot knows spell and it's not on cooldown
|
||||
if (_bot->HasSpell(spellId) && !_bot->GetSpellHistory()->HasCooldown(spellId))
|
||||
{
|
||||
result.push_back(spellId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CombatCoordinationIntegrator::CanDispelType(uint32 dispelMask) const
|
||||
{
|
||||
if (!_bot)
|
||||
return false;
|
||||
|
||||
Classes botClass = static_cast<Classes>(_bot->GetClass());
|
||||
|
||||
// Check by class what dispel types are available
|
||||
switch (botClass)
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
// Priests can dispel Magic, Disease
|
||||
return (dispelMask == DISPEL_MAGIC) || (dispelMask == DISPEL_DISEASE);
|
||||
case CLASS_PALADIN:
|
||||
// Paladins can dispel Disease, Poison, Magic (if Holy)
|
||||
return (dispelMask == DISPEL_DISEASE) || (dispelMask == DISPEL_POISON) || (dispelMask == DISPEL_MAGIC);
|
||||
case CLASS_DRUID:
|
||||
// Druids can dispel Curse, Poison, Magic (if Resto)
|
||||
return (dispelMask == DISPEL_CURSE) || (dispelMask == DISPEL_POISON) || (dispelMask == DISPEL_MAGIC);
|
||||
case CLASS_SHAMAN:
|
||||
// Shamans can dispel Curse, Magic (if Resto)
|
||||
return (dispelMask == DISPEL_CURSE) || (dispelMask == DISPEL_MAGIC);
|
||||
case CLASS_MAGE:
|
||||
// Mages can dispel Curse
|
||||
return (dispelMask == DISPEL_CURSE);
|
||||
case CLASS_MONK:
|
||||
// Monks can dispel Disease, Poison, Magic (if Mistweaver)
|
||||
return (dispelMask == DISPEL_DISEASE) || (dispelMask == DISPEL_POISON) || (dispelMask == DISPEL_MAGIC);
|
||||
case CLASS_EVOKER:
|
||||
// Evokers can dispel Magic, Poison (Preservation)
|
||||
return (dispelMask == DISPEL_MAGIC) || (dispelMask == DISPEL_POISON);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CombatCoordinationIntegrator::GetInterruptSpell() const
|
||||
{
|
||||
if (!_bot)
|
||||
return 0;
|
||||
|
||||
Classes botClass = static_cast<Classes>(_bot->GetClass());
|
||||
|
||||
// Return primary interrupt spell by class
|
||||
switch (botClass)
|
||||
{
|
||||
case CLASS_WARRIOR: return 6552; // Pummel
|
||||
case CLASS_PALADIN: return 96231; // Rebuke
|
||||
case CLASS_HUNTER: return 147362; // Counter Shot
|
||||
case CLASS_ROGUE: return 1766; // Kick
|
||||
case CLASS_PRIEST: return 0; // No interrupt (Silence is 15487 but long CD)
|
||||
case CLASS_DEATH_KNIGHT: return 47528; // Mind Freeze
|
||||
case CLASS_SHAMAN: return 57994; // Wind Shear
|
||||
case CLASS_MAGE: return 2139; // Counterspell
|
||||
case CLASS_WARLOCK: return 119910; // Spell Lock (pet)
|
||||
case CLASS_MONK: return 116705; // Spear Hand Strike
|
||||
case CLASS_DRUID: return 106839; // Skull Bash
|
||||
case CLASS_DEMON_HUNTER: return 183752; // Disrupt
|
||||
case CLASS_EVOKER: return 351338; // Quell
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float CombatCoordinationIntegrator::GetDistanceToTarget(ObjectGuid targetGuid) const
|
||||
{
|
||||
if (!_bot)
|
||||
return 999.0f;
|
||||
|
||||
Unit* target = ObjectAccessor::GetUnit(*_bot, targetGuid);
|
||||
if (!target)
|
||||
return 999.0f;
|
||||
|
||||
return _bot->GetDistance(target);
|
||||
}
|
||||
|
||||
} // namespace Playerbot
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright (C) 2024 TrinityCore <https://www.trinitycore.org/>
|
||||
*
|
||||
* Sprint 3: Combat Coordination Integration Layer
|
||||
* Bridges existing combat managers with BotMessageBus claim system
|
||||
*/
|
||||
|
||||
#ifndef PLAYERBOT_COMBAT_COORDINATION_INTEGRATOR_H
|
||||
#define PLAYERBOT_COMBAT_COORDINATION_INTEGRATOR_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "AI/Coordination/Messaging/BotMessageBus.h"
|
||||
#include "AI/Coordination/Messaging/ClaimResolver.h"
|
||||
#include "Cooldown/CooldownEventBus.h"
|
||||
#include "Cooldown/MajorCooldownTracker.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
|
||||
class Player;
|
||||
class Group;
|
||||
class Unit;
|
||||
|
||||
namespace Playerbot
|
||||
{
|
||||
|
||||
class BotAI;
|
||||
class InterruptCoordinatorFixed;
|
||||
class DefensiveBehaviorManager;
|
||||
class CrowdControlManager;
|
||||
class DispelCoordinator;
|
||||
|
||||
/**
|
||||
* @brief External defensive cooldown tiers for coordination
|
||||
*
|
||||
* Per GAP 3: Major CDs should not be wasted on moderate danger
|
||||
*/
|
||||
enum class ExternalCDTier : uint8
|
||||
{
|
||||
TIER_MAJOR, // Guardian Spirit, Pain Suppression, Ironbark, Life Cocoon
|
||||
TIER_MODERATE, // Blessing of Sacrifice, Vigilance
|
||||
TIER_MINOR, // Power Word: Barrier (group), Darkness, AMZ
|
||||
TIER_RAID, // Rallying Cry, Spirit Link, Devotion Aura, Healing Tide
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Danger level for external CD requests
|
||||
*/
|
||||
enum class DangerLevel : uint8
|
||||
{
|
||||
NONE = 0, // No danger
|
||||
MODERATE = 1, // Sustained damage, manageable
|
||||
HIGH = 2, // Spike incoming, need protection
|
||||
CRITICAL = 3, // Death imminent without intervention
|
||||
PRE_DANGER = 4, // Boss ability incoming (predictive)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tracked protection window for a target
|
||||
*
|
||||
* Per GAP 3: 6s window where target is "protected" after external CD
|
||||
*/
|
||||
struct ProtectionWindow
|
||||
{
|
||||
ObjectGuid targetGuid;
|
||||
ObjectGuid protectorGuid;
|
||||
uint32 spellId = 0;
|
||||
ExternalCDTier tier = ExternalCDTier::TIER_MINOR;
|
||||
std::chrono::steady_clock::time_point startTime;
|
||||
std::chrono::steady_clock::time_point endTime;
|
||||
|
||||
bool IsActive() const
|
||||
{
|
||||
return std::chrono::steady_clock::now() < endTime;
|
||||
}
|
||||
|
||||
uint32 GetRemainingMs() const
|
||||
{
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (now >= endTime) return 0;
|
||||
return static_cast<uint32>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(endTime - now).count());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief External CD database entry
|
||||
*/
|
||||
struct ExternalCDInfo
|
||||
{
|
||||
uint32 spellId;
|
||||
ExternalCDTier tier;
|
||||
uint32 cooldownMs;
|
||||
uint32 durationMs;
|
||||
bool isGroupwide; // AMZ, Barrier, Rallying Cry
|
||||
bool requiresTarget; // Pain Suppression, Guardian Spirit
|
||||
|
||||
static const std::unordered_map<uint32, ExternalCDInfo>& GetDatabase();
|
||||
};
|
||||
|
||||
/**
|
||||
* @class CombatCoordinationIntegrator
|
||||
* @brief Integrates combat managers with BotMessageBus claim system
|
||||
*
|
||||
* Sprint 3 Core Component:
|
||||
* - Routes interrupt claims through BotMessageBus
|
||||
* - Routes dispel claims through BotMessageBus
|
||||
* - Routes external defensive CD claims
|
||||
* - Manages protection windows (GAP 3 fix)
|
||||
* - Coordinates CC claims with DR awareness
|
||||
*
|
||||
* Performance: <0.05ms per Update() per bot
|
||||
*/
|
||||
class TC_GAME_API CombatCoordinationIntegrator
|
||||
{
|
||||
public:
|
||||
explicit CombatCoordinationIntegrator(BotAI* ai);
|
||||
~CombatCoordinationIntegrator();
|
||||
|
||||
// ========================================================================
|
||||
// LIFECYCLE
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Initialize with references to existing managers
|
||||
*/
|
||||
void Initialize(
|
||||
InterruptCoordinatorFixed* interruptCoord,
|
||||
DefensiveBehaviorManager* defensiveMgr,
|
||||
CrowdControlManager* ccMgr,
|
||||
DispelCoordinator* dispelCoord
|
||||
);
|
||||
|
||||
/**
|
||||
* Shutdown and cleanup subscriptions
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* Main update loop - processes claims and coordinates actions
|
||||
* @param diff Milliseconds since last update
|
||||
*/
|
||||
void Update(uint32 diff);
|
||||
|
||||
// ========================================================================
|
||||
// INTERRUPT COORDINATION (S3.4)
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Request to interrupt a spell via claim system
|
||||
* @param targetGuid Caster to interrupt
|
||||
* @param spellId Spell being cast
|
||||
* @param priority Interrupt priority
|
||||
* @return true if claim was submitted
|
||||
*/
|
||||
bool RequestInterrupt(ObjectGuid targetGuid, uint32 spellId, ClaimPriority priority);
|
||||
|
||||
/**
|
||||
* Check if this bot should interrupt (has active claim)
|
||||
* @param targetGuid Out: target to interrupt
|
||||
* @param spellId Out: spell to use
|
||||
* @return true if this bot should interrupt now
|
||||
*/
|
||||
bool ShouldInterrupt(ObjectGuid& targetGuid, uint32& spellId) const;
|
||||
|
||||
/**
|
||||
* Report interrupt result
|
||||
*/
|
||||
void OnInterruptExecuted(ObjectGuid targetGuid, uint32 spellId, bool success);
|
||||
|
||||
// ========================================================================
|
||||
// DISPEL COORDINATION (S3.2 - GAP 2 Fix)
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Request to dispel a debuff via claim system
|
||||
* @param targetGuid Friendly with debuff
|
||||
* @param auraId Debuff to dispel
|
||||
* @param priority Dispel urgency
|
||||
* @return true if claim was submitted
|
||||
*/
|
||||
bool RequestDispel(ObjectGuid targetGuid, uint32 auraId, ClaimPriority priority);
|
||||
|
||||
/**
|
||||
* Check if this bot should dispel (has active claim)
|
||||
* @param targetGuid Out: target to dispel
|
||||
* @param auraId Out: aura to dispel
|
||||
* @return true if this bot should dispel now
|
||||
*/
|
||||
bool ShouldDispel(ObjectGuid& targetGuid, uint32& auraId) const;
|
||||
|
||||
/**
|
||||
* Report dispel result
|
||||
*/
|
||||
void OnDispelExecuted(ObjectGuid targetGuid, uint32 auraId, bool success);
|
||||
|
||||
/**
|
||||
* Calculate dispel priority score
|
||||
* Per S3.2: Priority = base + canDispelType + distance + cdStatus + isHealer + gcdFree
|
||||
*/
|
||||
float CalculateDispelPriority(ObjectGuid targetGuid, uint32 auraId) const;
|
||||
|
||||
// ========================================================================
|
||||
// EXTERNAL DEFENSIVE CD COORDINATION (S3.3 - GAP 3 Fix)
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Request external defensive CD via claim system
|
||||
* @param targetGuid Friendly needing protection
|
||||
* @param danger Current danger level
|
||||
* @return true if claim was submitted
|
||||
*/
|
||||
bool RequestExternalDefensive(ObjectGuid targetGuid, DangerLevel danger);
|
||||
|
||||
/**
|
||||
* Check if this bot should provide external CD
|
||||
* @param targetGuid Out: who to protect
|
||||
* @param spellId Out: which CD to use
|
||||
* @return true if this bot should cast external CD
|
||||
*/
|
||||
bool ShouldProvideExternalCD(ObjectGuid& targetGuid, uint32& spellId) const;
|
||||
|
||||
/**
|
||||
* Report external CD usage
|
||||
*/
|
||||
void OnExternalCDUsed(ObjectGuid targetGuid, uint32 spellId);
|
||||
|
||||
/**
|
||||
* Check if target is currently protected (within danger window)
|
||||
* @param targetGuid Target to check
|
||||
* @return true if target has active protection
|
||||
*/
|
||||
bool IsTargetProtected(ObjectGuid targetGuid) const;
|
||||
|
||||
/**
|
||||
* Get protection window remaining for target
|
||||
* @return Milliseconds remaining or 0 if not protected
|
||||
*/
|
||||
uint32 GetProtectionRemaining(ObjectGuid targetGuid) const;
|
||||
|
||||
/**
|
||||
* Assess danger level for a target
|
||||
* @param targetGuid Target to assess
|
||||
* @return Current danger level
|
||||
*/
|
||||
DangerLevel AssessDanger(ObjectGuid targetGuid) const;
|
||||
|
||||
/**
|
||||
* Get appropriate CD tier for danger level
|
||||
* Per GAP 3: Don't waste major CDs on moderate danger
|
||||
*/
|
||||
ExternalCDTier GetAppropriateCDTier(DangerLevel danger) const;
|
||||
|
||||
// ========================================================================
|
||||
// CC COORDINATION (S3.6)
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Request to CC a target via claim system
|
||||
* @param targetGuid Enemy to CC
|
||||
* @param spellId CC spell to use
|
||||
* @param priority CC priority
|
||||
* @return true if claim was submitted
|
||||
*/
|
||||
bool RequestCC(ObjectGuid targetGuid, uint32 spellId, ClaimPriority priority);
|
||||
|
||||
/**
|
||||
* Check if this bot should CC (has active claim)
|
||||
* @param targetGuid Out: target to CC
|
||||
* @param spellId Out: CC spell to use
|
||||
* @return true if this bot should CC now
|
||||
*/
|
||||
bool ShouldCC(ObjectGuid& targetGuid, uint32& spellId) const;
|
||||
|
||||
/**
|
||||
* Report CC result
|
||||
*/
|
||||
void OnCCExecuted(ObjectGuid targetGuid, uint32 spellId, bool success);
|
||||
|
||||
// ========================================================================
|
||||
// CLAIM CALLBACKS
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Called when a claim we submitted is resolved
|
||||
*/
|
||||
void OnClaimResolved(BotMessage const& message, ClaimStatus status);
|
||||
|
||||
// ========================================================================
|
||||
// CONFIGURATION
|
||||
// ========================================================================
|
||||
|
||||
struct Config
|
||||
{
|
||||
uint32 protectionWindowMs = 6000; // GAP 3: 6 second danger window
|
||||
uint32 claimTimeoutMs = 200; // First-claim-wins timeout
|
||||
float dangerHealthCritical = 0.30f; // < 30% = CRITICAL
|
||||
float dangerHealthHigh = 0.50f; // < 50% = HIGH
|
||||
float dangerHealthModerate = 0.80f; // < 80% = MODERATE
|
||||
uint32 incomingDPSThreshold = 5; // % max HP/sec for danger
|
||||
bool enableInterruptClaims = true;
|
||||
bool enableDispelClaims = true;
|
||||
bool enableDefensiveClaims = true;
|
||||
bool enableCCClaims = true;
|
||||
};
|
||||
|
||||
void SetConfig(const Config& config) { _config = config; }
|
||||
const Config& GetConfig() const { return _config; }
|
||||
|
||||
// ========================================================================
|
||||
// METRICS
|
||||
// ========================================================================
|
||||
|
||||
struct Metrics
|
||||
{
|
||||
uint32 interruptClaimsSubmitted = 0;
|
||||
uint32 interruptClaimsWon = 0;
|
||||
uint32 interruptClaimsLost = 0;
|
||||
uint32 dispelClaimsSubmitted = 0;
|
||||
uint32 dispelClaimsWon = 0;
|
||||
uint32 dispelClaimsLost = 0;
|
||||
uint32 defensiveClaimsSubmitted = 0;
|
||||
uint32 defensiveClaimsWon = 0;
|
||||
uint32 defensiveClaimsLost = 0;
|
||||
uint32 ccClaimsSubmitted = 0;
|
||||
uint32 ccClaimsWon = 0;
|
||||
uint32 ccClaimsLost = 0;
|
||||
uint32 protectionWindowsCreated = 0;
|
||||
};
|
||||
|
||||
const Metrics& GetMetrics() const { return _metrics; }
|
||||
void ResetMetrics() { _metrics = Metrics(); }
|
||||
|
||||
private:
|
||||
// ========================================================================
|
||||
// INTERNAL METHODS
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Subscribe to BotMessageBus for this bot's group
|
||||
*/
|
||||
void SubscribeToMessageBus();
|
||||
|
||||
/**
|
||||
* Unsubscribe from BotMessageBus
|
||||
*/
|
||||
void UnsubscribeFromMessageBus();
|
||||
|
||||
/**
|
||||
* Handle incoming bot messages
|
||||
*/
|
||||
void OnBotMessage(BotMessage const& message);
|
||||
|
||||
/**
|
||||
* Update protection windows (expire old ones)
|
||||
*/
|
||||
void UpdateProtectionWindows();
|
||||
|
||||
/**
|
||||
* Get available external CDs this bot can provide
|
||||
*/
|
||||
std::vector<uint32> GetAvailableExternalCDs(ExternalCDTier maxTier) const;
|
||||
|
||||
/**
|
||||
* Check if bot can dispel the given type
|
||||
*/
|
||||
bool CanDispelType(uint32 dispelMask) const;
|
||||
|
||||
/**
|
||||
* Get bot's interrupt spell
|
||||
*/
|
||||
uint32 GetInterruptSpell() const;
|
||||
|
||||
/**
|
||||
* Calculate distance to target
|
||||
*/
|
||||
float GetDistanceToTarget(ObjectGuid targetGuid) const;
|
||||
|
||||
// ========================================================================
|
||||
// MEMBER VARIABLES
|
||||
// ========================================================================
|
||||
|
||||
BotAI* _ai;
|
||||
Player* _bot;
|
||||
ObjectGuid _groupGuid;
|
||||
|
||||
// Manager references (owned by BotAI, not us)
|
||||
InterruptCoordinatorFixed* _interruptCoord = nullptr;
|
||||
DefensiveBehaviorManager* _defensiveMgr = nullptr;
|
||||
CrowdControlManager* _ccMgr = nullptr;
|
||||
DispelCoordinator* _dispelCoord = nullptr;
|
||||
|
||||
// Active claims for this bot
|
||||
struct ActiveClaim
|
||||
{
|
||||
BotMessageType type;
|
||||
ObjectGuid targetGuid;
|
||||
uint32 spellOrAuraId = 0;
|
||||
ClaimStatus status = ClaimStatus::PENDING;
|
||||
std::chrono::steady_clock::time_point submitTime;
|
||||
std::chrono::steady_clock::time_point resolveTime;
|
||||
};
|
||||
std::unordered_map<uint64, ActiveClaim> _activeClaims; // key: hash of target+type
|
||||
|
||||
// Protection windows (GAP 3 fix)
|
||||
std::vector<ProtectionWindow> _protectionWindows;
|
||||
|
||||
// Configuration
|
||||
Config _config;
|
||||
|
||||
// Metrics
|
||||
Metrics _metrics;
|
||||
|
||||
// Subscription state
|
||||
bool _subscribed = false;
|
||||
uint32 _subscriptionId = 0;
|
||||
|
||||
// Update timing
|
||||
uint32 _lastUpdate = 0;
|
||||
static constexpr uint32 UPDATE_INTERVAL_MS = 100;
|
||||
};
|
||||
|
||||
} // namespace Playerbot
|
||||
|
||||
#endif // PLAYERBOT_COMBAT_COORDINATION_INTEGRATOR_H
|
||||
@@ -198,6 +198,54 @@ struct BotMessage
|
||||
return msg;
|
||||
}
|
||||
|
||||
static BotMessage ClaimCC(ObjectGuid sender, ObjectGuid group, ObjectGuid target,
|
||||
uint32 spellId, ClaimPriority priority)
|
||||
{
|
||||
BotMessage msg{};
|
||||
msg.type = BotMessageType::CLAIM_CC;
|
||||
msg.scope = MessageScope::GROUP_BROADCAST;
|
||||
msg.senderGuid = sender;
|
||||
msg.groupGuid = group;
|
||||
msg.targetGuid = target;
|
||||
msg.spellId = spellId;
|
||||
msg.claimPriority = priority;
|
||||
msg.claimStatus = ClaimStatus::PENDING;
|
||||
msg.timestamp = std::chrono::steady_clock::now();
|
||||
msg.expiryTime = msg.timestamp + std::chrono::milliseconds(200);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static BotMessage ClaimSoak(ObjectGuid sender, ObjectGuid group, ObjectGuid target,
|
||||
ClaimPriority priority)
|
||||
{
|
||||
BotMessage msg{};
|
||||
msg.type = BotMessageType::CLAIM_SOAK;
|
||||
msg.scope = MessageScope::GROUP_BROADCAST;
|
||||
msg.senderGuid = sender;
|
||||
msg.groupGuid = group;
|
||||
msg.targetGuid = target;
|
||||
msg.claimPriority = priority;
|
||||
msg.claimStatus = ClaimStatus::PENDING;
|
||||
msg.timestamp = std::chrono::steady_clock::now();
|
||||
msg.expiryTime = msg.timestamp + std::chrono::milliseconds(200);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static BotMessage RequestExternalCD(ObjectGuid sender, ObjectGuid group, ObjectGuid target, float urgency)
|
||||
{
|
||||
BotMessage msg{};
|
||||
msg.type = BotMessageType::REQUEST_EXTERNAL_CD;
|
||||
msg.scope = MessageScope::ROLE_BROADCAST;
|
||||
msg.senderGuid = sender;
|
||||
msg.groupGuid = group;
|
||||
msg.targetGuid = target;
|
||||
msg.targetRole = 1; // Healers primarily provide externals
|
||||
msg.value = urgency;
|
||||
msg.timestamp = std::chrono::steady_clock::now();
|
||||
msg.expiryTime = msg.timestamp + std::chrono::milliseconds(2000);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static BotMessage AnnounceCDUsage(ObjectGuid sender, ObjectGuid group,
|
||||
uint32 spellId, uint32 durationMs)
|
||||
{
|
||||
|
||||
@@ -560,6 +560,8 @@ set(PLAYERBOT_COMBAT_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/MechanicAwareness.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/InterruptCoordinator.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/InterruptCoordinator.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/CombatCoordinationIntegrator.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/CombatCoordinationIntegrator.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/InterruptAwareness.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/InterruptAwareness.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AI/Combat/InterruptManager.cpp
|
||||
|
||||
@@ -68,10 +68,18 @@ GameSystemsManager::~GameSystemsManager()
|
||||
// (managers may call UnsubscribeAll() in their destructors)
|
||||
|
||||
// 1. High-level systems first
|
||||
_combatCoordinationIntegrator.reset(); // Sprint 3: Must shutdown before managers it references
|
||||
_combatStateManager.reset();
|
||||
_deathRecoveryManager.reset();
|
||||
_unifiedMovementCoordinator.reset();
|
||||
|
||||
// Sprint 3: Combat Behaviors managers
|
||||
_aoeDecisionManager.reset();
|
||||
_cooldownStackingOptimizer.reset();
|
||||
_defensiveBehaviorManager.reset();
|
||||
_dispelCoordinator.reset();
|
||||
_interruptRotationManager.reset();
|
||||
|
||||
// 2. Game system managers
|
||||
_tradeManager.reset();
|
||||
_gatheringManager.reset();
|
||||
@@ -208,6 +216,28 @@ void GameSystemsManager::Initialize(Player* bot)
|
||||
// Combat state manager
|
||||
_combatStateManager = std::make_unique<CombatStateManager>(_bot, _botAI);
|
||||
|
||||
// ========================================================================
|
||||
// SPRINT 3: COMBAT COORDINATION - Essential for group coordination
|
||||
// ========================================================================
|
||||
|
||||
// Combat Behaviors managers - essential for group combat
|
||||
_aoeDecisionManager = std::make_unique<AoEDecisionManager>(_botAI);
|
||||
_cooldownStackingOptimizer = std::make_unique<CooldownStackingOptimizer>(_botAI);
|
||||
_defensiveBehaviorManager = std::make_unique<DefensiveBehaviorManager>(_botAI);
|
||||
_dispelCoordinator = std::make_unique<DispelCoordinator>(_botAI);
|
||||
_interruptRotationManager = std::make_unique<InterruptRotationManager>(_botAI);
|
||||
|
||||
// Combat Coordination Integrator - bridges managers with BotMessageBus claim system
|
||||
_combatCoordinationIntegrator = std::make_unique<CombatCoordinationIntegrator>(_botAI);
|
||||
|
||||
// Initialize CombatCoordinationIntegrator with references to combat managers
|
||||
_combatCoordinationIntegrator->Initialize(
|
||||
nullptr, // InterruptCoordinatorFixed (not yet migrated)
|
||||
_defensiveBehaviorManager.get(),
|
||||
nullptr, // CrowdControlManager (not yet migrated)
|
||||
_dispelCoordinator.get()
|
||||
);
|
||||
|
||||
// Manager creation complete - no logging to avoid GetName() during init
|
||||
|
||||
// ========================================================================
|
||||
@@ -676,6 +706,69 @@ void GameSystemsManager::UpdateManagers(uint32 diff)
|
||||
_pvpCombatAI->Update(diff);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// SPRINT 3: COMBAT COORDINATION - Essential for all bots in groups
|
||||
// Updates claim system, dispel coordination, interrupt rotation, etc.
|
||||
// ========================================================================
|
||||
|
||||
// Combat Coordination Integrator - bridges to BotMessageBus claim system
|
||||
// 100ms throttle - fast enough for responsive coordination
|
||||
_combatCoordTimer += diff;
|
||||
if (_combatCoordTimer >= 100)
|
||||
{
|
||||
_combatCoordTimer = 0;
|
||||
if (_combatCoordinationIntegrator)
|
||||
_combatCoordinationIntegrator->Update(diff);
|
||||
}
|
||||
|
||||
// Combat Behaviors managers - essential for group combat
|
||||
// 200ms throttle - responsive but not every frame
|
||||
|
||||
// DispelCoordinator - handles dispel rotation and claims (GAP 2 fix)
|
||||
_dispelTimer += diff;
|
||||
if (_dispelTimer >= 200)
|
||||
{
|
||||
_dispelTimer = 0;
|
||||
if (_dispelCoordinator)
|
||||
_dispelCoordinator->Update(diff);
|
||||
}
|
||||
|
||||
// InterruptRotationManager - handles interrupt assignment and rotation
|
||||
_interruptTimer += diff;
|
||||
if (_interruptTimer >= 100) // Interrupts need faster response
|
||||
{
|
||||
_interruptTimer = 0;
|
||||
if (_interruptRotationManager)
|
||||
_interruptRotationManager->Update(diff);
|
||||
}
|
||||
|
||||
// AoEDecisionManager - target clustering decisions (500ms throttle)
|
||||
_aoeTimer += diff;
|
||||
if (_aoeTimer >= 500)
|
||||
{
|
||||
_aoeTimer = 0;
|
||||
if (_aoeDecisionManager)
|
||||
_aoeDecisionManager->Update(diff);
|
||||
}
|
||||
|
||||
// CooldownStackingOptimizer - optimal CD stacking (500ms throttle)
|
||||
_cdStackTimer += diff;
|
||||
if (_cdStackTimer >= 500)
|
||||
{
|
||||
_cdStackTimer = 0;
|
||||
if (_cooldownStackingOptimizer)
|
||||
_cooldownStackingOptimizer->Update(diff);
|
||||
}
|
||||
|
||||
// DefensiveBehaviorManager - external CD coordination (200ms throttle)
|
||||
_defenseTimer += diff;
|
||||
if (_defenseTimer >= 200)
|
||||
{
|
||||
_defenseTimer = 0;
|
||||
if (_defensiveBehaviorManager)
|
||||
_defensiveBehaviorManager->Update(diff);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// MORE WORLD BOT ONLY - PROFESSION AUTOMATION - Check every 15 seconds
|
||||
// ========================================================================
|
||||
|
||||
@@ -72,6 +72,16 @@
|
||||
#include "AI/HybridAIController.h"
|
||||
#include "BehaviorPriorityManager.h"
|
||||
|
||||
// Sprint 3: Combat Coordination
|
||||
#include "AI/Combat/CombatCoordinationIntegrator.h"
|
||||
|
||||
// Combat Behaviors managers
|
||||
#include "AI/CombatBehaviors/AoEDecisionManager.h"
|
||||
#include "AI/CombatBehaviors/CooldownStackingOptimizer.h"
|
||||
#include "AI/CombatBehaviors/DefensiveBehaviorManager.h"
|
||||
#include "AI/CombatBehaviors/DispelCoordinator.h"
|
||||
#include "AI/CombatBehaviors/InterruptRotationManager.h"
|
||||
|
||||
namespace Playerbot
|
||||
{
|
||||
|
||||
@@ -223,6 +233,16 @@ public:
|
||||
HybridAIController* GetHybridAI() const override { return _hybridAI.get(); }
|
||||
BehaviorPriorityManager* GetPriorityManager() const override { return _priorityManager.get(); }
|
||||
|
||||
// Sprint 3: Combat Coordination
|
||||
CombatCoordinationIntegrator* GetCombatCoordinationIntegrator() const override { return _combatCoordinationIntegrator.get(); }
|
||||
|
||||
// Combat Behaviors managers
|
||||
AoEDecisionManager* GetAoEDecisionManager() const override { return _aoeDecisionManager.get(); }
|
||||
CooldownStackingOptimizer* GetCooldownStackingOptimizer() const override { return _cooldownStackingOptimizer.get(); }
|
||||
DefensiveBehaviorManager* GetDefensiveBehaviorManager() const override { return _defensiveBehaviorManager.get(); }
|
||||
DispelCoordinator* GetDispelCoordinator() const override { return _dispelCoordinator.get(); }
|
||||
InterruptRotationManager* GetInterruptRotationManager() const override { return _interruptRotationManager.get(); }
|
||||
|
||||
private:
|
||||
// ========================================================================
|
||||
// MANAGER INSTANCES - All 26 managers owned by facade
|
||||
@@ -294,6 +314,16 @@ private:
|
||||
// Behavior management
|
||||
std::unique_ptr<BehaviorPriorityManager> _priorityManager;
|
||||
|
||||
// Sprint 3: Combat Coordination
|
||||
std::unique_ptr<CombatCoordinationIntegrator> _combatCoordinationIntegrator;
|
||||
|
||||
// Combat Behaviors managers
|
||||
std::unique_ptr<AoEDecisionManager> _aoeDecisionManager;
|
||||
std::unique_ptr<CooldownStackingOptimizer> _cooldownStackingOptimizer;
|
||||
std::unique_ptr<DefensiveBehaviorManager> _defensiveBehaviorManager;
|
||||
std::unique_ptr<DispelCoordinator> _dispelCoordinator;
|
||||
std::unique_ptr<InterruptRotationManager> _interruptRotationManager;
|
||||
|
||||
// ========================================================================
|
||||
// INTERNAL STATE
|
||||
// ========================================================================
|
||||
@@ -321,6 +351,14 @@ private:
|
||||
uint32 _professionBridgeTimer{0}; // 5000ms - selling/buying materials
|
||||
uint32 _farmingUpdateTimer{0}; // 2000ms - farming coordination
|
||||
|
||||
// Sprint 3: Combat Coordination throttle timers
|
||||
uint32 _combatCoordTimer{0}; // 100ms - responsive coordination
|
||||
uint32 _dispelTimer{0}; // 200ms - dispel rotation
|
||||
uint32 _interruptTimer{0}; // 100ms - fast interrupt response
|
||||
uint32 _aoeTimer{0}; // 500ms - target clustering
|
||||
uint32 _cdStackTimer{0}; // 500ms - cooldown optimization
|
||||
uint32 _defenseTimer{0}; // 200ms - defensive coordination
|
||||
|
||||
// ========================================================================
|
||||
// HELPER METHODS
|
||||
// ========================================================================
|
||||
|
||||
@@ -75,6 +75,16 @@ class ManagerRegistry;
|
||||
class HybridAIController;
|
||||
class BehaviorPriorityManager;
|
||||
|
||||
// Combat Coordination (Sprint 3)
|
||||
class CombatCoordinationIntegrator;
|
||||
|
||||
// Combat Behaviors managers
|
||||
class AoEDecisionManager;
|
||||
class CooldownStackingOptimizer;
|
||||
class DefensiveBehaviorManager;
|
||||
class DispelCoordinator;
|
||||
class InterruptRotationManager;
|
||||
|
||||
namespace Advanced
|
||||
{
|
||||
class GroupCoordinator;
|
||||
@@ -312,6 +322,56 @@ public:
|
||||
* @return Non-owning pointer to BehaviorPriorityManager (owned by facade)
|
||||
*/
|
||||
virtual BehaviorPriorityManager* GetPriorityManager() const = 0;
|
||||
|
||||
// ========================================================================
|
||||
// COMBAT COORDINATION (Sprint 3)
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Get combat coordination integrator
|
||||
* Bridges combat managers with BotMessageBus claim system
|
||||
* @return Non-owning pointer to CombatCoordinationIntegrator (owned by facade)
|
||||
*/
|
||||
virtual CombatCoordinationIntegrator* GetCombatCoordinationIntegrator() const = 0;
|
||||
|
||||
// ========================================================================
|
||||
// COMBAT BEHAVIORS MANAGERS
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Get AoE decision manager
|
||||
* Target clustering and DoT spread decisions
|
||||
* @return Non-owning pointer to AoEDecisionManager (owned by facade)
|
||||
*/
|
||||
virtual AoEDecisionManager* GetAoEDecisionManager() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get cooldown stacking optimizer
|
||||
* 12-class cooldown database for optimal CD stacking
|
||||
* @return Non-owning pointer to CooldownStackingOptimizer (owned by facade)
|
||||
*/
|
||||
virtual CooldownStackingOptimizer* GetCooldownStackingOptimizer() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get defensive behavior manager
|
||||
* External defensive CD coordination (GAP 3 fix)
|
||||
* @return Non-owning pointer to DefensiveBehaviorManager (owned by facade)
|
||||
*/
|
||||
virtual DefensiveBehaviorManager* GetDefensiveBehaviorManager() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get dispel coordinator
|
||||
* Dispel rotation and claim system (GAP 2 fix)
|
||||
* @return Non-owning pointer to DispelCoordinator (owned by facade)
|
||||
*/
|
||||
virtual DispelCoordinator* GetDispelCoordinator() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get interrupt rotation manager
|
||||
* Interrupt assignment and rotation queue
|
||||
* @return Non-owning pointer to InterruptRotationManager (owned by facade)
|
||||
*/
|
||||
virtual InterruptRotationManager* GetInterruptRotationManager() const = 0;
|
||||
};
|
||||
|
||||
} // namespace Playerbot
|
||||
|
||||
Reference in New Issue
Block a user