Skip to content

Commit

Permalink
Refactored stats updates and consolidated extended messages
Browse files Browse the repository at this point in the history
  • Loading branch information
sven-n committed Oct 17, 2024
1 parent aff8615 commit 7fb2294
Show file tree
Hide file tree
Showing 31 changed files with 544 additions and 1,103 deletions.
Original file line number Diff line number Diff line change
@@ -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 |
| 8 | 4 | IntegerLittleEndian | | Shield |
| 12 | 4 | IntegerLittleEndian | | Mana |
| 16 | 4 | IntegerLittleEndian | | Ability |
20 changes: 0 additions & 20 deletions docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md

This file was deleted.

24 changes: 24 additions & 0 deletions docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md
Original file line number Diff line number Diff line change
@@ -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 |
20 changes: 0 additions & 20 deletions docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md

This file was deleted.

20 changes: 0 additions & 20 deletions docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md

This file was deleted.

6 changes: 2 additions & 4 deletions docs/Packets/ServerToClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 5 additions & 6 deletions src/GameLogic/AttackableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,13 @@ public static async ValueTask ApplyRegenerationAsync(this IAttackable target, Pl

if (target is IWorldObserver observer)
{
if (isHealthUpdated)
{
await observer.InvokeViewPlugInAsync<IUpdateCurrentHealthPlugIn>(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<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await observer.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(updatedStats)).ConfigureAwait(false);
}
}
}
Expand Down
38 changes: 27 additions & 11 deletions src/GameLogic/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace MUnique.OpenMU.GameLogic;

using System;
using System.Threading;
using MUnique.OpenMU.AttributeSystem;
using MUnique.OpenMU.DataModel.Attributes;
Expand All @@ -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;

/// <summary>
/// The base implementation of a player.
Expand Down Expand Up @@ -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<IUpdateCurrentHealthPlugIn>(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(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<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false);
}

await this.HitAsync(hitInfo, attacker, skill?.Skill).ConfigureAwait(false);
Expand Down Expand Up @@ -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<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateCurrentHealthPlugIn>(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync()).ConfigureAwait(false);
}

/// <summary>
Expand Down Expand Up @@ -1224,8 +1225,7 @@ public async Task RegenerateAsync()
attributes[r.MaximumAttribute]);
}

await this.InvokeViewPlugInAsync<IUpdateCurrentHealthPlugIn>(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync()).ConfigureAwait(false);

await this.RegenerateHeroStateAsync().ConfigureAwait(false);
}
Expand Down Expand Up @@ -1334,7 +1334,8 @@ public async ValueTask<bool> TryConsumeForSkillAsync(Skill skill)
this.Attributes![requirement.Attribute] -= this.GetRequiredValue(requirement);
}

await this.InvokeViewPlugInAsync<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false);

return true;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<IUpdateMaximumHealthPlugIn>(p => p.UpdateMaximumHealthAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateCurrentHealthPlugIn>(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false);

await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateMaximumStatsAsync(UpdatedStats.Health)).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(UpdatedStats.Health)).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -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<IUpdateMaximumManaPlugIn>(p => p.UpdateMaximumManaAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateMaximumStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false);
await this.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(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<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(UpdatedStats.Speed)).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public override async ValueTask<bool> ConsumeItemAsync(Player player, Item item,
if (await base.ConsumeItemAsync(player, item, targetItem, fruitUsage).ConfigureAwait(false))
{
await player.InvokeViewPlugInAsync<IDrinkAlcoholPlugIn>(p => p.DrinkAlcoholAsync()).ConfigureAwait(false);
// todo: add magic effect to update stat
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IUpdateCurrentHealthPlugIn>(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false);
await player.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Health)).ConfigureAwait(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public abstract class ManaPotionConsumeHandler : RecoverConsumeHandlerPlugIn.Man
/// <inheritdoc />
protected override async ValueTask OnAfterRecoverAsync(Player player)
{
await player.InvokeViewPlugInAsync<IUpdateCurrentManaPlugIn>(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false);
await player.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Mana)).ConfigureAwait(false);
}
}
2 changes: 1 addition & 1 deletion src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IUpdateCurrentHealthPlugIn>(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false);
await attackerPlayer.InvokeViewPlugInAsync<IUpdateStatsPlugIn>(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Health)).ConfigureAwait(false);
}
}
}
Expand Down
16 changes: 0 additions & 16 deletions src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs

This file was deleted.

16 changes: 0 additions & 16 deletions src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs

This file was deleted.

16 changes: 0 additions & 16 deletions src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs

This file was deleted.

16 changes: 0 additions & 16 deletions src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs

This file was deleted.

Loading

0 comments on commit 7fb2294

Please sign in to comment.