From fb3f6fa80f0d6eb25dd27e880666bcbe1cbb7129 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 9 Nov 2022 07:34:07 +1100 Subject: [PATCH] Predicted stamina (#12413) * Predicted stamina Needed to do some semblence of predicted melee. * Okay now done. * Pause support * Comment --- .../Abilities/Boxer/BoxingSystem.cs | 4 +- .../Atmos/EntitySystems/FlammableSystem.cs | 2 +- .../EntitySystems/ChemistrySystemHypospray.cs | 1 - Content.Server/Contests/ContestsSystem.cs | 1 + Content.Server/Flash/FlashSystem.cs | 2 +- Content.Server/Hands/Systems/HandsSystem.cs | 1 + .../Stunnable/Systems/StunbatonSystem.cs | 12 +- Content.Server/Tools/ToolSystem.Welder.cs | 2 +- .../Melee/EnergySword/EnergySwordSystem.cs | 2 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 2 +- .../Weapons/Ranged/Systems/GunSystem.cs | 1 + Content.Server/Wieldable/WieldableSystem.cs | 2 +- Content.Server/Zombies/ZombieSystem.cs | 2 +- .../CombatMode/DisarmedEvent.cs | 2 +- .../Components/ActiveStaminaComponent.cs | 2 +- .../Damage/Components/StaminaComponent.cs | 13 +- .../StaminaDamageOnCollideComponent.cs | 4 +- .../Components/StaminaDamageOnHitComponent.cs | 4 +- .../Events/StaminaDamageOnHitAttemptEvent.cs | 8 +- .../Damage/Events/StaminaMeleeHitEvent.cs | 11 +- .../Damage/Systems/StaminaSystem.cs | 160 ++++++++++++------ .../Weapons/Melee/Events/MeleeHitEvent.cs | 2 +- .../Weapons/Melee/SharedMeleeWeaponSystem.cs | 3 - 23 files changed, 148 insertions(+), 95 deletions(-) rename {Content.Server => Content.Shared}/CombatMode/DisarmedEvent.cs (93%) rename {Content.Server => Content.Shared}/Damage/Components/ActiveStaminaComponent.cs (81%) rename {Content.Server => Content.Shared}/Damage/Components/StaminaComponent.cs (71%) rename {Content.Server => Content.Shared}/Damage/Components/StaminaDamageOnCollideComponent.cs (77%) rename {Content.Server => Content.Shared}/Damage/Components/StaminaDamageOnHitComponent.cs (71%) rename {Content.Server => Content.Shared}/Damage/Events/StaminaDamageOnHitAttemptEvent.cs (54%) rename {Content.Server => Content.Shared}/Damage/Events/StaminaMeleeHitEvent.cs (73%) rename {Content.Server => Content.Shared}/Damage/Systems/StaminaSystem.cs (65%) rename {Content.Server => Content.Shared}/Weapons/Melee/Events/MeleeHitEvent.cs (97%) diff --git a/Content.Server/Abilities/Boxer/BoxingSystem.cs b/Content.Server/Abilities/Boxer/BoxingSystem.cs index 6c046bda9b..031c248a65 100644 --- a/Content.Server/Abilities/Boxer/BoxingSystem.cs +++ b/Content.Server/Abilities/Boxer/BoxingSystem.cs @@ -1,6 +1,6 @@ -using Content.Server.Damage.Events; -using Content.Server.Weapons.Melee.Events; +using Content.Shared.Damage.Events; using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Containers; namespace Content.Server.Abilities.Boxer diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index 7ebfe542d9..ec0087845b 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -3,7 +3,6 @@ using Content.Server.Atmos.Components; using Content.Server.Stunnable; using Content.Server.Temperature.Components; using Content.Server.Temperature.Systems; -using Content.Server.Weapons.Melee.Events; using Content.Shared.ActionBlocker; using Content.Shared.Alert; using Content.Shared.Atmos; @@ -14,6 +13,7 @@ using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Rejuvenate; using Content.Shared.Temperature; +using Content.Shared.Weapons.Melee.Events; using Robust.Server.GameObjects; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs index 7bcc39a59a..67ced4ede8 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs @@ -1,6 +1,5 @@ using System.Linq; using Content.Server.Chemistry.Components; -using Content.Server.Weapons.Melee.Events; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Weapons.Melee; diff --git a/Content.Server/Contests/ContestsSystem.cs b/Content.Server/Contests/ContestsSystem.cs index 4eaa524df0..01b6ac7a88 100644 --- a/Content.Server/Contests/ContestsSystem.cs +++ b/Content.Server/Contests/ContestsSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Damage; using Content.Shared.MobState.EntitySystems; using Content.Shared.MobState.Components; using Content.Server.Damage.Components; +using Content.Shared.Damage.Components; using Robust.Shared.Physics.Components; namespace Content.Server.Contests diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index c2bf86ef55..9db372aa8a 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Flash.Components; using Content.Server.Light.EntitySystems; using Content.Server.Stunnable; -using Content.Server.Weapons.Melee.Events; using Content.Shared.Examine; using Content.Shared.Flash; using Content.Shared.IdentityManagement; @@ -11,6 +10,7 @@ using Content.Shared.Inventory; using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Tag; +using Content.Shared.Weapons.Melee.Events; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Player; diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index e7bdc1b113..71c4dea9ab 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -10,6 +10,7 @@ using Content.Server.Storage.EntitySystems; using Content.Server.Strip; using Content.Server.Stunnable; using Content.Shared.ActionBlocker; +using Content.Shared.CombatMode; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; diff --git a/Content.Server/Stunnable/Systems/StunbatonSystem.cs b/Content.Server/Stunnable/Systems/StunbatonSystem.cs index eabe7beca0..b8581c2af7 100644 --- a/Content.Server/Stunnable/Systems/StunbatonSystem.cs +++ b/Content.Server/Stunnable/Systems/StunbatonSystem.cs @@ -1,24 +1,16 @@ -using System.Linq; -using Content.Server.Damage.Components; -using Content.Server.Damage.Events; using Content.Server.Power.Components; using Content.Server.Power.Events; -using Content.Server.Speech.EntitySystems; using Content.Server.Stunnable.Components; -using Content.Server.Weapons.Melee.Events; using Content.Shared.Audio; +using Content.Shared.Damage.Events; using Content.Shared.Examine; using Content.Shared.Interaction.Events; using Content.Shared.Item; -using Content.Shared.Jittering; using Content.Shared.Popups; -using Content.Shared.StatusEffect; -using Content.Shared.Throwing; using Content.Shared.Toggleable; -using Robust.Server.GameObjects; +using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio; using Robust.Shared.Player; -using Robust.Shared.Random; namespace Content.Server.Stunnable.Systems { diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs index 6a74b443d8..73282b6143 100644 --- a/Content.Server/Tools/ToolSystem.Welder.cs +++ b/Content.Server/Tools/ToolSystem.Welder.cs @@ -3,7 +3,6 @@ using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; using Content.Server.Tools.Components; -using Content.Server.Weapons.Melee.Events; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Interaction; @@ -11,6 +10,7 @@ using Content.Shared.Item; using Content.Shared.Temperature; using Content.Shared.Toggleable; using Content.Shared.Tools.Components; +using Content.Shared.Weapons.Melee.Events; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.GameStates; diff --git a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs index bd27330920..0caa21a4ef 100644 --- a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs +++ b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs @@ -1,7 +1,6 @@ using Content.Server.CombatMode.Disarm; using Content.Server.Kitchen.Components; using Content.Server.Weapons.Melee.EnergySword.Components; -using Content.Server.Weapons.Melee.Events; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Item; @@ -11,6 +10,7 @@ using Content.Shared.Temperature; using Content.Shared.Toggleable; using Content.Shared.Tools.Components; using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Random; diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index b00b919ea7..6d210e93f6 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -14,9 +14,9 @@ using Content.Server.Examine; using Content.Server.Hands.Components; using Content.Server.Movement.Systems; using Content.Server.Weapons.Melee.Components; -using Content.Server.Weapons.Melee.Events; using Content.Shared.CombatMode; using Content.Shared.Damage; +using Content.Shared.Damage.Systems; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.IdentityManagement; diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 783c903043..445c4b68c9 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -9,6 +9,7 @@ using Content.Server.Stunnable; using Content.Server.Weapons.Melee; using Content.Server.Weapons.Ranged.Components; using Content.Shared.Damage; +using Content.Shared.Damage.Systems; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Weapons.Melee; diff --git a/Content.Server/Wieldable/WieldableSystem.cs b/Content.Server/Wieldable/WieldableSystem.cs index 9fb04f81ae..40259867b3 100644 --- a/Content.Server/Wieldable/WieldableSystem.cs +++ b/Content.Server/Wieldable/WieldableSystem.cs @@ -11,7 +11,7 @@ using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Shared.Player; using Content.Server.Actions.Events; -using Content.Server.Weapons.Melee.Events; +using Content.Shared.Weapons.Melee.Events; namespace Content.Server.Wieldable diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index 8e0cfe83a9..76267b7e11 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -12,9 +12,9 @@ using Content.Server.Inventory; using Robust.Shared.Prototypes; using Content.Server.Speech; using Content.Server.Chat.Systems; -using Content.Server.Weapons.Melee.Events; using Content.Shared.Movement.Systems; using Content.Shared.Damage; +using Content.Shared.Weapons.Melee.Events; using Content.Shared.Zombies; namespace Content.Server.Zombies diff --git a/Content.Server/CombatMode/DisarmedEvent.cs b/Content.Shared/CombatMode/DisarmedEvent.cs similarity index 93% rename from Content.Server/CombatMode/DisarmedEvent.cs rename to Content.Shared/CombatMode/DisarmedEvent.cs index 8d3e3fdc74..653529fe02 100644 --- a/Content.Server/CombatMode/DisarmedEvent.cs +++ b/Content.Shared/CombatMode/DisarmedEvent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.CombatMode +namespace Content.Shared.CombatMode { public sealed class DisarmedEvent : HandledEntityEventArgs { diff --git a/Content.Server/Damage/Components/ActiveStaminaComponent.cs b/Content.Shared/Damage/Components/ActiveStaminaComponent.cs similarity index 81% rename from Content.Server/Damage/Components/ActiveStaminaComponent.cs rename to Content.Shared/Damage/Components/ActiveStaminaComponent.cs index 073d394728..35d21a0253 100644 --- a/Content.Server/Damage/Components/ActiveStaminaComponent.cs +++ b/Content.Shared/Damage/Components/ActiveStaminaComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Damage.Components; +namespace Content.Shared.Damage.Components; /// /// Tracks whether an entity has ANY stamina damage for update purposes only. diff --git a/Content.Server/Damage/Components/StaminaComponent.cs b/Content.Shared/Damage/Components/StaminaComponent.cs similarity index 71% rename from Content.Server/Damage/Components/StaminaComponent.cs rename to Content.Shared/Damage/Components/StaminaComponent.cs index 87e881016b..48bd01427a 100644 --- a/Content.Server/Damage/Components/StaminaComponent.cs +++ b/Content.Shared/Damage/Components/StaminaComponent.cs @@ -1,12 +1,13 @@ -using Content.Server.Damage.Systems; using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.Damage.Components; +namespace Content.Shared.Damage.Components; /// /// Add to an entity to paralyze it whenever it reaches critical amounts of Stamina DamageType. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent] public sealed class StaminaComponent : Component { /// @@ -40,8 +41,8 @@ public sealed class StaminaComponent : Component public float CritThreshold = 100f; /// - /// Next time we're allowed to decrease stamina damage. Refreshes whenever the stam damage is changed. + /// To avoid continuously updating our data we track the last time we updated so we can extrapolate our current stamina. /// - [ViewVariables(VVAccess.ReadWrite), DataField("decayAccumulator")] - public float StaminaDecayAccumulator; + [ViewVariables, DataField("lastUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate = TimeSpan.Zero; } diff --git a/Content.Server/Damage/Components/StaminaDamageOnCollideComponent.cs b/Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs similarity index 77% rename from Content.Server/Damage/Components/StaminaDamageOnCollideComponent.cs rename to Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs index 450fb56aab..1cb37e44b0 100644 --- a/Content.Server/Damage/Components/StaminaDamageOnCollideComponent.cs +++ b/Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs @@ -1,6 +1,4 @@ -using Robust.Shared.GameStates; - -namespace Content.Server.Damage.Components; +namespace Content.Shared.Damage.Components; /// /// Applies stamina damage when colliding with an entity. diff --git a/Content.Server/Damage/Components/StaminaDamageOnHitComponent.cs b/Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs similarity index 71% rename from Content.Server/Damage/Components/StaminaDamageOnHitComponent.cs rename to Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs index 88e92c6175..94fc40d112 100644 --- a/Content.Server/Damage/Components/StaminaDamageOnHitComponent.cs +++ b/Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs @@ -1,6 +1,4 @@ -using Robust.Shared.Audio; - -namespace Content.Server.Damage.Components; +namespace Content.Shared.Damage.Components; [RegisterComponent] public sealed class StaminaDamageOnHitComponent : Component diff --git a/Content.Server/Damage/Events/StaminaDamageOnHitAttemptEvent.cs b/Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs similarity index 54% rename from Content.Server/Damage/Events/StaminaDamageOnHitAttemptEvent.cs rename to Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs index a6e10b4172..9c9a587320 100644 --- a/Content.Server/Damage/Events/StaminaDamageOnHitAttemptEvent.cs +++ b/Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs @@ -1,6 +1,6 @@ using Robust.Shared.Audio; -namespace Content.Server.Damage.Events; +namespace Content.Shared.Damage.Events; /// /// Attempting to apply stamina damage on a melee hit to an entity. @@ -10,4 +10,10 @@ public struct StaminaDamageOnHitAttemptEvent { public bool Cancelled; public SoundSpecifier? HitSoundOverride; + + public StaminaDamageOnHitAttemptEvent(bool cancelled, SoundSpecifier? hitSoundOverride) + { + Cancelled = cancelled; + HitSoundOverride = hitSoundOverride; + } } diff --git a/Content.Server/Damage/Events/StaminaMeleeHitEvent.cs b/Content.Shared/Damage/Events/StaminaMeleeHitEvent.cs similarity index 73% rename from Content.Server/Damage/Events/StaminaMeleeHitEvent.cs rename to Content.Shared/Damage/Events/StaminaMeleeHitEvent.cs index e6a53d4466..39fe65c07b 100644 --- a/Content.Server/Damage/Events/StaminaMeleeHitEvent.cs +++ b/Content.Shared/Damage/Events/StaminaMeleeHitEvent.cs @@ -1,7 +1,7 @@ +using Content.Shared.Damage.Components; using Robust.Shared.Collections; -using Content.Server.Damage.Components; -namespace Content.Server.Damage.Events; +namespace Content.Shared.Damage.Events; /// /// The components in the list are going to be hit, @@ -11,9 +11,10 @@ public sealed class StaminaMeleeHitEvent : HandledEntityEventArgs { /// /// List of hit stamina components. - public ValueList HitList; + /// + public List HitList; - /// + /// /// The multiplier. Generally, try to use *= or /= instead of overwriting. /// public float Multiplier = 1; @@ -23,7 +24,7 @@ public sealed class StaminaMeleeHitEvent : HandledEntityEventArgs /// public float FlatModifier = 0; - public StaminaMeleeHitEvent(ValueList hitList) + public StaminaMeleeHitEvent(List hitList) { HitList = hitList; } diff --git a/Content.Server/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs similarity index 65% rename from Content.Server/Damage/Systems/StaminaSystem.cs rename to Content.Shared/Damage/Systems/StaminaSystem.cs index b7b5969668..fddbde5435 100644 --- a/Content.Server/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -1,59 +1,96 @@ -using Content.Server.Damage.Components; -using Content.Server.Damage.Events; -using Content.Server.Popups; -using Content.Server.Administration.Logs; -using Content.Server.CombatMode; -using Content.Server.Weapons.Melee.Events; +using Content.Shared.Administration.Logs; using Content.Shared.Alert; -using Content.Shared.Rounding; -using Content.Shared.Stunnable; +using Content.Shared.CombatMode; +using Content.Shared.Damage.Components; +using Content.Shared.Damage.Events; using Content.Shared.Database; using Content.Shared.IdentityManagement; using Content.Shared.Popups; -using Robust.Shared.Collections; -using Robust.Shared.Physics.Dynamics; -using Robust.Shared.Player; -using Robust.Shared.Timing; -using Robust.Shared.Audio; -using Robust.Shared.Random; +using Content.Shared.Rounding; +using Content.Shared.Stunnable; +using Content.Shared.Weapons.Melee.Events; +using JetBrains.Annotations; +using Robust.Shared.GameStates; using Robust.Shared.Physics.Events; +using Robust.Shared.Player; +using Robust.Shared.Random; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; - -namespace Content.Server.Damage.Systems; +namespace Content.Shared.Damage.Systems; public sealed class StaminaSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly AlertsSystem _alerts = default!; - [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly MetaDataSystem _metadata = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; - - private const float UpdateCooldown = 2f; - private float _accumulator; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; private const string CollideFixture = "projectile"; /// /// How much of a buffer is there between the stun duration and when stuns can be re-applied. /// - private const float StamCritBufferTime = 3f; - - private readonly List _dirtyEntities = new(); + private static readonly TimeSpan StamCritBufferTime = TimeSpan.FromSeconds(3f); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnStamGetState); + SubscribeLocalEvent(OnStamHandleState); SubscribeLocalEvent(OnDisarmed); SubscribeLocalEvent(OnCollide); SubscribeLocalEvent(OnHit); } + private void OnStamGetState(EntityUid uid, StaminaComponent component, ref ComponentGetState args) + { + args.State = new StaminaComponentState() + { + Critical = component.Critical, + Decay = component.Decay, + CritThreshold = component.CritThreshold, + DecayCooldown = component.DecayCooldown, + LastUpdate = component.NextUpdate, + StaminaDamage = component.StaminaDamage, + }; + } + + private void OnStamHandleState(EntityUid uid, StaminaComponent component, ref ComponentHandleState args) + { + if (args.Current is not StaminaComponentState state) + return; + + component.Critical = state.Critical; + component.Decay = state.Decay; + component.CritThreshold = state.CritThreshold; + component.DecayCooldown = state.DecayCooldown; + component.NextUpdate = state.LastUpdate; + component.StaminaDamage = state.StaminaDamage; + + if (component.Critical) + EnterStamCrit(uid, component); + else + { + if (component.StaminaDamage > 0f) + EnsureComp(uid); + + ExitStamCrit(uid, component); + } + } + private void OnShutdown(EntityUid uid, StaminaComponent component, ComponentShutdown args) { + if (MetaData(uid).EntityLifeStage < EntityLifeStage.Terminating) + { + RemCompDeferred(uid); + } + SetStaminaAlert(uid); } @@ -62,6 +99,17 @@ public sealed class StaminaSystem : EntitySystem SetStaminaAlert(uid, component); } + [PublicAPI] + public float GetStaminaDamage(EntityUid uid, StaminaComponent? component = null) + { + if (!Resolve(uid, ref component)) + return 0f; + + var curTime = _timing.CurTime; + var pauseTime = _metadata.GetPauseTime(uid); + return MathF.Max(0f, component.StaminaDamage - MathF.Max(0f, (float) (curTime - (component.NextUpdate + pauseTime)).TotalSeconds * component.Decay)); + } + private void OnDisarmed(EntityUid uid, StaminaComponent component, DisarmedEvent args) { if (args.Handled || !_random.Prob(args.PushProbability)) @@ -102,7 +150,7 @@ public sealed class StaminaSystem : EntitySystem args.HitSoundOverride = ev.HitSoundOverride; var stamQuery = GetEntityQuery(); - var toHit = new ValueList(); + var toHit = new List(); // Split stamina damage between all eligible targets. foreach (var ent in args.HitEntities) @@ -155,7 +203,8 @@ public sealed class StaminaSystem : EntitySystem public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? component = null) { - if (!Resolve(uid, ref component, false) || component.Critical) return; + if (!Resolve(uid, ref component, false) || component.Critical) + return; var oldDamage = component.StaminaDamage; component.StaminaDamage = MathF.Max(0f, component.StaminaDamage + value); @@ -163,7 +212,10 @@ public sealed class StaminaSystem : EntitySystem // Reset the decay cooldown upon taking damage. if (oldDamage < component.StaminaDamage) { - component.StaminaDecayAccumulator = component.DecayCooldown; + var nextUpdate = _timing.CurTime + TimeSpan.FromSeconds(component.DecayCooldown); + + if (component.NextUpdate < nextUpdate) + component.NextUpdate = nextUpdate; } var slowdownThreshold = component.CritThreshold / 2f; @@ -177,9 +229,6 @@ public sealed class StaminaSystem : EntitySystem SetStaminaAlert(uid, component); - // Can't do it here as resetting prediction gets cooked. - _dirtyEntities.Add(uid); - if (!component.Critical) { if (component.StaminaDamage >= component.CritThreshold) @@ -194,6 +243,9 @@ public sealed class StaminaSystem : EntitySystem ExitStamCrit(uid, component); } } + + EnsureComp(uid); + Dirty(component); } public override void Update(float frameTime) @@ -202,35 +254,25 @@ public sealed class StaminaSystem : EntitySystem if (!_timing.IsFirstTimePredicted) return; - _accumulator -= frameTime; - - if (_accumulator > 0f) return; - + var metaQuery = GetEntityQuery(); var stamQuery = GetEntityQuery(); - - foreach (var uid in _dirtyEntities) - { - // Don't need to RemComp as they will get handled below. - if (!stamQuery.TryGetComponent(uid, out var comp) || comp.StaminaDamage <= 0f) continue; - EnsureComp(uid); - } - - _dirtyEntities.Clear(); - _accumulator += UpdateCooldown; + var curTime = _timing.CurTime; foreach (var active in EntityQuery()) { // Just in case we have active but not stamina we'll check and account for it. if (!stamQuery.TryGetComponent(active.Owner, out var comp) || - comp.StaminaDamage <= 0f) + comp.StaminaDamage <= 0f && !comp.Critical) { RemComp(active.Owner); continue; } - comp.StaminaDecayAccumulator -= UpdateCooldown; + // Shouldn't need to consider paused time as we're only iterating non-paused stamina components. + var nextUpdate = comp.NextUpdate; - if (comp.StaminaDecayAccumulator > 0f) continue; + if (nextUpdate > curTime) + continue; // We were in crit so come out of it and continue. if (comp.Critical) @@ -239,8 +281,9 @@ public sealed class StaminaSystem : EntitySystem continue; } - comp.StaminaDecayAccumulator = 0f; - TakeStaminaDamage(comp.Owner, -comp.Decay * UpdateCooldown, comp); + comp.NextUpdate += TimeSpan.FromSeconds(1f); + TakeStaminaDamage(comp.Owner, -comp.Decay, comp); + Dirty(comp); } } @@ -254,13 +297,14 @@ public sealed class StaminaSystem : EntitySystem component.Critical = true; component.StaminaDamage = component.CritThreshold; - component.StaminaDecayAccumulator = 0f; var stunTime = TimeSpan.FromSeconds(6); _stunSystem.TryParalyze(uid, stunTime, true); // Give them buffer before being able to be re-stunned - component.StaminaDecayAccumulator = (float) stunTime.TotalSeconds + StamCritBufferTime; + component.NextUpdate = _timing.CurTime + stunTime + StamCritBufferTime; + EnsureComp(uid); + Dirty(component); } private void ExitStamCrit(EntityUid uid, StaminaComponent? component = null) @@ -270,6 +314,20 @@ public sealed class StaminaSystem : EntitySystem component.Critical = false; component.StaminaDamage = 0f; + component.NextUpdate = _timing.CurTime; SetStaminaAlert(uid, component); + RemComp(uid); + Dirty(component); + } + + [Serializable, NetSerializable] + private sealed class StaminaComponentState : ComponentState + { + public bool Critical; + public float Decay; + public float DecayCooldown; + public float StaminaDamage; + public float CritThreshold; + public TimeSpan LastUpdate; } } diff --git a/Content.Server/Weapons/Melee/Events/MeleeHitEvent.cs b/Content.Shared/Weapons/Melee/Events/MeleeHitEvent.cs similarity index 97% rename from Content.Server/Weapons/Melee/Events/MeleeHitEvent.cs rename to Content.Shared/Weapons/Melee/Events/MeleeHitEvent.cs index 1c16315c26..2b80cff7a1 100644 --- a/Content.Server/Weapons/Melee/Events/MeleeHitEvent.cs +++ b/Content.Shared/Weapons/Melee/Events/MeleeHitEvent.cs @@ -1,7 +1,7 @@ using Content.Shared.Damage; using Robust.Shared.Audio; -namespace Content.Server.Weapons.Melee.Events; +namespace Content.Shared.Weapons.Melee.Events; /// /// Raised directed on the melee weapon entity used to attack something in combat mode, diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index e9ddca6638..6d61fefd32 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -1,11 +1,8 @@ using Content.Shared.ActionBlocker; -using Content.Shared.Clothing.Components; using Content.Shared.CombatMode; using Content.Shared.Hands; using Content.Shared.Hands.Components; -using Content.Shared.Interaction.Events; using Content.Shared.Inventory; -using Content.Shared.Inventory.Events; using Content.Shared.Popups; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.GameStates;