From 419415627683d961c9a0f060e4e52d422baea40e Mon Sep 17 00:00:00 2001 From: Rutherther Date: Wed, 15 Feb 2023 19:49:45 +0100 Subject: [PATCH] feat(pathfinding): save mates state --- .../EntityState.cs | 28 +++++++ .../Errors/EntityStateNotFoundError.cs | 11 +++ .../Extensions/ServiceCollectionExtensions.cs | 2 + .../Pathfinder.cs | 30 ++++++- .../PathfinderState.cs | 81 +++++++++++++++++-- .../Responders/AtResponder.cs | 4 +- .../Responders/CInfoPacketResponder.cs | 2 +- .../Responders/CMapResponder.cs | 1 + .../Responders/InResponder.cs | 53 ++++++++++++ .../Responders/PtctlResponder.cs | 47 +++++++++++ .../Responders/SuPacketResponder.cs | 7 +- .../Responders/TpPacketResponder.cs | 6 +- .../Responders/WalkResponder.cs | 4 +- 13 files changed, 257 insertions(+), 19 deletions(-) create mode 100644 Extensions/NosSmooth.Extensions.Pathfinding/EntityState.cs create mode 100644 Extensions/NosSmooth.Extensions.Pathfinding/Errors/EntityStateNotFoundError.cs create mode 100644 Extensions/NosSmooth.Extensions.Pathfinding/Responders/InResponder.cs create mode 100644 Extensions/NosSmooth.Extensions.Pathfinding/Responders/PtctlResponder.cs diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/EntityState.cs b/Extensions/NosSmooth.Extensions.Pathfinding/EntityState.cs new file mode 100644 index 0000000000000000000000000000000000000000..b234b70d8d26e07c684f8ffce140b7c630791170 --- /dev/null +++ b/Extensions/NosSmooth.Extensions.Pathfinding/EntityState.cs @@ -0,0 +1,28 @@ +// +// EntityState.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace NosSmooth.Extensions.Pathfinding; + +/// +/// A state, position of an entity. +/// +internal class EntityState +{ + /// + /// Gets id of the entity. + /// + internal long Id { get; init; } + + /// + /// Gets or sets the x coordinate of the entity. + /// + internal short X { get; set; } + + /// + /// Gets or sets the y coordinate of the entity. + /// + internal short Y { get; set; } +} \ No newline at end of file diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Errors/EntityStateNotFoundError.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Errors/EntityStateNotFoundError.cs new file mode 100644 index 0000000000000000000000000000000000000000..f8e05da3a0ffb9f82441e789159bcc336ab5fc9c --- /dev/null +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Errors/EntityStateNotFoundError.cs @@ -0,0 +1,11 @@ +// +// EntityStateNotFoundError.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Remora.Results; + +namespace NosSmooth.Extensions.Pathfinding.Errors; + +public record EntityStateNotFoundError(long EntityId) : ResultError($"Could not find pathfinder state of entity {EntityId}"); \ No newline at end of file diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Extensions/ServiceCollectionExtensions.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Extensions/ServiceCollectionExtensions.cs index 0812beab7648e3f269ee658f63ad775203593791..510559e7419d527b479c215c542bffa87fe8391a 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Extensions/ServiceCollectionExtensions.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Extensions/ServiceCollectionExtensions.cs @@ -34,6 +34,8 @@ public static class ServiceCollectionExtensions .AddPacketResponder() .AddPacketResponder() .AddPacketResponder() + .AddPacketResponder() + .AddPacketResponder() .AddSingleton() .AddSingleton() .AddSingleton(); diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Pathfinder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Pathfinder.cs index f29412bf23bdbab3c16ac1f4b13d1fe70f84e286..31e11fa8afeccd13df6033cb50242bfe0a6712b8 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Pathfinder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Pathfinder.cs @@ -29,7 +29,7 @@ public class Pathfinder } /// - /// Attempts to find a path between the current position and the target. + /// Attempts to find a path between the current character position and the target. /// /// The target x coordinate. /// The target y coordinate. @@ -39,7 +39,33 @@ public class Pathfinder short targetX, short targetY ) - => FindPathFrom(_state.X, _state.Y, targetX, targetY); + => FindPathFrom(_state.Character.X, _state.Character.Y, targetX, targetY); + + /// + /// Attempts to find a path between the current position of the entity and the target. + /// + /// + /// Works only for entities that are stored in state, + /// that means only the character and mates owned by the character. + /// + /// The id of the entity to find path from. + /// The target x coordinate. + /// The target y coordinate. + /// A path or an error. + public Result FindPathFromEntity + ( + long entityId, + short targetX, + short targetY + ) + { + if (!_state.Entities.TryGetValue(entityId, out var entityState)) + { + return new EntityStateNotFoundError(entityId); + } + + return FindPathFrom(entityState.X, entityState.Y, targetX, targetY); + } /// /// Attempts to find a path between the given positions on the current map. diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/PathfinderState.cs b/Extensions/NosSmooth.Extensions.Pathfinding/PathfinderState.cs index 59b38817244a284bbf6315bc8f16dda796634fb2..5129b1df2d220dc8cc90b9a17f1b71cf03d973e1 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/PathfinderState.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/PathfinderState.cs @@ -4,6 +4,7 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Collections.Concurrent; using NosSmooth.Core.Client; using NosSmooth.Core.Stateful; using NosSmooth.Data.Abstractions.Infos; @@ -15,6 +16,27 @@ namespace NosSmooth.Extensions.Pathfinding; /// public class PathfinderState : IStatefulEntity { + private ConcurrentDictionary _entities; + + /// + /// Initializes a new instance of the class. + /// + public PathfinderState() + { + _entities = new ConcurrentDictionary(); + Character = new EntityState(); + } + + /// + /// Gets the entities. + /// + internal IReadOnlyDictionary Entities => _entities; + + /// + /// Gets the character entity state. + /// + internal EntityState Character { get; private set; } + /// /// Gets or sets the current map id. /// @@ -26,17 +48,64 @@ public class PathfinderState : IStatefulEntity internal IMapInfo? MapInfo { get; set; } /// - /// Gets or sets the current x. + /// Sets the id of the character entity. /// - internal short X { get; set; } + /// The character id. + internal void SetCharacterId(long characterId) + { + EntityState GetCharacter() + { + Character = new EntityState + { + Id = characterId, + X = Character.X, + Y = Character.Y + }; + + return Character; + } + + _entities.TryRemove(Character.Id, out _); + _entities.AddOrUpdate + ( + characterId, + _ => GetCharacter(), + (_, _) => GetCharacter() + ); + } /// - /// Gets or sets the current y. + /// Add the given entity to the list. /// - internal short Y { get; set; } + /// The id of the entity. + /// The x coordinate of the entity. + /// The y coordinate of the entity. + internal void AddEntity + ( + long entityId, + short x, + short y + ) + { + EntityState GetEntity() + { + return new EntityState + { + Id = entityId, + X = x, + Y = y + }; + } + + _entities.AddOrUpdate(entityId, _ => GetEntity(), (_, _) => GetEntity()); + } /// - /// Gets or sets the id of the charcter. + /// Remove all entities from the list. /// - internal long CharacterId { get; set; } + internal void ClearEntities() + { + _entities.Clear(); + SetCharacterId(Character.Id); + } } \ No newline at end of file diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/AtResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/AtResponder.cs index 0554bc5ccae140a1e2f3fdc76e51a0f841b9aa1d..855ef27ac72e66b8dadcf6a997b1c9b345ab9598 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/AtResponder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/AtResponder.cs @@ -30,8 +30,8 @@ internal class AtResponder : IPacketResponder { var packet = packetArgs.Packet; - _state.X = packet.X; - _state.Y = packet.Y; + _state.Character.X = packet.X; + _state.Character.Y = packet.Y; return Task.FromResult(Result.FromSuccess()); } diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CInfoPacketResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CInfoPacketResponder.cs index e0b258ddc6220f827dd9f03566845b7541ff4757..590f9ab17a4074c09b0ab3c692bd6cd7648f7e0a 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CInfoPacketResponder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CInfoPacketResponder.cs @@ -28,7 +28,7 @@ public class CInfoPacketResponder : IPacketResponder /// public Task Respond(PacketEventArgs packetArgs, CancellationToken ct = default) { - _state.CharacterId = packetArgs.Packet.CharacterId; + _state.SetCharacterId(packetArgs.Packet.CharacterId); return Task.FromResult(Result.FromSuccess()); } } \ No newline at end of file diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CMapResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CMapResponder.cs index 7c2796b47329d437a9085e50c0e5534cc4762a2e..b66b902aae57fffc460e524eabd68046878ae432 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CMapResponder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/CMapResponder.cs @@ -31,6 +31,7 @@ internal class CMapResponder : IPacketResponder /// public async Task Respond(PacketEventArgs packetArgs, CancellationToken ct = default) { + _state.ClearEntities(); var packet = packetArgs.Packet; _state.MapId = packet.Id; diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/InResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/InResponder.cs new file mode 100644 index 0000000000000000000000000000000000000000..7a1cbd4d6dd9f81fe2c94de82fffb19d3501ead5 --- /dev/null +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/InResponder.cs @@ -0,0 +1,53 @@ +// +// InResponder.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using NosSmooth.Core.Packets; +using NosSmooth.Packets.Client.Battle; +using NosSmooth.Packets.Enums.Entities; +using NosSmooth.Packets.Server.Maps; +using Remora.Results; + +namespace NosSmooth.Extensions.Pathfinding.Responders; + +/// +public class InResponder : IPacketResponder +{ + private readonly PathfinderState _state; + + /// + /// Initializes a new instance of the class. + /// + /// The pathfinder state. + public InResponder(PathfinderState state) + { + _state = state; + + } + + /// + public Task Respond(PacketEventArgs packetArgs, CancellationToken ct = default) + { + var packet = packetArgs.Packet; + + if (packet.EntityType != EntityType.Npc) + { + return Task.FromResult(Result.FromSuccess()); + } + + if (packet.NonPlayerSubPacket is null) + { + return Task.FromResult(Result.FromSuccess()); + } + + if (packet.NonPlayerSubPacket.OwnerId != _state.Character.Id) + { + return Task.FromResult(Result.FromSuccess()); + } + + _state.AddEntity(packet.EntityId, packet.PositionX, packet.PositionY); + return Task.FromResult(Result.FromSuccess()); + } +} \ No newline at end of file diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/PtctlResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/PtctlResponder.cs new file mode 100644 index 0000000000000000000000000000000000000000..37829b1056d57abcf20280b4e6905b33599a6670 --- /dev/null +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/PtctlResponder.cs @@ -0,0 +1,47 @@ +// +// PtctlResponder.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Security; +using NosSmooth.Core.Packets; +using NosSmooth.Packets.Client.Mates; +using Remora.Results; + +namespace NosSmooth.Extensions.Pathfinding.Responders; + +/// +public class PtctlResponder : IPacketResponder +{ + private readonly PathfinderState _state; + + /// + /// Initializes a new instance of the class. + /// + /// The state. + public PtctlResponder(PathfinderState state) + { + _state = state; + } + + /// + public Task Respond(PacketEventArgs packetArgs, CancellationToken ct = default) + { + var packet = packetArgs.Packet; + + foreach (var walkControl in packet.Controls) + { + if (!_state.Entities.TryGetValue(walkControl.MateTransportId, out var entityState)) + { + _state.AddEntity(walkControl.MateTransportId, walkControl.PositionX, walkControl.PositionY); + continue; + } + + entityState.X = walkControl.PositionX; + entityState.Y = walkControl.PositionY; + } + + return Task.FromResult(Result.FromSuccess()); + } +} \ No newline at end of file diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/SuPacketResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/SuPacketResponder.cs index dcb1ad4f62b348b8dc740616a0087a40d70b3617..66bc24467ba772f4ee6966e86c22fa7c7496d309 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/SuPacketResponder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/SuPacketResponder.cs @@ -29,7 +29,8 @@ public class SuPacketResponder : IPacketResponder public Task Respond(PacketEventArgs packetArgs, CancellationToken ct = default) { var packet = packetArgs.Packet; - if (packet.CasterEntityId == _state.CharacterId) + + if (_state.Entities.TryGetValue(packet.CasterEntityId, out var entityState)) { if (packet.PositionX is null || packet.PositionY is null) { @@ -41,8 +42,8 @@ public class SuPacketResponder : IPacketResponder return Task.FromResult(Result.FromSuccess()); } - _state.X = packet.PositionX.Value; - _state.Y = packet.PositionY.Value; + entityState.X = packet.PositionX.Value; + entityState.Y = packet.PositionY.Value; } return Task.FromResult(Result.FromSuccess()); diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/TpPacketResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/TpPacketResponder.cs index a72390defac9faef5783eebcf30840f3f55592c6..b79fa1e36838ae04a788c7e12de91f9b7514a40d 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/TpPacketResponder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/TpPacketResponder.cs @@ -28,10 +28,10 @@ public class TpPacketResponder : IPacketResponder public Task Respond(PacketEventArgs packetArgs, CancellationToken ct = default) { var packet = packetArgs.Packet; - if (packet.EntityId == _state.CharacterId) + if (_state.Entities.TryGetValue(packet.EntityId, out var entityState)) { - _state.X = packet.PositionX; - _state.Y = packet.PositionY; + entityState.X = packet.PositionX; + entityState.Y = packet.PositionY; } return Task.FromResult(Result.FromSuccess()); diff --git a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/WalkResponder.cs b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/WalkResponder.cs index e2b35f0994fdf0f1cb8f49afcf4263ee23e4a469..5b6233157f1a48c6fde0722e9f846cdbe69605f7 100644 --- a/Extensions/NosSmooth.Extensions.Pathfinding/Responders/WalkResponder.cs +++ b/Extensions/NosSmooth.Extensions.Pathfinding/Responders/WalkResponder.cs @@ -29,8 +29,8 @@ internal class WalkResponder : IPacketResponder { var packet = packetArgs.Packet; - _state.X = packet.PositionX; - _state.Y = packet.PositionY; + _state.Character.X = packet.PositionX; + _state.Character.Y = packet.PositionY; return Task.FromResult(Result.FromSuccess()); }