feat(movement): Task 3 COMPLETE - Final 3 Dungeon files migrated to BotMovementController

This completes Task 3 (Movement Generator Replacement) at 100% - all 33 files
migrated from legacy MotionMaster to validated BotMovementController.

Final migration details:

DungeonAutonomyManager.cpp (3 MovePoint → MoveTo migrations):
- Line 739: Pack navigation movement
- Line 765: Healer positioning behind tank
- Line 790: DPS positioning behind tank
- Kept MoveChase at line 429 as legacy (combat engagement)

DungeonBehavior.cpp (5 MovePoint → MoveTo migrations):
- Lines 663-664: Tank optimal position
- Lines 703-704: Healer safe position
- Lines 748-749: DPS optimal position
- Lines 880-881: Player optimal position
- Lines 983-984: Safe spot avoidance

EncounterStrategy.cpp (7 MovePoint → MoveTo migrations):
- Lines 440-441: AoE avoidance
- Lines 580-581: Optimal positioning
- Lines 665-666: Danger zone avoidance
- Line 1421: General positioning
- Lines 1577-1578: Target positioning
- Line 1742: Movement positioning
- Lines 1805-1806: Stack on tank positioning

All migrations follow enterprise pattern:
- BotAI::MoveTo() with ground/collision/liquid validation
- Fallback to legacy MotionMaster if validation fails
- Safe bot AI retrieval via GetBotAI() helper
- Added PlayerBotHelpers.h includes where needed

TASK 3 STATISTICS:
- Files migrated: 33/33 (100%)
- Total usages: 70 (69 migrated + 1 legacy MoveChase)
- HIGH PRIORITY: 13 files (combat systems) ✓
- MEDIUM PRIORITY: 9 files (ClassAI/Actions) ✓
- LOW PRIORITY: 11 files (dungeon/travel/behavior tree) ✓

