44 time %= TotalPathTime;
53 auto segmentItr = leg->
Segments.begin();
54 double distanceMoved = 0.0;
55 bool isOnPause =
false;
56 for (; segmentItr != std::prev(leg->
Segments.end()); ++segmentItr)
58 if (time < segmentItr->SegmentEndArrivalTimestamp)
61 distanceMoved = segmentItr->DistanceFromLegStartAtEnd;
62 if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
68 prevSegmentTime = segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
72 distanceMoved += CalculateDistanceMoved(
73 double(time - prevSegmentTime) * 0.001,
74 double(segmentItr->SegmentEndArrivalTimestamp - prevSegmentTime) * 0.001,
76 segmentItr == std::prev(leg->
Segments.end()));
79 float splinePointProgress;
80 leg->
Spline->computeIndex(std::fmin(distanceMoved / leg->
Spline->length(), 1.0), splineIndex, splinePointProgress);
82 G3D::Vector3 pos, dir;
83 leg->
Spline->evaluate_percent(splineIndex, splinePointProgress, pos);
84 leg->
Spline->evaluate_derivative(splineIndex, splinePointProgress, dir);
90 *legIndex = std::distance(PathLegs.data(), leg);
92 return Position(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) +
float(
M_PI));
98 while (legItr->StartTimestamp + legItr->Duration <= time)
115 auto segmentItr = leg->
Segments.begin();
116 for (; segmentItr != std::prev(leg->
Segments.end()); ++segmentItr)
117 if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
120 return segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
130 double segmentTimeAtFullSpeed = segmentDuration - accelerationTime;
131 if (timePassedInSegment <= segmentTimeAtFullSpeed)
133 return timePassedInSegment *
Speed;
137 double segmentAccelerationTime = timePassedInSegment - segmentTimeAtFullSpeed;
139 double segmentDistanceAtFullSpeed = segmentTimeAtFullSpeed *
Speed;
140 return (2.0 * segmentAccelerationDistance - segmentAccelerationTime *
AccelerationRate) * 0.5 * segmentAccelerationTime + segmentDistanceAtFullSpeed;
144 return timePassedInSegment *
Speed;
157 return timePassedInSegment *
Speed;
160 double accelerationTime = std::fmin(segmentDuration * 0.5,
AccelerationTime);
161 if (timePassedInSegment <= segmentDuration - accelerationTime)
163 if (timePassedInSegment <= accelerationTime)
170 double segmentTimeSpentAccelerating = timePassedInSegment - (segmentDuration - accelerationTime);
171 return (segmentDuration - 2 * accelerationTime) *
Speed
196 QueryResult result =
WorldDatabase.Query(
"SELECT entry FROM gameobject_template WHERE type = 15 ORDER BY entry ASC");
200 TC_LOG_INFO(
"server.loading",
">> Loaded 0 transport templates. DB table `gameobject_template` has no transports!");
208 Field* fields = result->Fetch();
211 if (goInfo ==
nullptr)
213 TC_LOG_ERROR(
"sql.sql",
"Transport {} has no associated GameObjectTemplate from `gameobject_template` , skipped.", entry);
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);
232 }
while (result->NextRow());
260 Field* fields = result->Fetch();
268 if (!transportTemplate)
270 TC_LOG_ERROR(
"sql.sql",
"Table `transports` have transport (GUID: {} Entry: {}) with unknown gameobject `entry` set, skipped.", guid, entry);
276 TC_LOG_ERROR(
"sql.sql",
"Table `transports` have transport (GUID: {} Entry: {}) with unknown `phaseUseFlags` set, removed unknown value.", guid, entry);
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;
287 if (phaseGroupId && phaseId)
289 TC_LOG_ERROR(
"sql.sql",
"Table `transports` have transport (GUID: {} Entry: {}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, entry);
297 TC_LOG_ERROR(
"sql.sql",
"Table `transports` have transport (GUID: {} Entry: {}) with `phaseid` {} does not exist, set to 0", guid, entry, phaseId);
306 TC_LOG_ERROR(
"sql.sql",
"Table `transports` have transport (GUID: {} Entry: {}) with `phaseGroup` {} does not exist, set to 0", guid, entry, phaseGroupId);
321 }
while (result->NextRow());
338 hi = points.size() - 2;
344static void InitializeLeg(
TransportPathLeg* leg, std::vector<TransportPathEvent>* outEvents, std::vector<TaxiPathNodeEntry const*>
const& pathPoints, std::vector<TaxiPathNodeEntry const*>
const& pauses,
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); });
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();
355 leg->
Segments.resize(pauses.size() + 1);
357 auto legTimeAccelDecel = [&](
double dist)
361 double accelDist = 0.5 * speed * speed / accel;
362 if (accelDist >= dist * 0.5)
363 return uint32(std::sqrt(dist / accel) * 2000.0);
365 return uint32((dist - (accelDist + accelDist)) / speed * 1000.0 + speed / accel * 2000.0);
368 auto legTimeAccel = [&](
double dist)
372 double accelDist = 0.5 * speed * speed / accel;
373 if (accelDist >= dist)
374 return uint32(std::sqrt((dist + dist) / accel) * 1000.0);
376 return uint32(((dist - accelDist) / speed + speed / accel) * 1000.0);
382 double splineLengthToPreviousNode = 0.0;
386 for (; pauseItr < pauses.size(); ++pauseItr)
388 auto pausePointItr = std::find(pathPoints.begin(), pathPoints.end(), pauses[pauseItr]);
389 if (*pausePointItr == pathPoints.back())
392 for (; eventItr < events.size(); ++eventItr)
394 auto eventPointItr = std::find(pathPoints.begin(), pathPoints.end(), events[eventItr]);
395 if (eventPointItr > pausePointItr)
398 double length = leg->
Spline->length(std::distance(pathPoints.begin(), eventPointItr)) - splineLengthToPreviousNode;
402 splineTime = legTimeAccelDecel(length);
404 splineTime = legTimeAccel(length);
406 if ((*eventPointItr)->ArrivalEventID)
410 event.EventId = (*eventPointItr)->ArrivalEventID;
413 if ((*eventPointItr)->DepartureEventID)
417 event.EventId = (*eventPointItr)->DepartureEventID;
421 double splineLengthToCurrentNode = leg->
Spline->length(std::distance(pathPoints.begin(), pausePointItr));
422 double length = splineLengthToCurrentNode - splineLengthToPreviousNode;
425 movementTime = legTimeAccelDecel(length);
427 movementTime = legTimeAccel(length);
430 leg->
Segments[pauseItr].SegmentEndArrivalTimestamp = leg->
Duration + delaySum;
432 leg->
Segments[pauseItr].DistanceFromLegStartAtEnd = splineLengthToCurrentNode;
434 splineLengthToPreviousNode = splineLengthToCurrentNode;
439 for (; eventItr < events.size(); ++eventItr)
441 auto eventPointItr = std::find(pathPoints.begin(), pathPoints.end(), events[eventItr]);
442 if (*eventPointItr == pathPoints.back())
445 double length = leg->
Spline->length(std::distance(pathPoints.begin(), eventPointItr)) - splineLengthToPreviousNode;
448 splineTime = legTimeAccel(length);
452 if ((*eventPointItr)->ArrivalEventID)
456 event.EventId = (*eventPointItr)->ArrivalEventID;
459 if ((*eventPointItr)->DepartureEventID)
463 event.EventId = (*eventPointItr)->DepartureEventID;
468 double length = leg->
Spline->length() - splineLengthToPreviousNode;
471 splineTime = legTimeAccel(length);
476 leg->
Duration += splineTime + delaySum;
479 leg->
Segments[pauseItr].DistanceFromLegStartAtEnd = leg->
Spline->length();
480 totalTime += leg->
Segments[pauseItr].SegmentEndArrivalTimestamp + leg->
Segments[pauseItr].Delay;
485 if (leg->
Segments.size() > pauseItr + 1)
499 std::vector<TaxiPathNodeEntry const*> pathPoints;
500 std::vector<TaxiPathNodeEntry const*> pauses;
501 std::vector<TaxiPathNodeEntry const*> events;
503 leg->
MapId = path[0]->ContinentID;
504 bool prevNodeWasTeleport =
false;
508 if (node->ContinentID != leg->
MapId || prevNodeWasTeleport)
512 leg = &transport->
PathLegs.emplace_back();
513 leg->
MapId = node->ContinentID;
520 pathPoints.push_back(node);
522 pauses.push_back(node);
524 if (node->ArrivalEventID || node->DepartureEventID)
525 events.push_back(node);
527 transport->
MapIds.insert(node->ContinentID);
533 if (transport->
MapIds.size() > 1)
546 animNode.
Path[timeSeg] = node;
563 entry =
instance->GetGameObjectEntry(0, entry);
571 TC_LOG_ERROR(
"sql.sql",
"Transport {} will not be loaded, `transport_template` missing", entry);
577 TC_LOG_ERROR(
"entities.transport",
"Transport {} attempted creation on map it has no path for {}!", entry, map->
GetId());
582 if (!startingPosition)
584 TC_LOG_ERROR(
"sql.sql",
"Transport {} will not be loaded, failed to compute starting position", entry);
592 float x = startingPosition->GetPositionX();
593 float y = startingPosition->GetPositionY();
594 float z = startingPosition->GetPositionZ();
595 float o = startingPosition->GetOrientation();
599 if (!trans->
Create(guidLow, entry, x, y, z, o))
650 auto itr =
Path.lower_bound(time);
651 if (itr !=
Path.begin())
652 return std::prev(itr)->second;
654 return Path.rbegin()->second;
664 return std::prev(itr)->second;
674 auto itr =
Path.lower_bound(time);
675 if (itr !=
Path.end())
678 return Path.begin()->second;
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
@ TAXI_PATH_NODE_FLAG_TELEPORT
@ TAXI_PATH_NODE_FLAG_STOP
@ PHASE_USE_FLAGS_ALWAYS_VISIBLE
@ PHASE_USE_FLAGS_INVERSE
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
std::optional< T > Optional
Optional helper class to wrap optional values within.
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
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)
Class used to access individual fields of database query result.
ObjectGuid::LowType GenerateLowGuid()
InstanceMap * ToInstanceMap()
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
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()
ZoneScript * m_zoneScript
virtual void SetMap(Map *map)
std::vector< Vector3 > PointsArray
auto MapGetValuePtr(M &map, typename M::key_type const &key)
struct GameObjectTemplate::@203::@220 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
uint32 SegmentEndArrivalTimestamp
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