TrinityCore
TransportMgr.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 "TransportMgr.h"
19#include "Containers.h"
20#include "DatabaseEnv.h"
21#include "DB2Stores.h"
22#include "InstanceScript.h"
23#include "Log.h"
24#include "Map.h"
25#include "MoveSplineInitArgs.h"
26#include "ObjectAccessor.h"
27#include "ObjectMgr.h"
28#include "PhasingHandler.h"
29#include "Spline.h"
30#include "Transport.h"
31
35TransportPathLeg& TransportPathLeg::operator=(TransportPathLeg&&) noexcept = default;
36
40TransportTemplate& TransportTemplate::operator=(TransportTemplate&&) noexcept = default;
41
42Optional<Position> TransportTemplate::ComputePosition(uint32 time, TransportMovementState* moveState, size_t* legIndex) const
43{
44 time %= TotalPathTime;
45
46 // find leg
47 TransportPathLeg const* leg = GetLegForTime(time);
48 if (!leg)
49 return {};
50
51 // find segment
52 uint32 prevSegmentTime = leg->StartTimestamp;
53 auto segmentItr = leg->Segments.begin();
54 double distanceMoved = 0.0;
55 bool isOnPause = false;
56 for (; segmentItr != std::prev(leg->Segments.end()); ++segmentItr)
57 {
58 if (time < segmentItr->SegmentEndArrivalTimestamp)
59 break;
60
61 distanceMoved = segmentItr->DistanceFromLegStartAtEnd;
62 if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
63 {
64 isOnPause = true;
65 break;
66 }
67
68 prevSegmentTime = segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
69 }
70
71 if (!isOnPause)
72 distanceMoved += CalculateDistanceMoved(
73 double(time - prevSegmentTime) * 0.001,
74 double(segmentItr->SegmentEndArrivalTimestamp - prevSegmentTime) * 0.001,
75 segmentItr == leg->Segments.begin(),
76 segmentItr == std::prev(leg->Segments.end()));
77
79 float splinePointProgress;
80 leg->Spline->computeIndex(std::fmin(distanceMoved / leg->Spline->length(), 1.0), splineIndex, splinePointProgress);
81
82 G3D::Vector3 pos, dir;
83 leg->Spline->evaluate_percent(splineIndex, splinePointProgress, pos);
84 leg->Spline->evaluate_derivative(splineIndex, splinePointProgress, dir);
85
86 if (moveState)
88
89 if (legIndex)
90 *legIndex = std::distance(PathLegs.data(), leg);
91
92 return Position(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) + float(M_PI));
93}
94
96{
97 auto legItr = PathLegs.begin();
98 while (legItr->StartTimestamp + legItr->Duration <= time)
99 {
100 ++legItr;
101
102 if (legItr == PathLegs.end())
103 return nullptr;
104 }
105
106 return &*legItr;
107}
108
110{
111 TransportPathLeg const* leg = GetLegForTime(time);
112 if (!leg)
113 return time;
114
115 auto segmentItr = leg->Segments.begin();
116 for (; segmentItr != std::prev(leg->Segments.end()); ++segmentItr)
117 if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
118 break;
119
120 return segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
121}
122
123double TransportTemplate::CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) const
124{
125 if (isFirstSegment)
126 {
127 if (!isLastSegment)
128 {
129 double accelerationTime = std::fmin(AccelerationTime, segmentDuration);
130 double segmentTimeAtFullSpeed = segmentDuration - accelerationTime;
131 if (timePassedInSegment <= segmentTimeAtFullSpeed)
132 {
133 return timePassedInSegment * Speed;
134 }
135 else
136 {
137 double segmentAccelerationTime = timePassedInSegment - segmentTimeAtFullSpeed;
138 double segmentAccelerationDistance = AccelerationRate * accelerationTime;
139 double segmentDistanceAtFullSpeed = segmentTimeAtFullSpeed * Speed;
140 return (2.0 * segmentAccelerationDistance - segmentAccelerationTime * AccelerationRate) * 0.5 * segmentAccelerationTime + segmentDistanceAtFullSpeed;
141 }
142 }
143
144 return timePassedInSegment * Speed;
145 }
146
147 if (isLastSegment)
148 {
149 if (!isFirstSegment)
150 {
151 if (timePassedInSegment <= std::fmin(AccelerationTime, segmentDuration))
152 return AccelerationRate * timePassedInSegment * 0.5 * timePassedInSegment;
153 else
154 return (timePassedInSegment - AccelerationTime) * Speed + AccelerationDistance;
155 }
156
157 return timePassedInSegment * Speed;
158 }
159
160 double accelerationTime = std::fmin(segmentDuration * 0.5, AccelerationTime);
161 if (timePassedInSegment <= segmentDuration - accelerationTime)
162 {
163 if (timePassedInSegment <= accelerationTime)
164 return AccelerationRate * timePassedInSegment * 0.5 * timePassedInSegment;
165 else
166 return (timePassedInSegment - AccelerationTime) * Speed + AccelerationDistance;
167 }
168 else
169 {
170 double segmentTimeSpentAccelerating = timePassedInSegment - (segmentDuration - accelerationTime);
171 return (segmentDuration - 2 * accelerationTime) * Speed
172 + AccelerationRate * accelerationTime * 0.5 * accelerationTime
173 + (2.0 * AccelerationRate * accelerationTime - segmentTimeSpentAccelerating * AccelerationRate) * 0.5 * segmentTimeSpentAccelerating;
174 }
175}
176
178
180
182{
183 static TransportMgr instance;
184 return &instance;
185}
186
188{
189 _transportTemplates.clear();
190}
191
193{
194 uint32 oldMSTime = getMSTime();
195
196 QueryResult result = WorldDatabase.Query("SELECT entry FROM gameobject_template WHERE type = 15 ORDER BY entry ASC");
197
198 if (!result)
199 {
200 TC_LOG_INFO("server.loading", ">> Loaded 0 transport templates. DB table `gameobject_template` has no transports!");
201 return;
202 }
203
204 uint32 count = 0;
205
206 do
207 {
208 Field* fields = result->Fetch();
209 uint32 entry = fields[0].GetUInt32();
210 GameObjectTemplate const* goInfo = sObjectMgr->GetGameObjectTemplate(entry);
211 if (goInfo == nullptr)
212 {
213 TC_LOG_ERROR("sql.sql", "Transport {} has no associated GameObjectTemplate from `gameobject_template` , skipped.", entry);
214 continue;
215 }
216
217 if (goInfo->moTransport.taxiPathID >= sTaxiPathNodesByPath.size())
218 {
219 TC_LOG_ERROR("sql.sql", "Transport {} (name: {}) has an invalid path specified in `gameobject_template`.`Data0` ({}) field, skipped.", entry, goInfo->name, goInfo->moTransport.taxiPathID);
220 continue;
221 }
222
223 if (!goInfo->moTransport.taxiPathID)
224 continue;
225
226 // paths are generated per template, saves us from generating it again in case of instanced transports
227 TransportTemplate& transport = _transportTemplates[entry];
228
229 GeneratePath(goInfo, &transport);
230
231 ++count;
232 } while (result->NextRow());
233
234 TC_LOG_INFO("server.loading", ">> Loaded {} transport templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
235}
236
238{
240 AddPathNodeToTransport(anim->TransportID, anim->TimeIndex, anim);
241
243 AddPathRotationToTransport(rot->GameObjectsID, rot->TimeIndex, rot);
244}
245
247{
248 if (_transportTemplates.empty())
249 return;
250
251 uint32 oldMSTime = getMSTime();
252
253 QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseUseFlags, phaseid, phasegroup FROM transports");
254
255 uint32 count = 0;
256 if (result)
257 {
258 do
259 {
260 Field* fields = result->Fetch();
261 ObjectGuid::LowType guid = fields[0].GetUInt64();
262 uint32 entry = fields[1].GetUInt32();
263 uint8 phaseUseFlags = fields[2].GetUInt8();
264 uint32 phaseId = fields[3].GetUInt32();
265 uint32 phaseGroupId = fields[4].GetUInt32();
266
267 TransportTemplate const* transportTemplate = GetTransportTemplate(entry);
268 if (!transportTemplate)
269 {
270 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with unknown gameobject `entry` set, skipped.", guid, entry);
271 continue;
272 }
273
274 if (phaseUseFlags & ~PHASE_USE_FLAGS_ALL)
275 {
276 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with unknown `phaseUseFlags` set, removed unknown value.", guid, entry);
277 phaseUseFlags &= PHASE_USE_FLAGS_ALL;
278 }
279
280 if (phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && phaseUseFlags & PHASE_USE_FLAGS_INVERSE)
281 {
282 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE,"
283 " removing PHASE_USE_FLAGS_INVERSE.", guid, entry);
284 phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE;
285 }
286
287 if (phaseGroupId && phaseId)
288 {
289 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, entry);
290 phaseGroupId = 0;
291 }
292
293 if (phaseId)
294 {
295 if (!sPhaseStore.LookupEntry(phaseId))
296 {
297 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with `phaseid` {} does not exist, set to 0", guid, entry, phaseId);
298 phaseId = 0;
299 }
300 }
301
302 if (phaseGroupId)
303 {
304 if (!sDB2Manager.GetPhasesForGroup(phaseGroupId))
305 {
306 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with `phaseGroup` {} does not exist, set to 0", guid, entry, phaseGroupId);
307 phaseGroupId = 0;
308 }
309 }
310
311 TransportSpawn& spawn = _transportSpawns[guid];
312 spawn.SpawnId = guid;
313 spawn.TransportGameObjectId = entry;
314 spawn.PhaseUseFlags = phaseUseFlags;
315 spawn.PhaseId = phaseId;
316 spawn.PhaseGroup = phaseGroupId;
317
318 for (uint32 mapId : transportTemplate->MapIds)
319 _transportsByMap[mapId].insert(&spawn);
320
321 } while (result->NextRow());
322 }
323
324 TC_LOG_INFO("server.loading", ">> Spawned {} continent transports in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
325}
326
328{
329public:
331
332 void operator()(uint8& mode, bool& cyclic, Movement::PointsArray& points, int& lo, int& hi) const
333 {
335 cyclic = false;
336 points.assign(_points.begin(), _points.end());
337 lo = 1;
338 hi = points.size() - 2;
339 }
340
342};
343
344static void InitializeLeg(TransportPathLeg* leg, std::vector<TransportPathEvent>* outEvents, std::vector<TaxiPathNodeEntry const*> const& pathPoints, std::vector<TaxiPathNodeEntry const*> const& pauses,
345 std::vector<TaxiPathNodeEntry const*> const& events, GameObjectTemplate const* goInfo, uint32& totalTime)
346{
347 Movement::PointsArray splinePath;
348 std::transform(pathPoints.begin(), pathPoints.end(), std::back_inserter(splinePath), [](TaxiPathNodeEntry const* node) { return Movement::Vector3(node->Loc.X, node->Loc.Y, node->Loc.Z); });
349 SplineRawInitializer initer(splinePath);
350 leg->Spline = std::make_unique<TransportSpline>();
351 leg->Spline->set_steps_per_segment(20);
352 leg->Spline->init_spline_custom(initer);
353 leg->Spline->initLengths();
354
355 leg->Segments.resize(pauses.size() + 1);
356
357 auto legTimeAccelDecel = [&](double dist)
358 {
359 double speed = double(goInfo->moTransport.moveSpeed);
360 double accel = double(goInfo->moTransport.accelRate);
361 double accelDist = 0.5 * speed * speed / accel;
362 if (accelDist >= dist * 0.5)
363 return uint32(std::sqrt(dist / accel) * 2000.0);
364 else
365 return uint32((dist - (accelDist + accelDist)) / speed * 1000.0 + speed / accel * 2000.0);
366 };
367
368 auto legTimeAccel = [&](double dist)
369 {
370 double speed = double(goInfo->moTransport.moveSpeed);
371 double accel = double(goInfo->moTransport.accelRate);
372 double accelDist = 0.5 * speed * speed / accel;
373 if (accelDist >= dist)
374 return uint32(std::sqrt((dist + dist) / accel) * 1000.0);
375 else
376 return uint32(((dist - accelDist) / speed + speed / accel) * 1000.0);
377 };
378
379 // Init segments
380 size_t pauseItr = 0;
381 size_t eventItr = 0;
382 double splineLengthToPreviousNode = 0.0;
383 uint32 delaySum = 0;
384 if (!pauses.empty())
385 {
386 for (; pauseItr < pauses.size(); ++pauseItr)
387 {
388 auto pausePointItr = std::find(pathPoints.begin(), pathPoints.end(), pauses[pauseItr]);
389 if (*pausePointItr == pathPoints.back()) // last point is a "fake" spline point, its position can never be reached so transport cannot stop there
390 break;
391
392 for (; eventItr < events.size(); ++eventItr)
393 {
394 auto eventPointItr = std::find(pathPoints.begin(), pathPoints.end(), events[eventItr]);
395 if (eventPointItr > pausePointItr)
396 break;
397
398 double length = leg->Spline->length(std::distance(pathPoints.begin(), eventPointItr)) - splineLengthToPreviousNode;
399
400 uint32 splineTime = 0;
401 if (pauseItr)
402 splineTime = legTimeAccelDecel(length);
403 else
404 splineTime = legTimeAccel(length);
405
406 if ((*eventPointItr)->ArrivalEventID)
407 {
408 TransportPathEvent& event = outEvents->emplace_back();
409 event.Timestamp = totalTime + splineTime + leg->Duration;
410 event.EventId = (*eventPointItr)->ArrivalEventID;
411 }
412
413 if ((*eventPointItr)->DepartureEventID)
414 {
415 TransportPathEvent& event = outEvents->emplace_back();
416 event.Timestamp = totalTime + splineTime + leg->Duration + (pausePointItr == eventPointItr ? (*eventPointItr)->Delay * IN_MILLISECONDS : 0);
417 event.EventId = (*eventPointItr)->DepartureEventID;
418 }
419 }
420
421 double splineLengthToCurrentNode = leg->Spline->length(std::distance(pathPoints.begin(), pausePointItr));
422 double length = splineLengthToCurrentNode - splineLengthToPreviousNode;
423 uint32 movementTime = 0;
424 if (pauseItr)
425 movementTime = legTimeAccelDecel(length);
426 else
427 movementTime = legTimeAccel(length);
428
429 leg->Duration += movementTime;
430 leg->Segments[pauseItr].SegmentEndArrivalTimestamp = leg->Duration + delaySum;
431 leg->Segments[pauseItr].Delay = (*pausePointItr)->Delay * IN_MILLISECONDS;
432 leg->Segments[pauseItr].DistanceFromLegStartAtEnd = splineLengthToCurrentNode;
433 delaySum += (*pausePointItr)->Delay * IN_MILLISECONDS;
434 splineLengthToPreviousNode = splineLengthToCurrentNode;
435 }
436 }
437
438 // Process events happening after last pause
439 for (; eventItr < events.size(); ++eventItr)
440 {
441 auto eventPointItr = std::find(pathPoints.begin(), pathPoints.end(), events[eventItr]);
442 if (*eventPointItr == pathPoints.back()) // last point is a "fake" spline node, events cannot happen there
443 break;
444
445 double length = leg->Spline->length(std::distance(pathPoints.begin(), eventPointItr)) - splineLengthToPreviousNode;
446 uint32 splineTime = 0;
447 if (pauseItr)
448 splineTime = legTimeAccel(length);
449 else
450 splineTime = uint32(length / double(goInfo->moTransport.moveSpeed) * 1000.0);
451
452 if ((*eventPointItr)->ArrivalEventID)
453 {
454 TransportPathEvent& event = outEvents->emplace_back();
455 event.Timestamp = totalTime + splineTime + leg->Duration;
456 event.EventId = (*eventPointItr)->ArrivalEventID;
457 }
458
459 if ((*eventPointItr)->DepartureEventID)
460 {
461 TransportPathEvent& event = outEvents->emplace_back();
462 event.Timestamp = totalTime + splineTime + leg->Duration;
463 event.EventId = (*eventPointItr)->DepartureEventID;
464 }
465 }
466
467 // Add segment after last pause
468 double length = leg->Spline->length() - splineLengthToPreviousNode;
469 uint32 splineTime = 0;
470 if (pauseItr)
471 splineTime = legTimeAccel(length);
472 else
473 splineTime = uint32(length / double(goInfo->moTransport.moveSpeed) * 1000.0);
474
475 leg->StartTimestamp = totalTime;
476 leg->Duration += splineTime + delaySum;
477 leg->Segments[pauseItr].SegmentEndArrivalTimestamp = leg->Duration;
478 leg->Segments[pauseItr].Delay = 0;
479 leg->Segments[pauseItr].DistanceFromLegStartAtEnd = leg->Spline->length();
480 totalTime += leg->Segments[pauseItr].SegmentEndArrivalTimestamp + leg->Segments[pauseItr].Delay;
481
482 for (TransportPathSegment& segment : leg->Segments)
484
485 if (leg->Segments.size() > pauseItr + 1)
486 leg->Segments.resize(pauseItr + 1);
487}
488
490{
491 uint32 pathId = goInfo->moTransport.taxiPathID;
492 TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathId];
493
494 transport->Speed = double(goInfo->moTransport.moveSpeed);
495 transport->AccelerationRate = double(goInfo->moTransport.accelRate);
496 transport->AccelerationTime = transport->Speed / transport->AccelerationRate;
497 transport->AccelerationDistance = 0.5 * transport->Speed * transport->Speed / transport->AccelerationRate;
498
499 std::vector<TaxiPathNodeEntry const*> pathPoints;
500 std::vector<TaxiPathNodeEntry const*> pauses;
501 std::vector<TaxiPathNodeEntry const*> events;
502 TransportPathLeg* leg = &transport->PathLegs.emplace_back();
503 leg->MapId = path[0]->ContinentID;
504 bool prevNodeWasTeleport = false;
505 uint32 totalTime = 0;
506 for (TaxiPathNodeEntry const* node : path)
507 {
508 if (node->ContinentID != leg->MapId || prevNodeWasTeleport)
509 {
510 InitializeLeg(leg, &transport->Events, pathPoints, pauses, events, goInfo, totalTime);
511
512 leg = &transport->PathLegs.emplace_back();
513 leg->MapId = node->ContinentID;
514 pathPoints.clear();
515 pauses.clear();
516 events.clear();
517 }
518
519 prevNodeWasTeleport = (node->Flags & TAXI_PATH_NODE_FLAG_TELEPORT) != 0;
520 pathPoints.push_back(node);
521 if (node->Flags & TAXI_PATH_NODE_FLAG_STOP)
522 pauses.push_back(node);
523
524 if (node->ArrivalEventID || node->DepartureEventID)
525 events.push_back(node);
526
527 transport->MapIds.insert(node->ContinentID);
528 }
529
530 if (!leg->Spline)
531 InitializeLeg(leg, &transport->Events, pathPoints, pauses, events, goInfo, totalTime);
532
533 if (transport->MapIds.size() > 1)
534 for (uint32 mapId : transport->MapIds)
535 ASSERT(!sMapStore.LookupEntry(mapId)->Instanceable());
536
537 transport->TotalPathTime = totalTime;
538}
539
541{
542 TransportAnimation& animNode = _transportAnimations[transportEntry];
543 if (animNode.TotalTime < timeSeg)
544 animNode.TotalTime = timeSeg;
545
546 animNode.Path[timeSeg] = node;
547}
548
550{
551 TransportAnimation& animNode = _transportAnimations[transportEntry];
552 animNode.Rotations[timeSeg] = node;
553
554 if (animNode.Path.empty() && animNode.TotalTime < timeSeg)
555 animNode.TotalTime = timeSeg;
556}
557
558Transport* TransportMgr::CreateTransport(uint32 entry, Map* map, ObjectGuid::LowType guid /*= 0*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/)
559{
560 // SetZoneScript() is called after adding to map, so fetch the script using map
561 if (InstanceMap* instanceMap = map->ToInstanceMap())
562 if (InstanceScript* instance = instanceMap->GetInstanceScript())
563 entry = instance->GetGameObjectEntry(0, entry);
564
565 if (!entry)
566 return nullptr;
567
568 TransportTemplate const* tInfo = GetTransportTemplate(entry);
569 if (!tInfo)
570 {
571 TC_LOG_ERROR("sql.sql", "Transport {} will not be loaded, `transport_template` missing", entry);
572 return nullptr;
573 }
574
575 if (tInfo->MapIds.find(map->GetId()) == tInfo->MapIds.end())
576 {
577 TC_LOG_ERROR("entities.transport", "Transport {} attempted creation on map it has no path for {}!", entry, map->GetId());
578 return nullptr;
579 }
580
581 Optional<Position> startingPosition = tInfo->ComputePosition(0, nullptr, nullptr);
582 if (!startingPosition)
583 {
584 TC_LOG_ERROR("sql.sql", "Transport {} will not be loaded, failed to compute starting position", entry);
585 return nullptr;
586 }
587
588 // create transport...
589 Transport* trans = new Transport();
590
591 // ...at first waypoint
592 float x = startingPosition->GetPositionX();
593 float y = startingPosition->GetPositionY();
594 float z = startingPosition->GetPositionZ();
595 float o = startingPosition->GetOrientation();
596
597 // initialize the gameobject base
598 ObjectGuid::LowType guidLow = guid ? guid : map->GenerateLowGuid<HighGuid::Transport>();
599 if (!trans->Create(guidLow, entry, x, y, z, o))
600 {
601 delete trans;
602 return nullptr;
603 }
604
605 PhasingHandler::InitDbPhaseShift(trans->GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId);
606
607 // use preset map for instances (need to know which instance)
608 trans->SetMap(map);
609 if (InstanceMap* instanceMap = map->ToInstanceMap())
610 trans->m_zoneScript = instanceMap->GetInstanceScript();
611
612 // Passengers will be loaded once a player is near
613 map->AddToMap<Transport>(trans);
614 return trans;
615}
616
618{
619 auto mapTransports = _transportsByMap.find(map->GetId());
620
621 // no transports here
622 if (mapTransports == _transportsByMap.end())
623 return;
624
625 // create transports
626 for (TransportSpawn const* transport : mapTransports->second)
627 CreateTransport(transport->TransportGameObjectId, map, transport->SpawnId, transport->PhaseUseFlags, transport->PhaseId, transport->PhaseGroup);
628}
629
631{
633}
634
636{
638}
639
641{
643}
644
646{
647 if (Path.empty())
648 return nullptr;
649
650 auto itr = Path.lower_bound(time);
651 if (itr != Path.begin())
652 return std::prev(itr)->second;
653
654 return Path.rbegin()->second;
655}
656
658{
659 if (Rotations.empty())
660 return nullptr;
661
662 auto itr = Rotations.lower_bound(time);
663 if (itr != Rotations.begin())
664 return std::prev(itr)->second;
665
666 return Rotations.rbegin()->second;
667}
668
670{
671 if (Path.empty())
672 return nullptr;
673
674 auto itr = Path.lower_bound(time);
675 if (itr != Path.end())
676 return itr->second;
677
678 return Path.begin()->second;
679}
680
682{
683 if (Rotations.empty())
684 return nullptr;
685
686 auto itr = Rotations.lower_bound(time);
687 if (itr != Rotations.end())
688 return itr->second;
689
690 return Rotations.begin()->second;
691}
@ IN_MILLISECONDS
Definition: Common.h:35
#define M_PI
Definition: Common.h:115
DB2Storage< PhaseEntry > sPhaseStore("Phase.db2", &PhaseLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
TaxiPathNodesByPath sTaxiPathNodesByPath
Definition: DB2Stores.cpp:383
DB2Storage< TransportRotationEntry > sTransportRotationStore("TransportRotation.db2", &TransportRotationLoadInfo::Instance)
DB2Storage< TransportAnimationEntry > sTransportAnimationStore("TransportAnimation.db2", &TransportAnimationLoadInfo::Instance)
std::vector< TaxiPathNodeEntry const * > TaxiPathNodeList
Definition: DB2Stores.h:332
#define sDB2Manager
Definition: DB2Stores.h:538
@ TAXI_PATH_NODE_FLAG_TELEPORT
Definition: DBCEnums.h:2152
@ TAXI_PATH_NODE_FLAG_STOP
Definition: DBCEnums.h:2153
@ PHASE_USE_FLAGS_ALWAYS_VISIBLE
Definition: DBCEnums.h:1746
@ PHASE_USE_FLAGS_ALL
Definition: DBCEnums.h:1749
@ PHASE_USE_FLAGS_INVERSE
Definition: DBCEnums.h:1747
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
static void InitializeLeg(TransportPathLeg *leg, std::vector< TransportPathEvent > *outEvents, std::vector< TaxiPathNodeEntry const * > const &pathPoints, std::vector< TaxiPathNodeEntry const * > const &pauses, std::vector< TaxiPathNodeEntry const * > const &events, GameObjectTemplate const *goInfo, uint32 &totalTime)
TransportMovementState
Definition: TransportMgr.h:44
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
uint64 GetUInt64() const
Definition: Field.cpp:78
uint32 GetUInt32() const
Definition: Field.cpp:62
Definition: Map.h:189
bool AddToMap(T *)
Definition: Map.cpp:550
ObjectGuid::LowType GenerateLowGuid()
Definition: Map.h:519
uint32 GetId() const
Definition: Map.cpp:3228
InstanceMap * ToInstanceMap()
Definition: Map.h:454
uint64 LowType
Definition: ObjectGuid.h:278
static void InitDbPhaseShift(PhaseShift &phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
SplineRawInitializer(Movement::PointsArray &points)
Movement::PointsArray & _points
void operator()(uint8 &mode, bool &cyclic, Movement::PointsArray &points, int &lo, int &hi) const
std::unordered_map< ObjectGuid::LowType, TransportSpawn > _transportSpawns
Definition: TransportMgr.h:180
void LoadTransportTemplates()
void CreateTransportsForMap(Map *map)
TransportAnimation const * GetTransportAnimInfo(uint32 entry) const
Transport * CreateTransport(uint32 entry, Map *map, ObjectGuid::LowType guid=0, uint8 phaseUseFlags=0, uint32 phaseId=0, uint32 phaseGroupId=0)
std::unordered_map< uint32, std::set< TransportSpawn * > > _transportsByMap
Definition: TransportMgr.h:176
void LoadTransportAnimationAndRotation()
void LoadTransportSpawns()
static TransportMgr * instance()
TransportTemplate const * GetTransportTemplate(uint32 entry) const
void AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const *node)
void AddPathRotationToTransport(uint32 transportEntry, uint32 timeSeg, TransportRotationEntry const *node)
std::map< uint32, TransportAnimation > _transportAnimations
Definition: TransportMgr.h:178
std::unordered_map< uint32, TransportTemplate > _transportTemplates
Definition: TransportMgr.h:173
TransportSpawn const * GetTransportSpawn(ObjectGuid::LowType spawnId) const
void GeneratePath(GameObjectTemplate const *goInfo, TransportTemplate *transport)
bool Create(ObjectGuid::LowType guidlow, uint32 entry, float x, float y, float z, float ang)
Definition: Transport.cpp:103
PhaseShift & GetPhaseShift()
Definition: Object.h:523
ZoneScript * m_zoneScript
Definition: Object.h:800
virtual void SetMap(Map *map)
Definition: Object.cpp:1794
std::vector< Vector3 > PointsArray
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition: MapUtils.h:29
struct GameObjectTemplate::@213::@230 moTransport
TransportRotationEntry const * GetNextAnimRotation(uint32 time) const
TransportAnimationEntry const * GetNextAnimNode(uint32 time) const
TransportAnimationEntry const * GetPrevAnimNode(uint32 time) const
TransportRotationEntry const * GetPrevAnimRotation(uint32 time) const
std::map< uint32, TransportAnimationEntry const * > Path
Definition: TransportMgr.h:112
std::map< uint32, TransportRotationEntry const * > Rotations
Definition: TransportMgr.h:113
std::vector< TransportPathSegment > Segments
Definition: TransportMgr.h:78
std::unique_ptr< TransportSpline > Spline
Definition: TransportMgr.h:75
uint32 StartTimestamp
Definition: TransportMgr.h:76
uint32 SegmentEndArrivalTimestamp
Definition: TransportMgr.h:52
ObjectGuid::LowType SpawnId
Definition: TransportMgr.h:125
uint32 TransportGameObjectId
Definition: TransportMgr.h:126
double AccelerationTime
Definition: TransportMgr.h:94
uint32 GetNextPauseWaypointTimestamp(uint32 time) const
Optional< Position > ComputePosition(uint32 time, TransportMovementState *moveState, size_t *legIndex) const
double AccelerationRate
Definition: TransportMgr.h:93
std::set< uint32 > MapIds
Definition: TransportMgr.h:105
std::vector< TransportPathEvent > Events
Definition: TransportMgr.h:97
TransportPathLeg const * GetLegForTime(uint32 time) const
double AccelerationDistance
Definition: TransportMgr.h:95
std::vector< TransportPathLeg > PathLegs
Definition: TransportMgr.h:96
double CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) const