diff --git a/src/common/Edelstein.Common.Gameplay.Game/Handling/Packets/UserAbilityMassUpRequestHandler.cs b/src/common/Edelstein.Common.Gameplay.Game/Handling/Packets/UserAbilityMassUpRequestHandler.cs new file mode 100644 index 000000000..5dadcef6b --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Game/Handling/Packets/UserAbilityMassUpRequestHandler.cs @@ -0,0 +1,34 @@ +using Edelstein.Common.Gameplay.Handling; +using Edelstein.Protocol.Gameplay.Game.Contracts; +using Edelstein.Protocol.Gameplay.Game.Objects.User; +using Edelstein.Protocol.Gameplay.Models.Characters.Stats.Modify; +using Edelstein.Protocol.Utilities.Packets; +using Edelstein.Protocol.Utilities.Pipelines; + +namespace Edelstein.Common.Gameplay.Game.Handling.Packets; + +public class UserAbilityMassUpRequestHandler : AbstractPipedFieldHandler +{ + public override short Operation => (short)PacketRecvOperations.UserAbilityMassUpRequest; + + public UserAbilityMassUpRequestHandler(IPipeline pipeline) : base(pipeline) + { + } + + protected override FieldOnPacketUserAbilityMassUpRequest? Serialize(IFieldUser user, IPacketReader reader) + { + var count = reader.Skip(4).ReadInt(); + var statUp = new Dictionary(); + + for (var i = 0; i < count; i++) + statUp.Add( + (ModifyStatType)reader.ReadInt(), + reader.ReadInt() + ); + + return new( + user, + statUp + ); + } +} diff --git a/src/common/Edelstein.Common.Gameplay.Game/Handling/Packets/UserAbilityUpRequestHandler.cs b/src/common/Edelstein.Common.Gameplay.Game/Handling/Packets/UserAbilityUpRequestHandler.cs new file mode 100644 index 000000000..a8e011564 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Game/Handling/Packets/UserAbilityUpRequestHandler.cs @@ -0,0 +1,23 @@ +using Edelstein.Common.Gameplay.Handling; +using Edelstein.Protocol.Gameplay.Game.Contracts; +using Edelstein.Protocol.Gameplay.Game.Objects.User; +using Edelstein.Protocol.Gameplay.Models.Characters.Stats.Modify; +using Edelstein.Protocol.Utilities.Packets; +using Edelstein.Protocol.Utilities.Pipelines; + +namespace Edelstein.Common.Gameplay.Game.Handling.Packets; + +public class UserAbilityUpRequestHandler : AbstractPipedFieldHandler +{ + public override short Operation => (short)PacketRecvOperations.UserAbilityUpRequest; + + public UserAbilityUpRequestHandler(IPipeline pipeline) : base(pipeline) + { + } + + protected override FieldOnPacketUserAbilityUpRequest? Serialize(IFieldUser user, IPacketReader reader) + => new( + user, + (ModifyStatType)reader.Skip(4).ReadInt() + ); +} diff --git a/src/common/Edelstein.Common.Gameplay.Game/Handling/Plugs/FieldOnPacketUserAbilityMassUpRequestPlug.cs b/src/common/Edelstein.Common.Gameplay.Game/Handling/Plugs/FieldOnPacketUserAbilityMassUpRequestPlug.cs new file mode 100644 index 000000000..31fe19f77 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Game/Handling/Plugs/FieldOnPacketUserAbilityMassUpRequestPlug.cs @@ -0,0 +1,68 @@ +using Edelstein.Common.Gameplay.Models.Characters.Stats.Modify; +using Edelstein.Protocol.Gameplay.Game.Contracts; +using Edelstein.Protocol.Gameplay.Models.Characters.Stats.Modify; +using Edelstein.Protocol.Utilities.Pipelines; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Common.Gameplay.Game.Handling.Plugs; + +public class FieldOnPacketUserAbilityMassUpRequestPlug : IPipelinePlug +{ + private readonly ILogger _logger; + + public FieldOnPacketUserAbilityMassUpRequestPlug(ILogger logger) + => _logger = logger; + + public async Task Handle(IPipelineContext ctx, FieldOnPacketUserAbilityMassUpRequest message) + { + var stats = new ModifyStatContext(message.User.Character); + + foreach (var pair in message.StatUp) + { + try + { + HandleStatUp(stats, pair.Key, pair.Value); + } + catch (ArgumentOutOfRangeException) + { + _logger.LogWarning("Unhandled ability up stat type {Type}", pair.Key); + } + } + + await message.User.ModifyStats(stats, exclRequest: true); + } + + public static void HandleStatUp(ModifyStatContext stats, ModifyStatType type, int value = 1) + { + switch (type) + { + case ModifyStatType.STR: + if (stats.STR + value > short.MaxValue) + return; + stats.STR += (short)value; + break; + case ModifyStatType.DEX: + if (stats.DEX + value > short.MaxValue) + return; + stats.DEX += (short)value; + break; + case ModifyStatType.INT: + if (stats.INT + value > short.MaxValue) + return; + stats.INT += (short)value; + break; + case ModifyStatType.LUK: + if (stats.LUK + value > short.MaxValue) + return; + stats.LUK += (short)value; + break; + case ModifyStatType.MaxHP: + case ModifyStatType.MaxMP: + // TODO + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + + stats.AP -= (short)value; + } +} diff --git a/src/common/Edelstein.Common.Gameplay.Game/Handling/Plugs/FieldOnPacketUserAbilityUpRequestPlug.cs b/src/common/Edelstein.Common.Gameplay.Game/Handling/Plugs/FieldOnPacketUserAbilityUpRequestPlug.cs new file mode 100644 index 000000000..7c7c0d7b4 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Game/Handling/Plugs/FieldOnPacketUserAbilityUpRequestPlug.cs @@ -0,0 +1,22 @@ +using Edelstein.Protocol.Gameplay.Game.Contracts; +using Edelstein.Protocol.Gameplay.Models.Characters.Stats.Modify; +using Edelstein.Protocol.Utilities.Pipelines; + +namespace Edelstein.Common.Gameplay.Game.Handling.Plugs; + +public class FieldOnPacketUserAbilityUpRequestPlug : IPipelinePlug +{ + private readonly FieldOnPacketUserAbilityMassUpRequestPlug _plug; + + public FieldOnPacketUserAbilityUpRequestPlug(FieldOnPacketUserAbilityMassUpRequestPlug plug) + => _plug = plug; + + public Task Handle(IPipelineContext ctx, FieldOnPacketUserAbilityUpRequest message) + => _plug.Handle(ctx, new FieldOnPacketUserAbilityMassUpRequest( + message.User, + new Dictionary + { + [message.Type] = 1 + } + )); +} diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Game/Contracts/FieldOnPacketUserAbilityMassUpRequest.cs b/src/protocol/Edelstein.Protocol.Gameplay.Game/Contracts/FieldOnPacketUserAbilityMassUpRequest.cs new file mode 100644 index 000000000..71d9d1ae2 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Gameplay.Game/Contracts/FieldOnPacketUserAbilityMassUpRequest.cs @@ -0,0 +1,9 @@ +using Edelstein.Protocol.Gameplay.Game.Objects.User; +using Edelstein.Protocol.Gameplay.Models.Characters.Stats.Modify; + +namespace Edelstein.Protocol.Gameplay.Game.Contracts; + +public record FieldOnPacketUserAbilityMassUpRequest( + IFieldUser User, + IDictionary StatUp +); diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Game/Contracts/FieldOnPacketUserAbilityUpRequest.cs b/src/protocol/Edelstein.Protocol.Gameplay.Game/Contracts/FieldOnPacketUserAbilityUpRequest.cs new file mode 100644 index 000000000..b5eed771d --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Gameplay.Game/Contracts/FieldOnPacketUserAbilityUpRequest.cs @@ -0,0 +1,9 @@ +using Edelstein.Protocol.Gameplay.Game.Objects.User; +using Edelstein.Protocol.Gameplay.Models.Characters.Stats.Modify; + +namespace Edelstein.Protocol.Gameplay.Game.Contracts; + +public record FieldOnPacketUserAbilityUpRequest( + IFieldUser User, + ModifyStatType Type +);