diff options
Diffstat (limited to 'src')
26 files changed, 553 insertions, 665 deletions
diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 763cd38d34f..be1dfb6a7de 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -44,19 +44,20 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_UPD_CREATURE_WANDER_DISTANCE, "UPDATE creature SET wander_distance = ?, MovementType = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS, "UPDATE creature SET spawntimesecs = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_INS_CREATURE_FORMATION, "INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(WORLD_INS_WAYPOINT_DATA, "INSERT INTO waypoint_data (id, point, position_x, position_y, position_z, orientation) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(WORLD_DEL_WAYPOINT_DATA, "DELETE FROM waypoint_data WHERE id = ? AND point = ?", CONNECTION_ASYNC); - PrepareStatement(WORLD_UPD_WAYPOINT_DATA_POINT, "UPDATE waypoint_data SET point = point - 1 WHERE id = ? AND point > ?", CONNECTION_ASYNC); - PrepareStatement(WORLD_UPD_WAYPOINT_DATA_POSITION, "UPDATE waypoint_data SET position_x = ?, position_y = ?, position_z = ?, orientation = ? where id = ? AND point = ?", CONNECTION_ASYNC); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_MAX_ID, "SELECT MAX(id) FROM waypoint_data", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_MAX_POINT, "SELECT MAX(point) FROM waypoint_data WHERE id = ?", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID, "SELECT point, position_x, position_y, position_z, orientation, move_type, delay FROM waypoint_data WHERE id = ? ORDER BY point", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_BY_ID, "SELECT point, position_x, position_y, position_z, orientation FROM waypoint_data WHERE id = ?", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_FIRST_BY_ID, "SELECT position_x, position_y, position_z, orientation FROM waypoint_data WHERE point = 1 AND id = ?", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_LAST_BY_ID, "SELECT position_x, position_y, position_z, orientation FROM waypoint_data WHERE id = ? ORDER BY point DESC LIMIT 1", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_POS, "SELECT id, point FROM waypoint_data WHERE (abs(position_x - ?) <= ?) and (abs(position_y - ?) <= ?) and (abs(position_z - ?) <= ?)", CONNECTION_SYNCH); - PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, path_id) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET path_id = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_BY_PATHID, "SELECT PathId, MoveType, Flags FROM waypoint_path WHERE PathId = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_INS_WAYPOINT_PATH_NODE, "INSERT INTO waypoint_path_node (PathId, NodeId, PositionX, PositionY, PositionZ, Orientation) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_DEL_WAYPOINT_PATH_NODE, "DELETE FROM waypoint_path_node WHERE PathId = ? AND NodeId = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_UPD_WAYPOINT_PATH_NODE, "UPDATE waypoint_path_node SET NodeId = NodeId - 1 WHERE PathId = ? AND NodeId > ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_UPD_WAYPOINT_PATH_NODE_POSITION, "UPDATE waypoint_path_node SET PositionX = ?, PositionY = ?, PositionZ = ?, Orientation = ? WHERE PathId = ? AND NodeId = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_MAX_PATHID, "SELECT MAX(PathId) FROM waypoint_path_node", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_MAX_NODEID, "SELECT MAX(NodeId) FROM waypoint_path_node WHERE PathId = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_BY_PATHID, "SELECT PathId, NodeId, PositionX, PositionY, PositionZ, Orientation, Delay FROM waypoint_path_node WHERE PathId = ? ORDER BY NodeId", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_POS_BY_PATHID, "SELECT NodeId, PositionX, PositionY, PositionZ, Orientation FROM waypoint_path_node WHERE PathId = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_POS_FIRST_BY_PATHID, "SELECT PositionX, PositionY, PositionZ, Orientation FROM waypoint_path_node WHERE NodeId = 1 AND PathId = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_POS_LAST_BY_PATHID, "SELECT PositionX, PositionY, PositionZ, Orientation FROM waypoint_path_node WHERE PathId = ? ORDER BY NodeId DESC LIMIT 1", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_PATH_NODE_BY_POS, "SELECT PathId, NodeId FROM waypoint_path_node WHERE (abs(PositionX - ?) <= ?) and (abs(PositionY - ?) <= ?) and (abs(PositionZ - ?) <= ?)", CONNECTION_SYNCH); + PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, PathId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET PathId = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_CREATURE_ADDON, "DELETE FROM creature_addon WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_CREATURE_ADDON_BY_GUID, "SELECT guid FROM creature_addon WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h index ea6475786d9..d24be6862b1 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.h +++ b/src/server/database/Database/Implementation/WorldDatabase.h @@ -49,22 +49,18 @@ enum WorldDatabaseStatements : uint32 WORLD_UPD_CREATURE_WANDER_DISTANCE, WORLD_UPD_CREATURE_SPAWN_TIME_SECS, WORLD_INS_CREATURE_FORMATION, - WORLD_INS_WAYPOINT_DATA, - WORLD_DEL_WAYPOINT_DATA, - WORLD_UPD_WAYPOINT_DATA_POINT, - WORLD_UPD_WAYPOINT_DATA_POSITION, - WORLD_UPD_WAYPOINT_DATA_WPGUID, - WORLD_UPD_WAYPOINT_DATA_ALL_WPGUID, - WORLD_SEL_WAYPOINT_DATA_MAX_ID, - WORLD_SEL_WAYPOINT_DATA_BY_ID, - WORLD_SEL_WAYPOINT_DATA_POS_BY_ID, - WORLD_SEL_WAYPOINT_DATA_POS_FIRST_BY_ID, - WORLD_SEL_WAYPOINT_DATA_POS_LAST_BY_ID, - WORLD_SEL_WAYPOINT_DATA_BY_WPGUID, - WORLD_SEL_WAYPOINT_DATA_ALL_BY_WPGUID, - WORLD_SEL_WAYPOINT_DATA_MAX_POINT, - WORLD_SEL_WAYPOINT_DATA_BY_POS, - WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, + WORLD_SEL_WAYPOINT_PATH_BY_PATHID, + WORLD_INS_WAYPOINT_PATH_NODE, + WORLD_DEL_WAYPOINT_PATH_NODE, + WORLD_UPD_WAYPOINT_PATH_NODE, + WORLD_UPD_WAYPOINT_PATH_NODE_POSITION, + WORLD_SEL_WAYPOINT_PATH_NODE_MAX_PATHID, + WORLD_SEL_WAYPOINT_PATH_NODE_BY_PATHID, + WORLD_SEL_WAYPOINT_PATH_NODE_POS_BY_PATHID, + WORLD_SEL_WAYPOINT_PATH_NODE_POS_FIRST_BY_PATHID, + WORLD_SEL_WAYPOINT_PATH_NODE_POS_LAST_BY_PATHID, + WORLD_SEL_WAYPOINT_PATH_NODE_MAX_NODEID, + WORLD_SEL_WAYPOINT_PATH_NODE_BY_POS, WORLD_UPD_CREATURE_ADDON_PATH, WORLD_INS_CREATURE_ADDON, WORLD_DEL_CREATURE_ADDON, diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index ecc44114f85..ca6290d1379 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -141,13 +141,13 @@ void EscortAI::MovementInform(uint32 type, uint32 id) } else if (type == WAYPOINT_MOTION_TYPE) { - ASSERT(id < _path.nodes.size(), "EscortAI::MovementInform: referenced movement id (%u) points to non-existing node in loaded path (%s)", id, me->GetGUID().ToString().c_str()); - WaypointNode waypoint = _path.nodes[id]; + ASSERT(id < _path.Nodes.size(), "EscortAI::MovementInform: referenced movement id (%u) points to non-existing node in loaded path (%s)", id, me->GetGUID().ToString().c_str()); + WaypointNode waypoint = _path.Nodes[id]; - TC_LOG_DEBUG("scripts.ai.escortai", "EscortAI::MovementInform: waypoint node {} reached ({})", waypoint.id, me->GetGUID().ToString()); + TC_LOG_DEBUG("scripts.ai.escortai", "EscortAI::MovementInform: waypoint node {} reached ({})", waypoint.Id, me->GetGUID().ToString()); // last point - if (id == _path.nodes.size() - 1) + if (id == _path.Nodes.size() - 1) { _started = false; _ended = true; @@ -264,20 +264,14 @@ void EscortAI::AddWaypoint(uint32 id, float x, float y, float z, float orientati Trinity::NormalizeMapCoord(x); Trinity::NormalizeMapCoord(y); - WaypointNode waypoint; - waypoint.id = id; - waypoint.x = x; - waypoint.y = y; - waypoint.z = z; - waypoint.orientation = orientation; - waypoint.moveType = run ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK; - waypoint.delay = waitTime.count(); - _path.nodes.push_back(std::move(waypoint)); + WaypointNode waypoint(id, x, y, z, orientation, waitTime.count()); + waypoint.MoveType = run ? WaypointMoveType::Run : WaypointMoveType::Walk; + _path.Nodes.push_back(std::move(waypoint)); } void EscortAI::ResetPath() { - _path.nodes.clear(); + _path.Nodes.clear(); } void EscortAI::LoadPath(uint32 pathId) @@ -294,7 +288,7 @@ void EscortAI::LoadPath(uint32 pathId) /// @todo get rid of this many variables passed in function. void EscortAI::Start(bool isActiveAttacker /* = true*/, ObjectGuid playerGUID /* = 0 */, Quest const* quest /* = nullptr */, bool instantRespawn /* = false */, bool canLoopPath /* = false */) { - if (_path.nodes.empty()) + if (_path.Nodes.empty()) { TC_LOG_ERROR("scripts.ai.escortai", "EscortAI::Start: (script: {}) path is empty ({})", me->GetScriptName(), me->GetGUID().ToString()); return; @@ -319,7 +313,7 @@ void EscortAI::Start(bool isActiveAttacker /* = true*/, ObjectGuid playerGUID /* return; } - if (_path.nodes.empty()) + if (_path.Nodes.empty()) { TC_LOG_ERROR("scripts.ai.escortai", "EscortAI::Start: (script: {}) is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn ({})", me->GetScriptName(), me->GetGUID().ToString()); return; @@ -348,7 +342,7 @@ void EscortAI::Start(bool isActiveAttacker /* = true*/, ObjectGuid playerGUID /* } TC_LOG_DEBUG("scripts.ai.escortai", "EscortAI::Start: (script: {}) started with {} waypoints. ActiveAttacker = {}, Player = {} ({})", - me->GetScriptName(), uint32(_path.nodes.size()), _activeAttacker, _playerGUID.ToString(), me->GetGUID().ToString()); + me->GetScriptName(), uint32(_path.Nodes.size()), _activeAttacker, _playerGUID.ToString(), me->GetGUID().ToString()); _started = false; AddEscortState(STATE_ESCORT_ESCORTING); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 3918f415f9d..370e2d1a9f8 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -33,7 +33,7 @@ #include "WaypointManager.h" SmartAI::SmartAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId), _charmed(false), _followCreditType(0), _followArrivedTimer(0), _followCredit(0), _followArrivedEntry(0), _followDistance(0.f), _followAngle(0.f), - _escortState(SMART_ESCORT_NONE), _escortNPCFlags(0), _escortInvokerCheckTimer(1000), _currentWaypointNode(0), _waypointReached(false), _waypointPauseTimer(0), _waypointPauseForced(false), _repeatWaypointPath(false), + _escortState(SMART_ESCORT_NONE), _escortNPCFlags(0), _escortInvokerCheckTimer(1000), _currentWaypointNodeId(0), _waypointReached(false), _waypointPauseTimer(0), _waypointPauseForced(false), _repeatWaypointPath(false), _OOCReached(false), _waypointPathEnded(false), _run(true), _evadeDisabled(false), _canCombatMove(true), _invincibilityHPLevel(0), _despawnTime(0), _despawnState(0), _vehicleConditionsTimer(0), _gossipReturn(false), _escortQuestId(0) { @@ -57,7 +57,7 @@ void SmartAI::StartPath(uint32 pathId/* = 0*/, bool repeat/* = false*/, Unit* in if (!path) return; - _currentWaypointNode = nodeId; + _currentWaypointNodeId = nodeId; _waypointPathEnded = false; _repeatWaypointPath = repeat; @@ -80,7 +80,7 @@ WaypointPath const* SmartAI::LoadPath(uint32 entry) return nullptr; WaypointPath const* path = sWaypointMgr->GetPath(entry); - if (!path || path->nodes.empty()) + if (!path || path->Nodes.empty()) { GetScript()->SetPathId(0); return nullptr; @@ -105,7 +105,7 @@ void SmartAI::PausePath(uint32 delay, bool forced) if (HasEscortState(SMART_ESCORT_PAUSED)) { - TC_LOG_ERROR("scripts.ai.sai", "SmartAI::PausePath: Creature wanted to pause waypoint (current waypoint: {}) movement while already paused, ignoring. ({})", _currentWaypointNode, me->GetGUID().ToString()); + TC_LOG_ERROR("scripts.ai.sai", "SmartAI::PausePath: Creature wanted to pause waypoint (current waypoint: {}) movement while already paused, ignoring. ({})", _currentWaypointNodeId, me->GetGUID().ToString()); return; } @@ -122,7 +122,7 @@ void SmartAI::PausePath(uint32 delay, bool forced) _waypointReached = false; AddEscortState(SMART_ESCORT_PAUSED); - GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); + GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, _currentWaypointNodeId, GetScript()->GetPathId()); } bool SmartAI::CanResumePath() @@ -170,7 +170,7 @@ void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail) me->GetMotionMaster()->MoveIdle(); - GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); + GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, _currentWaypointNodeId, GetScript()->GetPathId()); EndPath(fail); } @@ -235,7 +235,7 @@ void SmartAI::EndPath(bool fail) return; uint32 pathid = GetScript()->GetPathId(); - GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, _currentWaypointNode, pathid); + GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, _currentWaypointNodeId, pathid); if (_repeatWaypointPath) { @@ -251,7 +251,7 @@ void SmartAI::EndPath(bool fail) void SmartAI::ResumePath() { - GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); + GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, _currentWaypointNodeId, GetScript()->GetPathId()); RemoveEscortState(SMART_ESCORT_PAUSED); @@ -349,9 +349,9 @@ void SmartAI::WaypointReached(uint32 nodeId, uint32 pathId) return; } - _currentWaypointNode = nodeId; + _currentWaypointNodeId = nodeId; - GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, _currentWaypointNode, pathId); + GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, _currentWaypointNodeId, pathId); if (_waypointPauseTimer && !_waypointPauseForced) { @@ -362,7 +362,7 @@ void SmartAI::WaypointReached(uint32 nodeId, uint32 pathId) else if (HasEscortState(SMART_ESCORT_ESCORTING) && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) { WaypointPath const* path = sWaypointMgr->GetPath(pathId); - if (path && _currentWaypointNode == path->nodes.back().id) + if (path && _currentWaypointNodeId == path->Nodes.back().Id) _waypointPathEnded = true; else SetRun(_run); @@ -535,8 +535,8 @@ void SmartAI::JustReachedHome() { if (me->GetMotionMaster()->GetCurrentMovementGeneratorType(MOTION_SLOT_DEFAULT) != WAYPOINT_MOTION_TYPE) { - if (me->GetWaypointPath()) - me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true); + if (me->GetWaypointPathId()) + me->GetMotionMaster()->MovePath(me->GetWaypointPathId(), true); } me->ResumeMovement(); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index de11f4b7e00..e42e0b53b44 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -253,7 +253,7 @@ class TC_GAME_API SmartAI : public CreatureAI uint32 _escortState; uint32 _escortNPCFlags; uint32 _escortInvokerCheckTimer; - uint32 _currentWaypointNode; + uint32 _currentWaypointNodeId; bool _waypointReached; uint32 _waypointPauseTimer; bool _waypointPauseForced; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index b3c7be43c7a..c1e398bc37f 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2066,17 +2066,17 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (uint32 pathId : waypoints) { WaypointPath const* path = sWaypointMgr->GetPath(pathId); - if (!path || path->nodes.empty()) + if (!path || path->Nodes.empty()) continue; - for (WaypointNode const& waypoint : path->nodes) + for (WaypointNode const& waypoint : path->Nodes) { - float distamceToThisNode = creature->GetDistance(waypoint.x, waypoint.y, waypoint.z); - if (distamceToThisNode < distanceToClosest) + float distanceToThisNode = creature->GetDistance(waypoint.X, waypoint.Y, waypoint.Z); + if (distanceToThisNode < distanceToClosest) { - distanceToClosest = distamceToThisNode; + distanceToClosest = distanceToThisNode; closest.first = pathId; - closest.second = waypoint.id; + closest.second = waypoint.Id; } } } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 2aa5a25e129..a5e63f5ef22 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -1879,7 +1879,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_WP_START: { WaypointPath const* path = sWaypointMgr->GetPath(e.action.wpStart.pathID); - if (!path || path->nodes.empty()) + if (!path || path->Nodes.empty()) { TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature {} Event {} Action {} uses non-existent WaypointPath id {}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID); return false; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 904c21544ab..6108bc3144b 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -868,7 +868,7 @@ struct SmartAction struct { - SAIBool run; // unused / overridden by waypoint_data + SAIBool run; // unused defined by waypoint_path uint32 pathID; SAIBool repeat; uint32 quest; diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index c5f46ae0053..752fde07c7b 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -576,7 +576,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_TRINITY_STRING = 704, // 705 previously used, do not reuse // 706 previously used, do not reuse - RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA = 707, + RBAC_PERM_COMMAND_RELOAD_WAYPOINT_PATH = 707, RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESORY = 708, RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE_ACCESSORY = 709, RBAC_PERM_COMMAND_RESET = 710, diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 7ee64d90cdd..b662a7826d2 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2768,8 +2768,8 @@ bool Creature::LoadCreaturesAddon() SetVisibilityDistanceOverride(creatureAddon->visibilityDistanceType); // Load Path - if (creatureAddon->path_id != 0) - _waypointPathId = creatureAddon->path_id; + if (creatureAddon->PathId != 0) + _waypointPathId = creatureAddon->PathId; if (!creatureAddon->auras.empty()) { @@ -3496,7 +3496,7 @@ std::string Creature::GetDebugInfo() const std::stringstream sstr; sstr << Unit::GetDebugInfo() << "\n" << "AIName: " << GetAIName() << " ScriptName: " << GetScriptName() - << " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId(); + << " WaypointPath: " << GetWaypointPathId() << " SpawnId: " << GetSpawnId(); return sstr.str(); } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index e051458e820..84865873963 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -329,7 +329,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void GetTransportHomePosition(float& x, float& y, float& z, float& ori) const { m_transportHomePosition.GetPosition(x, y, z, ori); } Position const& GetTransportHomePosition() const { return m_transportHomePosition; } - uint32 GetWaypointPath() const { return _waypointPathId; } + uint32 GetWaypointPathId() const { return _waypointPathId; } void LoadPath(uint32 pathid) { _waypointPathId = pathid; } // nodeId, pathId diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 74c0a4bfd86..91ae066041d 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -676,7 +676,7 @@ enum InhabitTypeValues // `creature_addon` table struct CreatureAddon { - uint32 path_id; + uint32 PathId; uint32 mount; uint8 standState; uint8 animTier; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 17dc0b8dc59..982591cad03 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -741,7 +741,7 @@ void ObjectMgr::LoadCreatureTemplateAddons() uint32 oldMSTime = getMSTime(); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - QueryResult result = WorldDatabase.Query("SELECT entry, path_id, mount, StandState, AnimTier, VisFlags, SheathState, PvPFlags, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon"); + QueryResult result = WorldDatabase.Query("SELECT entry, PathId, mount, StandState, AnimTier, VisFlags, SheathState, PvPFlags, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon"); if (!result) { @@ -764,7 +764,7 @@ void ObjectMgr::LoadCreatureTemplateAddons() CreatureAddon& creatureAddon = _creatureTemplateAddonStore[entry]; - creatureAddon.path_id = fields[1].GetUInt32(); + creatureAddon.PathId = fields[1].GetUInt32(); creatureAddon.mount = fields[2].GetUInt32(); creatureAddon.standState = fields[3].GetUInt8(); creatureAddon.animTier = fields[4].GetUInt8(); @@ -1204,7 +1204,7 @@ void ObjectMgr::LoadCreatureAddons() uint32 oldMSTime = getMSTime(); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - QueryResult result = WorldDatabase.Query("SELECT guid, path_id, mount, StandState, AnimTier, VisFlags, SheathState, PvPFlags, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon"); + QueryResult result = WorldDatabase.Query("SELECT guid, PathId, mount, StandState, AnimTier, VisFlags, SheathState, PvPFlags, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon"); if (!result) { @@ -1228,8 +1228,8 @@ void ObjectMgr::LoadCreatureAddons() CreatureAddon& creatureAddon = _creatureAddonStore[guid]; - creatureAddon.path_id = fields[1].GetUInt32(); - if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.path_id) + creatureAddon.PathId = fields[1].GetUInt32(); + if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.PathId) { const_cast<CreatureData*>(creData)->movementType = IDLE_MOTION_TYPE; TC_LOG_ERROR("sql.sql", "Creature (GUID {}) has movement type set to WAYPOINT_MOTION_TYPE but no path assigned", guid); diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index a049481bee9..00ec6f25de0 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -1121,7 +1121,7 @@ void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional< Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})", - _owner->GetGUID().ToString(), path.id, repeatable ? "YES" : "NO"); + _owner->GetGUID().ToString(), path.Id, repeatable ? "YES" : "NO"); Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT); } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index cde3f8f097b..bd5e6cbe996 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -105,15 +105,15 @@ void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer/* = 0*/) bool WaypointMovementGenerator<Creature>::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z) { // prevent a crash at empty waypoint path. - if (!_path || _path->nodes.empty()) + if (!_path || _path->Nodes.empty()) return false; - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::GetResetPosition: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes.at(_currentNode); + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::GetResetPosition: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); + WaypointNode const &waypoint = _path->Nodes.at(_currentNode); - x = waypoint.x; - y = waypoint.y; - z = waypoint.z; + x = waypoint.X; + y = waypoint.Y; + z = waypoint.Z; return true; } @@ -124,7 +124,7 @@ void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner) if (_loadedFromDB) { if (!_pathId) - _pathId = owner->GetWaypointPath(); + _pathId = owner->GetWaypointPathId(); _path = sWaypointMgr->GetPath(_pathId); } @@ -135,6 +135,11 @@ void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner) return; } + _followPathBackwardsFromEndToStart = _path->Flags.HasFlag(WaypointPathFlags::FollowPathBackwardsFromEndToStart); + + if (_path->Nodes.size() == 1) + _repeating = false; + owner->StopMoving(); _nextMoveTime.Reset(1000); @@ -155,7 +160,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff) if (!owner || !owner->IsAlive()) return true; - if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->nodes.empty()) + if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->Nodes.empty()) return true; if (_duration) @@ -261,25 +266,29 @@ void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool activ void WaypointMovementGenerator<Creature>::MovementInform(Creature* owner) { - if (owner->AI()) - owner->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); + WaypointNode const& waypoint = _path->Nodes.at(_currentNode); + if (CreatureAI* AI = owner->AI()) + { + AI->MovementInform(WAYPOINT_MOTION_TYPE, waypoint.Id); + AI->WaypointReached(waypoint.Id, _path->Id); + } } void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner) { - if (!_path || _path->nodes.empty()) + if (!_path || _path->Nodes.empty()) return; - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::OnArrived: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes.at(_currentNode); - if (waypoint.delay) + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::OnArrived: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); + WaypointNode const &waypoint = _path->Nodes.at(_currentNode); + if (waypoint.Delay) { owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); - _nextMoveTime.Reset(waypoint.delay); + _nextMoveTime.Reset(waypoint.Delay); } - if (_waitTimeRangeAtPathEnd && _followPathBackwardsFromEndToStart - && ((_isReturningToStart && _currentNode == 0) || (!_isReturningToStart && _currentNode == _path->nodes.size() - 1))) + if (_waitTimeRangeAtPathEnd && _followPathBackwardsFromEndToStart && *_followPathBackwardsFromEndToStart + && ((_isReturningToStart && _currentNode == 0) || (!_isReturningToStart && _currentNode == _path->Nodes.size() - 1))) { owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); Milliseconds waitTime = randtime(_waitTimeRangeAtPathEnd->first, _waitTimeRangeAtPathEnd->second); @@ -292,20 +301,15 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner) _nextMoveTime.Reset(waitTime); } - // inform AI - if (CreatureAI* AI = owner->AI()) - { - AI->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); - AI->WaypointReached(waypoint.id, _path->id); - } + MovementInform(owner); - owner->UpdateCurrentWaypointInfo(waypoint.id, _path->id); + owner->UpdateCurrentWaypointInfo(waypoint.Id, _path->Id); } void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaunch/* = false*/) { // sanity checks - if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || !_path || _path->nodes.empty() || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)))) + if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || !_path || _path->Nodes.empty() || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)))) return; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || (owner->IsFormationLeader() && !owner->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation @@ -320,18 +324,18 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun { if (ComputeNextNode()) { - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); // inform AI if (CreatureAI* AI = owner->AI()) - AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id); + AI->WaypointStarted(_path->Nodes[_currentNode].Id, _path->Id); } else { - WaypointNode const &waypoint = _path->nodes[_currentNode]; - float x = waypoint.x; - float y = waypoint.y; - float z = waypoint.z; + WaypointNode const& waypoint = _path->Nodes[_currentNode]; + float x = waypoint.X; + float y = waypoint.Y; + float z = waypoint.Z; float o = owner->GetOrientation(); if (!transportPath) @@ -352,7 +356,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun // inform AI if (CreatureAI* AI = owner->AI()) - AI->WaypointPathEnded(waypoint.id, _path->id); + AI->WaypointPathEnded(waypoint.Id, _path->Id); return; } } @@ -362,11 +366,11 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun // inform AI if (CreatureAI* AI = owner->AI()) - AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id); + AI->WaypointStarted(_path->Nodes[_currentNode].Id, _path->Id); } - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes[_currentNode]; + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); + WaypointNode const &waypoint = _path->Nodes[_currentNode]; RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED); @@ -380,28 +384,29 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call //! but formationDest contains global coordinates - init.MoveTo(waypoint.x, waypoint.y, waypoint.z, _generatePath); + init.MoveTo(waypoint.X, waypoint.Y, waypoint.Z, _generatePath); - if (waypoint.orientation.has_value() && (waypoint.delay > 0 || _currentNode == _path->nodes.size() - 1)) - init.SetFacing(*waypoint.orientation); + if (waypoint.Orientation.has_value() && (waypoint.Delay > 0 || _currentNode == _path->Nodes.size() - 1)) + init.SetFacing(*waypoint.Orientation); - switch (waypoint.moveType) + switch (_path->MoveType) { - case WAYPOINT_MOVE_TYPE_LAND: + case WaypointMoveType::Land: init.SetAnimation(AnimTier::Ground); break; - case WAYPOINT_MOVE_TYPE_TAKEOFF: + case WaypointMoveType::TakeOff: init.SetAnimation(AnimTier::Hover); break; - case WAYPOINT_MOVE_TYPE_RUN: + case WaypointMoveType::Run: init.SetWalk(false); break; - case WAYPOINT_MOVE_TYPE_WALK: + case WaypointMoveType::Walk: init.SetWalk(true); break; default: break; } + switch (_speedSelectionMode) // overrides move type from each waypoint if set { case MovementWalkRunSpeedSelectionMode::Default: @@ -427,18 +432,18 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun bool WaypointMovementGenerator<Creature>::ComputeNextNode() { - if ((_currentNode == _path->nodes.size() - 1) && !_repeating) + if ((_currentNode == _path->Nodes.size() - 1) && !_repeating) return false; - if (!_followPathBackwardsFromEndToStart || _path->nodes.size() < 2) - _currentNode = (_currentNode + 1) % _path->nodes.size(); + if (!_followPathBackwardsFromEndToStart.value_or(false) || _path->Nodes.size() < WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES) + _currentNode = (_currentNode + 1) % _path->Nodes.size(); else { if (!_isReturningToStart) { - if (++_currentNode >= _path->nodes.size()) + if (++_currentNode >= _path->Nodes.size()) { - _currentNode -= 2; + _currentNode -= WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES; _isReturningToStart = true; } } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 3764a9629f0..6474e9df85e 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -85,7 +85,7 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat MovementWalkRunSpeedSelectionMode _speedSelectionMode; Optional<std::pair<Milliseconds, Milliseconds>> _waitTimeRangeAtPathEnd; Optional<float> _wanderDistanceAtPathEnds; - bool _followPathBackwardsFromEndToStart; + Optional<bool> _followPathBackwardsFromEndToStart; bool _isReturningToStart; bool _generatePath; }; diff --git a/src/server/game/Movement/Waypoints/WaypointDefines.h b/src/server/game/Movement/Waypoints/WaypointDefines.h index 119219dd3d4..d801531b316 100644 --- a/src/server/game/Movement/Waypoints/WaypointDefines.h +++ b/src/server/game/Movement/Waypoints/WaypointDefines.h @@ -19,51 +19,68 @@ #define TRINITY_WAYPOINTDEFINES_H #include "Define.h" +#include "EnumFlag.h" #include "Optional.h" #include <vector> -enum WaypointMoveType +#define WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES 2 + +enum class WaypointMoveType : uint8 { - WAYPOINT_MOVE_TYPE_WALK, - WAYPOINT_MOVE_TYPE_RUN, - WAYPOINT_MOVE_TYPE_LAND, - WAYPOINT_MOVE_TYPE_TAKEOFF, + Walk = 0, + Run = 1, + Land = 2, + TakeOff = 3, - WAYPOINT_MOVE_TYPE_MAX + Max }; +enum class WaypointPathFlags : uint8 +{ + None = 0x00, + FollowPathBackwardsFromEndToStart = 0x01, +}; + +DEFINE_ENUM_FLAG(WaypointPathFlags); + struct WaypointNode { - WaypointNode() : id(0), x(0.f), y(0.f), z(0.f), delay(0), moveType(WAYPOINT_MOVE_TYPE_RUN) { } - WaypointNode(uint32 _id, float _x, float _y, float _z, Optional<float> _orientation = { }, uint32 _delay = 0) + WaypointNode() : Id(0), X(0.f), Y(0.f), Z(0.f), Delay(0), MoveType(WaypointMoveType::Walk) { } + WaypointNode(uint32 id, float x, float y, float z, Optional<float> orientation = { }, uint32 delay = 0) { - id = _id; - x = _x; - y = _y; - z = _z; - orientation = _orientation; - delay = _delay; - moveType = WAYPOINT_MOVE_TYPE_WALK; + Id = id; + X = x; + Y = y; + Z = z; + Orientation = orientation; + Delay = delay; + MoveType = WaypointMoveType::Walk; } - uint32 id; - float x, y, z; - Optional<float> orientation; - uint32 delay; - uint32 moveType; + uint32 Id; + float X; + float Y; + float Z; + Optional<float> Orientation; + uint32 Delay; + WaypointMoveType MoveType; }; struct WaypointPath { - WaypointPath() : id(0) { } - WaypointPath(uint32 _id, std::vector<WaypointNode>&& _nodes) + WaypointPath() : Id(0), MoveType(WaypointMoveType::Walk), Flags(WaypointPathFlags::None) { } + WaypointPath(uint32 id, std::vector<WaypointNode>&& nodes, WaypointMoveType moveType = WaypointMoveType::Walk, WaypointPathFlags flags = WaypointPathFlags::None) { - id = _id; - nodes = _nodes; + Id = id; + Nodes = nodes; + Flags = flags; + MoveType = moveType; } - std::vector<WaypointNode> nodes; - uint32 id; + std::vector<WaypointNode> Nodes; + uint32 Id; + WaypointMoveType MoveType; + EnumFlag<WaypointPathFlags> Flags = WaypointPathFlags::None; }; #endif diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp index ab018e66233..cb282e6ec30 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.cpp +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -19,17 +19,31 @@ #include "DatabaseEnv.h" #include "GridDefines.h" #include "Log.h" +#include "MapUtils.h" +#include "ObjectAccessor.h" +#include "Optional.h" +#include "TemporarySummon.h" +#include "Unit.h" -void WaypointMgr::Load() +void WaypointMgr::LoadPaths() +{ + _LoadPaths(); + _LoadPathNodes(); + DoPostLoadingChecks(); +} + +void WaypointMgr::_LoadPaths() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 - QueryResult result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, orientation, move_type, delay FROM waypoint_data ORDER BY id, point"); + _pathStore.clear(); + + // 0 1 2 + QueryResult result = WorldDatabase.Query("SELECT PathId, MoveType, Flags FROM waypoint_path"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 waypoints. DB table `waypoint_data` is empty!"); + TC_LOG_INFO("server.loading", ">> Loaded 0 waypoint paths. DB table `waypoint_path` is empty!"); return; } @@ -37,42 +51,92 @@ void WaypointMgr::Load() do { - Field* fields = result->Fetch(); - uint32 pathId = fields[0].GetUInt32(); - float x = fields[2].GetFloat(); - float y = fields[3].GetFloat(); - float z = fields[4].GetFloat(); - Optional<float> o; - if (!fields[5].IsNull()) - o = fields[5].GetFloat(); - - Trinity::NormalizeMapCoord(x); - Trinity::NormalizeMapCoord(y); - - WaypointNode waypoint; - waypoint.id = fields[1].GetUInt32(); - waypoint.x = x; - waypoint.y = y; - waypoint.z = z; - waypoint.orientation = o; - waypoint.moveType = fields[6].GetUInt32(); - - if (waypoint.moveType >= WAYPOINT_MOVE_TYPE_MAX) - { - TC_LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", waypoint.id); - continue; - } + LoadPathFromDB(result->Fetch()); + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded {} waypoint paths in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void WaypointMgr::_LoadPathNodes() +{ + uint32 oldMSTime = getMSTime(); + // 0 1 2 3 4 5 6 + QueryResult result = WorldDatabase.Query("SELECT PathId, NodeId, PositionX, PositionY, PositionZ, Orientation, Delay FROM waypoint_path_node ORDER BY PathId, NodeId"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 waypoint path nodes. DB table `waypoint_path_node` is empty!"); + return; + } - waypoint.delay = fields[7].GetUInt32(); + uint32 count = 0; - WaypointPath& path = _waypointStore[pathId]; - path.id = pathId; - path.nodes.push_back(std::move(waypoint)); + do + { + LoadPathNodesFromDB(result->Fetch()); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded {} waypoints in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded {} waypoint path nodes in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + DoPostLoadingChecks(); +} + +void WaypointMgr::LoadPathFromDB(Field* fields) +{ + uint32 pathId = fields[0].GetUInt32(); + + WaypointPath& path = _pathStore[pathId]; + path.Id = pathId; + path.MoveType = (WaypointMoveType)fields[1].GetUInt8(); + + if (path.MoveType >= WaypointMoveType::Max) + { + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has invalid MoveType {}, ignoring", pathId, AsUnderlyingType(path.MoveType)); + return; + } + path.Flags = (WaypointPathFlags)fields[2].GetUInt8(); + path.Nodes.clear(); +} + +void WaypointMgr::LoadPathNodesFromDB(Field* fields) +{ + uint32 pathId = fields[0].GetUInt32(); + + if (_pathStore.find(pathId) == _pathStore.end()) + { + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path_node` does not exist in `waypoint_path`, ignoring", pathId); + return; + } + + float x = fields[2].GetFloat(); + float y = fields[3].GetFloat(); + float z = fields[4].GetFloat(); + Optional<float> o; + if (!fields[5].IsNull()) + o = fields[5].GetFloat(); + + Trinity::NormalizeMapCoord(x); + Trinity::NormalizeMapCoord(y); + + WaypointNode waypoint(fields[1].GetUInt32(), x, y, z, o, fields[6].GetUInt32()); + + WaypointPath& path = _pathStore[pathId]; + path.Nodes.push_back(std::move(waypoint)); +} + +void WaypointMgr::DoPostLoadingChecks() +{ + for (auto const& path : _pathStore) + { + WaypointPath pathInfo = path.second; + if (pathInfo.Nodes.empty()) + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has no assigned nodes in `waypoint_path_node`", pathInfo.Id); + + if (pathInfo.Flags.HasFlag(WaypointPathFlags::FollowPathBackwardsFromEndToStart) && pathInfo.Nodes.size() < WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES) + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has FollowPathBackwardsFromEndToStart set, but only {} nodes, requires {}", pathInfo.Id, pathInfo.Nodes.size(), WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES); + } } WaypointMgr* WaypointMgr::instance() @@ -81,61 +145,177 @@ WaypointMgr* WaypointMgr::instance() return &instance; } -void WaypointMgr::ReloadPath(uint32 id) +void WaypointMgr::ReloadPath(uint32 pathId) { - WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID); + // waypoint_path + { + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_PATH_BY_PATHID); + stmt->setUInt32(0, pathId); - stmt->setUInt32(0, id); + PreparedQueryResult result = WorldDatabase.Query(stmt); - PreparedQueryResult result = WorldDatabase.Query(stmt); + if (!result) + { + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` not found, ignoring", pathId); + return; + } - if (!result) - return; + do + { + LoadPathFromDB(result->Fetch()); + } while (result->NextRow()); + } - std::vector<WaypointNode> values; - do + // waypoint_path_data { - Field* fields = result->Fetch(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - Optional<float> o; - if (!fields[4].IsNull()) - o = fields[4].GetFloat(); - - Trinity::NormalizeMapCoord(x); - Trinity::NormalizeMapCoord(y); - - WaypointNode waypoint; - waypoint.id = fields[0].GetUInt32(); - waypoint.x = x; - waypoint.y = y; - waypoint.z = z; - waypoint.orientation = o; - waypoint.moveType = fields[5].GetUInt32(); - - if (waypoint.moveType >= WAYPOINT_MOVE_TYPE_MAX) + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_PATH_NODE_BY_PATHID); + stmt->setUInt32(0, pathId); + + PreparedQueryResult result = WorldDatabase.Query(stmt); + + if (!result) { - TC_LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", waypoint.id); + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path_node` not found, ignoring", pathId); + return; + } + + do + { + LoadPathNodesFromDB(result->Fetch()); + } while (result->NextRow()); + } +} + +void WaypointMgr::VisualizePath(Unit* owner, WaypointPath const* path, Optional<uint32> displayId) +{ + for (WaypointNode const& node : path->Nodes) + { + std::pair<uint32, uint32> pathNodePair(path->Id, node.Id); + + auto itr = _nodeToVisualWaypointGUIDsMap.find(pathNodePair); + if (itr != _nodeToVisualWaypointGUIDsMap.end()) + continue; + + TempSummon* summon = owner->SummonCreature(VISUAL_WAYPOINT, node.X, node.Y, node.Z, node.Orientation ? *node.Orientation : 0.0f); + if (!summon) continue; + + if (displayId) + { + summon->SetDisplayId(*displayId, true); + summon->SetObjectScale(0.5f); } - waypoint.delay = fields[6].GetUInt32(); + _nodeToVisualWaypointGUIDsMap[pathNodePair] = summon->GetGUID(); + _visualWaypointGUIDToNodeMap[summon->GetGUID()] = std::pair<WaypointPath const*, WaypointNode const*>(path, &node); + } +} + +void WaypointMgr::DevisualizePath(Unit* owner, WaypointPath const* path) +{ + for (WaypointNode const& node : path->Nodes) + { + std::pair<uint32, uint32> pathNodePair(path->Id, node.Id); + auto itr = _nodeToVisualWaypointGUIDsMap.find(pathNodePair); + if (itr == _nodeToVisualWaypointGUIDsMap.end()) + continue; + + Creature* creature = ObjectAccessor::GetCreature(*owner, itr->second); + if (!creature) + continue; + + _visualWaypointGUIDToNodeMap.erase(itr->second); + _nodeToVisualWaypointGUIDsMap.erase(pathNodePair); - values.push_back(std::move(waypoint)); + creature->DespawnOrUnsummon(); } - while (result->NextRow()); +} + +void WaypointMgr::MoveNode(WaypointPath const* path, WaypointNode const* node, Position const& pos) +{ + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_PATH_NODE_POSITION); + stmt->setFloat(0, pos.GetPositionX()); + stmt->setFloat(1, pos.GetPositionY()); + stmt->setFloat(2, pos.GetPositionZ()); + stmt->setFloat(3, pos.GetOrientation()); + stmt->setUInt32(4, path->Id); + stmt->setUInt32(5, node->Id); + WorldDatabase.Execute(stmt); +} + +void WaypointMgr::DeleteNode(WaypointPath const* path, WaypointNode const* node) +{ + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_WAYPOINT_PATH_NODE); + stmt->setUInt32(0, path->Id); + stmt->setUInt32(1, node->Id); + WorldDatabase.Execute(stmt); + + stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_PATH_NODE); + stmt->setUInt32(0, path->Id); + stmt->setUInt32(1, node->Id); + WorldDatabase.Execute(stmt); +} + +void WaypointMgr::DeleteNode(uint32 pathId, uint32 nodeId) +{ + WaypointPath const* path = GetPath(pathId); + if (!path) + return; + + WaypointNode const* node = GetNode(path, nodeId); + if (!node) + return; - WaypointPath& path = _waypointStore[id]; - path.id = id; - path.nodes = std::move(values); + DeleteNode(path, node); } -WaypointPath const* WaypointMgr::GetPath(uint32 id) const +WaypointPath const* WaypointMgr::GetPath(uint32 pathId) const { - auto itr = _waypointStore.find(id); - if (itr != _waypointStore.end()) - return &itr->second; + return Trinity::Containers::MapGetValuePtr(_pathStore, pathId); +} +WaypointNode const* WaypointMgr::GetNode(WaypointPath const* path, uint32 nodeId) const +{ + for (WaypointNode const& node : path->Nodes) + { + if (node.Id == nodeId) + return &node; + } return nullptr; } + +WaypointNode const* WaypointMgr::GetNode(uint32 pathId, uint32 nodeId) const +{ + WaypointPath const* path = GetPath(pathId); + if (!path) + return nullptr; + + return GetNode(path->Id, nodeId); +} + +WaypointPath const* WaypointMgr::GetPathByVisualGUID(ObjectGuid guid) const +{ + auto itr = _visualWaypointGUIDToNodeMap.find(guid); + if (itr == _visualWaypointGUIDToNodeMap.end()) + return nullptr; + + return itr->second.first; +} + +WaypointNode const* WaypointMgr::GetNodeByVisualGUID(ObjectGuid guid) const +{ + auto itr = _visualWaypointGUIDToNodeMap.find(guid); + if (itr == _visualWaypointGUIDToNodeMap.end()) + return nullptr; + + return itr->second.second; +} + +ObjectGuid const& WaypointMgr::GetVisualGUIDByNode(uint32 pathId, uint32 nodeId) const +{ + auto itr = _nodeToVisualWaypointGUIDsMap.find(std::make_pair(pathId, nodeId)); + if (itr == _nodeToVisualWaypointGUIDsMap.end()) + return ObjectGuid::Empty; + + return itr->second; +} diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h index 906c6981e28..721f79d76a6 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.h +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -19,27 +19,53 @@ #define TRINITY_WAYPOINTMANAGER_H #include "Define.h" +#include "Field.h" +#include "Hash.h" +#include "ObjectGuid.h" +#include "Position.h" #include "WaypointDefines.h" #include <unordered_map> +class Unit; + class TC_GAME_API WaypointMgr { public: static WaypointMgr* instance(); // Attempts to reload a single path from database - void ReloadPath(uint32 id); + void ReloadPath(uint32 pathId); // Loads all paths from database, should only run on startup - void Load(); + void LoadPaths(); + void LoadPathFromDB(Field* fields); + void LoadPathNodesFromDB(Field* fields); + void DoPostLoadingChecks(); + + void VisualizePath(Unit* owner, WaypointPath const* path, Optional<uint32> displayId); + void DevisualizePath(Unit* owner, WaypointPath const* path); + + void MoveNode(WaypointPath const* path, WaypointNode const* node, Position const& pos); + void DeleteNode(WaypointPath const* path, WaypointNode const* node); + void DeleteNode(uint32 pathId, uint32 nodeId); - // Returns the path from a given id - WaypointPath const* GetPath(uint32 id) const; + WaypointPath const* GetPath(uint32 pathId) const; + WaypointNode const* GetNode(WaypointPath const* path, uint32 nodeId) const; + WaypointNode const* GetNode(uint32 pathId, uint32 nodeId) const; + WaypointPath const* GetPathByVisualGUID(ObjectGuid guid) const; + WaypointNode const* GetNodeByVisualGUID(ObjectGuid guid) const; + ObjectGuid const& GetVisualGUIDByNode(uint32 pathId, uint32 nodeId) const; private: WaypointMgr() { } - std::unordered_map<uint32, WaypointPath> _waypointStore; + void _LoadPaths(); + void _LoadPathNodes(); + + std::unordered_map<uint32 /*pathId*/, WaypointPath> _pathStore; + + std::unordered_map<std::pair<uint32 /*pathId*/, uint32 /*nodeId*/>, ObjectGuid> _nodeToVisualWaypointGUIDsMap; + std::unordered_map<ObjectGuid, std::pair<WaypointPath const*, WaypointNode const*>> _visualWaypointGUIDToNodeMap; }; #define sWaypointMgr WaypointMgr::instance() diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 20855aa107f..bece9fcfb1f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2279,8 +2279,8 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Vendors..."); sObjectMgr->LoadVendors(); // must be after load CreatureTemplate and ItemTemplate - TC_LOG_INFO("server.loading", "Loading Waypoints..."); - sWaypointMgr->Load(); + TC_LOG_INFO("server.loading", "Loading Waypoint paths..."); + sWaypointMgr->LoadPaths(); TC_LOG_INFO("server.loading", "Loading Creature Formations..."); sFormationMgr->LoadCreatureFormations(); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 1ddfa4f7332..332d75df8d1 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -163,7 +163,7 @@ public: { "support", rbac::RBAC_PERM_COMMAND_RELOAD_SUPPORT_SYSTEM, true, &HandleReloadSupportSystemCommand, "" }, { "trainer", rbac::RBAC_PERM_COMMAND_RELOAD_TRAINER, true, &HandleReloadTrainerCommand, "" }, { "trinity_string", rbac::RBAC_PERM_COMMAND_RELOAD_TRINITY_STRING, true, &HandleReloadTrinityStringCommand, "" }, - { "waypoint_data", rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA, true, &HandleReloadWpCommand, "" }, + { "waypoint_path", rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_PATH, true, &HandleReloadWpCommand, "" }, { "vehicle_template", rbac::RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE, true, &HandleReloadVehicleTemplateCommand, "" }, { "vehicle_accessory", rbac::RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESORY, true, &HandleReloadVehicleAccessoryCommand, "" }, { "vehicle_template_accessory", rbac::RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE_ACCESSORY, true, &HandleReloadVehicleTemplateAccessoryCommand, "" }, @@ -907,12 +907,12 @@ public: static bool HandleReloadWpCommand(ChatHandler* handler, char const* args) { if (*args != 'a') - TC_LOG_INFO("misc", "Re-Loading Waypoints data from 'waypoints_data'"); + TC_LOG_INFO("misc", "Re-Loading Waypoints data from 'waypoint_path' and 'waypoint_path_node'"); - sWaypointMgr->Load(); + sWaypointMgr->LoadPaths(); if (*args != 'a') - handler->SendGlobalGMSysMessage("DB Table 'waypoint_data' reloaded."); + handler->SendGlobalGMSysMessage("DB Tables 'waypoint_path' and 'waypoint_path_node' reloaded."); return true; } diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index 124c7a9a1a0..498570496cc 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -93,16 +93,15 @@ public: if (*args) path_number = strtok((char*)args, " "); - uint32 point = 0; Creature* target = handler->getSelectedCreature(); if (!path_number) { if (target) - pathid = target->GetWaypointPath(); + pathid = target->GetWaypointPathId(); else { - WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_MAX_ID); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_PATH_NODE_MAX_PATHID); PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -114,7 +113,7 @@ public: else pathid = atoi(path_number); - // path_id -> ID of the Path + // PathId -> ID of the Path // point -> number of the waypoint (if not 0) if (!pathid) @@ -123,28 +122,40 @@ public: return true; } - WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_MAX_POINT); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_PATH_NODE_MAX_NODEID); stmt->setUInt32(0, pathid); PreparedQueryResult result = WorldDatabase.Query(stmt); + uint32 nodeId = 0; if (result) - point = (*result)[0].GetUInt32(); + nodeId = (*result)[0].GetUInt32() + 1; - Player* player = handler->GetSession()->GetPlayer(); + Player* player = handler->GetPlayer(); //Map* map = player->GetMap(); - stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_WAYPOINT_DATA); - + stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_WAYPOINT_PATH_NODE); stmt->setUInt32(0, pathid); - stmt->setUInt32(1, point + 1); + stmt->setUInt32(1, nodeId); stmt->setFloat(2, player->GetPositionX()); stmt->setFloat(3, player->GetPositionY()); stmt->setFloat(4, player->GetPositionZ()); stmt->setFloat(5, player->GetOrientation()); - WorldDatabase.Execute(stmt); - handler->PSendSysMessage("%s%s%u%s%u%s|r", "|cff00ff00", "PathID: |r|cff00ffff", pathid, "|r|cff00ff00: Waypoint |r|cff00ffff", point+1, "|r|cff00ff00 created. "); + if (target) + { + uint32 displayId = target->GetDisplayId(); + + WaypointPath const* path = sWaypointMgr->GetPath(pathid); + if (!path) + return true; + + sWaypointMgr->DevisualizePath(handler->GetPlayer(), path); + sWaypointMgr->ReloadPath(pathid); + sWaypointMgr->VisualizePath(handler->GetPlayer(), path, displayId); + } + + handler->PSendSysMessage("%s%s%u%s%u%s|r", "|cff00ff00", "PathID: |r|cff00ffff", pathid, "|r|cff00ff00: Waypoint |r|cff00ffff", nodeId, "|r|cff00ff00 created. "); return true; } // HandleWpAddCommand @@ -163,7 +174,7 @@ public: ObjectGuid::LowType guidLow = UI64LIT(0); Creature* target = handler->getSelectedCreature(); - // Did player provide a path_id? + // Did player provide a PathId? if (!path_number) return false; @@ -215,10 +226,8 @@ public: WorldDatabase.Execute(stmt); stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE); - stmt->setUInt8(0, uint8(WAYPOINT_MOTION_TYPE)); stmt->setUInt64(1, guidLow); - WorldDatabase.Execute(stmt); target->LoadPath(pathid); @@ -246,7 +255,6 @@ public: static bool HandleWpUnLoadCommand(ChatHandler* handler, char const* /*args*/) { - Creature* target = handler->getSelectedCreature(); WorldDatabasePreparedStatement* stmt = nullptr; @@ -264,7 +272,7 @@ public: } CreatureAddon const* addon = sObjectMgr->GetCreatureAddon(guidLow); - if (!addon || addon->path_id == 0) + if (!addon || addon->PathId == 0) { handler->PSendSysMessage("%s%s|r", "|cffff33ff", "Target does not have a loaded path."); return true; @@ -302,25 +310,11 @@ public: } std::string show = show_str; - // Check - // Remember: "show" must also be the name of a column! - if ((show != "delay") && (show != "action") && (show != "action_chance") - && (show != "move_type") && (show != "del") && (show != "move") - ) - { - return false; - } - - // Next arg is: <PATHID> <WPNUM> <ARGUMENT> - char* arg_str = nullptr; // Did user provide a GUID // or did the user select a creature? // -> variable lowguid is filled with the GUID of the NPC - uint32 pathid = 0; - uint32 point = 0; Creature* target = handler->getSelectedCreature(); - WorldDatabasePreparedStatement* stmt = nullptr; // User did select a visual waypoint? if (!target || target->GetEntry() != VISUAL_WAYPOINT) @@ -329,155 +323,51 @@ public: return false; } - // Check the creature - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_WPGUID); - stmt->setUInt64(0, target->GetSpawnId()); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, std::to_string(target->GetSpawnId()).c_str()); - // Select waypoint number from database - // Since we compare float values, we have to deal with - // some difficulties. - // Here we search for all waypoints that only differ in one from 1 thousand - // (0.001) - There is no other way to compare C++ floats with mySQL floats - // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html - std::string maxDiff = "0.01"; - - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_POS); - stmt->setFloat(0, target->GetPositionX()); - stmt->setString(1, maxDiff); - stmt->setFloat(2, target->GetPositionY()); - stmt->setString(3, maxDiff); - stmt->setFloat(4, target->GetPositionZ()); - stmt->setString(5, maxDiff); - result = WorldDatabase.Query(stmt); - - if (!result) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, std::to_string(target->GetSpawnId()).c_str()); - return true; - } - } - - do + WaypointPath const* path = sWaypointMgr->GetPathByVisualGUID(target->GetGUID()); + if (!path) { - Field* fields = result->Fetch(); - pathid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); + handler->PSendSysMessage("|cff00ff00Path does not exist or target has no path|r"); + handler->SetSentErrorMessage(true); + return false; } - while (result->NextRow()); - // We have the waypoint number and the GUID of the "master npc" - // Text is enclosed in "<>", all other arguments not - arg_str = strtok((char*)nullptr, " "); - - // Check for argument - if (show != "del" && show != "move" && arg_str == nullptr) + WaypointNode const* node = sWaypointMgr->GetNodeByVisualGUID(target->GetGUID()); + if (!node) { - handler->PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str); + handler->PSendSysMessage("|cff00ff00Path does not exist or target has no path|r"); + handler->SetSentErrorMessage(true); return false; } if (show == "del") { - handler->PSendSysMessage("|cff00ff00DEBUG: wp modify del, PathID: |r|cff00ffff%u|r", pathid); + handler->PSendSysMessage("|cff00ff00DEBUG: .wp modify del, PathId: |r|cff00ffff%u|r, NodeId: |r|cff00ffff%u|r", path->Id, node->Id); - if (Creature::DeleteFromDB(target->GetSpawnId())) - { - stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_WAYPOINT_DATA); - stmt->setUInt32(0, pathid); - stmt->setUInt32(1, point); - WorldDatabase.Execute(stmt); + uint32 displayId = target->GetDisplayId(); - stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_POINT); - stmt->setUInt32(0, pathid); - stmt->setUInt32(1, point); - WorldDatabase.Execute(stmt); + sWaypointMgr->DevisualizePath(handler->GetPlayer(), path); + sWaypointMgr->DeleteNode(path, node); + sWaypointMgr->ReloadPath(path->Id); + sWaypointMgr->VisualizePath(handler->GetPlayer(), path, displayId); - handler->SendSysMessage(LANG_WAYPOINT_REMOVED); - return true; - } - else - { - handler->SendSysMessage(LANG_WAYPOINT_NOTREMOVED); - handler->SetSentErrorMessage(true); - return false; - } - } // del - - if (show == "move") + handler->SendSysMessage(LANG_WAYPOINT_REMOVED); + return true; + } + else if (show == "move") { - handler->PSendSysMessage("|cff00ff00DEBUG: wp move, PathID: |r|cff00ffff%u|r", pathid); - - Player* chr = handler->GetSession()->GetPlayer(); - Map* map = chr->GetMap(); - // What to do: - // Move the visual spawnpoint - // Respawn the owner of the waypoints - if (!Creature::DeleteFromDB(target->GetSpawnId())) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - handler->SetSentErrorMessage(true); - return false; - } - - // re-create - Creature* wpCreature = Creature::CreateCreature(VISUAL_WAYPOINT, map, chr->GetPosition()); - if (!wpCreature) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - return false; - } - - PhasingHandler::InheritPhaseShift(wpCreature, chr); - wpCreature->SaveToDB(map->GetId(), { map->GetDifficultyID() }); - - ObjectGuid::LowType dbGuid = wpCreature->GetSpawnId(); + handler->PSendSysMessage("|cff00ff00DEBUG: .wp move, PathId: |r|cff00ffff%u|r, NodeId: |r|cff00ffff%u|r", path->Id, node->Id); - // current "wpCreature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior - wpCreature->CleanupsBeforeDelete(); - delete wpCreature; - - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature = Creature::CreateCreatureFromDB(dbGuid, map, true, true); - if (!wpCreature) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - return false; - } + uint32 displayId = target->GetDisplayId(); - stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_POSITION); - stmt->setFloat(0, chr->GetPositionX()); - stmt->setFloat(1, chr->GetPositionY()); - stmt->setFloat(2, chr->GetPositionZ()); - stmt->setFloat(3, chr->GetOrientation()); - stmt->setUInt32(4, pathid); - stmt->setUInt32(5, point); - WorldDatabase.Execute(stmt); + sWaypointMgr->DevisualizePath(handler->GetPlayer(), path); + sWaypointMgr->MoveNode(path, node, handler->GetPlayer()->GetPosition()); + sWaypointMgr->ReloadPath(path->Id); + sWaypointMgr->VisualizePath(handler->GetPlayer(), path, displayId); handler->PSendSysMessage(LANG_WAYPOINT_CHANGED); return true; - } // move - - const char *text = arg_str; - - if (text == nullptr) - { - // show_str check for present in list of correct values, no sql injection possible - WorldDatabase.PExecute("UPDATE waypoint_data SET {}=NULL WHERE id='{}' AND point='{}'", show_str, pathid, point); // Query can't be a prepared statement } - else - { - // show_str check for present in list of correct values, no sql injection possible - std::string text2 = text; - WorldDatabase.EscapeString(text2); - WorldDatabase.PExecute("UPDATE waypoint_data SET {}='{}' WHERE id='{}' AND point='{}'", show_str, text2, pathid, point); // Query can't be a prepared statement - } - - handler->PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str); - return true; + return false; } static bool HandleWpShowCommand(ChatHandler* handler, char const* args) @@ -495,10 +385,8 @@ public: uint32 pathid = 0; Creature* target = handler->getSelectedCreature(); - WorldDatabasePreparedStatement* stmt = nullptr; // Did player provide a PathID? - if (!guid_str) { // No PathID provided @@ -511,7 +399,7 @@ public: return false; } - pathid = target->GetWaypointPath(); + pathid = target->GetWaypointPathId(); } else { @@ -531,7 +419,6 @@ public: // Show info for the selected waypoint if (show == "info") { - // Check if the user did specify a visual waypoint if (!target || target->GetEntry() != VISUAL_WAYPOINT) { handler->PSendSysMessage(LANG_WAYPOINT_VP_SELECT); @@ -539,296 +426,78 @@ public: return false; } - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_ALL_BY_WPGUID); - stmt->setUInt64(0, target->GetSpawnId()); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, std::to_string(target->GetSpawnId()).c_str()); - return true; - } - - handler->SendSysMessage("|cff00ffffDEBUG: wp show info:|r"); - do + WaypointPath const* path = sWaypointMgr->GetPathByVisualGUID(target->GetGUID()); + if (!path) { - Field* fields = result->Fetch(); - pathid = fields[0].GetUInt32(); - uint32 point = fields[1].GetUInt32(); - uint32 delay = fields[2].GetUInt32(); - uint32 flag = fields[3].GetUInt32(); - - handler->PSendSysMessage("|cff00ff00Show info: for current point: |r|cff00ffff%u|r|cff00ff00, Path ID: |r|cff00ffff%u|r", point, pathid); - handler->PSendSysMessage("|cff00ff00Show info: delay: |r|cff00ffff%u|r", delay); - handler->PSendSysMessage("|cff00ff00Show info: Move flag: |r|cff00ffff%u|r", flag); - } - while (result->NextRow()); - - return true; - } - - if (show == "on") - { - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_POS_BY_ID); - stmt->setUInt32(0, pathid); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) - { - handler->SendSysMessage("|cffff33ffPath no found.|r"); + handler->PSendSysMessage("|cff00ff00Path does not exist or target has no path|r"); handler->SetSentErrorMessage(true); return false; } - handler->PSendSysMessage("|cff00ff00DEBUG: wp on, PathID: |cff00ffff%u|r", pathid); - - // Delete all visuals for this NPC - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID); - - stmt->setUInt32(0, pathid); - - PreparedQueryResult result2 = WorldDatabase.Query(stmt); - - if (result2) - { - bool hasError = false; - do - { - Field* fields = result2->Fetch(); - ObjectGuid::LowType wpguid = fields[0].GetUInt64(); - if (!Creature::DeleteFromDB(wpguid)) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, std::to_string(wpguid).c_str()); - hasError = true; - } - - } - while (result2->NextRow()); - - if (hasError) - { - handler->PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - handler->PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - handler->PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - } - - do + WaypointNode const* node = sWaypointMgr->GetNodeByVisualGUID(target->GetGUID()); + if (!node) { - Field* fields = result->Fetch(); - uint32 point = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - float o = fields[4].GetFloat(); - - uint32 id = VISUAL_WAYPOINT; - - Player* chr = handler->GetSession()->GetPlayer(); - Map* map = chr->GetMap(); - - Creature* wpCreature = Creature::CreateCreature(id, map, { x, y, z, o }); - if (!wpCreature) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - return false; - } - - PhasingHandler::InheritPhaseShift(wpCreature, chr); - wpCreature->SaveToDB(map->GetId(), { map->GetDifficultyID() }); - - ObjectGuid::LowType dbGuid = wpCreature->GetSpawnId(); - - // current "wpCreature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior - wpCreature->CleanupsBeforeDelete(); - delete wpCreature; - - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature = Creature::CreateCreatureFromDB(dbGuid, map, true, true); - if (!wpCreature) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - return false; - } - - if (target) - { - wpCreature->SetDisplayId(target->GetDisplayId()); - wpCreature->SetObjectScale(0.5f); - wpCreature->SetLevel(std::min<uint32>(point, STRONG_MAX_LEVEL)); - } - - // Set "wpguid" column to the visual waypoint - stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID); - stmt->setUInt64(0, wpCreature->GetSpawnId()); - stmt->setUInt32(1, pathid); - stmt->setUInt32(2, point); - WorldDatabase.Execute(stmt); - } - while (result->NextRow()); - - handler->SendSysMessage("|cff00ff00Showing the current creature's path.|r"); - return true; - } - - if (show == "first") - { - handler->PSendSysMessage("|cff00ff00DEBUG: wp first, pathid: %u|r", pathid); - - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_POS_FIRST_BY_ID); - stmt->setUInt32(0, pathid); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid); + handler->PSendSysMessage("|cff00ff00Path does not exist or target has no path|r"); handler->SetSentErrorMessage(true); return false; } - Field* fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float o = fields[3].GetFloat(); - - uint32 id = VISUAL_WAYPOINT; - - Player* chr = handler->GetSession()->GetPlayer(); - Map* map = chr->GetMap(); - - Creature* creature = Creature::CreateCreature(id, map, { x, y, z, o }); - if (!creature) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - return false; - } - - PhasingHandler::InheritPhaseShift(creature, chr); - creature->SaveToDB(map->GetId(), { map->GetDifficultyID() }); - - ObjectGuid::LowType dbGuid = creature->GetSpawnId(); - - // current "creature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior - creature->CleanupsBeforeDelete(); - delete creature; - - creature = Creature::CreateCreatureFromDB(dbGuid, map, true, true); - if (!creature) - { - handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - return false; - } - - if (target) - { - creature->SetDisplayId(target->GetDisplayId()); - creature->SetObjectScale(0.5f); - } + handler->SendSysMessage("|cff00ffffDEBUG: .wp show info:|r"); + handler->PSendSysMessage("|cff00ff00Show info: Path Id: |r|cff00ffff%u|r", path->Id); + handler->PSendSysMessage("|cff00ff00Show info: Path MoveType: |r|cff00ffff%u|r", AsUnderlyingType(path->MoveType)); + handler->PSendSysMessage("|cff00ff00Show info: Path Flags: |r|cff00ffff%u|r", path->Flags.AsUnderlyingType()); + handler->PSendSysMessage("|cff00ff00Show info: Node Id: |r|cff00ffff%u|r", node->Id); + handler->PSendSysMessage("|cff00ff00Show info: Node Delay: |r|cff00ffff%u|r", node->Id); return true; } - - if (show == "last") + else if (show == "on") { - handler->PSendSysMessage("|cff00ff00DEBUG: wp last, PathID: |r|cff00ffff%u|r", pathid); - - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_POS_LAST_BY_ID); - stmt->setUInt32(0, pathid); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) + WaypointPath const* path = sWaypointMgr->GetPath(pathid); + if (!path) { - handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, pathid); - handler->SetSentErrorMessage(true); - return false; - } - Field* fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float o = fields[3].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player* chr = handler->GetSession()->GetPlayer(); - Map* map = chr->GetMap(); - Position pos = { x, y, z, o }; - - Creature* creature = Creature::CreateCreature(id, map, pos); - if (!creature) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); - return false; + handler->PSendSysMessage("|cff00ff00Path does not exist: id %u|r", pathid); + return true; } - PhasingHandler::InheritPhaseShift(creature, chr); - creature->SaveToDB(map->GetId(), { map->GetDifficultyID() }); - - ObjectGuid::LowType dbGuid = creature->GetSpawnId(); - - // current "creature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior - creature->CleanupsBeforeDelete(); - delete creature; - - creature = Creature::CreateCreatureFromDB(dbGuid, map, true, true); - if (!creature) + if (path->Nodes.empty()) { - handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); - return false; + handler->PSendSysMessage("|cff00ff00Path does not have any nodes: id %u|r", pathid); + return true; } + Optional<uint32> displayId; if (target) + displayId = target->GetDisplayId(); + + sWaypointMgr->VisualizePath(handler->GetPlayer(), path, displayId); + + ObjectGuid const& guid = sWaypointMgr->GetVisualGUIDByNode(path->Id, path->Nodes.front().Id); + if (!guid.IsEmpty()) { - creature->SetDisplayId(target->GetDisplayId()); - creature->SetObjectScale(0.5f); + handler->SendSysMessage("|cff00ff00Path with id %u is already showing.|r", pathid); + return true; } + handler->SendSysMessage("|cff00ff00Showing path with id %u.|r", pathid); return true; } - - if (show == "off") + else if (show == "off") { - stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_BY_ID); - stmt->setUInt32(0, 1); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) + WaypointPath const* path = sWaypointMgr->GetPath(pathid); + if (!path) { - handler->SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); - handler->SetSentErrorMessage(true); - return false; - } - bool hasError = false; - do - { - Field* fields = result->Fetch(); - ObjectGuid::LowType lowguid = fields[0].GetUInt64(); - - if (!Creature::DeleteFromDB(lowguid)) - { - handler->PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, std::to_string(lowguid).c_str()); - hasError = true; - } + handler->PSendSysMessage("|cff00ff00Path does not exist: id %u|r", pathid); + return true; } - while (result->NextRow()); - // set "wpguid" column to "empty" - no visual waypoint spawned - stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_ALL_WPGUID); - - WorldDatabase.Execute(stmt); - //WorldDatabase.PExecute("UPDATE creature_movement SET wpguid = '0' WHERE wpguid <> '0'"); - if (hasError) - { - handler->PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - handler->PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - handler->PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } + sWaypointMgr->DevisualizePath(handler->GetPlayer(), path); handler->SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED); return true; } - handler->PSendSysMessage("|cffff33ffDEBUG: wpshow - no valid command found|r"); + handler->PSendSysMessage("|cffff33ffDEBUG: .wp show - no valid command found|r"); return true; } }; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp index e9f53d68c92..40d5d9d5cee 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp @@ -256,7 +256,7 @@ class npc_twilight_torturer : public CreatureScript void Reset() override { Initialize(); - if (!me->GetWaypointPath()) + if (!me->GetWaypointPathId()) _events.ScheduleEvent(EVENT_INFLICT_PAIN_TT, 6s, 18s); } @@ -356,7 +356,7 @@ class npc_twilight_sadist : public CreatureScript void Reset() override { _combatPhase = false; - if (!me->GetWaypointPath()) + if (!me->GetWaypointPathId()) _events.ScheduleEvent(EVENT_INFLICT_PAIN_TS, 6s, 18s); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp index 86225fce859..97c1f3de988 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp @@ -207,7 +207,7 @@ struct npc_thrall_old_hillsbrad : public EscortAI void InitializeAI() override { /* correct respawn positions after wipe cannot be used because of how waypoints are set up for this creature - * it would require splitting the path into 4 segments, moving it out of waypoint_data table and changing + * it would require splitting the path into 4 segments, moving it out of waypoint_path_node table and changing * all waypoint ids in WaypointReached function switch (instance->GetData(TYPE_THRALL_EVENT)) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 3d9b5808204..b7b45af37b0 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -625,7 +625,7 @@ public: bool operator()(Creature* target) const { - if (!target->IsAlive() || (_checkCasting && target->HasUnitState(UNIT_STATE_CASTING)) || target->GetWaypointPath() || _owner->GetDistance(target) > 10.0f) + if (!target->IsAlive() || (_checkCasting && target->HasUnitState(UNIT_STATE_CASTING)) || target->GetWaypointPathId() || _owner->GetDistance(target) > 10.0f) return false; switch (target->GetEntry()) @@ -779,7 +779,7 @@ struct DarkFallenAI : public ScriptedAI void Reset() override { - IsDoingEmotes = me->GetWaypointPath() ? false : true; + IsDoingEmotes = me->GetWaypointPathId() ? false : true; Scheduler.CancelAll(); Scheduler.SetValidator([this] { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_general_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_general_bjarngrim.cpp index 2a54638e94d..05211042a1f 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_general_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_general_bjarngrim.cpp @@ -122,7 +122,7 @@ enum Stances MAX_STANCE }; -// These values must be sync with the data in waypoint_data. +// These values must be sync with the data in waypoint_path_node. // Each of these points is going to trigger a Charge Up sequence static std::array<uint8, 2> const ChargeUpWaypointIds = { 7, 15 }; // Each of these points is going to remove the Tempoary Electrical Charge buff from General Bjarngrim |