TrinityCore
Loading...
Searching...
No Matches
WaypointManager.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WaypointManager.h"
19#include "DatabaseEnv.h"
20#include "GridDefines.h"
21#include "Log.h"
22#include "MapUtils.h"
23#include "ObjectAccessor.h"
24#include "Optional.h"
26#include "TemporarySummon.h"
27#include "Unit.h"
28
29DEFINE_FIELD_ACCESSOR_CACHE(WaypointMgr::, PathQueryResult, PreparedResultSet, (PathId)(MoveType)(Flags)(Velocity));
30DEFINE_FIELD_ACCESSOR_CACHE(WaypointMgr::, PathNodeQueryResult, PreparedResultSet, (PathId)(NodeId)(PositionX)(PositionY)(PositionZ)(Orientation)(Delay));
31
32WaypointMgr::WaypointMgr() = default;
34
41
43{
44 uint32 oldMSTime = getMSTime();
45
46 _pathStore.clear();
47
49 stmt->setUInt32(0, 0);
50 stmt->setUInt32(1, 1);
51
52 PreparedQueryResult result = WorldDatabase.Query(stmt);
53
54 if (!result)
55 {
56 TC_LOG_INFO("server.loading", ">> Loaded 0 waypoint paths. DB table `waypoint_path` is empty!");
57 return;
58 }
59
60 uint32 count = 0;
61
62 do
63 {
64 LoadPathFromDB(*result);
65 ++count;
66 } while (result->NextRow());
67
68 TC_LOG_INFO("server.loading", ">> Loaded {} waypoint paths in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
69}
70
72{
73 uint32 oldMSTime = getMSTime();
74
76 stmt->setUInt32(0, 0);
77 stmt->setUInt32(1, 1);
78
79 PreparedQueryResult result = WorldDatabase.Query(stmt);
80
81 if (!result)
82 {
83 TC_LOG_INFO("server.loading", ">> Loaded 0 waypoint path nodes. DB table `waypoint_path_node` is empty!");
84 return;
85 }
86
87 uint32 count = 0;
88
89 do
90 {
91 LoadPathNodesFromDB(*result);
92 ++count;
93 }
94 while (result->NextRow());
95
96 TC_LOG_INFO("server.loading", ">> Loaded {} waypoint path nodes in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
97}
98
99void WaypointMgr::LoadPathFromDB(PathQueryResult const& fields)
100{
101 uint32 pathId = fields.PathId().GetUInt32();
102
103 WaypointPath& path = _pathStore[pathId];
104
105 path.MoveType = WaypointMoveType(fields.MoveType().GetUInt8());
107 {
108 TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has invalid MoveType {}, ignoring", pathId, AsUnderlyingType(path.MoveType));
109 return;
110 }
111
112 path.Id = pathId;
113 path.Flags = WaypointPathFlags(fields.Flags().GetUInt8());
114 path.Velocity = fields.Velocity().GetFloatOrNull();
115
116 if (path.Velocity && *path.Velocity <= 0.0f)
117 {
118 TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has invalid velocity {}, using default velocity instead", pathId, *path.Velocity);
119 path.Velocity.reset();
120 }
121
122 path.Nodes.clear();
123}
124
125void WaypointMgr::LoadPathNodesFromDB(PathNodeQueryResult const& fields)
126{
127 uint32 pathId = fields.PathId().GetUInt32();
128
130 if (!path)
131 {
132 TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path_node` does not exist in `waypoint_path`, ignoring", pathId);
133 return;
134 }
135
136 float x = fields.PositionX().GetFloat();
137 float y = fields.PositionY().GetFloat();
138 float z = fields.PositionZ().GetFloat();
139 Optional<float> o = fields.Orientation().GetFloatOrNull();
140
142 if (uint32 delayMs = fields.Delay().GetUInt32())
143 delay.emplace(delayMs);
144
147
148 path->Nodes.emplace_back(fields.NodeId().GetUInt32(), x, y, z, o, delay);
149}
150
152{
153 for (auto& [pathId, pathInfo] : _pathStore)
154 {
155 pathInfo.BuildSegments();
156
157 if (pathInfo.Nodes.empty())
158 TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has no assigned nodes in `waypoint_path_node`", pathInfo.Id);
159
161 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);
162 }
163}
164
166{
167 static WaypointMgr instance;
168 return &instance;
169}
170
172{
173 // waypoint_path
174 {
176 stmt->setUInt32(0, pathId);
177 stmt->setUInt32(1, 0);
178
179 PreparedQueryResult result = WorldDatabase.Query(stmt);
180
181 if (!result)
182 {
183 TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` not found, ignoring", pathId);
184 return;
185 }
186
187 do
188 {
189 LoadPathFromDB(*result);
190 } while (result->NextRow());
191 }
192
193 // waypoint_path_data
194 {
196 stmt->setUInt32(0, pathId);
197 stmt->setUInt32(1, 0);
198
199 PreparedQueryResult result = WorldDatabase.Query(stmt);
200
201 if (!result)
202 {
203 TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path_node` not found, ignoring", pathId);
204 return;
205 }
206
207 do
208 {
209 LoadPathNodesFromDB(*result);
210 } while (result->NextRow());
211
213 path->BuildSegments();
214 }
215}
216
218{
219 for (WaypointNode const& node : path->Nodes)
220 {
221 std::pair<uint32, uint32> pathNodePair(path->Id, node.Id);
222
223 auto itr = _nodeToVisualWaypointGUIDsMap.find(pathNodePair);
224 if (itr != _nodeToVisualWaypointGUIDsMap.end())
225 continue;
226
227 TempSummon* summon = owner->SummonCreature(VISUAL_WAYPOINT, node.X, node.Y, node.Z, node.Orientation ? *node.Orientation : 0.0f);
228 if (!summon)
229 continue;
230
231 if (displayId)
232 {
233 summon->SetDisplayId(*displayId, true);
234 summon->SetObjectScale(0.5f);
235 }
236
237 _nodeToVisualWaypointGUIDsMap[pathNodePair] = summon->GetGUID();
238 _visualWaypointGUIDToNodeMap[summon->GetGUID()] = std::pair<WaypointPath const*, WaypointNode const*>(path, &node);
239 }
240}
241
243{
244 for (WaypointNode const& node : path->Nodes)
245 {
246 std::pair<uint32, uint32> pathNodePair(path->Id, node.Id);
247 auto itr = _nodeToVisualWaypointGUIDsMap.find(pathNodePair);
248 if (itr == _nodeToVisualWaypointGUIDsMap.end())
249 continue;
250
251 Creature* creature = ObjectAccessor::GetCreature(*owner, itr->second);
252 if (!creature)
253 continue;
254
255 _visualWaypointGUIDToNodeMap.erase(itr->second);
256 _nodeToVisualWaypointGUIDsMap.erase(pathNodePair);
257
258 creature->DespawnOrUnsummon();
259 }
260}
261
262void WaypointMgr::MoveNode(WaypointPath const* path, WaypointNode const* node, Position const& pos)
263{
265 stmt->setFloat(0, pos.GetPositionX());
266 stmt->setFloat(1, pos.GetPositionY());
267 stmt->setFloat(2, pos.GetPositionZ());
268 stmt->setFloat(3, pos.GetOrientation());
269 stmt->setUInt32(4, path->Id);
270 stmt->setUInt32(5, node->Id);
271 WorldDatabase.Execute(stmt);
272}
273
275{
277 stmt->setUInt32(0, path->Id);
278 stmt->setUInt32(1, node->Id);
279 WorldDatabase.Execute(stmt);
280
281 stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_PATH_NODE);
282 stmt->setUInt32(0, path->Id);
283 stmt->setUInt32(1, node->Id);
284 WorldDatabase.Execute(stmt);
285}
286
288{
289 WaypointPath const* path = GetPath(pathId);
290 if (!path)
291 return;
292
293 WaypointNode const* node = GetNode(path, nodeId);
294 if (!node)
295 return;
296
297 DeleteNode(path, node);
298}
299
304
305WaypointNode const* WaypointMgr::GetNode(WaypointPath const* path, uint32 nodeId) const
306{
307 for (WaypointNode const& node : path->Nodes)
308 {
309 if (node.Id == nodeId)
310 return &node;
311 }
312 return nullptr;
313}
314
315WaypointNode const* WaypointMgr::GetNode(uint32 pathId, uint32 nodeId) const
316{
317 WaypointPath const* path = GetPath(pathId);
318 if (!path)
319 return nullptr;
320
321 return GetNode(path, nodeId);
322}
323
325{
326 auto itr = _visualWaypointGUIDToNodeMap.find(guid);
327 if (itr == _visualWaypointGUIDToNodeMap.end())
328 return nullptr;
329
330 return itr->second.first;
331}
332
334{
335 auto itr = _visualWaypointGUIDToNodeMap.find(guid);
336 if (itr == _visualWaypointGUIDToNodeMap.end())
337 return nullptr;
338
339 return itr->second.second;
340}
341
343{
344 auto itr = _nodeToVisualWaypointGUIDsMap.find(std::make_pair(pathId, nodeId));
345 if (itr == _nodeToVisualWaypointGUIDsMap.end())
346 return ObjectGuid::Empty;
347
348 return itr->second;
349}
350
352{
353 ContinuousSegments.assign(1, { 0, 0 });
354 for (std::size_t i = 0; i < Nodes.size(); ++i)
355 {
356 ++ContinuousSegments.back().second;
357
358 // split on delay or different move type
359 if (i + 1 != Nodes.size() && (Nodes[i].Delay || Nodes[i].MoveType != Nodes[i + 1].MoveType))
360 ContinuousSegments.emplace_back(i, 1);
361 }
362}
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint32_t uint32
Definition Define.h:154
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
#define DEFINE_FIELD_ACCESSOR_CACHE(namespace_name, struct_name, result_type, fields_list)
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
#define VISUAL_WAYPOINT
Definition Unit.h:35
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
static constexpr std::size_t WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES
WaypointMoveType
WaypointPathFlags
@ FollowPathBackwardsFromEndToStart
@ WORLD_SEL_WAYPOINT_PATH_NODE
@ WORLD_DEL_WAYPOINT_PATH_NODE
@ WORLD_UPD_WAYPOINT_PATH_NODE
@ WORLD_UPD_WAYPOINT_PATH_NODE_POSITION
@ WORLD_SEL_WAYPOINT_PATH
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void SetObjectScale(float scale) override
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
void SetDisplayId(uint32 displayId, bool setNative=false) override
static ObjectGuid const Empty
Definition ObjectGuid.h:314
void setUInt32(uint8 index, uint32 value)
void setFloat(uint8 index, float value)
Definition Unit.h:635
void DoPostLoadingChecks()
void DeleteNode(WaypointPath const *path, WaypointNode const *node)
void LoadPathNodesFromDB(PathNodeQueryResult const &fields)
std::unordered_map< std::pair< uint32, uint32 >, ObjectGuid > _nodeToVisualWaypointGUIDsMap
std::unordered_map< ObjectGuid, std::pair< WaypointPath const *, WaypointNode const * > > _visualWaypointGUIDToNodeMap
WaypointNode const * GetNodeByVisualGUID(ObjectGuid guid) const
WaypointPath const * GetPathByVisualGUID(ObjectGuid guid) const
std::unordered_map< uint32, WaypointPath > _pathStore
void MoveNode(WaypointPath const *path, WaypointNode const *node, Position const &pos)
WaypointNode const * GetNode(WaypointPath const *path, uint32 nodeId) const
static WaypointMgr * instance()
void ReloadPath(uint32 pathId)
WaypointPath const * GetPath(uint32 pathId) const
void VisualizePath(Unit *owner, WaypointPath const *path, Optional< uint32 > displayId)
void LoadPathFromDB(PathQueryResult const &fields)
ObjectGuid const & GetVisualGUIDByNode(uint32 pathId, uint32 nodeId) const
void DevisualizePath(Unit *owner, WaypointPath const *path)
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1398
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
void NormalizeMapCoord(float &c)
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
std::vector< std::pair< std::size_t, std::size_t > > ContinuousSegments
std::vector< WaypointNode > Nodes
EnumFlag< WaypointPathFlags > Flags
Optional< float > Velocity
WaypointMoveType MoveType