feature(SmartAI/Movement) - Unify waypoint systems (#23251)

This commit is contained in:
killerwife
2025-10-26 17:52:59 +01:00
committed by GitHub
parent af2cb8d227
commit 6292f80219
71 changed files with 447 additions and 485 deletions

View File

@@ -32,6 +32,7 @@
#include "TargetedMovementGenerator.h"
#include "WaypointMgr.h"
#include "WaypointMovementGenerator.h"
#include "SmartScriptMgr.h"
inline MovementGenerator* GetIdleMovementGenerator()
{
@@ -503,19 +504,35 @@ void MotionMaster::MoveSplinePath(Movement::PointsArray* path, ForcedMovement fo
}
}
void MotionMaster::MoveSplinePath(uint32 path_id, ForcedMovement forcedMovement)
void MotionMaster::MovePath(uint32 path_id, ForcedMovement forcedMovement, PathSource pathSource)
{
// convert the path id to a Movement::PointsArray*
Movement::PointsArray* points = new Movement::PointsArray();
WaypointPath const* path = sWaypointMgr->GetPath(path_id);
for (uint8 i = 0; i < path->size(); ++i)
WaypointPath const* path;
switch (pathSource)
{
WaypointData const* node = path->at(i);
points->push_back(G3D::Vector3(node->x, node->y, node->z));
default:
case PathSource::WAYPOINT_MGR:
path = sWaypointMgr->GetPath(path_id);
break;
case PathSource::SMART_WAYPOINT_MGR:
path = sSmartWaypointMgr->GetPath(path_id);
break;
}
if (path == nullptr)
{
LOG_ERROR("sql.sql", "WaypointMovementGenerator::LoadPath: creature {} ({}) doesn't have waypoint path id: {} pathSource: {}",
_owner->GetName(), _owner->GetGUID().ToString(), path_id, pathSource);
return;
}
Movement::PointsArray points;
for (auto& point : *path)
{
points.push_back(G3D::Vector3(point.second.x, point.second.y, point.second.z));
}
// pass the new PointsArray* to the appropriate MoveSplinePath function
MoveSplinePath(points, forcedMovement);
MoveSplinePath(&points, forcedMovement);
}
/**
@@ -881,7 +898,7 @@ void MotionMaster::Mutate(MovementGenerator* m, MovementSlot slot)
/**
* @brief Move the unit following a specific path. Doesn't work with UNIT_FLAG_DISABLE_MOVE
*/
void MotionMaster::MovePath(uint32 path_id, bool repeatable)
void MotionMaster::MoveWaypoint(uint32 path_id, bool repeatable, PathSource pathSource)
{
if (!path_id)
return;
@@ -889,20 +906,7 @@ void MotionMaster::MovePath(uint32 path_id, bool repeatable)
if (_owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
return;
//We set waypoint movement as new default movement generator
// clear ALL movement generators (including default)
/*while (!empty())
{
MovementGenerator *curr = top();
curr->Finalize(*_owner);
pop();
if (!isStatic(curr))
delete curr;
}*/
//_owner->IsPlayer() ?
//Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)):
Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE);
Mutate(new WaypointMovementGenerator<Creature>(path_id, pathSource, repeatable), MOTION_SLOT_IDLE);
LOG_DEBUG("movement.motionmaster", "{} ({}) start moving over path(Id:{}, repeatable: {})",
_owner->IsPlayer() ? "Player" : "Creature", _owner->GetGUID().ToString(), path_id, repeatable ? "YES" : "NO");

View File

@@ -89,6 +89,12 @@ enum ForcedMovement
FORCED_MOVEMENT_MAX
};
enum class PathSource
{
WAYPOINT_MGR = 0,
SMART_WAYPOINT_MGR = 1,
};
struct ChaseRange
{
ChaseRange(float range);
@@ -223,7 +229,7 @@ public:
{ MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, forcedMovement, speed, pos.GetOrientation(), generatePath, forceDestination, MOTION_SLOT_ACTIVE); }
void MovePoint(uint32 id, float x, float y, float z, ForcedMovement forcedMovement = FORCED_MOVEMENT_NONE, float speed = 0.f, float orientation = 0.0f, bool generatePath = true, bool forceDestination = true, MovementSlot slot = MOTION_SLOT_ACTIVE);
void MoveSplinePath(Movement::PointsArray* path, ForcedMovement forcedMovement = FORCED_MOVEMENT_NONE);
void MoveSplinePath(uint32 path_id, ForcedMovement forcedMovement = FORCED_MOVEMENT_NONE);
void MovePath(uint32 path_id, ForcedMovement forcedMovement = FORCED_MOVEMENT_NONE, PathSource pathSource = PathSource::WAYPOINT_MGR);
// These two movement types should only be used with creatures having landing/takeoff animations
void MoveLand(uint32 id, Position const& pos, float speed = 0.0f);
@@ -244,7 +250,7 @@ public:
void MoveSeekAssistanceDistract(uint32 timer);
void MoveTaxiFlight(uint32 path, uint32 pathnode);
void MoveDistract(uint32 time);
void MovePath(uint32 path_id, bool repeatable);
void MoveWaypoint(uint32 path_id, bool repeatable, PathSource pathSource = PathSource::WAYPOINT_MGR);
void MoveRotate(uint32 time, RotateDirection direction);
[[nodiscard]] MovementGeneratorType GetCurrentMovementGeneratorType() const;

View File

@@ -28,13 +28,26 @@
#include "Spell.h"
#include "Transport.h"
#include "World.h"
#include "SmartScriptMgr.h"
void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
{
if (!path_id)
path_id = creature->GetWaypointPath();
switch (i_pathSource)
{
case PathSource::WAYPOINT_MGR:
{
if (!path_id)
path_id = creature->GetWaypointPath();
i_path = sWaypointMgr->GetPath(path_id);
i_path = sWaypointMgr->GetPath(path_id);
break;
}
case PathSource::SMART_WAYPOINT_MGR:
{
i_path = sSmartWaypointMgr->GetPath(path_id);
break;
}
}
if (!i_path)
{
@@ -44,6 +57,8 @@ void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
return;
}
i_currentNode = i_path->begin()->first;
StartMoveNow(creature);
}
@@ -78,22 +93,24 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature)
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
m_isArrivalDone = true;
if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
auto currentNodeItr = i_path->find(i_currentNode);
if (currentNodeItr->second.event_id && urand(0, 99) < currentNodeItr->second.event_chance)
{
LOG_DEBUG("maps.script", "Creature movement start script {} at point {} for {}.",
i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID().ToString());
currentNodeItr->second.event_id, i_currentNode, creature->GetGUID().ToString());
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, nullptr);
creature->GetMap()->ScriptsStart(sWaypointScripts, currentNodeItr->second.event_id, creature, nullptr);
}
// Inform script
MovementInform(creature);
creature->UpdateWaypointID(i_currentNode);
if (i_path->at(i_currentNode)->delay)
if (currentNodeItr->second.delay)
{
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
Stop(i_path->at(i_currentNode)->delay);
Stop(currentNodeItr->second.delay);
}
}
@@ -116,9 +133,10 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
// Xinef: not true... update this at every waypoint!
//if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
{
float x = i_path->at(i_currentNode)->x;
float y = i_path->at(i_currentNode)->y;
float z = i_path->at(i_currentNode)->z;
auto currentNodeItr = i_path->find(i_currentNode);
float x = currentNodeItr->second.x;
float y = currentNodeItr->second.y;
float z = currentNodeItr->second.z;
float o = creature->GetOrientation();
if (!transportPath)
@@ -146,7 +164,9 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
return false;
}
i_currentNode = (i_currentNode + 1) % i_path->size();
++i_currentNode;
if (i_path->rbegin()->first < i_currentNode)
i_currentNode = i_path->begin()->first;
}
// xinef: do not initialize motion if we got stunned in movementinform
@@ -155,13 +175,14 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
return true;
}
WaypointData const* node = i_path->at(i_currentNode);
auto currentNodeItr = i_path->find(i_currentNode);
WaypointData const& node = currentNodeItr->second;
m_isArrivalDone = false;
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::Location formationDest(node->x, node->y, node->z, 0.0f);
Movement::Location formationDest(node.x, node.y, node.z, 0.0f);
Movement::MoveSplineInit init(creature);
//! If creature is on transport, we assume waypoints set in DB are already transport offsets
@@ -172,16 +193,16 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
}
float z = node->z;
creature->UpdateAllowedPositionZ(node->x, node->y, z);
float z = node.z;
creature->UpdateAllowedPositionZ(node.x, node.y, z);
//! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
//! but formationDest contains global coordinates
init.MoveTo(node->x, node->y, z, true, true);
init.MoveTo(node.x, node.y, z, true, true);
if (node->orientation.has_value() && node->delay > 0)
init.SetFacing(*node->orientation);
if (node.orientation.has_value() && node.delay > 0)
init.SetFacing(*node.orientation);
switch (node->move_type)
switch (node.move_type)
{
case WAYPOINT_MOVE_TYPE_LAND:
init.SetAnimation(Movement::ToGround);
@@ -203,7 +224,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
//Call for creature group update
if (creature->GetFormation() && creature->GetFormation()->GetLeader() == creature)
creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z, node->move_type);
creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z, node.move_type);
return true;
}

