diff --git a/Content.Shared/Damage/Components/DamageableComponent.cs b/Content.Shared/Damage/Components/DamageableComponent.cs index 428d2aa9cd..00fbcda561 100644 --- a/Content.Shared/Damage/Components/DamageableComponent.cs +++ b/Content.Shared/Damage/Components/DamageableComponent.cs @@ -17,7 +17,7 @@ namespace Content.Shared.Damage.Components; /// may also have resistances to certain damage types, defined via a . /// [RegisterComponent] -[NetworkedComponent, AutoGenerateComponentState(true)] +[NetworkedComponent] [Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)] public sealed partial class DamageableComponent : Component { @@ -25,7 +25,7 @@ public sealed partial class DamageableComponent : Component /// This specifies what damage types are supported by this component. /// If null, all damage types will be supported. /// - [DataField("damageContainer"), AutoNetworkedField] + [DataField("damageContainer")] // ReSharper disable once InconsistentNaming - This is wrong but fixing it is potentially annoying for downstreams. public ProtoId? DamageContainerID; @@ -37,7 +37,7 @@ public sealed partial class DamageableComponent : Component /// Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here /// to reduce duplication. /// - [DataField("damageModifierSet"), AutoNetworkedField] + [DataField("damageModifierSet")] public ProtoId? DamageModifierSetId; /// @@ -46,7 +46,7 @@ public sealed partial class DamageableComponent : Component /// /// If this data-field is specified, this allows damageable components to be initialized with non-zero damage. /// - [DataField, AutoNetworkedField] + [DataField] public DamageSpecifier Damage = new(); /// @@ -87,6 +87,20 @@ public sealed partial class DamageableComponent : Component [DataField] public ProtoId RottingIcon = "HealthIconRotting"; - [DataField, AutoNetworkedField] + [DataField] public FixedPoint2? HealthBarThreshold; } + +[Serializable, NetSerializable] +public sealed class DamageableComponentState( + DamageSpecifier damage, + ProtoId? damageContainerId, + ProtoId? modifierSetId, + FixedPoint2? healthBarThreshold) + : ComponentState +{ + public readonly DamageSpecifier Damage = damage; + public readonly ProtoId? DamageContainerId = damageContainerId; + public readonly ProtoId? ModifierSetId = modifierSetId; + public readonly FixedPoint2? HealthBarThreshold = healthBarThreshold; +} diff --git a/Content.Shared/Damage/Systems/DamageableSystem.Events.cs b/Content.Shared/Damage/Systems/DamageableSystem.Events.cs index 78b00f4d56..fcb97763db 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.Events.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.Events.cs @@ -20,7 +20,8 @@ public sealed partial class DamageableSystem SubscribeLocalEvent(DamageableInit); SubscribeLocalEvent(OnIrradiated); SubscribeLocalEvent(OnRejuvenate); - SubscribeLocalEvent(OnAfterAutoHandleState); + SubscribeLocalEvent(DamageableHandleState); + SubscribeLocalEvent(DamageableGetState); _appearanceQuery = GetEntityQuery(); _damageableQuery = GetEntityQuery(); @@ -155,11 +156,6 @@ public sealed partial class DamageableSystem } } - private void OnAfterAutoHandleState(Entity ent, ref AfterAutoHandleStateEvent args) - { - OnEntityDamageChanged(ent); - } - /// /// Initialize a damageable component /// @@ -190,6 +186,37 @@ public sealed partial class DamageableSystem ClearAllDamage(ent.AsNullable()); _mobThreshold.SetAllowRevives(ent, false); } + + private void DamageableGetState(Entity ent, ref ComponentGetState args) + { + args.State = new DamageableComponentState( + _netMan.IsServer ? ent.Comp.Damage : ent.Comp.Damage.Clone(), + ent.Comp.DamageContainerID, + ent.Comp.DamageModifierSetId, + ent.Comp.HealthBarThreshold + ); + } + + private void DamageableHandleState(Entity ent, ref ComponentHandleState args) + { + if (args.Current is not DamageableComponentState state) + return; + + ent.Comp.DamageContainerID = state.DamageContainerId; + ent.Comp.DamageModifierSetId = state.ModifierSetId; + ent.Comp.HealthBarThreshold = state.HealthBarThreshold; + + // Has the damage actually changed? + var delta = state.Damage - ent.Comp.Damage; + delta.TrimZeros(); + + if (delta.Empty) + return; + + ent.Comp.Damage = state.Damage; + + OnEntityDamageChanged(ent, delta); + } } /// diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 8743ec3752..2d707568f0 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -17,6 +17,7 @@ public sealed partial class DamageableSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; [Dependency] private readonly IConfigurationManager _config = default!; [Dependency] private readonly SharedChemistryGuideDataSystem _chemistryGuideData = default!;