diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 4fd1bd6eb..97113cb5b 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -3663,7 +3663,7 @@ namespace Game.Entities ITransport m_transport; Map _currMap; - uint instanceId; + public uint instanceId; PhaseShift _phaseShift = new(); PhaseShift _suppressedPhaseShift = new(); // contains phases for current area but not applied due to conditions int _dbPhase; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index ad7ae88dc..9efcac8e8 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -612,22 +612,14 @@ namespace Game.Entities { var createPosition = m_createMode == PlayerCreateMode.NPE && info.createPositionNPE.HasValue ? info.createPositionNPE.Value : info.createPosition; - homebind.WorldRelocate(createPosition.Loc); - if (createPosition.TransportGuid.HasValue) + if (!createPosition.TransportGuid.HasValue) { - Transport transport = Global.ObjAccessor.FindTransport(ObjectGuid.Create(HighGuid.Transport, createPosition.TransportGuid.Value)); - if (transport != null) - { - float orientation = homebind.GetOrientation(); - transport.CalculatePassengerPosition(ref homebind.posX, ref homebind.posY, ref homebind.posZ, ref orientation); - homebind.SetOrientation(orientation); - } + homebind.WorldRelocate(createPosition.Loc); + homebindAreaId = Global.MapMgr.GetAreaId(PhasingHandler.EmptyPhaseShift, homebind); + + saveHomebindToDb(); + ok = true; } - - homebindAreaId = Global.MapMgr.GetAreaId(PhasingHandler.EmptyPhaseShift, homebind); - - saveHomebindToDb(); - ok = true; } if (!ok) @@ -2864,10 +2856,25 @@ namespace Game.Entities ObjectGuid transGUID = ObjectGuid.Create(HighGuid.Transport, transguid); Transport transport = null; - Transport go = Global.ObjAccessor.FindTransport(transGUID); - if (go) - transport = go; - + Map transportMap = Global.MapMgr.CreateMap(mapId, this, instanceId); + if (transportMap != null) + { + Transport transportOnMap = transportMap.GetTransport(transGUID); + if (transportOnMap != null) + { + if (transportOnMap.GetExpectedMapId() != mapId) + { + mapId = transportOnMap.GetExpectedMapId(); + instanceId = 0; + transportMap = Global.MapMgr.CreateMap(mapId, this, instanceId); + if (transportMap) + transport = transportMap.GetTransport(transGUID); + } + else + transport = transportOnMap; + } + } + if (transport) { float x = trans_x; diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index daafa0ae0..ce429e5ef 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -203,7 +203,7 @@ namespace Game.Entities if (position.TransportGuid.HasValue) { - Transport transport = Global.ObjAccessor.FindTransport(ObjectGuid.Create(HighGuid.Transport, position.TransportGuid.Value)); + Transport transport = ObjectAccessor.GetTransport(this, ObjectGuid.Create(HighGuid.Transport, position.TransportGuid.Value)); if (transport != null) { transport.AddPassenger(this); diff --git a/Source/Game/Entities/Transport.cs b/Source/Game/Entities/Transport.cs index ca8972bc2..1ef152426 100644 --- a/Source/Game/Entities/Transport.cs +++ b/Source/Game/Entities/Transport.cs @@ -18,6 +18,7 @@ using Framework.Constants; using Game.DataStorage; using Game.Maps; +using Game.Networking.Packets; using System; using System.Collections; using System.Collections.Generic; @@ -142,14 +143,13 @@ namespace Game.Entities base.Dispose(); } - public bool Create(ulong guidlow, uint entry, uint mapid, float x, float y, float z, float ang, uint animprogress) + public bool Create(ulong guidlow, uint entry, float x, float y, float z, float ang) { Relocate(x, y, z, ang); if (!IsPositionValid()) { - Log.outError(LogFilter.Transport, "Transport (GUID: {0}) not created. Suggested coordinates isn't valid (X: {1} Y: {2})", - guidlow, x, y); + Log.outError(LogFilter.Transport, $"Transport (GUID: {guidlow}) not created. Suggested coordinates isn't valid (X: {x} Y: {y})"); return false; } @@ -159,7 +159,7 @@ namespace Game.Entities if (goinfo == null) { - Log.outError(LogFilter.Sql, "Transport not created: entry in `gameobject_template` not found, guidlow: {0} map: {1} (X: {2} Y: {3} Z: {4}) ang: {5}", guidlow, mapid, x, y, z, ang); + Log.outError(LogFilter.Sql, $"Transport not created: entry in `gameobject_template` not found, entry: {entry}"); return false; } @@ -191,12 +191,20 @@ namespace Game.Entities SetDisplayId(goinfo.displayId); SetGoState(goinfo.MoTransport.allowstopping == 0 ? GameObjectState.Ready : GameObjectState.Active); SetGoType(GameObjectTypes.MapObjTransport); - SetGoAnimProgress(animprogress); + SetGoAnimProgress(255); SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.SpawnTrackingStateAnimID), Global.DB2Mgr.GetEmptyAnimStateID()); SetName(goinfo.name); SetLocalRotation(0.0f, 0.0f, 0.0f, 1.0f); SetParentRotation(Quaternion.Identity); + int legIndex; + var position = _transportInfo.ComputePosition(_pathProgress, out _, out legIndex); + if (position != null) + { + Relocate(position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(), position.GetOrientation()); + _currentPathLeg = legIndex; + } + CreateModel(); return true; } @@ -258,7 +266,11 @@ namespace Game.Entities { while (eventToTriggerIndex < _transportInfo.Events.Count && _transportInfo.Events[eventToTriggerIndex].Timestamp < timer) { - GameEvents.Trigger(_transportInfo.Events[eventToTriggerIndex].EventId, this, this); + TransportPathLeg leg = _transportInfo.GetLegForTime(_transportInfo.Events[eventToTriggerIndex].Timestamp); + if (leg != null) + if (leg.MapId == GetMapId()) + GameEvents.Trigger(_transportInfo.Events[eventToTriggerIndex].EventId, this, this); + _eventsToTrigger.Set(eventToTriggerIndex, false); ++eventToTriggerIndex; } @@ -283,13 +295,14 @@ namespace Game.Entities if (legIndex != _currentPathLeg) { + uint oldMapId = _transportInfo.PathLegs[_currentPathLeg].MapId; _currentPathLeg = legIndex; - TeleportTransport(_transportInfo.PathLegs[legIndex].MapId, newPosition.GetPositionX(), newPosition.GetPositionY(), newPosition.GetPositionZ(), newPosition.GetOrientation()); + TeleportTransport(oldMapId, _transportInfo.PathLegs[legIndex].MapId, newPosition.GetPositionX(), newPosition.GetPositionY(), newPosition.GetPositionZ(), newPosition.GetOrientation()); return; } // set position - if (_positionChangeTimer.Passed()) + if (_positionChangeTimer.Passed() && GetExpectedMapId() == GetMapId()) { _positionChangeTimer.Reset(positionUpdateDelay); if (_movementState == TransportMovementState.Moving || justStopped) @@ -323,11 +336,6 @@ namespace Game.Entities } } - public void DelayedUpdate(uint diff) - { - DelayedTeleportTransport(); - } - public void AddPassenger(WorldObject passenger) { if (!IsInWorld) @@ -646,14 +654,12 @@ namespace Game.Entities public void SetDelayedAddModelToMap() { _delayedAddModel = true; } - bool TeleportTransport(uint newMapid, float x, float y, float z, float o) + bool TeleportTransport(uint oldMapId, uint newMapId, float x, float y, float z, float o) { - Map oldMap = GetMap(); - - if (oldMap.GetId() != newMapid) + if (oldMapId != newMapId) { - _delayedTeleport = new(newMapid, x, y, z, o); UnloadStaticPassengers(); + TeleportPassengersAndHideTransport(newMapId, x, y, z, o); return true; } else @@ -683,21 +689,41 @@ namespace Game.Entities } } - void DelayedTeleportTransport() + void TeleportPassengersAndHideTransport(uint newMapid, float x, float y, float z, float o) { - if (_delayedTeleport == null) - return; + if (newMapid == GetMapId()) + { + AddToWorld(); - Map newMap = Global.MapMgr.CreateBaseMap(_delayedTeleport.GetMapId()); - GetMap().RemoveFromMap(this, false); - SetMap(newMap); + foreach (var player in GetMap().GetPlayers()) + { + if (player.GetTransport() != this && player.IsInPhase(this)) + { + UpdateData data = new(GetMap().GetId()); + BuildCreateUpdateBlockForPlayer(data, player); + player.m_visibleTransports.Add(GetGUID()); + data.BuildPacket(out UpdateObject packet); + player.SendPacket(packet); + } + } + } + else + { + UpdateData data = new(GetMap().GetId()); + BuildOutOfRangeUpdateBlock(data); - float x = _delayedTeleport.GetPositionX(), - y = _delayedTeleport.GetPositionY(), - z = _delayedTeleport.GetPositionZ(), - o = _delayedTeleport.GetOrientation(); + data.BuildPacket(out UpdateObject packet); + foreach (var player in GetMap().GetPlayers()) + { + if (player.GetTransport() != this && player.m_visibleTransports.Contains(GetGUID())) + { + player.SendPacket(packet); + player.m_visibleTransports.Remove(GetGUID()); + } + } - _delayedTeleport = null; + RemoveFromWorld(); + } List passengersToTeleport = new(_passengers); foreach (WorldObject obj in passengersToTeleport) @@ -709,7 +735,7 @@ namespace Game.Entities switch (obj.GetTypeId()) { case TypeId.Player: - if (!obj.ToPlayer().TeleportTo(newMap.GetId(), destX, destY, destZ, destO, TeleportToOptions.NotLeaveTransport, newMap.GetInstanceId())) + if (!obj.ToPlayer().TeleportTo(newMapid, destX, destY, destZ, destO, TeleportToOptions.NotLeaveTransport)) RemovePassenger(obj); break; case TypeId.DynamicObject: @@ -721,9 +747,6 @@ namespace Game.Entities break; } } - - Relocate(x, y, z, o); - GetMap().AddToMap(this); } void UpdatePassengerPositions(HashSet passengers) @@ -750,6 +773,11 @@ namespace Game.Entities ClearUpdateMask(true); } + public uint GetExpectedMapId() + { + return _transportInfo.PathLegs[_currentPathLeg].MapId; + } + public HashSet GetPassengers() { return _passengers; } public ObjectGuid GetTransportGUID() { return GetGUID(); } @@ -772,6 +800,5 @@ namespace Game.Entities HashSet _staticPassengers = new(); bool _delayedAddModel; - WorldLocation _delayedTeleport; } } diff --git a/Source/Game/Globals/ObjectAccessor.cs b/Source/Game/Globals/ObjectAccessor.cs index fe609ca51..d9e149c50 100644 --- a/Source/Game/Globals/ObjectAccessor.cs +++ b/Source/Game/Globals/ObjectAccessor.cs @@ -27,7 +27,6 @@ public class ObjectAccessor : Singleton object _lockObject = new(); Dictionary _players = new(); - Dictionary _transports = new(); ObjectAccessor() { } @@ -119,16 +118,11 @@ public class ObjectAccessor : Singleton return u.GetMap().GetGameObject(guid); } - static Transport GetTransportOnMap(WorldObject u, ObjectGuid guid) + public static Transport GetTransport(WorldObject u, ObjectGuid guid) { return u.GetMap().GetTransport(guid); } - Transport GetTransport(ObjectGuid guid) - { - return _transports.LookupByKey(guid); - } - static DynamicObject GetDynamicObject(WorldObject u, ObjectGuid guid) { return u.GetMap().GetDynamicObject(guid); @@ -227,12 +221,6 @@ public class ObjectAccessor : Singleton return PlayerNameMapHolder.Find(name); } - public Transport FindTransport(ObjectGuid guid) - { - lock (_lockObject) - return _transports.LookupByKey(guid); - } - public void SaveAllPlayers() { lock (_lockObject) @@ -256,11 +244,6 @@ public class ObjectAccessor : Singleton _players[obj.GetGUID()] = obj; } } - public void AddObject(Transport obj) - { - lock (_lockObject) - _transports[obj.GetGUID()] = obj; - } public void RemoveObject(Player obj) { @@ -270,11 +253,6 @@ public class ObjectAccessor : Singleton _players.Remove(obj.GetGUID()); } } - public void RemoveObject(Transport obj) - { - lock (_lockObject) - _transports.Remove(obj.GetGUID()); - } } class PlayerNameMapHolder diff --git a/Source/Game/Handlers/MovementHandler.cs b/Source/Game/Handlers/MovementHandler.cs index 0b53ceaf2..efa00f643 100644 --- a/Source/Game/Handlers/MovementHandler.cs +++ b/Source/Game/Handlers/MovementHandler.cs @@ -255,6 +255,11 @@ namespace Game Map oldMap = player.GetMap(); Map newMap = GetPlayer().GetTeleportDestInstanceId().HasValue ? Global.MapMgr.FindMap(loc.GetMapId(), GetPlayer().GetTeleportDestInstanceId().Value) : Global.MapMgr.CreateMap(loc.GetMapId(), GetPlayer()); + MovementInfo.TransportInfo transportInfo = player.m_movementInfo.transport; + ITransport transport = player.GetTransport(); + if (transport != null) + transport.RemovePassenger(player); + if (player.IsInWorld) { Log.outError(LogFilter.Network, $"Player (Name {player.GetName()}) is still in world when teleported from map {oldMap.GetId()} to new map {loc.GetMapId()}"); @@ -286,6 +291,14 @@ namespace Game if (!seamlessTeleport) player.SendInitialPacketsBeforeAddToMap(); + // move player between transport copies on each map + Transport newTransport = newMap.GetTransport(transportInfo.guid); + if (newTransport != null) + { + player.m_movementInfo.transport = transportInfo; + newTransport.AddPassenger(player); + } + if (!player.GetMap().AddPlayerToMap(player, !seamlessTeleport)) { Log.outError(LogFilter.Network, $"WORLD: failed to teleport player {player.GetName()} ({player.GetGUID()}) to map {loc.GetMapId()} ({(newMap ? newMap.GetMapName() : "Unknown")}) because of unknown reason!"); diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index d17d01246..16dfd3680 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -83,6 +83,8 @@ namespace Game.Maps _poolData = Global.PoolMgr.InitPoolsForMap(this); + Global.TransportMgr.CreateTransportsForMap(this); + Global.MMapMgr.LoadMapInstance(Global.WorldMgr.GetDataPath(), GetId(), i_InstanceId); Global.ScriptMgr.OnCreateMap(this); @@ -408,12 +410,6 @@ namespace Game.Maps player.Dispose(); } - void DeleteFromWorld(Transport transport) - { - Global.ObjAccessor.RemoveObject(transport); - transport.Dispose(); - } - void DeleteFromWorld(WorldObject obj) { obj.Dispose(); @@ -642,20 +638,24 @@ namespace Game.Maps return false; //Should delete object } - obj.AddToWorld(); _transports.Add(obj); - // Broadcast creation to players - foreach (Player player in GetPlayers()) + if (obj.GetExpectedMapId() == GetId()) { - if (player.GetTransport() != obj) + obj.AddToWorld(); + + // Broadcast creation to players + foreach (var player in GetPlayers()) { - var data = new UpdateData(GetId()); - obj.BuildCreateUpdateBlockForPlayer(data, player); - player.m_visibleTransports.Add(obj.GetGUID()); - UpdateObject packet; - data.BuildPacket(out packet); - player.SendPacket(packet); + if (player.GetTransport() != obj && player.IsInPhase(obj)) + { + var data = new UpdateData(GetId()); + obj.BuildCreateUpdateBlockForPlayer(data, player); + player.m_visibleTransports.Add(obj.GetGUID()); + UpdateObject packet; + data.BuildPacket(out packet); + player.SendPacket(packet); + } } } @@ -830,7 +830,7 @@ namespace Game.Maps for (var i = 0; i < _transports.Count; ++i) { Transport transport = _transports[i]; - if (!transport || !transport.IsInWorld) + if (!transport) continue; transport.Update(diff); @@ -1011,19 +1011,22 @@ namespace Game.Maps public void RemoveFromMap(Transport obj, bool remove) { - obj.RemoveFromWorld(); - - var players = GetPlayers(); - if (!players.Empty()) + if (obj.IsInWorld) { + obj.RemoveFromWorld(); + UpdateData data = new(GetId()); - obj.BuildOutOfRangeUpdateBlock(data); + if (obj.IsDestroyedObject()) + obj.BuildDestroyUpdateBlock(data); + else + obj.BuildOutOfRangeUpdateBlock(data); + UpdateObject packet; data.BuildPacket(out packet); - foreach (var player in players) + foreach (var player in GetPlayers()) { - if (player.GetTransport() != obj) + if (player.GetTransport() != obj && player.m_visibleTransports.Contains(obj.GetGUID())) { player.SendPacket(packet); player.m_visibleTransports.Remove(obj.GetGUID()); @@ -2270,11 +2273,11 @@ namespace Game.Maps void SendInitTransports(Player player) { - var transData = new UpdateData(player.GetMapId()); + var transData = new UpdateData(GetId()); foreach (Transport transport in _transports) { - if (transport != player.GetTransport() && player.IsInPhase(transport)) + if (transport.IsInWorld && transport != player.GetTransport() && player.IsInPhase(transport)) { transport.BuildCreateUpdateBlockForPlayer(transData, player); player.m_visibleTransports.Add(transport.GetGUID()); @@ -2291,7 +2294,7 @@ namespace Game.Maps var transData = new UpdateData(player.GetMapId()); foreach (Transport transport in _transports) { - if (transport != player.GetTransport()) + if (player.m_visibleTransports.Contains(transport.GetGUID()) && transport != player.GetTransport()) { transport.BuildOutOfRangeUpdateBlock(transData); player.m_visibleTransports.Remove(transport.GetGUID()); @@ -2309,6 +2312,9 @@ namespace Game.Maps UpdateData transData = new(player.GetMapId()); foreach (var transport in _transports) { + if (!transport.IsInWorld) + continue; + var hasTransport = player.m_visibleTransports.Contains(transport.GetGUID()); if (player.IsInPhase(transport)) { @@ -2914,15 +2920,6 @@ namespace Game.Maps while (_farSpellCallbacks.TryDequeue(out FarSpellCallback callback)) callback(this); - for (var i = 0; i < _transports.Count; ++i) - { - Transport transport = _transports[i]; - if (!transport.IsInWorld) - continue; - - transport.DelayedUpdate(diff); - } - RemoveAllObjectsInRemoveList(); // Don't unload grids if it's Battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load ! diff --git a/Source/Game/Maps/TransportManager.cs b/Source/Game/Maps/TransportManager.cs index a2e415e37..d93e37a4c 100644 --- a/Source/Game/Maps/TransportManager.cs +++ b/Source/Game/Maps/TransportManager.cs @@ -72,15 +72,7 @@ namespace Game.Maps // paths are generated per template, saves us from generating it again in case of instanced transports TransportTemplate transport = new(); - List mapsUsed = new(); - - GeneratePath(goInfo, transport, mapsUsed); - - _transportTemplates[entry] = transport; - - // transports in instance are only on one map - if (transport.InInstance) - _instanceTransports.Add(mapsUsed.First(), entry); + GeneratePath(goInfo, transport); ++count; } while (result.NextRow()); @@ -118,7 +110,8 @@ namespace Game.Maps uint phaseId = result.Read(3); uint phaseGroupId = result.Read(4); - if (GetTransportTemplate(entry) == null) + TransportTemplate transportTemplate = GetTransportTemplate(entry); + if (transportTemplate == null) { Log.outError(LogFilter.Sql, $"Table `transports` have transport (GUID: {guid} Entry: {entry}) with unknown gameobject `entry` set, skipped."); continue; @@ -167,6 +160,9 @@ namespace Game.Maps spawn.PhaseId = phaseId; spawn.PhaseGroup = phaseGroupId; + foreach (uint mapId in transportTemplate.MapIds) + _transportsByMap[mapId].Add(spawn); + _transportSpawns[guid] = spawn; } while (result.NextRow()); @@ -321,7 +317,7 @@ namespace Game.Maps } } - void GeneratePath(GameObjectTemplate goInfo, TransportTemplate transport, List mapsUsed) + void GeneratePath(GameObjectTemplate goInfo, TransportTemplate transport) { uint pathId = goInfo.MoTransport.taxiPathID; TaxiPathNodeRecord[] path = CliDB.TaxiPathNodesByPath[pathId]; @@ -360,21 +356,21 @@ namespace Game.Maps if (node.ArrivalEventID != 0 || node.DepartureEventID != 0) events.Add(node); - mapsUsed.Add(node.ContinentID); + transport.MapIds.Add(node.ContinentID); } if (leg.Spline == null) InitializeLeg(leg, transport.Events, pathPoints, pauses, events, goInfo, ref totalTime); - if (mapsUsed.Count > 1) + if (transport.MapIds.Count > 1) { - foreach (uint mapId in mapsUsed) + foreach (uint mapId in transport.MapIds) Cypher.Assert(!CliDB.MapStorage.LookupByKey(mapId).Instanceable()); transport.InInstance = false; } else - transport.InInstance = CliDB.MapStorage.LookupByKey(mapsUsed.First()).Instanceable(); + transport.InInstance = CliDB.MapStorage.LookupByKey(transport.MapIds.First()).Instanceable(); transport.TotalPathTime = totalTime; transport.PathLegs.Add(leg); @@ -403,23 +399,20 @@ namespace Game.Maps animNode.TotalTime = timeSeg; } - public Transport CreateTransport(uint entry, ulong guid = 0, Map map = null, PhaseUseFlagsValues phaseUseFlags = 0, uint phaseId = 0, uint phaseGroupId = 0) + public Transport CreateTransport(uint entry, Map map, ulong guid = 0, PhaseUseFlagsValues phaseUseFlags = 0, uint phaseId = 0, uint phaseGroupId = 0) { - // instance case, execute GetGameObjectEntry hook - if (map != null) + // SetZoneScript() is called after adding to map, so fetch the script using map + InstanceMap instanceMap = map.ToInstanceMap(); + if (instanceMap != null) { - // SetZoneScript() is called after adding to map, so fetch the script using map - if (map.IsDungeon()) - { - InstanceScript instance = ((InstanceMap)map).GetInstanceScript(); - if (instance != null) - entry = instance.GetGameObjectEntry(0, entry); - } - - if (entry == 0) - return null; + InstanceScript instance = instanceMap.GetInstanceScript(); + if (instance != null) + entry = instance.GetGameObjectEntry(0, entry); } + if (entry == 0) + return null; + TransportTemplate tInfo = GetTransportTemplate(entry); if (tInfo == null) { @@ -446,7 +439,7 @@ namespace Game.Maps // initialize the gameobject base ulong guidLow = guid != 0 ? guid : map.GenerateLowGuid(HighGuid.Transport); - if (!trans.Create(guidLow, entry, mapId, x, y, z, o, 255)) + if (!trans.Create(guidLow, entry, x, y, z, o)) return null; PhasingHandler.InitDbPhaseShift(trans.GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId); @@ -462,42 +455,27 @@ namespace Game.Maps } // use preset map for instances (need to know which instance) - trans.SetMap(map != null ? map : Global.MapMgr.CreateMap(mapId, null)); - if (map != null && map.IsDungeon()) - trans.m_zoneScript = map.ToInstanceMap().GetInstanceScript(); + trans.SetMap(map); + if (instanceMap != null) + trans.m_zoneScript = instanceMap.GetInstanceScript(); // Passengers will be loaded once a player is near - Global.ObjAccessor.AddObject(trans); - trans.GetMap().AddToMap(trans); + map.AddToMap(trans); return trans; } - public void SpawnContinentTransports() + public void CreateTransportsForMap(Map map) { - uint oldMSTime = Time.GetMSTime(); - - uint count = 0; - - foreach (var pair in _transportSpawns) - if (!GetTransportTemplate(pair.Value.TransportGameObjectId).InInstance) - if (CreateTransport(pair.Value.TransportGameObjectId, pair.Value.SpawnId, null, pair.Value.PhaseUseFlags, pair.Value.PhaseId, pair.Value.PhaseGroup)) - ++count; - - Log.outInfo(LogFilter.ServerLoading, "Spawned {0} continent transports in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); - } - - public void CreateInstanceTransports(Map map) - { - var mapTransports = _instanceTransports.LookupByKey(map.GetId()); + var mapTransports = _transportsByMap.LookupByKey(map.GetId()); // no transports here if (mapTransports.Empty()) return; // create transports - foreach (var transportGameObjectId in mapTransports) - CreateTransport(transportGameObjectId, 0, map); + foreach (var transport in mapTransports) + CreateTransport(transport.TransportGameObjectId, map, transport.SpawnId, transport.PhaseUseFlags, transport.PhaseId, transport.PhaseGroup); } public TransportTemplate GetTransportTemplate(uint entry) @@ -516,7 +494,7 @@ namespace Game.Maps } Dictionary _transportTemplates = new(); - MultiMap _instanceTransports = new(); + MultiMap _transportsByMap = new(); Dictionary _transportAnimations = new(); Dictionary _transportSpawns = new(); } @@ -553,34 +531,29 @@ namespace Game.Maps public List PathLegs = new(); public List Events = new(); + public List MapIds = new(); public bool InInstance; public Position ComputePosition(uint time, out TransportMovementState moveState, out int legIndex) { moveState = TransportMovementState.Moving; + legIndex = 0; time %= TotalPathTime; // find leg - legIndex = 0; - while (PathLegs[legIndex].StartTimestamp + PathLegs[legIndex].Duration <= time) - { - ++legIndex; - - if (PathLegs.Count >= legIndex) - return null; - } - - var legItr = PathLegs[legIndex]; + TransportPathLeg leg = GetLegForTime(time); + if (leg == null) + return null; // find segment - uint prevSegmentTime = legItr.StartTimestamp; + uint prevSegmentTime = leg.StartTimestamp; var segmentIndex = 0; double distanceMoved = 0.0; bool isOnPause = false; - for (segmentIndex = 0; segmentIndex < legItr.Segments.Count; ++segmentIndex) + for (segmentIndex = 0; segmentIndex < leg.Segments.Count; ++segmentIndex) { - var segment = legItr.Segments[segmentIndex]; + var segment = leg.Segments[segmentIndex]; if (time < segment.SegmentEndArrivalTimestamp) break; @@ -594,28 +567,57 @@ namespace Game.Maps prevSegmentTime = segment.SegmentEndArrivalTimestamp + segment.Delay; } - var pathSegment = legItr.Segments[segmentIndex]; + var pathSegment = leg.Segments[segmentIndex]; if (!isOnPause) distanceMoved += CalculateDistanceMoved( (double)(time - prevSegmentTime) * 0.001, (double)(pathSegment.SegmentEndArrivalTimestamp - prevSegmentTime) * 0.001, segmentIndex == 0, - segmentIndex == legItr.Segments.Count); + segmentIndex == leg.Segments.Count); int splineIndex = 0; float splinePointProgress = 0; - legItr.Spline.ComputeIndex((float)Math.Min(distanceMoved / legItr.Spline.Length(), 1.0), ref splineIndex, ref splinePointProgress); + leg.Spline.ComputeIndex((float)Math.Min(distanceMoved / leg.Spline.Length(), 1.0), ref splineIndex, ref splinePointProgress); Vector3 pos, dir; - legItr.Spline.Evaluate_Percent(splineIndex, splinePointProgress, out pos); - legItr.Spline.Evaluate_Derivative(splineIndex, splinePointProgress, out dir); + leg.Spline.Evaluate_Percent(splineIndex, splinePointProgress, out pos); + leg.Spline.Evaluate_Derivative(splineIndex, splinePointProgress, out dir); moveState = isOnPause ? TransportMovementState.WaitingOnPauseWaypoint : TransportMovementState.Moving; + legIndex = PathLegs.IndexOf(leg); return new Position(pos.X, pos.Y, pos.Z, MathF.Atan2(dir.Y, dir.X) + MathF.PI); } + public TransportPathLeg GetLegForTime(uint time) + { + int legIndex = 0; + while (PathLegs[legIndex].StartTimestamp + PathLegs[legIndex].Duration <= time) + { + ++legIndex; + + if (PathLegs.Count >= legIndex) + return null; + } + + return PathLegs[legIndex]; + } + + public uint GetNextPauseWaypointTimestamp(uint time) + { + TransportPathLeg leg = GetLegForTime(time); + if (leg == null) + return time; + + int segmentIndex = 0; + for (; segmentIndex != leg.Segments.Count - 1; ++segmentIndex) + if (time < leg.Segments[segmentIndex].SegmentEndArrivalTimestamp + leg.Segments[segmentIndex].Delay) + break; + + return leg.Segments[segmentIndex].SegmentEndArrivalTimestamp + leg.Segments[segmentIndex].Delay; + } + double CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) { if (isFirstSegment) @@ -669,27 +671,6 @@ namespace Game.Maps + (2.0 * AccelerationRate * accelerationTime1 - segmentTimeSpentAccelerating * AccelerationRate) * 0.5 * segmentTimeSpentAccelerating; } } - - public uint GetNextPauseWaypointTimestamp(uint time) - { - var legIndex = 0; - while (PathLegs[legIndex].StartTimestamp + PathLegs[legIndex].Duration <= time) - { - ++legIndex; - - if (legIndex >= PathLegs.Count) - return time; - } - - var leg = PathLegs[legIndex]; - - var segmentIndex = 0; - for (; segmentIndex != leg.Segments.Count - 1; ++segmentIndex) - if (time < leg.Segments[segmentIndex].SegmentEndArrivalTimestamp + leg.Segments[segmentIndex].Delay) - break; - - return leg.Segments[segmentIndex].SegmentEndArrivalTimestamp + leg.Segments[segmentIndex].Delay; - } } public class SplineRawInitializer diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index 02a859ed2..ef936851e 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -1053,9 +1053,6 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Starting Battlefield System"); Global.BattleFieldMgr.InitBattlefield(); - Log.outInfo(LogFilter.ServerLoading, "Loading Transports..."); - Global.TransportMgr.SpawnContinentTransports(); - // Initialize Warden Log.outInfo(LogFilter.ServerLoading, "Loading Warden Checks..."); Global.WardenCheckMgr.LoadWardenChecks();