From 7fb2294d9f26d15688d097274853dc3f4d7b36fb Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 17 Oct 2024 21:47:44 +0200 Subject: [PATCH] Refactored stats updates and consolidated extended messages --- ...1-26-FE-MaximumStatsExtended_by-server.md} | 12 +- ...urrentHealthAndShieldExtended_by-server.md | 20 - ...C1-26-FF-CurrentStatsExtended_by-server.md | 24 ++ ...MaximumManaAndAbilityExtended_by-server.md | 20 - ...CurrentManaAndAbilityExtended_by-server.md | 20 - docs/Packets/ServerToClient.md | 6 +- src/GameLogic/AttackableExtensions.cs | 11 +- src/GameLogic/Player.cs | 38 +- .../AlcoholConsumeHandlerPlugIn.cs | 1 + .../HealthPotionConsumeHandlerPlugIn.cs | 2 +- .../ManaPotionConsumehandler.cs | 2 +- .../Skills/DrainLifeSkillPlugIn.cs | 2 +- .../Character/IUpdateCurrentHealthPlugIn.cs | 16 - .../Character/IUpdateCurrentManaPlugIn.cs | 16 - .../Character/IUpdateMaximumHealthPlugIn.cs | 16 - .../Character/IUpdateMaximumManaPlugIn.cs | 16 - .../Views/Character/IUpdateStatsPlugIn.cs | 53 +++ .../UpdateCurrentHealthExtendedPlugIn.cs | 42 --- .../Character/UpdateCurrentHealthPlugIn.cs | 40 -- .../UpdateCurrentManaExtendedPlugIn.cs | 42 --- .../Character/UpdateCurrentManaPlugIn.cs | 40 -- .../UpdateMaximumHealthExtendedPlugIn.cs | 43 --- .../Character/UpdateMaximumHealthPlugIn.cs | 41 --- .../UpdateMaximumManaExtendedPlugIn.cs | 43 --- .../Character/UpdateMaximumManaPlugIn.cs | 41 --- .../Character/UpdateStatsExtendedPlugIn.cs | 63 ++++ .../RemoteView/Character/UpdateStatsPlugIn.cs | 75 ++++ .../ServerToClient/ConnectionExtensions.cs | 106 ++---- .../ServerToClient/ServerToClientPackets.cs | 342 ++++++------------ .../ServerToClient/ServerToClientPackets.xml | 112 +++--- .../ServerToClientPacketsRef.cs | 342 ++++++------------ 31 files changed, 544 insertions(+), 1103 deletions(-) rename docs/Packets/{C1-26-FE-MaximumHealthAndShieldExtended_by-server.md => C1-26-FE-MaximumStatsExtended_by-server.md} (50%) delete mode 100644 docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md create mode 100644 docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md delete mode 100644 docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md delete mode 100644 docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md delete mode 100644 src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs delete mode 100644 src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs delete mode 100644 src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs delete mode 100644 src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs create mode 100644 src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs create mode 100644 src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs create mode 100644 src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs diff --git a/docs/Packets/C1-26-FE-MaximumHealthAndShieldExtended_by-server.md b/docs/Packets/C1-26-FE-MaximumStatsExtended_by-server.md similarity index 50% rename from docs/Packets/C1-26-FE-MaximumHealthAndShieldExtended_by-server.md rename to docs/Packets/C1-26-FE-MaximumStatsExtended_by-server.md index 9ea3b588d..789acc585 100644 --- a/docs/Packets/C1-26-FE-MaximumHealthAndShieldExtended_by-server.md +++ b/docs/Packets/C1-26-FE-MaximumStatsExtended_by-server.md @@ -1,20 +1,22 @@ -# C1 26 FE - MaximumHealthAndShieldExtended (by server) +# C1 26 FE - MaximumStatsExtended (by server) ## Is sent when -When the maximum health changed, e.g. by adding stat points or changed items. +When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. ## Causes the following actions on the client side -The health and shield bar is updated on the game client user interface. +The values are updated on the game client user interface. ## Structure | Index | Length | Data Type | Value | Description | |-------|--------|-----------|-------|-------------| | 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | +| 1 | 1 | Byte | 20 | Packet header - length of the packet | | 2 | 1 | Byte | 0x26 | Packet header - packet type identifier | | 3 | 1 | Byte | 0xFE | Packet header - sub packet type identifier | | 4 | 4 | IntegerLittleEndian | | Health | -| 8 | 4 | IntegerLittleEndian | | Shield | \ No newline at end of file +| 8 | 4 | IntegerLittleEndian | | Shield | +| 12 | 4 | IntegerLittleEndian | | Mana | +| 16 | 4 | IntegerLittleEndian | | Ability | \ No newline at end of file diff --git a/docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md b/docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md deleted file mode 100644 index 72edaaf40..000000000 --- a/docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md +++ /dev/null @@ -1,20 +0,0 @@ -# C1 26 FF - CurrentHealthAndShieldExtended (by server) - -## Is sent when - -Periodically, or if the current health or shield changed on the server side, e.g. by hits. - -## Causes the following actions on the client side - -The health and shield bar is updated on the game client user interface. - -## Structure - -| Index | Length | Data Type | Value | Description | -|-------|--------|-----------|-------|-------------| -| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | -| 2 | 1 | Byte | 0x26 | Packet header - packet type identifier | -| 3 | 1 | Byte | 0xFF | Packet header - sub packet type identifier | -| 4 | 4 | IntegerLittleEndian | | Health | -| 8 | 4 | IntegerLittleEndian | | Shield | \ No newline at end of file diff --git a/docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md b/docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md new file mode 100644 index 000000000..a979a7139 --- /dev/null +++ b/docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md @@ -0,0 +1,24 @@ +# C1 26 FF - CurrentStatsExtended (by server) + +## Is sent when + +Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. + +## Causes the following actions on the client side + +The values are updated on the game client user interface. + +## Structure + +| Index | Length | Data Type | Value | Description | +|-------|--------|-----------|-------|-------------| +| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | +| 1 | 1 | Byte | 24 | Packet header - length of the packet | +| 2 | 1 | Byte | 0x26 | Packet header - packet type identifier | +| 3 | 1 | Byte | 0xFF | Packet header - sub packet type identifier | +| 4 | 4 | IntegerLittleEndian | | Health | +| 8 | 4 | IntegerLittleEndian | | Shield | +| 12 | 4 | IntegerLittleEndian | | Mana | +| 16 | 4 | IntegerLittleEndian | | Ability | +| 20 | 2 | ShortLittleEndian | | AttackSpeed | +| 22 | 2 | ShortLittleEndian | | MagicSpeed | \ No newline at end of file diff --git a/docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md b/docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md deleted file mode 100644 index 360ea9520..000000000 --- a/docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md +++ /dev/null @@ -1,20 +0,0 @@ -# C1 27 FE - MaximumManaAndAbilityExtended (by server) - -## Is sent when - -The maximum available mana or ability has changed, e.g. by adding stat points. - -## Causes the following actions on the client side - -The mana and ability bar is updated on the game client user interface. - -## Structure - -| Index | Length | Data Type | Value | Description | -|-------|--------|-----------|-------|-------------| -| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | -| 2 | 1 | Byte | 0x27 | Packet header - packet type identifier | -| 3 | 1 | Byte | 0xFE | Packet header - sub packet type identifier | -| 4 | 4 | IntegerLittleEndian | | Mana | -| 8 | 4 | IntegerLittleEndian | | Ability | \ No newline at end of file diff --git a/docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md b/docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md deleted file mode 100644 index cafa844ab..000000000 --- a/docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md +++ /dev/null @@ -1,20 +0,0 @@ -# C1 27 FF - CurrentManaAndAbilityExtended (by server) - -## Is sent when - -The currently available mana or ability has changed, e.g. by using a skill. - -## Causes the following actions on the client side - -The mana and ability bar is updated on the game client user interface. - -## Structure - -| Index | Length | Data Type | Value | Description | -|-------|--------|-----------|-------|-------------| -| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | -| 2 | 1 | Byte | 0x27 | Packet header - packet type identifier | -| 3 | 1 | Byte | 0xFF | Packet header - sub packet type identifier | -| 4 | 4 | IntegerLittleEndian | | Mana | -| 8 | 4 | IntegerLittleEndian | | Ability | \ No newline at end of file diff --git a/docs/Packets/ServerToClient.md b/docs/Packets/ServerToClient.md index f840be18d..5d975f20f 100644 --- a/docs/Packets/ServerToClient.md +++ b/docs/Packets/ServerToClient.md @@ -50,13 +50,11 @@ * [C1 26 FD - ItemConsumptionFailed (by server)](C1-26-FD-ItemConsumptionFailed_by-server.md) * [C1 26 FD - ItemConsumptionFailedExtended (by server)](C1-26-FD-ItemConsumptionFailedExtended_by-server.md) * [C1 26 FE - MaximumHealthAndShield (by server)](C1-26-FE-MaximumHealthAndShield_by-server.md) - * [C1 26 FE - MaximumHealthAndShieldExtended (by server)](C1-26-FE-MaximumHealthAndShieldExtended_by-server.md) + * [C1 26 FE - MaximumStatsExtended (by server)](C1-26-FE-MaximumStatsExtended_by-server.md) * [C1 26 FF - CurrentHealthAndShield (by server)](C1-26-FF-CurrentHealthAndShield_by-server.md) - * [C1 26 FF - CurrentHealthAndShieldExtended (by server)](C1-26-FF-CurrentHealthAndShieldExtended_by-server.md) + * [C1 26 FF - CurrentStatsExtended (by server)](C1-26-FF-CurrentStatsExtended_by-server.md) * [C1 27 FE - MaximumManaAndAbility (by server)](C1-27-FE-MaximumManaAndAbility_by-server.md) - * [C1 27 FE - MaximumManaAndAbilityExtended (by server)](C1-27-FE-MaximumManaAndAbilityExtended_by-server.md) * [C1 27 FF - CurrentManaAndAbility (by server)](C1-27-FF-CurrentManaAndAbility_by-server.md) - * [C1 27 FF - CurrentManaAndAbilityExtended (by server)](C1-27-FF-CurrentManaAndAbilityExtended_by-server.md) * [C1 28 - ItemRemoved (by server)](C1-28-ItemRemoved_by-server.md) * [C3 29 - ConsumeItemWithEffect (by server)](C3-29-ConsumeItemWithEffect_by-server.md) * [C1 2A - ItemDurabilityChanged (by server)](C1-2A-ItemDurabilityChanged_by-server.md) diff --git a/src/GameLogic/AttackableExtensions.cs b/src/GameLogic/AttackableExtensions.cs index 04942f473..9dddcb103 100644 --- a/src/GameLogic/AttackableExtensions.cs +++ b/src/GameLogic/AttackableExtensions.cs @@ -199,14 +199,13 @@ public static async ValueTask ApplyRegenerationAsync(this IAttackable target, Pl if (target is IWorldObserver observer) { - if (isHealthUpdated) - { - await observer.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); - } + var updatedStats = + (isHealthUpdated ? IUpdateStatsPlugIn.UpdatedStats.Health : IUpdateStatsPlugIn.UpdatedStats.Undefined) + | (isManaUpdated ? IUpdateStatsPlugIn.UpdatedStats.Mana : IUpdateStatsPlugIn.UpdatedStats.Undefined); - if (isManaUpdated) + if (updatedStats != IUpdateStatsPlugIn.UpdatedStats.Undefined) { - await observer.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await observer.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(updatedStats)).ConfigureAwait(false); } } } diff --git a/src/GameLogic/Player.cs b/src/GameLogic/Player.cs index 6d0ae48e4..8c5851f48 100644 --- a/src/GameLogic/Player.cs +++ b/src/GameLogic/Player.cs @@ -4,6 +4,7 @@ namespace MUnique.OpenMU.GameLogic; +using System; using System.Threading; using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.DataModel.Attributes; @@ -28,6 +29,7 @@ namespace MUnique.OpenMU.GameLogic; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.PlugIns; using Nito.AsyncEx; +using static MUnique.OpenMU.GameLogic.Views.Character.IUpdateStatsPlugIn; /// /// The base implementation of a player. @@ -622,13 +624,13 @@ public bool IsAnySelfDefenseActive() if (Rand.NextRandomBool(this.Attributes[Stats.FullyRecoverHealthAfterHitChance])) { this.Attributes[Stats.CurrentHealth] = this.Attributes[Stats.MaximumHealth]; - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Health)).ConfigureAwait(false); } if (Rand.NextRandomBool(this.Attributes[Stats.FullyRecoverManaAfterHitChance])) { this.Attributes[Stats.CurrentMana] = this.Attributes[Stats.MaximumMana]; - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); } await this.HitAsync(hitInfo, attacker, skill?.Skill).ConfigureAwait(false); @@ -731,8 +733,7 @@ public async ValueTask AfterKilledMonsterAsync() this.Attributes[recoverAfterMonsterKill.CurrentAttribute] = (uint)Math.Min(this.Attributes[recoverAfterMonsterKill.MaximumAttribute], this.Attributes[recoverAfterMonsterKill.CurrentAttribute] + additionalValue); } - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync()).ConfigureAwait(false); } /// @@ -1224,8 +1225,7 @@ public async Task RegenerateAsync() attributes[r.MaximumAttribute]); } - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync()).ConfigureAwait(false); await this.RegenerateHeroStateAsync().ConfigureAwait(false); } @@ -1334,7 +1334,8 @@ public async ValueTask TryConsumeForSkillAsync(Skill skill) this.Attributes![requirement.Attribute] -= this.GetRequiredValue(requirement); } - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); + return true; } @@ -2082,6 +2083,7 @@ private async ValueTask OnPlayerEnteredWorldAsync() this.Attributes.GetOrCreateAttribute(Stats.MaximumHealth).ValueChanged += this.OnMaximumHealthOrShieldChanged; this.Attributes.GetOrCreateAttribute(Stats.MaximumShield).ValueChanged += this.OnMaximumHealthOrShieldChanged; this.Attributes.GetOrCreateAttribute(Stats.TransformationSkin).ValueChanged += this.OnTransformationSkinChanged; + this.Attributes.GetOrCreateAttribute(Stats.AttackSpeed).ValueChanged += this.OnAttackSpeedChanged; var ammoAttribute = this.Attributes.GetOrCreateAttribute(Stats.AmmunitionAmount); this.Attributes[Stats.AmmunitionAmount] = (float)(this.Inventory?.EquippedAmmunitionItem?.Durability ?? 0); @@ -2176,8 +2178,9 @@ private async void OnMaximumHealthOrShieldChanged(object? sender, EventArgs args { this.Attributes![Stats.CurrentHealth] = Math.Min(this.Attributes[Stats.CurrentHealth], this.Attributes[Stats.MaximumHealth]); this.Attributes[Stats.CurrentShield] = Math.Min(this.Attributes[Stats.CurrentShield], this.Attributes[Stats.MaximumShield]); - await this.InvokeViewPlugInAsync(p => p.UpdateMaximumHealthAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + + await this.InvokeViewPlugInAsync(p => p.UpdateMaximumStatsAsync(UpdatedStats.Health)).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Health)).ConfigureAwait(false); } catch (Exception ex) { @@ -2218,8 +2221,21 @@ private async void OnMaximumManaOrAbilityChanged(object? sender, EventArgs args) { this.Attributes![Stats.CurrentMana] = Math.Min(this.Attributes[Stats.CurrentMana], this.Attributes[Stats.MaximumMana]); this.Attributes[Stats.CurrentAbility] = Math.Min(this.Attributes[Stats.CurrentAbility], this.Attributes[Stats.MaximumAbility]); - await this.InvokeViewPlugInAsync(p => p.UpdateMaximumManaAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateMaximumStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); + } + catch (Exception ex) + { + this.Logger.LogError(ex, nameof(this.OnMaximumManaOrAbilityChanged)); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "Catching all Exceptions.")] + private async void OnAttackSpeedChanged(object? sender, EventArgs args) + { + try + { + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Speed)).ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs index 3bc03506d..7c75a7663 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs @@ -26,6 +26,7 @@ public override async ValueTask ConsumeItemAsync(Player player, Item item, if (await base.ConsumeItemAsync(player, item, targetItem, fruitUsage).ConfigureAwait(false)) { await player.InvokeViewPlugInAsync(p => p.DrinkAlcoholAsync()).ConfigureAwait(false); + // todo: add magic effect to update stat return true; } diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs index aa91b1a62..dd230f5c9 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs @@ -25,6 +25,6 @@ public abstract class HealthPotionConsumeHandlerPlugIn : RecoverConsumeHandlerPl protected override async ValueTask OnAfterRecoverAsync(Player player) { // maybe instead of calling UpdateCurrentHealth etc. provide a more general method where we pass this.CurrentAttribute. The view can then decide what to do with it. - await player.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await player.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Health)).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs index d27931806..30efe2401 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs @@ -24,6 +24,6 @@ public abstract class ManaPotionConsumeHandler : RecoverConsumeHandlerPlugIn.Man /// protected override async ValueTask OnAfterRecoverAsync(Player player) { - await player.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await player.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Mana)).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs b/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs index 05dc28838..5cf55d416 100644 --- a/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs +++ b/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs @@ -31,7 +31,7 @@ public async ValueTask AfterTargetGotAttackedAsync(IAttacker attacker, IAttackab if (playerAttributes != null) { playerAttributes[Stats.CurrentHealth] = (uint)Math.Min(playerAttributes[Stats.MaximumHealth], playerAttributes[Stats.CurrentHealth] + hitInfo.Value.HealthDamage); - await attackerPlayer.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await attackerPlayer.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Health)).ConfigureAwait(false); } } } diff --git a/src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs b/src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs deleted file mode 100644 index da9d4a4c6..000000000 --- a/src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated current health. -/// -public interface IUpdateCurrentHealthPlugIn : IViewPlugIn -{ - /// - /// Updates the current health. - /// - ValueTask UpdateCurrentHealthAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs b/src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs deleted file mode 100644 index f259fa355..000000000 --- a/src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated current mana. -/// -public interface IUpdateCurrentManaPlugIn : IViewPlugIn -{ - /// - /// Updates the current mana. - /// - ValueTask UpdateCurrentManaAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs b/src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs deleted file mode 100644 index 967c3b766..000000000 --- a/src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated maximum health. -/// -public interface IUpdateMaximumHealthPlugIn : IViewPlugIn -{ - /// - /// Updates the maximum health. - /// - ValueTask UpdateMaximumHealthAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs b/src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs deleted file mode 100644 index 34a096165..000000000 --- a/src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated maximum mana. -/// -public interface IUpdateMaximumManaPlugIn : IViewPlugIn -{ - /// - /// Updates the maximum mana. - /// - ValueTask UpdateMaximumManaAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs b/src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs new file mode 100644 index 000000000..6e6d81f42 --- /dev/null +++ b/src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs @@ -0,0 +1,53 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.Views.Character; + +using MUnique.OpenMU.AttributeSystem; + +/// +/// Interface of a view whose implementation informs about updated stats. +/// +public interface IUpdateStatsPlugIn : IViewPlugIn +{ + /// + /// Updates the maximum stats. + /// + /// The updated stats. + ValueTask UpdateMaximumStatsAsync(UpdatedStats updatedStats = UpdatedStats.Health | UpdatedStats.Mana | UpdatedStats.Speed); + + /// + /// Updates the current stats. + /// + /// The updated stats. + ValueTask UpdateCurrentStatsAsync(UpdatedStats updatedStats = UpdatedStats.Health | UpdatedStats.Mana | UpdatedStats.Speed); + + /// + /// The updated stat. + /// This might be replaced by the actual in the future. + /// + [Flags] + public enum UpdatedStats + { + /// + /// Undefined. + /// + Undefined, + + /// + /// The health or shield changed. + /// + Health = 0x01, + + /// + /// The mana or ability changed. + /// + Mana = 0x02, + + /// + /// The attack speed changed. + /// + Speed = 0x04, + } +} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs deleted file mode 100644 index daf062c2c..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateCurrentHealthExtendedPlugIn), "The extended implementation of the IUpdateCurrentHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("C609BC7E-170B-4C79-94E5-D97AB9A3CB4B")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateCurrentHealthExtendedPlugIn : IUpdateCurrentHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentHealthExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentHealthAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentHealthAndShieldExtendedAsync( - (uint)Math.Max(this._player.Attributes[Stats.CurrentHealth], 0f), - (uint)Math.Max(this._player.Attributes[Stats.CurrentShield], 0f)).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs deleted file mode 100644 index 71847fab1..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateCurrentHealthPlugIn", "The default implementation of the IUpdateCurrentHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("0c832ed3-fea7-4239-8208-b46897b44c84")] -public class UpdateCurrentHealthPlugIn : IUpdateCurrentHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentHealthPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentHealthAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentHealthAndShieldAsync( - (ushort)Math.Max(this._player.Attributes[Stats.CurrentHealth], 0f), - (ushort)Math.Max(this._player.Attributes[Stats.CurrentShield], 0f)).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs deleted file mode 100644 index eb58815d1..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateCurrentManaExtendedPlugIn), "The extended implementation of the IUpdateCurrentManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("1F99BFB4-35FC-489B-AB3C-E0738314DF37")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateCurrentManaExtendedPlugIn : IUpdateCurrentManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentManaExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentManaAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentManaAndAbilityExtendedAsync( - (uint)this._player.Attributes[Stats.CurrentMana], - (uint)this._player.Attributes[Stats.CurrentAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs deleted file mode 100644 index b661c3625..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateCurrentManaPlugIn", "The default implementation of the IUpdateCurrentManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("814fcc24-022a-47c8-b7d2-b1d1ca0208cb")] -public class UpdateCurrentManaPlugIn : IUpdateCurrentManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentManaPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentManaAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentManaAndAbilityAsync( - (ushort)this._player.Attributes[Stats.CurrentMana], - (ushort)this._player.Attributes[Stats.CurrentAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs deleted file mode 100644 index 5dd404843..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateMaximumHealthExtendedPlugIn), "The extended implementation of the IUpdateMaximumHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("7A287D6D-5C32-4FA9-9A0D-A4E0DEB053D1")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateMaximumHealthExtendedPlugIn : IUpdateMaximumHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumHealthExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumHealthAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumHealthAndShieldExtendedAsync( - (uint)this._player.Attributes[Stats.MaximumHealth], - (uint)this._player.Attributes[Stats.MaximumShield]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs deleted file mode 100644 index e683b6f7b..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateMaximumHealthPlugIn", "The default implementation of the IUpdateMaximumHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("6f8e7d9a-7d15-4e76-a650-8bfa70c7298e")] -public class UpdateMaximumHealthPlugIn : IUpdateMaximumHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumHealthPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumHealthAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumHealthAndShieldAsync( - (ushort)this._player.Attributes[Stats.MaximumHealth], - (ushort)this._player.Attributes[Stats.MaximumShield]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs deleted file mode 100644 index 899f989c9..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateMaximumManaExtendedPlugIn), "The extended implementation of the IUpdateMaximumManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("25AF11D5-FA10-4634-AF5A-CBF6F5E8BDFE")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateMaximumManaExtendedPlugIn : IUpdateMaximumManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumManaExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumManaAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumManaAndAbilityExtendedAsync( - (uint)this._player.Attributes[Stats.MaximumMana], - (uint)this._player.Attributes[Stats.MaximumAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs deleted file mode 100644 index eff798d68..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateMaximumManaPlugIn", "The default implementation of the IUpdateMaximumManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("dc84be82-7ab0-4348-aa34-4a3dc8c1ee7a")] -public class UpdateMaximumManaPlugIn : IUpdateMaximumManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumManaPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumManaAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumManaAndAbilityAsync( - (ushort)this._player.Attributes[Stats.MaximumMana], - (ushort)this._player.Attributes[Stats.MaximumAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs new file mode 100644 index 000000000..1e70249c4 --- /dev/null +++ b/src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs @@ -0,0 +1,63 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameServer.RemoteView.Character; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.GameLogic.Views.Character; +using MUnique.OpenMU.Network.Packets.ServerToClient; +using MUnique.OpenMU.Network.PlugIns; +using MUnique.OpenMU.PlugIns; + +/// +/// The extended implementation of the which is forwarding everything to the game client with specific data packets. +/// +[PlugIn(nameof(UpdateStatsExtendedPlugIn), "The extended implementation of the IUpdateStatsPlugIn which is forwarding everything to the game client with specific data packets.")] +[Guid("E9A1CCBE-416F-41BA-8E74-74CBEB7042DD")] +[MinimumClient(106, 3, ClientLanguage.Invariant)] +public class UpdateStatsExtendedPlugIn : IUpdateStatsPlugIn +{ + private readonly RemotePlayer _player; + + /// + /// Initializes a new instance of the class. + /// + /// The player. + public UpdateStatsExtendedPlugIn(RemotePlayer player) => this._player = player; + + /// + public async ValueTask UpdateMaximumStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + await this._player.Connection.SendMaximumStatsExtendedAsync( + (uint)this._player.Attributes[Stats.MaximumHealth], + (uint)this._player.Attributes[Stats.MaximumShield], + (uint)this._player.Attributes[Stats.MaximumMana], + (uint)this._player.Attributes[Stats.MaximumAbility]).ConfigureAwait(false); + } + + /// + public async ValueTask UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + await this._player.Connection.SendCurrentStatsExtendedAsync( + (uint)this._player.Attributes[Stats.CurrentHealth], + (uint)this._player.Attributes[Stats.CurrentShield], + (uint)this._player.Attributes[Stats.CurrentMana], + (uint)this._player.Attributes[Stats.CurrentAbility], + (ushort)this._player.Attributes[Stats.AttackSpeed], + (ushort)this._player.Attributes[Stats.MagicSpeed]).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs new file mode 100644 index 000000000..bbffdd33a --- /dev/null +++ b/src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs @@ -0,0 +1,75 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameServer.RemoteView.Character; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.GameLogic.Views.Character; +using MUnique.OpenMU.Network.Packets.ServerToClient; +using MUnique.OpenMU.PlugIns; + +/// +/// The default implementation of the which is forwarding everything to the game client with specific data packets. +/// +[PlugIn(nameof(UpdateStatsPlugIn), "The default implementation of the IUpdateStatsPlugIn which is forwarding everything to the game client with specific data packets.")] +[Guid("2A8BFB0C-2AFF-4A52-B390-5A68D5C5F26A")] +public class UpdateStatsPlugIn : IUpdateStatsPlugIn +{ + private readonly RemotePlayer _player; + + /// + /// Initializes a new instance of the class. + /// + /// The player. + public UpdateStatsPlugIn(RemotePlayer player) => this._player = player; + + /// + public async ValueTask UpdateMaximumStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined | IUpdateStatsPlugIn.UpdatedStats.Health | IUpdateStatsPlugIn.UpdatedStats.Mana | IUpdateStatsPlugIn.UpdatedStats.Speed) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Health)) + { + await this._player.Connection.SendMaximumHealthAndShieldAsync( + (ushort)Math.Max(this._player.Attributes[Stats.MaximumHealth], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.MaximumShield], 0f)).ConfigureAwait(false); + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Mana)) + { + await this._player.Connection.SendMaximumManaAndAbilityAsync( + (ushort)Math.Max(this._player.Attributes[Stats.MaximumMana], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.MaximumAbility], 0f)).ConfigureAwait(false); + } + } + + /// + public async ValueTask UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined | IUpdateStatsPlugIn.UpdatedStats.Health | IUpdateStatsPlugIn.UpdatedStats.Mana | IUpdateStatsPlugIn.UpdatedStats.Speed) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Health)) + { + await this._player.Connection.SendCurrentHealthAndShieldAsync( + (ushort)Math.Max(this._player.Attributes[Stats.CurrentHealth], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.CurrentShield], 0f)).ConfigureAwait(false); + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Mana)) + { + await this._player.Connection.SendCurrentHealthAndShieldAsync( + (ushort)Math.Max(this._player.Attributes[Stats.CurrentMana], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.CurrentAbility], 0f)).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Network/Packets/ServerToClient/ConnectionExtensions.cs b/src/Network/Packets/ServerToClient/ConnectionExtensions.cs index ec13a7a62..d7d1e18d2 100644 --- a/src/Network/Packets/ServerToClient/ConnectionExtensions.cs +++ b/src/Network/Packets/ServerToClient/ConnectionExtensions.cs @@ -1726,16 +1726,16 @@ int WritePacket() } /// - /// Sends a to this connection. + /// Sends a to this connection. /// /// The connection. /// The health. /// The shield. /// - /// Is sent by the server when: Periodically, or if the current health or shield changed on the server side, e.g. by hits. + /// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. /// - public static async ValueTask SendCurrentHealthAndShieldExtendedAsync(this IConnection? connection, uint @health, uint @shield) + public static async ValueTask SendMaximumHealthAndShieldAsync(this IConnection? connection, ushort @health, ushort @shield) { if (connection is null) { @@ -1744,8 +1744,8 @@ public static async ValueTask SendCurrentHealthAndShieldExtendedAsync(this IConn int WritePacket() { - var length = CurrentHealthAndShieldExtendedRef.Length; - var packet = new CurrentHealthAndShieldExtendedRef(connection.Output.GetSpan(length)[..length]); + var length = MaximumHealthAndShieldRef.Length; + var packet = new MaximumHealthAndShieldRef(connection.Output.GetSpan(length)[..length]); packet.Health = @health; packet.Shield = @shield; @@ -1756,16 +1756,20 @@ int WritePacket() } /// - /// Sends a to this connection. + /// Sends a to this connection. /// /// The connection. /// The health. /// The shield. + /// The mana. + /// The ability. + /// The attack speed. + /// The magic speed. /// - /// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. - /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. + /// Is sent by the server when: Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. + /// Causes reaction on client side: The values are updated on the game client user interface. /// - public static async ValueTask SendMaximumHealthAndShieldAsync(this IConnection? connection, ushort @health, ushort @shield) + public static async ValueTask SendCurrentStatsExtendedAsync(this IConnection? connection, uint @health, uint @shield, uint @mana, uint @ability, ushort @attackSpeed, ushort @magicSpeed) { if (connection is null) { @@ -1774,10 +1778,14 @@ public static async ValueTask SendMaximumHealthAndShieldAsync(this IConnection? int WritePacket() { - var length = MaximumHealthAndShieldRef.Length; - var packet = new MaximumHealthAndShieldRef(connection.Output.GetSpan(length)[..length]); + var length = CurrentStatsExtendedRef.Length; + var packet = new CurrentStatsExtendedRef(connection.Output.GetSpan(length)[..length]); packet.Health = @health; packet.Shield = @shield; + packet.Mana = @mana; + packet.Ability = @ability; + packet.AttackSpeed = @attackSpeed; + packet.MagicSpeed = @magicSpeed; return packet.Header.Length; } @@ -1786,16 +1794,18 @@ int WritePacket() } /// - /// Sends a to this connection. + /// Sends a to this connection. /// /// The connection. /// The health. /// The shield. + /// The mana. + /// The ability. /// - /// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. - /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. + /// Is sent by the server when: When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. + /// Causes reaction on client side: The values are updated on the game client user interface. /// - public static async ValueTask SendMaximumHealthAndShieldExtendedAsync(this IConnection? connection, uint @health, uint @shield) + public static async ValueTask SendMaximumStatsExtendedAsync(this IConnection? connection, uint @health, uint @shield, uint @mana, uint @ability) { if (connection is null) { @@ -1804,10 +1814,12 @@ public static async ValueTask SendMaximumHealthAndShieldExtendedAsync(this IConn int WritePacket() { - var length = MaximumHealthAndShieldExtendedRef.Length; - var packet = new MaximumHealthAndShieldExtendedRef(connection.Output.GetSpan(length)[..length]); + var length = MaximumStatsExtendedRef.Length; + var packet = new MaximumStatsExtendedRef(connection.Output.GetSpan(length)[..length]); packet.Health = @health; packet.Shield = @shield; + packet.Mana = @mana; + packet.Ability = @ability; return packet.Header.Length; } @@ -1905,36 +1917,6 @@ int WritePacket() await connection.SendAsync(WritePacket).ConfigureAwait(false); } - /// - /// Sends a to this connection. - /// - /// The connection. - /// The mana. - /// The ability. - /// - /// Is sent by the server when: The currently available mana or ability has changed, e.g. by using a skill. - /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. - /// - public static async ValueTask SendCurrentManaAndAbilityExtendedAsync(this IConnection? connection, uint @mana, uint @ability) - { - if (connection is null) - { - return; - } - - int WritePacket() - { - var length = CurrentManaAndAbilityExtendedRef.Length; - var packet = new CurrentManaAndAbilityExtendedRef(connection.Output.GetSpan(length)[..length]); - packet.Mana = @mana; - packet.Ability = @ability; - - return packet.Header.Length; - } - - await connection.SendAsync(WritePacket).ConfigureAwait(false); - } - /// /// Sends a to this connection. /// @@ -1965,36 +1947,6 @@ int WritePacket() await connection.SendAsync(WritePacket).ConfigureAwait(false); } - /// - /// Sends a to this connection. - /// - /// The connection. - /// The mana. - /// The ability. - /// - /// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. - /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. - /// - public static async ValueTask SendMaximumManaAndAbilityExtendedAsync(this IConnection? connection, uint @mana, uint @ability) - { - if (connection is null) - { - return; - } - - int WritePacket() - { - var length = MaximumManaAndAbilityExtendedRef.Length; - var packet = new MaximumManaAndAbilityExtendedRef(connection.Output.GetSpan(length)[..length]); - packet.Mana = @mana; - packet.Ability = @ability; - - return packet.Header.Length; - } - - await connection.SendAsync(WritePacket).ConfigureAwait(false); - } - /// /// Sends a to this connection. /// diff --git a/src/Network/Packets/ServerToClient/ServerToClientPackets.cs b/src/Network/Packets/ServerToClient/ServerToClientPackets.cs index 2cd7d3da8..28a34366d 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPackets.cs +++ b/src/Network/Packets/ServerToClient/ServerToClientPackets.cs @@ -8874,28 +8874,28 @@ public ushort Shield /// -/// Is sent by the server when: Periodically, or if the current health or shield changed on the server side, e.g. by hits. +/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. /// -public readonly struct CurrentHealthAndShieldExtended +public readonly struct MaximumHealthAndShield { private readonly Memory _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public CurrentHealthAndShieldExtended(Memory data) + public MaximumHealthAndShield(Memory data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentHealthAndShieldExtended(Memory data, bool initialize) + private MaximumHealthAndShield(Memory data, bool initialize) { this._data = data; if (initialize) @@ -8922,12 +8922,12 @@ private CurrentHealthAndShieldExtended(Memory data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFF; + public static byte SubCode => 0xFE; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 9; /// /// Gets the header of this packet. @@ -8937,60 +8937,60 @@ private CurrentHealthAndShieldExtended(Memory data, bool initialize) /// /// Gets or sets the health. /// - public uint Health + public ushort Health { - get => ReadUInt32LittleEndian(this._data.Span[4..]); - set => WriteUInt32LittleEndian(this._data.Span[4..], value); + get => ReadUInt16BigEndian(this._data.Span[4..]); + set => WriteUInt16BigEndian(this._data.Span[4..], value); } /// /// Gets or sets the shield. /// - public uint Shield + public ushort Shield { - get => ReadUInt32LittleEndian(this._data.Span[8..]); - set => WriteUInt32LittleEndian(this._data.Span[8..], value); + get => ReadUInt16BigEndian(this._data.Span[7..]); + set => WriteUInt16BigEndian(this._data.Span[7..], value); } /// - /// Performs an implicit conversion from a Memory of bytes to a . + /// Performs an implicit conversion from a Memory of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator CurrentHealthAndShieldExtended(Memory packet) => new (packet, false); + public static implicit operator MaximumHealthAndShield(Memory packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Memory of bytes. + /// Performs an implicit conversion from to a Memory of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Memory(CurrentHealthAndShieldExtended packet) => packet._data; + public static implicit operator Memory(MaximumHealthAndShield packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly struct MaximumHealthAndShield +public readonly struct CurrentStatsExtended { private readonly Memory _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShield(Memory data) + public CurrentStatsExtended(Memory data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShield(Memory data, bool initialize) + private CurrentStatsExtended(Memory data, bool initialize) { this._data = data; if (initialize) @@ -9017,12 +9017,12 @@ private MaximumHealthAndShield(Memory data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFE; + public static byte SubCode => 0xFF; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 9; + public static int Length => 24; /// /// Gets the header of this packet. @@ -9032,60 +9032,96 @@ private MaximumHealthAndShield(Memory data, bool initialize) /// /// Gets or sets the health. /// - public ushort Health + public uint Health { - get => ReadUInt16BigEndian(this._data.Span[4..]); - set => WriteUInt16BigEndian(this._data.Span[4..], value); + get => ReadUInt32LittleEndian(this._data.Span[4..]); + set => WriteUInt32LittleEndian(this._data.Span[4..], value); } /// /// Gets or sets the shield. /// - public ushort Shield + public uint Shield { - get => ReadUInt16BigEndian(this._data.Span[7..]); - set => WriteUInt16BigEndian(this._data.Span[7..], value); + get => ReadUInt32LittleEndian(this._data.Span[8..]); + set => WriteUInt32LittleEndian(this._data.Span[8..], value); } /// - /// Performs an implicit conversion from a Memory of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data.Span[12..]); + set => WriteUInt32LittleEndian(this._data.Span[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data.Span[16..]); + set => WriteUInt32LittleEndian(this._data.Span[16..], value); + } + + /// + /// Gets or sets the attack speed. + /// + public ushort AttackSpeed + { + get => ReadUInt16LittleEndian(this._data.Span[20..]); + set => WriteUInt16LittleEndian(this._data.Span[20..], value); + } + + /// + /// Gets or sets the magic speed. + /// + public ushort MagicSpeed + { + get => ReadUInt16LittleEndian(this._data.Span[22..]); + set => WriteUInt16LittleEndian(this._data.Span[22..], value); + } + + /// + /// Performs an implicit conversion from a Memory of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShield(Memory packet) => new (packet, false); + public static implicit operator CurrentStatsExtended(Memory packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Memory of bytes. + /// Performs an implicit conversion from to a Memory of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Memory(MaximumHealthAndShield packet) => packet._data; + public static implicit operator Memory(CurrentStatsExtended packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly struct MaximumHealthAndShieldExtended +public readonly struct MaximumStatsExtended { private readonly Memory _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShieldExtended(Memory data) + public MaximumStatsExtended(Memory data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShieldExtended(Memory data, bool initialize) + private MaximumStatsExtended(Memory data, bool initialize) { this._data = data; if (initialize) @@ -9117,7 +9153,7 @@ private MaximumHealthAndShieldExtended(Memory data, bool initialize) /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 20; /// /// Gets the header of this packet. @@ -9143,18 +9179,36 @@ public uint Shield } /// - /// Performs an implicit conversion from a Memory of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data.Span[12..]); + set => WriteUInt32LittleEndian(this._data.Span[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data.Span[16..]); + set => WriteUInt32LittleEndian(this._data.Span[16..], value); + } + + /// + /// Performs an implicit conversion from a Memory of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShieldExtended(Memory packet) => new (packet, false); + public static implicit operator MaximumStatsExtended(Memory packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Memory of bytes. + /// Performs an implicit conversion from to a Memory of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Memory(MaximumHealthAndShieldExtended packet) => packet._data; + public static implicit operator Memory(MaximumStatsExtended packet) => packet._data; } @@ -9443,101 +9497,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The currently available mana or ability has changed, e.g. by using a skill. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly struct CurrentManaAndAbilityExtended -{ - private readonly Memory _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public CurrentManaAndAbilityExtended(Memory data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentManaAndAbilityExtended(Memory data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFF; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCode Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data.Span[4..]); - set => WriteUInt32LittleEndian(this._data.Span[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data.Span[8..]); - set => WriteUInt32LittleEndian(this._data.Span[8..], value); - } - - /// - /// Performs an implicit conversion from a Memory of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator CurrentManaAndAbilityExtended(Memory packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Memory of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Memory(CurrentManaAndAbilityExtended packet) => packet._data; -} - - /// /// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. @@ -9633,101 +9592,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly struct MaximumManaAndAbilityExtended -{ - private readonly Memory _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public MaximumManaAndAbilityExtended(Memory data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumManaAndAbilityExtended(Memory data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFE; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCode Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data.Span[4..]); - set => WriteUInt32LittleEndian(this._data.Span[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data.Span[8..]); - set => WriteUInt32LittleEndian(this._data.Span[8..], value); - } - - /// - /// Performs an implicit conversion from a Memory of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator MaximumManaAndAbilityExtended(Memory packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Memory of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Memory(MaximumManaAndAbilityExtended packet) => packet._data; -} - - /// /// Is sent by the server when: The item has been removed from the inventory of the player. /// Causes reaction on client side: The client removes the item in the inventory user interface. diff --git a/src/Network/Packets/ServerToClient/ServerToClientPackets.xml b/src/Network/Packets/ServerToClient/ServerToClientPackets.xml index 3a93efe10..207bedd9a 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPackets.xml +++ b/src/Network/Packets/ServerToClient/ServerToClientPackets.xml @@ -3168,21 +3168,21 @@ C1HeaderWithSubCode 26 - FF - CurrentHealthAndShieldExtended - 12 + FE + MaximumHealthAndShield + 9 ServerToClient - Periodically, or if the current health or shield changed on the server side, e.g. by hits. + When the maximum health changed, e.g. by adding stat points or changed items. The health and shield bar is updated on the game client user interface. 4 - IntegerLittleEndian + ShortBigEndian Health - 8 - IntegerLittleEndian + 7 + ShortBigEndian Shield @@ -3190,34 +3190,54 @@ C1HeaderWithSubCode 26 - FE - MaximumHealthAndShield - 9 + FF + CurrentStatsExtended + 24 ServerToClient - When the maximum health changed, e.g. by adding stat points or changed items. - The health and shield bar is updated on the game client user interface. + Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. + The values are updated on the game client user interface. 4 - ShortBigEndian + IntegerLittleEndian Health - 7 - ShortBigEndian + 8 + IntegerLittleEndian Shield + + 12 + IntegerLittleEndian + Mana + + + 16 + IntegerLittleEndian + Ability + + + 20 + ShortLittleEndian + AttackSpeed + + + 22 + ShortLittleEndian + MagicSpeed + C1HeaderWithSubCode 26 FE - MaximumHealthAndShieldExtended - 12 + MaximumStatsExtended + 20 ServerToClient - When the maximum health changed, e.g. by adding stat points or changed items. - The health and shield bar is updated on the game client user interface. + When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. + The values are updated on the game client user interface. 4 @@ -3229,6 +3249,16 @@ IntegerLittleEndian Shield + + 12 + IntegerLittleEndian + Mana + + + 16 + IntegerLittleEndian + Ability + @@ -3297,28 +3327,6 @@ - - C1HeaderWithSubCode - 27 - FF - CurrentManaAndAbilityExtended - 12 - ServerToClient - The currently available mana or ability has changed, e.g. by using a skill. - The mana and ability bar is updated on the game client user interface. - - - 4 - IntegerLittleEndian - Mana - - - 8 - IntegerLittleEndian - Ability - - - C1HeaderWithSubCode 27 @@ -3341,28 +3349,6 @@ - - C1HeaderWithSubCode - 27 - FE - MaximumManaAndAbilityExtended - 12 - ServerToClient - The maximum available mana or ability has changed, e.g. by adding stat points. - The mana and ability bar is updated on the game client user interface. - - - 4 - IntegerLittleEndian - Mana - - - 8 - IntegerLittleEndian - Ability - - - C1Header 28 diff --git a/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs b/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs index 8f55d24bb..10192f384 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs +++ b/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs @@ -8668,28 +8668,28 @@ public ushort Shield /// -/// Is sent by the server when: Periodically, or if the current health or shield changed on the server side, e.g. by hits. +/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. /// -public readonly ref struct CurrentHealthAndShieldExtendedRef +public readonly ref struct MaximumHealthAndShieldRef { private readonly Span _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public CurrentHealthAndShieldExtendedRef(Span data) + public MaximumHealthAndShieldRef(Span data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentHealthAndShieldExtendedRef(Span data, bool initialize) + private MaximumHealthAndShieldRef(Span data, bool initialize) { this._data = data; if (initialize) @@ -8716,12 +8716,12 @@ private CurrentHealthAndShieldExtendedRef(Span data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFF; + public static byte SubCode => 0xFE; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 9; /// /// Gets the header of this packet. @@ -8731,60 +8731,60 @@ private CurrentHealthAndShieldExtendedRef(Span data, bool initialize) /// /// Gets or sets the health. /// - public uint Health + public ushort Health { - get => ReadUInt32LittleEndian(this._data[4..]); - set => WriteUInt32LittleEndian(this._data[4..], value); + get => ReadUInt16BigEndian(this._data[4..]); + set => WriteUInt16BigEndian(this._data[4..], value); } /// /// Gets or sets the shield. /// - public uint Shield + public ushort Shield { - get => ReadUInt32LittleEndian(this._data[8..]); - set => WriteUInt32LittleEndian(this._data[8..], value); + get => ReadUInt16BigEndian(this._data[7..]); + set => WriteUInt16BigEndian(this._data[7..], value); } /// - /// Performs an implicit conversion from a Span of bytes to a . + /// Performs an implicit conversion from a Span of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator CurrentHealthAndShieldExtendedRef(Span packet) => new (packet, false); + public static implicit operator MaximumHealthAndShieldRef(Span packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Span of bytes. + /// Performs an implicit conversion from to a Span of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Span(CurrentHealthAndShieldExtendedRef packet) => packet._data; + public static implicit operator Span(MaximumHealthAndShieldRef packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly ref struct MaximumHealthAndShieldRef +public readonly ref struct CurrentStatsExtendedRef { private readonly Span _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShieldRef(Span data) + public CurrentStatsExtendedRef(Span data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShieldRef(Span data, bool initialize) + private CurrentStatsExtendedRef(Span data, bool initialize) { this._data = data; if (initialize) @@ -8811,12 +8811,12 @@ private MaximumHealthAndShieldRef(Span data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFE; + public static byte SubCode => 0xFF; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 9; + public static int Length => 24; /// /// Gets the header of this packet. @@ -8826,60 +8826,96 @@ private MaximumHealthAndShieldRef(Span data, bool initialize) /// /// Gets or sets the health. /// - public ushort Health + public uint Health { - get => ReadUInt16BigEndian(this._data[4..]); - set => WriteUInt16BigEndian(this._data[4..], value); + get => ReadUInt32LittleEndian(this._data[4..]); + set => WriteUInt32LittleEndian(this._data[4..], value); } /// /// Gets or sets the shield. /// - public ushort Shield + public uint Shield { - get => ReadUInt16BigEndian(this._data[7..]); - set => WriteUInt16BigEndian(this._data[7..], value); + get => ReadUInt32LittleEndian(this._data[8..]); + set => WriteUInt32LittleEndian(this._data[8..], value); } /// - /// Performs an implicit conversion from a Span of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data[12..]); + set => WriteUInt32LittleEndian(this._data[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data[16..]); + set => WriteUInt32LittleEndian(this._data[16..], value); + } + + /// + /// Gets or sets the attack speed. + /// + public ushort AttackSpeed + { + get => ReadUInt16LittleEndian(this._data[20..]); + set => WriteUInt16LittleEndian(this._data[20..], value); + } + + /// + /// Gets or sets the magic speed. + /// + public ushort MagicSpeed + { + get => ReadUInt16LittleEndian(this._data[22..]); + set => WriteUInt16LittleEndian(this._data[22..], value); + } + + /// + /// Performs an implicit conversion from a Span of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShieldRef(Span packet) => new (packet, false); + public static implicit operator CurrentStatsExtendedRef(Span packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Span of bytes. + /// Performs an implicit conversion from to a Span of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Span(MaximumHealthAndShieldRef packet) => packet._data; + public static implicit operator Span(CurrentStatsExtendedRef packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly ref struct MaximumHealthAndShieldExtendedRef +public readonly ref struct MaximumStatsExtendedRef { private readonly Span _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShieldExtendedRef(Span data) + public MaximumStatsExtendedRef(Span data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShieldExtendedRef(Span data, bool initialize) + private MaximumStatsExtendedRef(Span data, bool initialize) { this._data = data; if (initialize) @@ -8911,7 +8947,7 @@ private MaximumHealthAndShieldExtendedRef(Span data, bool initialize) /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 20; /// /// Gets the header of this packet. @@ -8937,18 +8973,36 @@ public uint Shield } /// - /// Performs an implicit conversion from a Span of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data[12..]); + set => WriteUInt32LittleEndian(this._data[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data[16..]); + set => WriteUInt32LittleEndian(this._data[16..], value); + } + + /// + /// Performs an implicit conversion from a Span of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShieldExtendedRef(Span packet) => new (packet, false); + public static implicit operator MaximumStatsExtendedRef(Span packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Span of bytes. + /// Performs an implicit conversion from to a Span of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Span(MaximumHealthAndShieldExtendedRef packet) => packet._data; + public static implicit operator Span(MaximumStatsExtendedRef packet) => packet._data; } @@ -9237,101 +9291,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The currently available mana or ability has changed, e.g. by using a skill. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly ref struct CurrentManaAndAbilityExtendedRef -{ - private readonly Span _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public CurrentManaAndAbilityExtendedRef(Span data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentManaAndAbilityExtendedRef(Span data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFF; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCodeRef Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data[4..]); - set => WriteUInt32LittleEndian(this._data[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data[8..]); - set => WriteUInt32LittleEndian(this._data[8..], value); - } - - /// - /// Performs an implicit conversion from a Span of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator CurrentManaAndAbilityExtendedRef(Span packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Span of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Span(CurrentManaAndAbilityExtendedRef packet) => packet._data; -} - - /// /// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. @@ -9427,101 +9386,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly ref struct MaximumManaAndAbilityExtendedRef -{ - private readonly Span _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public MaximumManaAndAbilityExtendedRef(Span data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumManaAndAbilityExtendedRef(Span data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFE; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCodeRef Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data[4..]); - set => WriteUInt32LittleEndian(this._data[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data[8..]); - set => WriteUInt32LittleEndian(this._data[8..], value); - } - - /// - /// Performs an implicit conversion from a Span of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator MaximumManaAndAbilityExtendedRef(Span packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Span of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Span(MaximumManaAndAbilityExtendedRef packet) => packet._data; -} - - /// /// Is sent by the server when: The item has been removed from the inventory of the player. /// Causes reaction on client side: The client removes the item in the inventory user interface.