From 63cbd183503a1c12bc123fbf2db7159c70d867b5 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 21 Jun 2022 14:56:22 -0400 Subject: [PATCH] Fixed crashes and errors when loading into world. --- Source/Game/AI/SmartScripts/SmartAI.cs | 4 +- Source/Game/AI/SmartScripts/SmartAIManager.cs | 16 ++++---- Source/Game/DataStorage/CliDB.cs | 2 +- Source/Game/Entities/GameObject/GameObject.cs | 2 +- .../Entities/Object/Update/UpdateField.cs | 2 +- Source/Game/Entities/Object/WorldObject.cs | 4 +- Source/Game/Entities/Player/PlayerTaxi.cs | 4 ++ Source/Game/Globals/ObjectManager.cs | 10 ++--- Source/Game/Maps/TransportManager.cs | 21 ++++++---- .../Networking/Packets/MovementPackets.cs | 2 +- Source/Game/Pools/PoolManager.cs | 41 +++++++++++++++++++ Source/Game/Spells/Auras/AuraEffect.cs | 2 +- 12 files changed, 79 insertions(+), 31 deletions(-) diff --git a/Source/Game/AI/SmartScripts/SmartAI.cs b/Source/Game/AI/SmartScripts/SmartAI.cs index ff5377536..f8bb41dc9 100644 --- a/Source/Game/AI/SmartScripts/SmartAI.cs +++ b/Source/Game/AI/SmartScripts/SmartAI.cs @@ -47,7 +47,7 @@ namespace Game.AI SmartEscortState _escortState; uint _escortNPCFlags; uint _escortInvokerCheckTimer; - WaypointPath _path; + WaypointPath _path = new(); uint _currentWaypointNode; bool _waypointReached; uint _waypointPauseTimer; @@ -132,7 +132,6 @@ namespace Game.AI return false; } - _path = new WaypointPath(); _path.id = path.id; _path.nodes.AddRange(path.nodes); foreach (WaypointNode waypoint in _path.nodes) @@ -802,6 +801,7 @@ namespace Game.AI { me.SetWalk(!run); _run = run; + foreach (var node in _path.nodes) node.moveType = run ? WaypointMoveType.Run : WaypointMoveType.Walk; } diff --git a/Source/Game/AI/SmartScripts/SmartAIManager.cs b/Source/Game/AI/SmartScripts/SmartAIManager.cs index 65bc7ac04..180a2451e 100644 --- a/Source/Game/AI/SmartScripts/SmartAIManager.cs +++ b/Source/Game/AI/SmartScripts/SmartAIManager.cs @@ -912,7 +912,7 @@ namespace Game.AI return true; } - + bool IsEventValid(SmartScriptHolder e) { if (e.Event.type >= SmartEvents.End) @@ -2435,7 +2435,7 @@ namespace Game.AI } } - public class SmartScriptHolder : IComparer + public class SmartScriptHolder : IComparable { public const uint DefaultPriority = uint.MaxValue; @@ -2478,17 +2478,17 @@ namespace Game.AI return $"Entry {EntryOrGuid} SourceType {GetScriptType()} Event {EventId} Action {GetActionType()}"; } - public int Compare(SmartScriptHolder left, SmartScriptHolder right) + public int CompareTo(SmartScriptHolder other) { - int result = left.Priority.CompareTo(right.Priority); + int result = Priority.CompareTo(other.Priority); if (result == 0) - result = left.EntryOrGuid.CompareTo(right.EntryOrGuid); + result = EntryOrGuid.CompareTo(other.EntryOrGuid); if (result == 0) - result = left.SourceType.CompareTo(right.SourceType); + result = SourceType.CompareTo(other.SourceType); if (result == 0) - result = left.EventId.CompareTo(right.EventId); + result = EventId.CompareTo(other.EventId); if (result == 0) - result = left.Link.CompareTo(right.Link); + result = Link.CompareTo(other.Link); return result; } diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index b97efddda..690771093 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -370,7 +370,7 @@ namespace Game.DataStorage foreach (var entry in TaxiPathNodeStorage.Values) TaxiPathNodesByPath[entry.PathID][entry.NodeIndex] = entry; - var taxiMaskSize = TaxiNodesStorage.GetNumRows() + 1; + var taxiMaskSize = ((TaxiNodesStorage.GetNumRows() - 1) / 8) + 1; TaxiNodesMask = new byte[taxiMaskSize]; OldContinentsNodesMask = new byte[taxiMaskSize]; HordeTaxiNodesMask = new byte[taxiMaskSize]; diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index d82b1e5b0..91c1786de 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -3559,7 +3559,7 @@ namespace Game.Entities uint _stateChangeProgress; List _stopFrames = new(); bool _autoCycleBetweenStopFrames; - TimeTracker _positionUpdateTimer; + TimeTracker _positionUpdateTimer = new(); List _passengers = new(); static TimeSpan PositionUpdateInterval = TimeSpan.FromMilliseconds(50); diff --git a/Source/Game/Entities/Object/Update/UpdateField.cs b/Source/Game/Entities/Object/Update/UpdateField.cs index 8ff1799c3..bb9044b92 100644 --- a/Source/Game/Entities/Object/Update/UpdateField.cs +++ b/Source/Game/Entities/Object/Update/UpdateField.cs @@ -382,7 +382,7 @@ namespace Game.Entities public void ClearChangesMask(OptionalUpdateField updateField) where U : new() { - if (typeof(IHasChangesMask).IsAssignableFrom(typeof(U))) + if (typeof(IHasChangesMask).IsAssignableFrom(typeof(U)) && updateField.HasValue()) ((IHasChangesMask)updateField._value).ClearChangesMask(); } diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 0bb7892e3..9bccded1c 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -2981,9 +2981,9 @@ namespace Game.Entities public bool IsPermanentWorldObject() { return m_isWorldObject; } public ITransport GetTransport() { return m_transport; } - public T GetTransport() where T : ITransport + public T GetTransport() where T : class, ITransport { - return (T)m_transport; + return m_transport as T; } public float GetTransOffsetX() { return m_movementInfo.transport.pos.GetPositionX(); } public float GetTransOffsetY() { return m_movementInfo.transport.pos.GetPositionY(); } diff --git a/Source/Game/Entities/Player/PlayerTaxi.cs b/Source/Game/Entities/Player/PlayerTaxi.cs index 051f918ee..1179db13d 100644 --- a/Source/Game/Entities/Player/PlayerTaxi.cs +++ b/Source/Game/Entities/Player/PlayerTaxi.cs @@ -33,6 +33,8 @@ namespace Game.Entities public void InitTaxiNodesForLevel(Race race, Class chrClass, uint level) { + m_taximask = new byte[((CliDB.TaxiNodesStorage.GetNumRows() - 1) / 8) + 1]; + // class specific initial known nodes if (chrClass == Class.Deathknight) { @@ -105,6 +107,8 @@ namespace Game.Entities public void LoadTaxiMask(string data) { + m_taximask = new byte[((CliDB.TaxiNodesStorage.GetNumRows() - 1) / 8) + 1]; + var split = new StringArray(data, ' '); int index = 0; diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 86cfbc9de..f3393f22f 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -127,11 +127,11 @@ namespace Game public static void ChooseCreatureFlags(CreatureTemplate cInfo, out ulong npcFlag, out uint unitFlags, out uint unitFlags2, out uint unitFlags3, out uint dynamicFlags, CreatureData data = null) { - npcFlag = data?.npcflag != 0 ? data.npcflag : cInfo.Npcflag; - unitFlags = data?.unit_flags != 0 ? data.unit_flags : (uint)cInfo.UnitFlags; - unitFlags2 = data?.unit_flags2 != 0 ? data.unit_flags2 : cInfo.UnitFlags2; - unitFlags3 = data?.unit_flags3 != 0 ? data.unit_flags3 : cInfo.UnitFlags3; - dynamicFlags = data?.dynamicflags != 0 ? data.dynamicflags : cInfo.DynamicFlags; + npcFlag = data != null && data.npcflag != 0 ? data.npcflag : cInfo.Npcflag; + unitFlags = data != null && data.unit_flags != 0 ? data.unit_flags : (uint)cInfo.UnitFlags; + unitFlags2 = data != null && data.unit_flags2 != 0 ? data.unit_flags2 : cInfo.UnitFlags2; + unitFlags3 = data != null && data.unit_flags3 != 0 ? data.unit_flags3 : cInfo.UnitFlags3; + dynamicFlags = data != null && data.dynamicflags != 0 ? data.dynamicflags : cInfo.DynamicFlags; } public static ResponseCodes CheckPlayerName(string name, Locale locale, bool create = false) diff --git a/Source/Game/Maps/TransportManager.cs b/Source/Game/Maps/TransportManager.cs index d93e37a4c..f7aae8e8e 100644 --- a/Source/Game/Maps/TransportManager.cs +++ b/Source/Game/Maps/TransportManager.cs @@ -212,7 +212,7 @@ namespace Game.Maps for (; pauseItr < pauses.Count; ++pauseItr) { var pausePointIndex = pathPoints.IndexOf(pauses[pauseItr]); - if (pausePointIndex == -1) // last point is a "fake" spline point, its position can never be reached so transport cannot stop there + if (pausePointIndex == pathPoints.Count - 1) // last point is a "fake" spline point, its position can never be reached so transport cannot stop there break; for (; eventItr < events.Count; ++eventItr) @@ -254,10 +254,11 @@ namespace Game.Maps movementTime = legTimeAccel(length1); leg.Duration += movementTime; - var segment = leg.Segments[pauseItr]; + TransportPathSegment segment = new(); segment.SegmentEndArrivalTimestamp = leg.Duration + delaySum; segment.Delay = pathPoints[pausePointIndex].Delay * Time.InMilliseconds; segment.DistanceFromLegStartAtEnd = splineLengthToCurrentNode; + leg.Segments.Add(segment); delaySum += pathPoints[pausePointIndex].Delay * Time.InMilliseconds; splineLengthToPreviousNode = splineLengthToCurrentNode; } @@ -304,10 +305,11 @@ namespace Game.Maps leg.StartTimestamp = totalTime; leg.Duration += splineTime + delaySum; - var pauseSegment = leg.Segments[pauseItr]; + TransportPathSegment pauseSegment = new(); pauseSegment.SegmentEndArrivalTimestamp = leg.Duration; pauseSegment.Delay = 0; pauseSegment.DistanceFromLegStartAtEnd = leg.Spline.Length(); + leg.Segments.Add(pauseSegment); totalTime += leg.Segments[pauseItr].SegmentEndArrivalTimestamp + leg.Segments[pauseItr].Delay; for (var i = 0; i < leg.Segments.Count; ++i) @@ -378,13 +380,14 @@ namespace Game.Maps public void AddPathNodeToTransport(uint transportEntry, uint timeSeg, TransportAnimationRecord node) { - TransportAnimation animNode = new(); + if (!_transportAnimations.ContainsKey(transportEntry)) + _transportAnimations[transportEntry] = new(); + + TransportAnimation animNode = _transportAnimations[transportEntry]; if (animNode.TotalTime < timeSeg) animNode.TotalTime = timeSeg; animNode.Path[timeSeg] = node; - - _transportAnimations[transportEntry] = animNode; } public void AddPathRotationToTransport(uint transportEntry, uint timeSeg, TransportRotationRecord node) @@ -531,7 +534,7 @@ namespace Game.Maps public List PathLegs = new(); public List Events = new(); - public List MapIds = new(); + public HashSet MapIds = new(); public bool InInstance; public Position ComputePosition(uint time, out TransportMovementState moveState, out int legIndex) @@ -708,10 +711,10 @@ namespace Game.Maps return null; List lKeys = Path.Keys.ToList(); - int reqIndex = lKeys.IndexOf(time) - 1; + int reqIndex = lKeys.IndexOf(time); if (reqIndex != -1) - return Path[lKeys[reqIndex]]; + return Path[lKeys[reqIndex - 1]]; return Path.LastOrDefault().Value; } diff --git a/Source/Game/Networking/Packets/MovementPackets.cs b/Source/Game/Networking/Packets/MovementPackets.cs index af17f65e9..47fb7f25e 100644 --- a/Source/Game/Networking/Packets/MovementPackets.cs +++ b/Source/Game/Networking/Packets/MovementPackets.cs @@ -1244,7 +1244,7 @@ namespace Game.Networking.Packets public override void Read() { - _worldPacket.WriteUInt32(Ticks); + Ticks = _worldPacket.ReadUInt32(); } } diff --git a/Source/Game/Pools/PoolManager.cs b/Source/Game/Pools/PoolManager.cs index c0056558d..c88222af1 100644 --- a/Source/Game/Pools/PoolManager.cs +++ b/Source/Game/Pools/PoolManager.cs @@ -268,6 +268,47 @@ namespace Game } while (result.NextRow()); + // Now check for circular reference + // All pool_ids are in pool_template + foreach (var (id, poolData) in mPoolTemplate) + { + List checkedPools = new(); + var poolItr = mPoolSearchMap.LookupByKey(id); + while (poolItr != 0) + { + if (poolData.MapId != -1) + { + if (mPoolTemplate[poolItr].MapId == -1) + mPoolTemplate[poolItr].MapId = poolData.MapId; + + if (mPoolTemplate[poolItr].MapId != poolData.MapId) + { + Log.outError(LogFilter.Sql, $"`pool_pool` has child pools on multiple maps in pool id ({poolItr}), skipped."); + mPoolPoolGroups[poolItr].RemoveOneRelation(id); + mPoolSearchMap.Remove(poolItr); + --count; + break; + } + } + + checkedPools.Add(id); + if (checkedPools.Contains(poolItr)) + { + string ss = "The pool(s) "; + foreach (var itr in checkedPools) + ss += $"{itr} "; + ss += $"create(s) a circular reference, which can cause the server to freeze.\nRemoving the last link between mother pool {id} and child pool {poolItr}"; + Log.outError(LogFilter.Sql, ss); + mPoolPoolGroups[poolItr].RemoveOneRelation(id); + mPoolSearchMap.Remove(poolItr); + --count; + break; + } + + poolItr = mPoolSearchMap.LookupByKey(poolItr); + } + } + Log.outInfo(LogFilter.ServerLoading, "Loaded {0} pools in mother pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 8fc4aebaf..2a4de1b5c 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -90,7 +90,7 @@ namespace Game.Spells case AuraType.Transform: case AuraType.ModRoot2: m_canBeRecalculated = false; - if (!m_spellInfo.ProcFlags) + if (m_spellInfo.ProcFlags == null) break; amount = (int)(GetBase().GetUnitOwner().CountPctFromMaxHealth(10)); break;