mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-28 08:06:23 +00:00
feature(SmartAI/Movement) - Unify waypoint systems (#23251)
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user