View File

@@ -54,8 +54,8 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
public PathMovementBase<Creature, WaypointPath const*>
{
public:
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true, bool _stalled = false)
: PathMovementBase((WaypointPath const*)nullptr), i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating), stalled(_stalled) {}
WaypointMovementGenerator(uint32 _path_id = 0, PathSource pathSource = PathSource::WAYPOINT_MGR, bool _repeating = true, bool _stalled = false)
: PathMovementBase((WaypointPath const*)nullptr), i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating), stalled(_stalled), i_pathSource(pathSource) {}
~WaypointMovementGenerator() { i_path = nullptr; }
void DoInitialize(Creature*);
void DoFinalize(Creature*);
@@ -96,6 +96,7 @@ private:
uint32 path_id;
bool repeating;
bool stalled;
PathSource i_pathSource;
};
/** FlightPathMovementGenerator generates movement of the player for the paths

View File

@@ -30,9 +30,6 @@ WaypointMgr::~WaypointMgr()
{
for (WaypointPathContainer::iterator itr = _waypointStore.begin(); itr != _waypointStore.end(); ++itr)
{
for (WaypointPath::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
delete *it;
itr->second.clear();
}
@@ -64,7 +61,7 @@ void WaypointMgr::Load()
do
{
Field* fields = result->Fetch();
WaypointData* wp = new WaypointData();
WaypointData data;
uint32 pathId = fields[0].Get<uint32>();
WaypointPath& path = _waypointStore[pathId];
@@ -79,28 +76,40 @@ void WaypointMgr::Load()
Acore::NormalizeMapCoord(x);
Acore::NormalizeMapCoord(y);
wp->id = fields[1].Get<uint32>();
wp->x = x;
wp->y = y;
wp->z = z;
wp->orientation = o;
wp->move_type = fields[6].Get<uint32>();
data.id = fields[1].Get<uint32>();
data.x = x;
data.y = y;
data.z = z;
data.orientation = o;
data.move_type = fields[6].Get<uint32>();
if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX)
if (data.move_type >= WAYPOINT_MOVE_TYPE_MAX)
{
//LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", wp->id);
delete wp;
continue;
}
wp->delay = fields[7].Get<uint32>();
wp->event_id = fields[8].Get<uint32>();
wp->event_chance = fields[9].Get<int16>();
data.delay = fields[7].Get<uint32>();
data.event_id = fields[8].Get<uint32>();
data.event_chance = fields[9].Get<int16>();
path.push_back(wp);
path.emplace(data.id, data);
++count;
} while (result->NextRow());
for (auto itr = _waypointStore.begin(); itr != _waypointStore.end(); )
{
uint32 first = itr->second.begin()->first;
uint32 last = itr->second.rbegin()->first;
if (last - first + 1 != itr->second.size())
{
LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has non-contiguous pointids, skipping", itr->first);
itr = _waypointStore.erase(itr);
}
else
++itr;
}
LOG_INFO("server.loading", ">> Loaded {} waypoints in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@@ -110,9 +119,6 @@ void WaypointMgr::ReloadPath(uint32 id)
WaypointPathContainer::iterator itr = _waypointStore.find(id);
if (itr != _waypointStore.end())
{
for (WaypointPath::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
delete *it;
_waypointStore.erase(itr);
}
@@ -130,7 +136,7 @@ void WaypointMgr::ReloadPath(uint32 id)
do
{
Field* fields = result->Fetch();
WaypointData* wp = new WaypointData();
WaypointData data;
float x = fields[1].Get<float>();
float y = fields[2].Get<float>();
@@ -142,24 +148,23 @@ void WaypointMgr::ReloadPath(uint32 id)
Acore::NormalizeMapCoord(x);
Acore::NormalizeMapCoord(y);
wp->id = fields[0].Get<uint32>();
wp->x = x;
wp->y = y;
wp->z = z;
wp->orientation = o;
wp->move_type = fields[5].Get<uint32>();
data.id = fields[0].Get<uint32>();
data.x = x;
data.y = y;
data.z = z;
data.orientation = o;
data.move_type = fields[5].Get<uint32>();
if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX)
if (data.move_type >= WAYPOINT_MOVE_TYPE_MAX)
{
//LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", wp->id);
delete wp;
continue;
}
wp->delay = fields[6].Get<uint32>();
wp->event_id = fields[7].Get<uint32>();
wp->event_chance = fields[8].Get<uint8>();
data.delay = fields[6].Get<uint32>();
data.event_id = fields[7].Get<uint32>();
data.event_chance = fields[8].Get<uint8>();
path.push_back(wp);
path.emplace(data.id, data);
} while (result->NextRow());
}

View File

@@ -22,6 +22,7 @@
#include <optional>
#include <unordered_map>
#include <vector>
#include <map>
enum WaypointMoveType
{
@@ -39,12 +40,12 @@ struct WaypointData
float x, y, z;
std::optional<float> orientation;
uint32 delay;
uint32 event_id;
uint32 move_type;
uint8 event_chance;
uint32 event_id = 0;
uint32 move_type = 0;
uint8 event_chance = 0;
};
typedef std::vector<WaypointData*> WaypointPath;
typedef std::map<uint32, WaypointData> WaypointPath;
typedef std::unordered_map<uint32, WaypointPath> WaypointPathContainer;
class WaypointMgr