From 0b24eb8dded8b7bb4456d595c5f5baacb01ad905 Mon Sep 17 00:00:00 2001 From: Centronias Date: Thu, 24 Oct 2024 14:08:27 -0700 Subject: [PATCH 1/6] reduce network burden of the hunger system --- .../Nutrition/EntitySystems/HungerSystem.cs | 84 ++++++++++--------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index 6196669c1901..e0dc7df3c878 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -54,8 +54,8 @@ public override void Initialize() private void OnMapInit(EntityUid uid, HungerComponent component, MapInitEvent args) { var amount = _random.Next( - (int) component.Thresholds[HungerThreshold.Peckish] + 10, - (int) component.Thresholds[HungerThreshold.Okay]); + (int)component.Thresholds[HungerThreshold.Peckish] + 10, + (int)component.Thresholds[HungerThreshold.Okay]); SetHunger(uid, amount, component); } @@ -81,11 +81,11 @@ private void OnRejuvenate(EntityUid uid, HungerComponent component, RejuvenateEv } /// - /// Adds to the current hunger of an entity by the specified value + /// Adds to the current hunger of an entity by the specified amount. /// - /// - /// - /// + /// The entity whose hunger will be modified + /// The amount by which to modify the entity's hunger + /// The entity's . If null, this function will try to it. public void ModifyHunger(EntityUid uid, float amount, HungerComponent? component = null) { if (!Resolve(uid, ref component)) @@ -94,55 +94,60 @@ public void ModifyHunger(EntityUid uid, float amount, HungerComponent? component } /// - /// Sets the current hunger of an entity to the specified value + /// Sets the current hunger of an entity to the specified value. /// - /// - /// - /// - public void SetHunger(EntityUid uid, float amount, HungerComponent? component = null) + /// The entity whose hunger will be modified + /// The value to set the entity's hunger to + /// The entity's . If null, this function will try to it. + public void SetHunger(EntityUid uid, float value, HungerComponent? component = null) { if (!Resolve(uid, ref component)) return; - component.CurrentHunger = Math.Clamp(amount, - component.Thresholds[HungerThreshold.Dead], - component.Thresholds[HungerThreshold.Overfed]); - UpdateCurrentThreshold(uid, component); + SetHungerInternal((uid, component), value); Dirty(uid, component); } - private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = null) + /// + /// This "overload" avoids dirtying the component, with the + /// intention being that this function is called directly from Update, which is run + /// on both client and server, meaning needless cross-network synchronization is avoided. + /// + private void SetHungerInternal(Entity entity, float value) { - if (!Resolve(uid, ref component)) - return; - - var calculatedHungerThreshold = GetHungerThreshold(component); - if (calculatedHungerThreshold == component.CurrentThreshold) - return; - component.CurrentThreshold = calculatedHungerThreshold; - DoHungerThresholdEffects(uid, component); - Dirty(uid, component); + entity.Comp.CurrentHunger = Math.Clamp(value, + entity.Comp.Thresholds[HungerThreshold.Dead], + entity.Comp.Thresholds[HungerThreshold.Overfed]); + UpdateCurrentThreshold(entity); } - private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component = null, bool force = false) + private void UpdateCurrentThreshold(Entity entity) { - if (!Resolve(uid, ref component)) + var calculatedHungerThreshold = GetHungerThreshold(entity.Comp); + if (calculatedHungerThreshold == entity.Comp.CurrentThreshold) return; + entity.Comp.CurrentThreshold = calculatedHungerThreshold; + DoHungerThresholdEffects(entity); + Dirty(entity); + } - if (component.CurrentThreshold == component.LastThreshold && !force) + private void DoHungerThresholdEffects(Entity entity) + { + var component = entity.Comp; + if (component.CurrentThreshold == component.LastThreshold) return; if (GetMovementThreshold(component.CurrentThreshold) != GetMovementThreshold(component.LastThreshold)) { - _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); + _movementSpeedModifier.RefreshMovementSpeedModifiers(entity); } if (component.HungerThresholdAlerts.TryGetValue(component.CurrentThreshold, out var alertId)) { - _alerts.ShowAlert(uid, alertId); + _alerts.ShowAlert(entity, alertId); } else { - _alerts.ClearAlertCategory(uid, component.HungerAlertCategory); + _alerts.ClearAlertCategory(entity, component.HungerAlertCategory); } if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier)) @@ -153,16 +158,13 @@ private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component component.LastThreshold = component.CurrentThreshold; } - private void DoContinuousHungerEffects(EntityUid uid, HungerComponent? component = null) + private void DoContinuousHungerEffects(Entity entity) { - if (!Resolve(uid, ref component)) - return; - - if (component.CurrentThreshold <= HungerThreshold.Starving && - component.StarvationDamage is { } damage && - !_mobState.IsDead(uid)) + if (entity.Comp.CurrentThreshold <= HungerThreshold.Starving && + entity.Comp.StarvationDamage is { } damage && + !_mobState.IsDead(entity)) { - _damageable.TryChangeDamage(uid, damage, true, false); + _damageable.TryChangeDamage(entity, damage, true, false); } } @@ -248,8 +250,8 @@ public override void Update(float frameTime) continue; hunger.NextUpdateTime = _timing.CurTime + hunger.UpdateRate; - ModifyHunger(uid, -hunger.ActualDecayRate, hunger); - DoContinuousHungerEffects(uid, hunger); + SetHungerInternal((uid, hunger), hunger.CurrentHunger - hunger.ActualDecayRate); + DoContinuousHungerEffects((uid, hunger)); } } } From 41c9cb874f8c0ce56e267328d74101a017871dbc Mon Sep 17 00:00:00 2001 From: Centronias Date: Mon, 28 Oct 2024 13:37:30 -0700 Subject: [PATCH 2/6] explicit start + last updated --- .../Animals/Systems/EggLayerSystem.cs | 4 +- .../EffectConditions/TotalHunger.cs | 7 +- .../EntitySystems/FatExtractorSystem.cs | 2 +- Content.Server/RatKing/RatKingSystem.cs | 4 +- .../Nutrition/Components/HungerComponent.cs | 32 +++-- .../Nutrition/EntitySystems/HungerSystem.cs | 127 ++++++++++++------ .../Sericulture/SericultureSystem.cs | 13 +- 7 files changed, 124 insertions(+), 65 deletions(-) diff --git a/Content.Server/Animals/Systems/EggLayerSystem.cs b/Content.Server/Animals/Systems/EggLayerSystem.cs index 55d63808a4b9..727a04746de3 100644 --- a/Content.Server/Animals/Systems/EggLayerSystem.cs +++ b/Content.Server/Animals/Systems/EggLayerSystem.cs @@ -14,7 +14,7 @@ namespace Content.Server.Animals.Systems; /// -/// Gives ability to produce eggs, produces endless if the +/// Gives ability to produce eggs, produces endless if the /// owner has no HungerComponent /// public sealed class EggLayerSystem : EntitySystem @@ -79,7 +79,7 @@ public bool TryLayEgg(EntityUid uid, EggLayerComponent? egglayer) // Allow infinitely laying eggs if they can't get hungry if (TryComp(uid, out var hunger)) { - if (hunger.CurrentHunger < egglayer.HungerUsage) + if (_hunger.GetHunger(hunger) < egglayer.HungerUsage) { _popup.PopupEntity(Loc.GetString("action-popup-lay-egg-too-hungry"), uid, uid); return false; diff --git a/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs b/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs index 84ad4c22403b..72c7ca01ba52 100644 --- a/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs +++ b/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs @@ -1,6 +1,6 @@ using Content.Shared.EntityEffects; using Content.Shared.Nutrition.Components; -using Content.Shared.FixedPoint; +using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.Prototypes; namespace Content.Server.EntityEffects.EffectConditions; @@ -15,9 +15,10 @@ public sealed partial class Hunger : EntityEffectCondition public override bool Condition(EntityEffectBaseArgs args) { - if (args.EntityManager.TryGetComponent(args.TargetEntity, out HungerComponent? hunger)) + if (args.EntityManager.TryGetComponent(args.TargetEntity, out HungerComponent? hunger) && + args.EntityManager.SystemOrNull() is { } hungerSystem) { - var total = hunger.CurrentHunger; + var total = hungerSystem.GetHunger(hunger); if (total > Min && total < Max) return true; } diff --git a/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs b/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs index c91a6f795b2c..6e9856a61dc0 100644 --- a/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs @@ -100,7 +100,7 @@ public bool TryGetValidOccupant(EntityUid uid, [NotNullWhen(true)] out EntityUid if (!TryComp(occupant, out var hunger)) return false; - if (hunger.CurrentHunger < component.NutritionPerSecond) + if (_hunger.GetHunger(hunger) < component.NutritionPerSecond) return false; if (hunger.CurrentThreshold < component.MinHungerThreshold && !HasComp(uid)) diff --git a/Content.Server/RatKing/RatKingSystem.cs b/Content.Server/RatKing/RatKingSystem.cs index 4b82dba33590..01c213d5403e 100644 --- a/Content.Server/RatKing/RatKingSystem.cs +++ b/Content.Server/RatKing/RatKingSystem.cs @@ -47,7 +47,7 @@ private void OnRaiseArmy(EntityUid uid, RatKingComponent component, RatKingRaise return; //make sure the hunger doesn't go into the negatives - if (hunger.CurrentHunger < component.HungerPerArmyUse) + if (_hunger.GetHunger(hunger) < component.HungerPerArmyUse) { _popup.PopupEntity(Loc.GetString("rat-king-too-hungry"), uid, uid); return; @@ -77,7 +77,7 @@ private void OnDomain(EntityUid uid, RatKingComponent component, RatKingDomainAc return; //make sure the hunger doesn't go into the negatives - if (hunger.CurrentHunger < component.HungerPerDomainUse) + if (_hunger.GetHunger(hunger) < component.HungerPerDomainUse) { _popup.PopupEntity(Loc.GetString("rat-king-too-hungry"), uid, uid); return; diff --git a/Content.Shared/Nutrition/Components/HungerComponent.cs b/Content.Shared/Nutrition/Components/HungerComponent.cs index 79d895ddae66..5664e580b0d3 100644 --- a/Content.Shared/Nutrition/Components/HungerComponent.cs +++ b/Content.Shared/Nutrition/Components/HungerComponent.cs @@ -14,22 +14,33 @@ namespace Content.Shared.Nutrition.Components; public sealed partial class HungerComponent : Component { /// - /// The current hunger amount of the entity + /// The hunger value as authoritatively set by the server as of . + /// This value should be updated relatively infrequently. To get the current hunger, which changes with each update, + /// use . /// - [DataField("currentHunger"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] - public float CurrentHunger; + public float LastAuthoritativeHungerValue; /// - /// The base amount at which decays. + /// The time at which was last updated. /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public TimeSpan LastAuthoritativeHungerChangeTime; + + /// + /// The base amount at which decays. + /// + /// Any time this is modified, should be called. [DataField("baseDecayRate"), ViewVariables(VVAccess.ReadWrite)] public float BaseDecayRate = 0.01666666666f; /// - /// The actual amount at which decays. + /// The actual amount at which decays. /// Affected by /// + /// Any time this is modified, should be called. [DataField("actualDecayRate"), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] public float ActualDecayRate; @@ -45,12 +56,13 @@ public sealed partial class HungerComponent : Component /// /// The current hunger threshold the entity is at /// + /// Any time this is modified, should be called. [DataField("currentThreshold"), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] public HungerThreshold CurrentThreshold; /// - /// A dictionary relating HungerThreshold to the amount of needed for each one + /// A dictionary relating HungerThreshold to the amount of current hunger needed for each one /// [DataField("thresholds", customTypeSerializer: typeof(DictionarySerializer))] [AutoNetworkedField] @@ -106,19 +118,19 @@ public sealed partial class HungerComponent : Component public DamageSpecifier? StarvationDamage; /// - /// The time when the hunger will update next. + /// The time when the hunger threshold will update next. /// [DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] [AutoPausedField] - public TimeSpan NextUpdateTime; + public TimeSpan NextThresholdUpdateTime; /// - /// The time between each update. + /// The time between each hunger threshold update. /// [ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] - public TimeSpan UpdateRate = TimeSpan.FromSeconds(1); + public TimeSpan ThresholdUpdateRate = TimeSpan.FromSeconds(1); } [Serializable, NetSerializable] diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index e0dc7df3c878..5bdcae078fa6 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Nutrition.Components; using Content.Shared.Rejuvenate; using Content.Shared.StatusIcon; +using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -23,6 +24,7 @@ public sealed class HungerSystem : EntitySystem [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; [Dependency] private readonly SharedJetpackSystem _jetpack = default!; + [Dependency] private readonly INetManager _net = default!; [ValidatePrototypeId] private const string HungerIconOverfedId = "HungerIconOverfed"; @@ -81,73 +83,102 @@ private void OnRejuvenate(EntityUid uid, HungerComponent component, RejuvenateEv } /// - /// Adds to the current hunger of an entity by the specified amount. + /// Gets the current hunger value of the given . /// - /// The entity whose hunger will be modified - /// The amount by which to modify the entity's hunger - /// The entity's . If null, this function will try to it. + public float GetHunger(HungerComponent component) + { + var dt = _timing.CurTime - component.LastAuthoritativeHungerChangeTime; + var value = component.LastAuthoritativeHungerValue - (float)dt.TotalSeconds * component.ActualDecayRate; + + return Math.Clamp(value, + component.Thresholds[HungerThreshold.Dead], + component.Thresholds[HungerThreshold.Overfed]); + } + + /// + /// Adds to the current hunger of an entity by the specified value + /// + /// + /// + /// public void ModifyHunger(EntityUid uid, float amount, HungerComponent? component = null) { if (!Resolve(uid, ref component)) return; - SetHunger(uid, component.CurrentHunger + amount, component); + SetHunger(uid, GetHunger(component) + amount, component); } /// - /// Sets the current hunger of an entity to the specified value. + /// Sets the current hunger of an entity to the specified value /// - /// The entity whose hunger will be modified - /// The value to set the entity's hunger to - /// The entity's . If null, this function will try to it. - public void SetHunger(EntityUid uid, float value, HungerComponent? component = null) + /// + /// + /// + public void SetHunger(EntityUid uid, float amount, HungerComponent? component = null) { if (!Resolve(uid, ref component)) return; - SetHungerInternal((uid, component), value); - Dirty(uid, component); + + SetAuthoritativeHungerValue((uid, component), amount); + UpdateCurrentThreshold(uid, component); } /// - /// This "overload" avoids dirtying the component, with the - /// intention being that this function is called directly from Update, which is run - /// on both client and server, meaning needless cross-network synchronization is avoided. + /// If on the server, sets and + /// , and dirties this entity. This "resets" the + /// starting point for 's calculation. + /// Does nothing on the client. /// - private void SetHungerInternal(Entity entity, float value) + /// The entity whose hunger will be set. + /// The value to set the entity's hunger to. + private void SetAuthoritativeHungerValue(Entity entity, float value) { - entity.Comp.CurrentHunger = Math.Clamp(value, + // Don't try to set the authoritative value on the client. + if (_net.IsClient) + { + return; + } + + entity.Comp.LastAuthoritativeHungerChangeTime = _timing.CurTime; + entity.Comp.LastAuthoritativeHungerValue = Math.Clamp(value, entity.Comp.Thresholds[HungerThreshold.Dead], entity.Comp.Thresholds[HungerThreshold.Overfed]); - UpdateCurrentThreshold(entity); + Dirty(entity); } - private void UpdateCurrentThreshold(Entity entity) + private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = null) { - var calculatedHungerThreshold = GetHungerThreshold(entity.Comp); - if (calculatedHungerThreshold == entity.Comp.CurrentThreshold) + if (!Resolve(uid, ref component)) return; - entity.Comp.CurrentThreshold = calculatedHungerThreshold; - DoHungerThresholdEffects(entity); - Dirty(entity); + + var calculatedHungerThreshold = GetHungerThreshold(component); + if (calculatedHungerThreshold == component.CurrentThreshold) + return; + component.CurrentThreshold = calculatedHungerThreshold; + DoHungerThresholdEffects(uid, component); + SetAuthoritativeHungerValue((uid, component), GetHunger(component)); } - private void DoHungerThresholdEffects(Entity entity) + private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component = null, bool force = false) { - var component = entity.Comp; - if (component.CurrentThreshold == component.LastThreshold) + if (!Resolve(uid, ref component)) + return; + + if (component.CurrentThreshold == component.LastThreshold && !force) return; if (GetMovementThreshold(component.CurrentThreshold) != GetMovementThreshold(component.LastThreshold)) { - _movementSpeedModifier.RefreshMovementSpeedModifiers(entity); + _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); } if (component.HungerThresholdAlerts.TryGetValue(component.CurrentThreshold, out var alertId)) { - _alerts.ShowAlert(entity, alertId); + _alerts.ShowAlert(uid, alertId); } else { - _alerts.ClearAlertCategory(entity, component.HungerAlertCategory); + _alerts.ClearAlertCategory(uid, component.HungerAlertCategory); } if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier)) @@ -158,13 +189,16 @@ private void DoHungerThresholdEffects(Entity entity) component.LastThreshold = component.CurrentThreshold; } - private void DoContinuousHungerEffects(Entity entity) + private void DoContinuousHungerEffects(EntityUid uid, HungerComponent? component = null) { - if (entity.Comp.CurrentThreshold <= HungerThreshold.Starving && - entity.Comp.StarvationDamage is { } damage && - !_mobState.IsDead(entity)) + if (!Resolve(uid, ref component)) + return; + + if (component.CurrentThreshold <= HungerThreshold.Starving && + component.StarvationDamage is { } damage && + !_mobState.IsDead(uid)) { - _damageable.TryChangeDamage(entity, damage, true, false); + _damageable.TryChangeDamage(uid, damage, true, false); } } @@ -177,7 +211,7 @@ entity.Comp.StarvationDamage is { } damage && /// public HungerThreshold GetHungerThreshold(HungerComponent component, float? food = null) { - food ??= component.CurrentHunger; + food ??= GetHunger(component); var result = HungerThreshold.Dead; var value = component.Thresholds[HungerThreshold.Overfed]; foreach (var threshold in component.Thresholds) @@ -188,16 +222,21 @@ public HungerThreshold GetHungerThreshold(HungerComponent component, float? food value = threshold.Value; } } + return result; } /// /// A check that returns if the entity is below a hunger threshold. /// - public bool IsHungerBelowState(EntityUid uid, HungerThreshold threshold, float? food = null, HungerComponent? comp = null) + public bool IsHungerBelowState(EntityUid uid, + HungerThreshold threshold, + float? food = null, + HungerComponent? comp = null) { if (!Resolve(uid, ref comp)) - return false; // It's never going to go hungry, so it's probably fine to assume that it's not... you know, hungry. + return + false; // It's never going to go hungry, so it's probably fine to assume that it's not... you know, hungry. return GetHungerThreshold(comp, food) < threshold; } @@ -218,7 +257,8 @@ private bool GetMovementThreshold(HungerThreshold threshold) } } - public bool TryGetStatusIconPrototype(HungerComponent component, [NotNullWhen(true)] out SatiationIconPrototype? prototype) + public bool TryGetStatusIconPrototype(HungerComponent component, + [NotNullWhen(true)] out SatiationIconPrototype? prototype) { switch (component.CurrentThreshold) { @@ -246,13 +286,12 @@ public override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var hunger)) { - if (_timing.CurTime < hunger.NextUpdateTime) + if (_timing.CurTime < hunger.NextThresholdUpdateTime) continue; - hunger.NextUpdateTime = _timing.CurTime + hunger.UpdateRate; + hunger.NextThresholdUpdateTime = _timing.CurTime + hunger.ThresholdUpdateRate; - SetHungerInternal((uid, hunger), hunger.CurrentHunger - hunger.ActualDecayRate); - DoContinuousHungerEffects((uid, hunger)); + UpdateCurrentThreshold(uid, hunger); + DoContinuousHungerEffects(uid, hunger); } } } - diff --git a/Content.Shared/Sericulture/SericultureSystem.cs b/Content.Shared/Sericulture/SericultureSystem.cs index f7586cc1ec30..8c10d0f3d050 100644 --- a/Content.Shared/Sericulture/SericultureSystem.cs +++ b/Content.Shared/Sericulture/SericultureSystem.cs @@ -53,7 +53,10 @@ private void OnCompRemove(EntityUid uid, SericultureComponent comp, ComponentShu private void OnSericultureStart(EntityUid uid, SericultureComponent comp, SericultureActionEvent args) { if (TryComp(uid, out var hungerComp) - && _hungerSystem.IsHungerBelowState(uid, comp.MinHungerThreshold, hungerComp.CurrentHunger - comp.HungerCost, hungerComp)) + && _hungerSystem.IsHungerBelowState(uid, + comp.MinHungerThreshold, + _hungerSystem.GetHunger(hungerComp) - comp.HungerCost, + hungerComp)) { _popupSystem.PopupClient(Loc.GetString(comp.PopupText), uid, uid); return; @@ -76,8 +79,12 @@ private void OnSericultureDoAfter(EntityUid uid, SericultureComponent comp, Seri if (args.Cancelled || args.Handled || comp.Deleted) return; - if (TryComp(uid, out var hungerComp) // A check, just incase the doafter is somehow performed when the entity is not in the right hunger state. - && _hungerSystem.IsHungerBelowState(uid, comp.MinHungerThreshold, hungerComp.CurrentHunger - comp.HungerCost, hungerComp)) + if (TryComp(uid, + out var hungerComp) // A check, just incase the doafter is somehow performed when the entity is not in the right hunger state. + && _hungerSystem.IsHungerBelowState(uid, + comp.MinHungerThreshold, + _hungerSystem.GetHunger(hungerComp) - comp.HungerCost, + hungerComp)) { _popupSystem.PopupClient(Loc.GetString(comp.PopupText), uid, uid); return; From c1b6bb724ddf5e833dfcfb31540442f6dd6cefc2 Mon Sep 17 00:00:00 2001 From: Centronias Date: Mon, 28 Oct 2024 14:16:54 -0700 Subject: [PATCH 3/6] remove auto reformat changes to otherwise untouched code add clamp helper --- .../Nutrition/EntitySystems/HungerSystem.cs | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index 5bdcae078fa6..bc735462d6fb 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -56,8 +56,8 @@ public override void Initialize() private void OnMapInit(EntityUid uid, HungerComponent component, MapInitEvent args) { var amount = _random.Next( - (int)component.Thresholds[HungerThreshold.Peckish] + 10, - (int)component.Thresholds[HungerThreshold.Okay]); + (int) component.Thresholds[HungerThreshold.Peckish] + 10, + (int) component.Thresholds[HungerThreshold.Okay]); SetHunger(uid, amount, component); } @@ -89,10 +89,7 @@ public float GetHunger(HungerComponent component) { var dt = _timing.CurTime - component.LastAuthoritativeHungerChangeTime; var value = component.LastAuthoritativeHungerValue - (float)dt.TotalSeconds * component.ActualDecayRate; - - return Math.Clamp(value, - component.Thresholds[HungerThreshold.Dead], - component.Thresholds[HungerThreshold.Overfed]); + return ClampHungerWithinThresholds(component, value); } /// @@ -140,9 +137,7 @@ private void SetAuthoritativeHungerValue(Entity entity, float v } entity.Comp.LastAuthoritativeHungerChangeTime = _timing.CurTime; - entity.Comp.LastAuthoritativeHungerValue = Math.Clamp(value, - entity.Comp.Thresholds[HungerThreshold.Dead], - entity.Comp.Thresholds[HungerThreshold.Overfed]); + entity.Comp.LastAuthoritativeHungerValue = ClampHungerWithinThresholds(entity.Comp, value); Dirty(entity); } @@ -229,14 +224,10 @@ public HungerThreshold GetHungerThreshold(HungerComponent component, float? food /// /// A check that returns if the entity is below a hunger threshold. /// - public bool IsHungerBelowState(EntityUid uid, - HungerThreshold threshold, - float? food = null, - HungerComponent? comp = null) + public bool IsHungerBelowState(EntityUid uid, HungerThreshold threshold, float? food = null, HungerComponent? comp = null) { if (!Resolve(uid, ref comp)) - return - false; // It's never going to go hungry, so it's probably fine to assume that it's not... you know, hungry. + return false; // It's never going to go hungry, so it's probably fine to assume that it's not... you know, hungry. return GetHungerThreshold(comp, food) < threshold; } @@ -257,8 +248,7 @@ private bool GetMovementThreshold(HungerThreshold threshold) } } - public bool TryGetStatusIconPrototype(HungerComponent component, - [NotNullWhen(true)] out SatiationIconPrototype? prototype) + public bool TryGetStatusIconPrototype(HungerComponent component, [NotNullWhen(true)] out SatiationIconPrototype? prototype) { switch (component.CurrentThreshold) { @@ -279,6 +269,13 @@ public bool TryGetStatusIconPrototype(HungerComponent component, return prototype != null; } + private static float ClampHungerWithinThresholds(HungerComponent component, float hungerValue) + { + return Math.Clamp(hungerValue, + component.Thresholds[HungerThreshold.Dead], + component.Thresholds[HungerThreshold.Overfed]); + } + public override void Update(float frameTime) { base.Update(frameTime); From ec498bbb6a7a92dc9b38c79b75e24bb68766782f Mon Sep 17 00:00:00 2001 From: Centronias Date: Mon, 28 Oct 2024 14:16:54 -0700 Subject: [PATCH 4/6] imagine making breaking changes, documenting them, and then not thinking to check the yaml --- Resources/Prototypes/Entities/Mobs/NPCs/animals.yml | 4 ++-- Resources/Prototypes/Entities/Mobs/NPCs/space.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index e2dd9ac3f305..066e8259df8c 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1686,7 +1686,7 @@ Dead: 0 baseDecayRate: 0.04 - type: Hunger - currentHunger: 25 # spawn with Okay hunger state + lastAuthoritativeHungerValue: 25 # spawn with Okay hunger state thresholds: Overfed: 35 Okay: 25 @@ -3381,7 +3381,7 @@ - type: HTN rootTask: task: RuminantCompound - + - type: entity name: diona nymph parent: [SimpleMobBase, StripableInventoryBase] diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml index a51fe522381a..bb4c03ab5f20 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml @@ -448,7 +448,7 @@ Dead: 0 baseDecayRate: 0.04 - type: Hunger - currentHunger: 25 # spawn with Okay hunger state + lastAuthoritativeHungerValue: 25 # spawn with Okay hunger state thresholds: Overfed: 35 Okay: 25 From ca8d7cd3b920266006a302a84c179c3b7f2094a9 Mon Sep 17 00:00:00 2001 From: Centronias Date: Wed, 30 Oct 2024 11:36:35 -0700 Subject: [PATCH 5/6] comments --- .../EntityEffects/EffectConditions/TotalHunger.cs | 5 ++--- .../Nutrition/Components/HungerComponent.cs | 2 +- .../Nutrition/EntitySystems/HungerSystem.cs | 11 ++--------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs b/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs index 72c7ca01ba52..c4f69b60de67 100644 --- a/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs +++ b/Content.Server/EntityEffects/EffectConditions/TotalHunger.cs @@ -15,10 +15,9 @@ public sealed partial class Hunger : EntityEffectCondition public override bool Condition(EntityEffectBaseArgs args) { - if (args.EntityManager.TryGetComponent(args.TargetEntity, out HungerComponent? hunger) && - args.EntityManager.SystemOrNull() is { } hungerSystem) + if (args.EntityManager.TryGetComponent(args.TargetEntity, out HungerComponent? hunger)) { - var total = hungerSystem.GetHunger(hunger); + var total = args.EntityManager.System().GetHunger(hunger); if (total > Min && total < Max) return true; } diff --git a/Content.Shared/Nutrition/Components/HungerComponent.cs b/Content.Shared/Nutrition/Components/HungerComponent.cs index 5664e580b0d3..33abb257dd10 100644 --- a/Content.Shared/Nutrition/Components/HungerComponent.cs +++ b/Content.Shared/Nutrition/Components/HungerComponent.cs @@ -18,7 +18,7 @@ public sealed partial class HungerComponent : Component /// This value should be updated relatively infrequently. To get the current hunger, which changes with each update, /// use . /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadOnly)] [AutoNetworkedField] public float LastAuthoritativeHungerValue; diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index bc735462d6fb..ab9bcaf115a4 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -121,21 +121,14 @@ public void SetHunger(EntityUid uid, float amount, HungerComponent? component = } /// - /// If on the server, sets and + /// Sets and /// , and dirties this entity. This "resets" the /// starting point for 's calculation. - /// Does nothing on the client. /// /// The entity whose hunger will be set. /// The value to set the entity's hunger to. private void SetAuthoritativeHungerValue(Entity entity, float value) { - // Don't try to set the authoritative value on the client. - if (_net.IsClient) - { - return; - } - entity.Comp.LastAuthoritativeHungerChangeTime = _timing.CurTime; entity.Comp.LastAuthoritativeHungerValue = ClampHungerWithinThresholds(entity.Comp, value); Dirty(entity); @@ -151,7 +144,6 @@ private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = return; component.CurrentThreshold = calculatedHungerThreshold; DoHungerThresholdEffects(uid, component); - SetAuthoritativeHungerValue((uid, component), GetHunger(component)); } private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component = null, bool force = false) @@ -179,6 +171,7 @@ private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier)) { component.ActualDecayRate = component.BaseDecayRate * modifier; + SetAuthoritativeHungerValue((uid, component), GetHunger(component)); } component.LastThreshold = component.CurrentThreshold; From 503c1b1435505c5a7116afd5f78a8a49d94ccab4 Mon Sep 17 00:00:00 2001 From: Centronias Date: Thu, 14 Nov 2024 09:54:26 -0800 Subject: [PATCH 6/6] Remove unused net manager in hunger system Remove lastAuthoritativeHungerValue from prototypes --- Content.Shared/Nutrition/EntitySystems/HungerSystem.cs | 1 - Resources/Prototypes/Entities/Mobs/NPCs/animals.yml | 1 - Resources/Prototypes/Entities/Mobs/NPCs/space.yml | 1 - 3 files changed, 3 deletions(-) diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index be8fd61698cb..063c1f6bb1a6 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -24,7 +24,6 @@ public sealed class HungerSystem : EntitySystem [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; [Dependency] private readonly SharedJetpackSystem _jetpack = default!; - [Dependency] private readonly INetManager _net = default!; [ValidatePrototypeId] private const string HungerIconOverfedId = "HungerIconOverfed"; diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 9338283f4246..85f412e92e23 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1686,7 +1686,6 @@ Dead: 0 baseDecayRate: 0.04 - type: Hunger - lastAuthoritativeHungerValue: 25 # spawn with Okay hunger state thresholds: Overfed: 35 Okay: 25 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml index bb4c03ab5f20..0dc96ba6f31c 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml @@ -448,7 +448,6 @@ Dead: 0 baseDecayRate: 0.04 - type: Hunger - lastAuthoritativeHungerValue: 25 # spawn with Okay hunger state thresholds: Overfed: 35 Okay: 25