Build: Successful (RelWithDebInfo, worldserver.exe created)
Test: Ready for production testing

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: luis <[email protected]>
This commit is contained in:
agatho
2026-02-04 20:56:37 -03:00
committed by luis
co-authored by Claude Opus 4.5
parent 2af8c650a7
commit 5ceb60ffeb
3 changed files with 236 additions and 38 deletions
@@ -23,6 +23,7 @@
#include "MotionMaster.h"
#include "MovementGenerator.h"
#include "DBCEnums.h" // For ChrSpecialization enum
#include "Core/PlayerBotHelpers.h"
namespace Playerbot
{
@@ -735,8 +736,21 @@ bool DungeonAutonomyManager::UpdateTankAI(Player* tank, BotAI* ai, Group* group,
TrashPack* pack = coordinator->GetCurrentPullTarget();
if (pack)
{
// Move toward next pack
tank->GetMotionMaster()->MovePoint(0, pack->x, pack->y, pack->z);
// Use validated pathfinding for pack navigation
Position dest(pack->x, pack->y, pack->z, 0.0f);
if (BotAI* ai = GetBotAI(tank))
{
if (!ai->MoveTo(dest, true))
{
// Fallback to legacy if validation fails
tank->GetMotionMaster()->MovePoint(0, pack->x, pack->y, pack->z);
}
}
else
{
// Non-bot player - use standard movement
tank->GetMotionMaster()->MovePoint(0, pack->x, pack->y, pack->z);
}
return true;
}
}
@@ -762,7 +776,20 @@ bool DungeonAutonomyManager::UpdateHealerAI(Player* healer, BotAI* ai, Group* gr
followPos.m_positionY = tank->GetPositionY() + 15.0f * sin(angle);
followPos.m_positionZ = tank->GetPositionZ();
healer->GetMotionMaster()->MovePoint(0, followPos);
// Use validated pathfinding for healer positioning
if (BotAI* ai = GetBotAI(healer))
{
if (!ai->MoveTo(followPos, true))
{
// Fallback to legacy if validation fails
healer->GetMotionMaster()->MovePoint(0, followPos);
}
}
else
{
// Non-bot player - use standard movement
healer->GetMotionMaster()->MovePoint(0, followPos);
}
return true;
}
@@ -787,7 +814,20 @@ bool DungeonAutonomyManager::UpdateDpsAI(Player* dps, BotAI* ai, Group* group, D
followPos.m_positionY = tank->GetPositionY() + 20.0f * sin(angle);
followPos.m_positionZ = tank->GetPositionZ();
dps->GetMotionMaster()->MovePoint(0, followPos);
// Use validated pathfinding for DPS positioning
if (BotAI* ai = GetBotAI(dps))
{
if (!ai->MoveTo(followPos, true))
{
// Fallback to legacy if validation fails
dps->GetMotionMaster()->MovePoint(0, followPos);
}
}
else
{
// Non-bot player - use standard movement
dps->GetMotionMaster()->MovePoint(0, followPos);
}
return true;
}
@@ -659,9 +659,22 @@ void DungeonBehavior::CoordinateTankBehavior(Player* tank, const DungeonEncounte
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
tank->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
// Use validated pathfinding for tank positioning
if (BotAI* ai = GetBotAI(tank))
{
if (!ai->MoveTo(optimalPos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
tank->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
tank->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
}
@@ -699,9 +712,22 @@ void DungeonBehavior::CoordinateHealerBehavior(Player* healer, const DungeonEnco
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
healer->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
// Use validated pathfinding for healer positioning
if (BotAI* ai = GetBotAI(healer))
{
if (!ai->MoveTo(safePos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
healer->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
healer->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
}
}
}
@@ -744,9 +770,22 @@ void DungeonBehavior::CoordinateDpsBehavior(Player* dps, const DungeonEncounter&
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
dps->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
// Use validated pathfinding for DPS positioning
if (BotAI* ai = GetBotAI(dps))
{
if (!ai->MoveTo(optimalPos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
dps->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
dps->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
}
@@ -876,9 +915,22 @@ void DungeonBehavior::UpdateGroupPositioning(Group* group, const DungeonEncounte
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
// Use validated pathfinding for player positioning
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(optimalPos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
}
}
@@ -979,9 +1031,22 @@ void DungeonBehavior::AvoidDangerousAreas(Player* player, const ::std::vector<Po
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, nearestSafeSpot.GetPositionX(),
nearestSafeSpot.GetPositionY(), nearestSafeSpot.GetPositionZ());
// Use validated pathfinding for safe spot movement
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(nearestSafeSpot, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, nearestSafeSpot.GetPositionX(),
nearestSafeSpot.GetPositionY(), nearestSafeSpot.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, nearestSafeSpot.GetPositionX(),
nearestSafeSpot.GetPositionY(), nearestSafeSpot.GetPositionZ());
}
}
TC_LOG_DEBUG("module.playerbot", "Player {} moving to avoid dangerous area", player->GetName());
@@ -37,6 +37,7 @@
#include "../Movement/Arbiter/MovementPriorityMapper.h"
#include "../AI/BotAI.h"
#include "UnitAI.h"
#include "../Core/PlayerBotHelpers.h"
namespace Playerbot
{
@@ -436,9 +437,22 @@ void EncounterStrategy::HandleAoEDamageMechanic(Group* group, const Position& da
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
// Use validated pathfinding for AoE avoidance
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(safePos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
}
TC_LOG_TRACE("module.playerbot", "Player {} moving to avoid AoE", player->GetName());
}
}
@@ -576,9 +590,22 @@ void EncounterStrategy::UpdateEncounterPositioning(Group* group, uint32 encounte
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
// Use validated pathfinding for optimal positioning
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(optimalPos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, optimalPos.GetPositionX(),
optimalPos.GetPositionY(), optimalPos.GetPositionZ());
}
}
}
}
@@ -661,9 +688,22 @@ void EncounterStrategy::AvoidMechanicAreas(Group* group, const ::std::vector<Pos
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
// Use validated pathfinding for danger zone avoidance
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(safePos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, safePos.GetPositionX(),
safePos.GetPositionY(), safePos.GetPositionZ());
}
}
}
}
@@ -1417,8 +1457,21 @@ void EncounterStrategy::HandleGenericGroundAvoidance(::Player* player, ::Creatur
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, x, y, z);
// Use validated pathfinding for positioning
Position dest(x, y, z, 0.0f);
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(dest, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, x, y, z);
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, x, y, z);
}
}
return;
}
@@ -1573,9 +1626,22 @@ void EncounterStrategy::HandleGenericPositioning(::Player* player, ::Creature* b
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, targetPos.GetPositionX(),
targetPos.GetPositionY(), targetPos.GetPositionZ());
// Use validated pathfinding for target positioning
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(targetPos, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, targetPos.GetPositionX(),
targetPos.GetPositionY(), targetPos.GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, targetPos.GetPositionX(),
targetPos.GetPositionY(), targetPos.GetPositionZ());
}
}
}
}
@@ -1738,8 +1804,21 @@ void EncounterStrategy::HandleGenericSpread(::Player* player, ::Creature* boss,
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, x, y, z);
// Use validated pathfinding for positioning
Position dest(x, y, z, 0.0f);
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(dest, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, x, y, z);
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, x, y, z);
}
}
return;
}
@@ -1801,9 +1880,23 @@ void EncounterStrategy::HandleGenericStack(::Player* player, ::Creature* boss)
}
else
{
// FALLBACK: Direct MotionMaster if arbiter not available
player->GetMotionMaster()->MovePoint(0, tank->GetPositionX(),
tank->GetPositionY(), tank->GetPositionZ());
// Use validated pathfinding for stacking on tank
Position dest(tank->GetPositionX(), tank->GetPositionY(), tank->GetPositionZ(), 0.0f);
if (BotAI* ai = GetBotAI(player))
{
if (!ai->MoveTo(dest, true))
{
// FALLBACK: Direct MotionMaster if validation fails
player->GetMotionMaster()->MovePoint(0, tank->GetPositionX(),
tank->GetPositionY(), tank->GetPositionZ());
}
}
else
{
// Non-bot player - use standard movement
player->GetMotionMaster()->MovePoint(0, tank->GetPositionX(),
tank->GetPositionY(), tank->GetPositionZ());
}
}
}
}