From 475bc73063afb04979d91b1024ce02330f7e087a Mon Sep 17 00:00:00 2001 From: Robbie Lodico Date: Sat, 25 Jan 2025 15:16:31 +0100 Subject: [PATCH 1/2] add logging to Options.LoadFromServer --- Framework/Intersect.Framework.Core/Config/Options.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Framework/Intersect.Framework.Core/Config/Options.cs b/Framework/Intersect.Framework.Core/Config/Options.cs index 3102ea4ac2..1080ef0904 100644 --- a/Framework/Intersect.Framework.Core/Config/Options.cs +++ b/Framework/Intersect.Framework.Core/Config/Options.cs @@ -285,7 +285,15 @@ public static void SaveToDisk() public static void LoadFromServer(string data) { - Instance = JsonConvert.DeserializeObject(data); + try + { + Instance = JsonConvert.DeserializeObject(data); + } + catch (Exception exception) + { + ApplicationContext.CurrentContext.Logger.LogError(exception, "Failed to load options from server"); + throw; + } } // ReSharper disable once UnusedMember.Global From 5934947e4771270c122fd0d903d450e2b496099d Mon Sep 17 00:00:00 2001 From: Robbie Lodico Date: Sat, 25 Jan 2025 16:14:54 +0100 Subject: [PATCH 2/2] fix(982): expire dashes based on end time in case packets are delayed --- .../Packets/Server/EntityDashPacket.cs | 14 ++- Intersect.Client.Core/Entities/Dash.cs | 108 +++++++++++------- .../Networking/PacketHandler.cs | 21 ++-- Intersect.Server.Core/Entities/Combat/Dash.cs | 22 +++- .../Networking/PacketSender.cs | 24 +++- 5 files changed, 129 insertions(+), 60 deletions(-) diff --git a/Intersect (Core)/Network/Packets/Server/EntityDashPacket.cs b/Intersect (Core)/Network/Packets/Server/EntityDashPacket.cs index ec3227000c..ba94c8fbe2 100644 --- a/Intersect (Core)/Network/Packets/Server/EntityDashPacket.cs +++ b/Intersect (Core)/Network/Packets/Server/EntityDashPacket.cs @@ -11,13 +11,14 @@ public EntityDashPacket() { } - public EntityDashPacket(Guid entityId, Guid endMapId, byte endX, byte endY, int dashTime, Direction direction) + public EntityDashPacket(Guid entityId, Guid endMapId, int endX, int endY, long dashEndMilliseconds, int dashLengthMilliseconds, Direction direction) { EntityId = entityId; EndMapId = endMapId; - EndX = endX; - EndY = endY; - DashTime = dashTime; + EndX = (byte)endX; + EndY = (byte)endY; + DashEndMilliseconds = dashEndMilliseconds; + DashLengthMilliseconds = dashLengthMilliseconds; Direction = direction; } @@ -34,9 +35,12 @@ public EntityDashPacket(Guid entityId, Guid endMapId, byte endX, byte endY, int public byte EndY { get; set; } [Key(4)] - public int DashTime { get; set; } + public long DashEndMilliseconds { get; set; } [Key(5)] + public int DashLengthMilliseconds { get; set; } + + [Key(6)] public Direction Direction { get; set; } } diff --git a/Intersect.Client.Core/Entities/Dash.cs b/Intersect.Client.Core/Entities/Dash.cs index 0c2c17aa66..4ce82c4f43 100644 --- a/Intersect.Client.Core/Entities/Dash.cs +++ b/Intersect.Client.Core/Entities/Dash.cs @@ -1,7 +1,9 @@ using Intersect.Client.Framework.Entities; using Intersect.Client.Maps; +using Intersect.Core; using Intersect.Enums; using Intersect.Utilities; +using Microsoft.Extensions.Logging; namespace Intersect.Client.Entities; @@ -9,7 +11,11 @@ public partial class Dash : IDash { private readonly Direction mChangeDirection = Direction.None; - private readonly int mDashTime; + private readonly long _serverDashEndMilliseconds; + + private readonly long _dashLengthMilliseconds; + + private long _dashEndMilliseconds; private readonly Guid mEndMapId; @@ -31,75 +37,99 @@ public partial class Dash : IDash public float OffsetY => GetYOffset(); - public Dash(Guid endMapId, byte endX, byte endY, int dashTime, Direction changeDirection = Direction.None) + public Dash( + Guid endMapId, + byte endX, + byte endY, + long dashEndMilliseconds, + long dashLengthMilliseconds, + Direction changeDirection = Direction.None + ) { mChangeDirection = changeDirection; mEndMapId = endMapId; mEndX = endX; mEndY = endY; - mDashTime = dashTime; + _serverDashEndMilliseconds = dashEndMilliseconds; + _dashLengthMilliseconds = dashLengthMilliseconds; } - public void Start(Entity en) + public void Start(Entity entity) { - if (MapInstance.Get(en.MapId) == null || - MapInstance.Get(mEndMapId) == null || - mEndMapId == en.MapId && mEndX == en.X && mEndY == en.Y) + var now = Timing.Global.Milliseconds; + + if (_serverDashEndMilliseconds < now) + { + ApplicationContext.CurrentContext.Logger.LogDebug("Skipping already-expired dash"); + entity.Dashing = null; + return; + } + + if (mEndMapId == entity.MapId && mEndX == entity.X && mEndY == entity.Y) + { + entity.Dashing = null; + return; + } + + if (!MapInstance.TryGet(entity.MapId, out var currentMap) || !MapInstance.TryGet(mEndMapId, out var targetMap)) { - en.Dashing = null; + entity.Dashing = null; + return; } - else + + mStartTime = now; + _dashEndMilliseconds = Math.Min(_serverDashEndMilliseconds, mStartTime + _dashLengthMilliseconds); + + ApplicationContext.CurrentContext.Logger.LogDebug( + "Starting dash that is {DashLength}ms long, and there are {RemainingTime}ms before it is completed on the server", + _dashLengthMilliseconds, + _serverDashEndMilliseconds - now + ); + + mStartXCoord = entity.X; + mStartYCoord = entity.Y; + mEndXCoord = targetMap.X + mEndX * Options.Instance.Map.TileWidth - (currentMap.X + entity.X * Options.Instance.Map.TileWidth); + mEndYCoord = targetMap.Y + mEndY * Options.Instance.Map.TileHeight - (currentMap.Y + entity.Y * Options.Instance.Map.TileHeight); + if (mChangeDirection > Direction.None) { - var startMap = MapInstance.Get(en.MapId); - var endMap = MapInstance.Get(mEndMapId); - mStartTime = Timing.Global.Milliseconds; - mStartXCoord = en.OffsetX; - mStartYCoord = en.OffsetY; - mEndXCoord = endMap.X + mEndX * Options.Instance.Map.TileWidth - (startMap.X + en.X * Options.Instance.Map.TileWidth); - mEndYCoord = endMap.Y + mEndY * Options.Instance.Map.TileHeight - (startMap.Y + en.Y * Options.Instance.Map.TileHeight); - if (mChangeDirection > Direction.None) - { - en.Dir = mChangeDirection; - } + entity.Dir = mChangeDirection; } } public float GetXOffset() { - if (Timing.Global.Milliseconds > mStartTime + mDashTime) + if (Timing.Global.Milliseconds > mStartTime + _dashLengthMilliseconds) { return mEndXCoord; } - else - { - return (mEndXCoord - mStartXCoord) * ((Timing.Global.Milliseconds - mStartTime) / (float)mDashTime); - } + + return (mEndXCoord - mStartXCoord) * ((Timing.Global.Milliseconds - mStartTime) / (float)_dashLengthMilliseconds); } public float GetYOffset() { - if (Timing.Global.Milliseconds > mStartTime + mDashTime) + if (Timing.Global.Milliseconds > mStartTime + _dashLengthMilliseconds) { return mEndYCoord; } - else - { - return (mEndYCoord - mStartYCoord) * ((Timing.Global.Milliseconds - mStartTime) / (float)mDashTime); - } + + return (mEndYCoord - mStartYCoord) * ((Timing.Global.Milliseconds - mStartTime) / (float)_dashLengthMilliseconds); } - public bool Update(Entity en) + public bool Update(Entity entity) { - if (Timing.Global.Milliseconds > mStartTime + mDashTime) + if (Timing.Global.Milliseconds <= _dashEndMilliseconds) { - en.Dashing = null; - en.OffsetX = 0; - en.OffsetY = 0; - en.MapId = mEndMapId; - en.X = mEndX; - en.Y = mEndY; + return entity.Dashing != null; } - return en.Dashing != null; + ApplicationContext.CurrentContext.Logger.LogDebug("Dash finished"); + entity.Dashing = null; + entity.OffsetX = 0; + entity.OffsetY = 0; + entity.MapId = mEndMapId; + entity.X = mEndX; + entity.Y = mEndY; + return false; } } diff --git a/Intersect.Client.Core/Networking/PacketHandler.cs b/Intersect.Client.Core/Networking/PacketHandler.cs index c9f2b4eaed..5abb59f7be 100644 --- a/Intersect.Client.Core/Networking/PacketHandler.cs +++ b/Intersect.Client.Core/Networking/PacketHandler.cs @@ -1838,16 +1838,21 @@ public void HandlePacket(IPacketSender packetSender, GameObjectPacket packet) //EntityDashPacket public void HandlePacket(IPacketSender packetSender, EntityDashPacket packet) { - if (Globals.Entities.ContainsKey(packet.EntityId)) + if (!Globals.Entities.TryGetValue(packet.EntityId, out var value)) { - Globals.Entities[packet.EntityId] - .DashQueue.Enqueue( - new Dash( - packet.EndMapId, packet.EndX, packet.EndY, - packet.DashTime, packet.Direction - ) - ); + return; } + + value.DashQueue.Enqueue( + new Dash( + packet.EndMapId, + packet.EndX, + packet.EndY, + packet.DashEndMilliseconds, + packet.DashLengthMilliseconds, + packet.Direction + ) + ); } //MapGridPacket diff --git a/Intersect.Server.Core/Entities/Combat/Dash.cs b/Intersect.Server.Core/Entities/Combat/Dash.cs index 7a6c454dca..7f3dc9db70 100644 --- a/Intersect.Server.Core/Entities/Combat/Dash.cs +++ b/Intersect.Server.Core/Entities/Combat/Dash.cs @@ -17,7 +17,7 @@ public partial class Dash public int Range; public Dash( - Entity en, + Entity entity, int range, Direction direction, bool blockPass = false, @@ -27,20 +27,30 @@ public Dash( ) { Direction = direction; - Facing = en.Dir; + Facing = entity.Dir; - CalculateRange(en, range, blockPass, activeResourcePass, deadResourcePass, zdimensionPass); + CalculateRange(entity, range, blockPass, activeResourcePass, deadResourcePass, zdimensionPass); if (Range <= 0) { return; } //Remove dash instance if no where to dash + var endX = entity.X; + var endY = entity.Y; + + var dashLengthMilliseconds = (int)(Options.Instance.Combat.MaxDashSpeed);// * (Range / 10f)); + var dashEndMilliseconds = Timing.Global.Milliseconds + dashLengthMilliseconds; + entity.MoveTimer = dashEndMilliseconds; + PacketSender.SendEntityDash( - en, en.MapId, (byte) en.X, (byte) en.Y, (int) (Options.Instance.Combat.MaxDashSpeed * (Range / 10f)), + entity, + entity.MapId, + endX, + endY, + dashEndMilliseconds, + dashLengthMilliseconds, Direction == Facing ? Direction : Direction.None ); - - en.MoveTimer = Timing.Global.Milliseconds + Options.Instance.Combat.MaxDashSpeed; } public void CalculateRange( diff --git a/Intersect.Server.Core/Networking/PacketSender.cs b/Intersect.Server.Core/Networking/PacketSender.cs index 0f70fb4cf2..c39a5f0907 100644 --- a/Intersect.Server.Core/Networking/PacketSender.cs +++ b/Intersect.Server.Core/Networking/PacketSender.cs @@ -1922,9 +1922,29 @@ public static void SendOpenEditor(Client client, GameObjectType type) } //EntityDashPacket - public static void SendEntityDash(Entity en, Guid endMapId, byte endX, byte endY, int dashTime, Direction direction) + public static void SendEntityDash( + Entity en, + Guid endMapId, + int endX, + int endY, + long dashEndMilliseconds, + int dashLengthMilliseconds, + Direction direction + ) { - SendDataToProximityOnMapInstance(en.MapId, en.MapInstanceId, new EntityDashPacket(en.Id, endMapId, endX, endY, dashTime, direction)); + SendDataToProximityOnMapInstance( + en.MapId, + en.MapInstanceId, + new EntityDashPacket( + en.Id, + endMapId, + endX, + endY, + dashEndMilliseconds, + dashLengthMilliseconds, + direction + ) + ); } ///