TrinityCore
Loading...
Searching...
No Matches
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 "DB2Stores.h"
20#include "DatabaseEnv.h"
21#include "InstanceScript.h"
22#include "Log.h"
23#include "Map.h"
24#include "MapUtils.h"
25#include "ObjectMgr.h"
26#include "PhasingHandler.h"
27#include "Spline.h"
28#include "Transport.h"
29
33TransportPathLeg& TransportPathLeg::operator=(TransportPathLeg&&) noexcept = default;
34
38TransportTemplate& TransportTemplate::operator=(TransportTemplate&&) noexcept = default;
39
40Optional<Position> TransportTemplate::ComputePosition(uint32 time, TransportMovementState* moveState, size_t* legIndex) const
41{
42 time %= TotalPathTime;
43
44 // find leg
45 TransportPathLeg const* leg = GetLegForTime(time);
46 if (!leg)
47 return {};
48
49 // find segment
50 uint32 prevSegmentTime = leg->StartTimestamp;
51 auto segmentItr = leg->Segments.begin();
52 double distanceMoved = 0.0;
53 bool isOnPause = false;
54 for (; segmentItr != std::prev(leg->Segments.end()); ++segmentItr)
55 {
56 if (time < segmentItr->SegmentEndArrivalTimestamp)
57 break;
58
59 distanceMoved = segmentItr->DistanceFromLegStartAtEnd;
60 if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
61 {
62 isOnPause = true;
63 break;
64 }
65
66 prevSegmentTime = segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
67 }
68
69 if (!isOnPause)
70 distanceMoved += CalculateDistanceMoved(
71 double(time - prevSegmentTime) * 0.001,
72 double(segmentItr->SegmentEndArrivalTimestamp - prevSegmentTime) * 0.001,
73 segmentItr == leg->Segments.begin(),
74 segmentItr == std::prev(leg->Segments.end()));
75
77 float splinePointProgress;
78 leg->Spline->computeIndex(std::fmin(distanceMoved / leg->Spline->length(), 1.0), splineIndex, splinePointProgress);
79
80 G3D::Vector3 pos, dir;
81 leg->Spline->evaluate_percent(splineIndex, splinePointProgress, pos);
82 leg->Spline->evaluate_derivative(splineIndex, splinePointProgress, dir);
83
84 if (moveState)
86
87 if (legIndex)
88 *legIndex = std::distance(PathLegs.data(), leg);
89
90 return Position(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) + float(M_PI));
91}
92
94{
95 auto legItr = PathLegs.begin();
96 while (legItr->StartTimestamp + legItr->Duration <= time)
97 {
98 ++legItr;
99
100 if (legItr == PathLegs.end())
101 return nullptr;
102 }
103
104 return &*legItr;
105}
106
108{
109 TransportPathLeg const* leg = GetLegForTime(time);
110 if (!leg)
111 return time;
112
113 auto segmentItr = leg->Segments.begin();
114 for (; segmentItr != std::prev(leg->Segments.end()); ++segmentItr)
115 if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
116 break;
117
118 return segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
119}
120
121double TransportTemplate::CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) const
122{
123 if (isFirstSegment)
124 {
125 if (!isLastSegment)
126 {
127 double accelerationTime = std::fmin(AccelerationTime, segmentDuration);
128 double segmentTimeAtFullSpeed = segmentDuration - accelerationTime;
129 if (timePassedInSegment <= segmentTimeAtFullSpeed)
130 {
131 return timePassedInSegment * Speed;
132 }
133 else
134 {
135 double segmentAccelerationTime = timePassedInSegment - segmentTimeAtFullSpeed;
136 double segmentAccelerationDistance = AccelerationRate * accelerationTime;
137 double segmentDistanceAtFullSpeed = segmentTimeAtFullSpeed * Speed;
138 return (2.0 * segmentAccelerationDistance - segmentAccelerationTime * AccelerationRate) * 0.5 * segmentAccelerationTime + segmentDistanceAtFullSpeed;
139 }
140 }
141
142 return timePassedInSegment * Speed;
143 }
144
145 if (isLastSegment)
146 {
147 if (!isFirstSegment)
148 {
149 if (timePassedInSegment <= std::fmin(AccelerationTime, segmentDuration))
150 return AccelerationRate * timePassedInSegment * 0.5 * timePassedInSegment;
151 else
152 return (timePassedInSegment - AccelerationTime) * Speed + AccelerationDistance;
153 }
154
155 return timePassedInSegment * Speed;
156 }
157
158 double accelerationTime = std::fmin(segmentDuration * 0.5, AccelerationTime);
159 if (timePassedInSegment <= segmentDuration - accelerationTime)
160 {
161 if (timePassedInSegment <= accelerationTime)
162 return AccelerationRate * timePassedInSegment * 0.5 * timePassedInSegment;
163 else
164 return (timePassedInSegment - AccelerationTime) * Speed + AccelerationDistance;
165 }
166 else
167 {
168 double segmentTimeSpentAccelerating = timePassedInSegment - (segmentDuration - accelerationTime);
169 return (segmentDuration - 2 * accelerationTime) * Speed
170 + AccelerationRate * accelerationTime * 0.5 * accelerationTime
171 + (2.0 * AccelerationRate * accelerationTime - segmentTimeSpentAccelerating * AccelerationRate) * 0.5 * segmentTimeSpentAccelerating;
172 }
173}
174
178TransportAnimation& TransportAnimation::operator=(TransportAnimation&&) noexcept = default;
179
180TransportMgr::TransportMgr() = default;
181TransportMgr::~TransportMgr() = default;
182
184{
185 static TransportMgr instance;
186 return &instance;
187}
188
190{
191 _transportTemplates.clear();
192}
193
195{
196 uint32 oldMSTime = getMSTime();
197
198 QueryResult result = WorldDatabase.Query("SELECT entry FROM gameobject_template WHERE type = 15 ORDER BY entry ASC");
199
200 if (!result)
201 {
202 TC_LOG_INFO("server.loading", ">> Loaded 0 transport templates. DB table `gameobject_template` has no transports!");
203 return;
204 }
205
206 uint32 count = 0;
207
208 do
209 {
210 Field* fields = result->Fetch();
211 uint32 entry = fields[0].GetUInt32();
212 GameObjectTemplate const* goInfo = sObjectMgr->GetGameObjectTemplate(entry);
213 if (goInfo == nullptr)
214 {
215 TC_LOG_ERROR("sql.sql", "Transport {} has no associated GameObjectTemplate from `gameobject_template` , skipped.", entry);
216 continue;
217 }
218
219 if (goInfo->moTransport.taxiPathID >= sTaxiPathNodesByPath.size())
220 {
221 TC_LOG_ERROR("sql.sql", "Transport {} (name: {}) has an invalid path specified in `gameobject_template`.`Data0` ({}) field, skipped.", entry, goInfo->name, goInfo->moTransport.taxiPathID);
222 continue;
223 }
224
225 if (!goInfo->moTransport.taxiPathID)
226 continue;
227
228 // paths are generated per template, saves us from generating it again in case of instanced transports
229 TransportTemplate& transport = _transportTemplates[entry];
230
231 GeneratePath(goInfo, &transport);
232
233 ++count;
234 } while (result->NextRow());
235
236 TC_LOG_INFO("server.loading", ">> Loaded {} transport templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
237}
238
240{
242 AddPathNodeToTransport(anim->TransportID, anim->TimeIndex, anim);
243
245 AddPathRotationToTransport(rot->GameObjectsID, rot->TimeIndex, rot);
246}
247
249{
250 if (_transportTemplates.empty())
251 return;
252
253 uint32 oldMSTime = getMSTime();
254
255 QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseUseFlags, phaseid, phasegroup FROM transports");
256
257 uint32 count = 0;
258 if (result)
259 {
260 do
261 {
262 Field* fields = result->Fetch();
263 ObjectGuid::LowType guid = fields[0].GetUInt64();
264 uint32 entry = fields[1].GetUInt32();
265 uint8 phaseUseFlags = fields[2].GetUInt8();
266 uint32 phaseId = fields[3].GetUInt32();
267 uint32 phaseGroupId = fields[4].GetUInt32();
268
269 TransportTemplate const* transportTemplate = GetTransportTemplate(entry);
270 if (!transportTemplate)
271 {
272 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with unknown gameobject `entry` set, skipped.", guid, entry);
273 continue;
274 }
275
276 if (phaseUseFlags & ~PHASE_USE_FLAGS_ALL)
277 {
278 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with unknown `phaseUseFlags` set, removed unknown value.", guid, entry);
279 phaseUseFlags &= PHASE_USE_FLAGS_ALL;
280 }
281
282 if (phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && phaseUseFlags & PHASE_USE_FLAGS_INVERSE)
283 {
284 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE,"
285 " removing PHASE_USE_FLAGS_INVERSE.", guid, entry);
286 phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE;
287 }
288
289 if (phaseGroupId && phaseId)
290 {
291 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, entry);
292 phaseGroupId = 0;
293 }
294
295 if (phaseId)
296 {
297 if (!sPhaseStore.LookupEntry(phaseId))
298 {
299 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with `phaseid` {} does not exist, set to 0", guid, entry, phaseId);
300 phaseId = 0;
301 }
302 }
303
304 if (phaseGroupId)
305 {
306 if (!sDB2Manager.GetPhasesForGroup(phaseGroupId))
307 {
308 TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: {} Entry: {}) with `phaseGroup` {} does not exist, set to 0", guid, entry, phaseGroupId);
309 phaseGroupId = 0;
310 }
311 }
312
313 TransportSpawn& spawn = _transportSpawns[guid];
314 spawn.SpawnId = guid;
315 spawn.TransportGameObjectId = entry;
316 spawn.PhaseUseFlags = phaseUseFlags;
317 spawn.PhaseId = phaseId;
318 spawn.PhaseGroup = phaseGroupId;
319
320 for (uint32 mapId : transportTemplate->MapIds)
321 _transportsByMap[mapId].insert(&spawn);
322
323 } while (result->NextRow());
324 }
325
326 TC_LOG_INFO("server.loading", ">> Spawned {} continent transports in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
327}
328
330{
331public:
332 SplineRawInitializer(std::vector<TaxiPathNodeEntry const*> const& points) : _points(points) { }
333
334 void operator()(uint8& mode, bool& cyclic, std::vector<Movement::Vector3>& points, int& lo, int& hi) const
335 {
337 cyclic = false;
338 points.resize(_points.size());
339 std::ranges::transform(_points, points.begin(), [](TaxiPathNodeEntry const* node) { return Movement::Vector3(node->Loc.X, node->Loc.Y, node->Loc.Z); });
340 lo = 1;
341 hi = points.size() - 2;
342 }
343
344 std::vector<TaxiPathNodeEntry const*> const& _points;
345};
346
347static void InitializeLeg(TransportPathLeg* leg, std::vector<TransportPathEvent>* outEvents, std::vector<TaxiPathNodeEntry const*> const& pathPoints, std::vector<TaxiPathNodeEntry const*> const& pauses,
348 std::vector<TaxiPathNodeEntry const*> const& events, GameObjectTemplate const* goInfo, uint32& totalTime)
349{
350 leg->Spline = std::make_unique<TransportSpline>();
351 leg->Spline->set_steps_per_segment(20);
352 leg->Spline->init_spline_custom(SplineRawInitializer(pathPoints));
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 + delaySum;
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 + delaySum + (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 + delaySum;
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 + delaySum;
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)
483 segment.SegmentEndArrivalTimestamp += leg->StartTimestamp;
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 if (prevNodeWasTeleport && !pathPoints.empty())
511 pathPoints.push_back(pathPoints.back());
512
513 InitializeLeg(leg, &transport->Events, pathPoints, pauses, events, goInfo, totalTime);
514
515 leg = &transport->PathLegs.emplace_back();
516 leg->MapId = node->ContinentID;
517 pathPoints.clear();
518 pauses.clear();
519 events.clear();
520 }
521
522 prevNodeWasTeleport = (node->Flags & TAXI_PATH_NODE_FLAG_TELEPORT) != 0;
523 if (!pathPoints.empty() && node->Flags & TAXI_PATH_NODE_FLAG_STOP)
524 pauses.push_back(node);
525
526 if (node->ArrivalEventID || node->DepartureEventID)
527 events.push_back(node);
528
529 pathPoints.push_back(node);
530 transport->MapIds.insert(node->ContinentID);
531 }
532
533 if (!leg->Spline)
534 InitializeLeg(leg, &transport->Events, pathPoints, pauses, events, goInfo, totalTime);
535
536 if (transport->MapIds.size() > 1)
537 for (uint32 mapId : transport->MapIds)
538 ASSERT(!sMapStore.LookupEntry(mapId)->Instanceable());
539
540 transport->TotalPathTime = totalTime;
541}
542
544{
545 TransportAnimation& animNode = _transportAnimations[transportEntry];
546 if (animNode.TotalTime < timeSeg)
547 animNode.TotalTime = timeSeg;
548
549 animNode.Path[timeSeg] = node;
550}
551
553{
554 TransportAnimation& animNode = _transportAnimations[transportEntry];
555 animNode.Rotations[timeSeg] = node;
556
557 if (animNode.Path.empty() && animNode.TotalTime < timeSeg)
558 animNode.TotalTime = timeSeg;
559}
560
561Transport* TransportMgr::CreateTransport(uint32 entry, Map* map, ObjectGuid::LowType guid /*= 0*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/)
562{
563 // SetZoneScript() is called after adding to map, so fetch the script using map
564 if (InstanceMap* instanceMap = map->ToInstanceMap())
565 if (InstanceScript* instance = instanceMap->GetInstanceScript())
566 entry = instance->GetGameObjectEntry(0, entry);
567
568 if (!entry)
569 return nullptr;
570
571 TransportTemplate const* tInfo = GetTransportTemplate(entry);
572 if (!tInfo)
573 {
574 TC_LOG_ERROR("sql.sql", "Transport {} will not be loaded, `transport_template` missing", entry);
575 return nullptr;
576 }
577
578 if (tInfo->MapIds.find(map->GetId()) == tInfo->MapIds.end())
579 {
580 TC_LOG_ERROR("entities.transport", "Transport {} attempted creation on map it has no path for {}!", entry, map->GetId());
581 return nullptr;
582 }
583
584 Optional<Position> startingPosition = tInfo->ComputePosition(0, nullptr, nullptr);
585 if (!startingPosition)
586 {
587 TC_LOG_ERROR("sql.sql", "Transport {} will not be loaded, failed to compute starting position", entry);
588 return nullptr;
589 }
590
591 // create transport...
592 Transport* trans = new Transport();
593
594 // ...at first waypoint
595 float x = startingPosition->GetPositionX();
596 float y = startingPosition->GetPositionY();
597 float z = startingPosition->GetPositionZ();
598 float o = startingPosition->GetOrientation();
599
600 // initialize the gameobject base
601 ObjectGuid::LowType guidLow = guid ? guid : map->GenerateLowGuid<HighGuid::Transport>();
602 if (!trans->Create(guidLow, entry, x, y, z, o))
603 {
604 delete trans;
605 return nullptr;
606 }
607
608 PhasingHandler::InitDbPhaseShift(trans->GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId);
609
610 // use preset map for instances (need to know which instance)
611 trans->SetMap(map);
612 if (InstanceMap* instanceMap = map->ToInstanceMap())
613 trans->m_zoneScript = instanceMap->GetInstanceScript();
614
615 // Passengers will be loaded once a player is near
616 map->AddToMap<Transport>(trans);
617 return trans;
618}
619
621{
622 auto mapTransports = _transportsByMap.find(map->GetId());
623
624 // no transports here
625 if (mapTransports == _transportsByMap.end())
626 return;
627
628 // create transports
629 for (TransportSpawn const* transport : mapTransports->second)
630 CreateTransport(transport->TransportGameObjectId, map, transport->SpawnId, transport->PhaseUseFlags, transport->PhaseId, transport->PhaseGroup);
631}
632
637
642
647
649{
650 if (Path.empty())
651 return nullptr;
652
653 auto itr = Path.lower_bound(time);
654 if (itr != Path.begin())
655 return std::prev(itr)->second;
656
657 return Path.rbegin()->second;
658}
659
661{
662 if (Rotations.empty())
663 return nullptr;
664
665 auto itr = Rotations.lower_bound(time);
666 if (itr != Rotations.begin())
667 return std::prev(itr)->second;
668
669 return Rotations.rbegin()->second;
670}
671
673{
674 if (Path.empty())
675 return nullptr;
676
677 auto itr = Path.lower_bound(time);
678 if (itr != Path.end())
679 return itr->second;
680
681 return Path.begin()->second;
682}
683
685{
686 if (Rotations.empty())
687 return nullptr;
688
689 auto itr = Rotations.lower_bound(time);
690 if (itr != Rotations.end())
691 return itr->second;
692
693 return Rotations.begin()->second;
694}
@ IN_MILLISECONDS
Definition Common.h:38
#define M_PI
Definition Common.h:118
DB2Storage< PhaseEntry > sPhaseStore("Phase.db2", &PhaseLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
TaxiPathNodesByPath sTaxiPathNodesByPath
DB2Storage< TransportRotationEntry > sTransportRotationStore("TransportRotation.db2", &TransportRotationLoadInfo::Instance)
DB2Storage< TransportAnimationEntry > sTransportAnimationStore("TransportAnimation.db2", &TransportAnimationLoadInfo::Instance)
std::vector< TaxiPathNodeEntry const * > TaxiPathNodeList
Definition DB2Stores.h:365
#define sDB2Manager
Definition DB2Stores.h:569
@ TAXI_PATH_NODE_FLAG_TELEPORT
Definition DBCEnums.h:2816
@ TAXI_PATH_NODE_FLAG_STOP
Definition DBCEnums.h:2817
@ PHASE_USE_FLAGS_ALWAYS_VISIBLE
Definition DBCEnums.h:2167
@ PHASE_USE_FLAGS_ALL
Definition DBCEnums.h:2170
@ PHASE_USE_FLAGS_INVERSE
Definition DBCEnums.h:2168
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
#define ASSERT
Definition Errors.h:80
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
#define sObjectMgr
Definition ObjectMgr.h:1885
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
Class used to access individual fields of database query result.
Definition Field.h:94
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
Definition Map.h:225
bool AddToMap(T *)
Definition Map.cpp:517
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:558
uint32 GetId() const
Definition Map.cpp:3257
InstanceMap * ToInstanceMap()
Definition Map.h:490
uint64 LowType
Definition ObjectGuid.h:321
static void InitDbPhaseShift(PhaseShift &phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
std::vector< TaxiPathNodeEntry const * > const & _points
SplineRawInitializer(std::vector< TaxiPathNodeEntry const * > const &points)
void operator()(uint8 &mode, bool &cyclic, std::vector< Movement::Vector3 > &points, int &lo, int &hi) const
std::unordered_map< ObjectGuid::LowType, TransportSpawn > _transportSpawns
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
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
std::unordered_map< uint32, TransportTemplate > _transportTemplates
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)
PhaseShift & GetPhaseShift()
Definition Object.h:310
ZoneScript * m_zoneScript
Definition Object.h:584
virtual void SetMap(Map *map)
Definition Object.cpp:1144
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
struct GameObjectTemplate::@197::@214 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
std::map< uint32, TransportRotationEntry const * > Rotations
std::vector< TransportPathSegment > Segments
std::unique_ptr< TransportSpline > Spline
ObjectGuid::LowType SpawnId
uint32 TransportGameObjectId
uint32 GetNextPauseWaypointTimestamp(uint32 time) const
Optional< Position > ComputePosition(uint32 time, TransportMovementState *moveState, size_t *legIndex) const
std::set< uint32 > MapIds
std::vector< TransportPathEvent > Events
TransportPathLeg const * GetLegForTime(uint32 time) const
double AccelerationDistance
std::vector< TransportPathLeg > PathLegs
double CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) const