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!;