From 271e271cc92e7e5336dbf13e17f2d33f523566fc Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Thu, 31 Jul 2025 00:38:38 +0200 Subject: [PATCH] Predict passive welding fuel consumption (#38876) * predict welding fuel consumption * autopaused * review Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> --------- Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> --- Content.Server/Tools/ToolSystem.cs | 46 +------------------ .../Tools/Components/WelderComponent.cs | 44 ++++++++++++------ .../Tools/Systems/SharedToolSystem.Welder.cs | 45 ++++++++++++++++-- .../Tools/Systems/SharedToolSystem.cs | 9 ++++ 4 files changed, 82 insertions(+), 62 deletions(-) diff --git a/Content.Server/Tools/ToolSystem.cs b/Content.Server/Tools/ToolSystem.cs index a88dbd3653..c8defb5ef9 100644 --- a/Content.Server/Tools/ToolSystem.cs +++ b/Content.Server/Tools/ToolSystem.cs @@ -1,47 +1,5 @@ -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.FixedPoint; -using Content.Shared.Tools.Components; - -using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; +using Content.Shared.Tools.Systems; namespace Content.Server.Tools; -public sealed class ToolSystem : SharedToolSystem -{ - public override void Update(float frameTime) - { - base.Update(frameTime); - - UpdateWelders(frameTime); - } - - //todo move to shared once you can remove reagents from shared without it freaking out. - private void UpdateWelders(float frameTime) - { - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var welder, out var solutionContainer)) - { - if (!welder.Enabled) - continue; - - welder.WelderTimer += frameTime; - - if (welder.WelderTimer < welder.WelderUpdateTimer) - continue; - - if (!SolutionContainerSystem.TryGetSolution((uid, solutionContainer), welder.FuelSolutionName, out var solutionComp, out var solution)) - continue; - - SolutionContainerSystem.RemoveReagent(solutionComp.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderTimer); - - if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero) - { - ItemToggle.Toggle(uid, predicted: false); - } - - Dirty(uid, welder); - welder.WelderTimer -= welder.WelderUpdateTimer; - } - } -} - +public sealed class ToolSystem : SharedToolSystem; diff --git a/Content.Shared/Tools/Components/WelderComponent.cs b/Content.Shared/Tools/Components/WelderComponent.cs index 3c78a03fde..a9111c7f53 100644 --- a/Content.Shared/Tools/Components/WelderComponent.cs +++ b/Content.Shared/Tools/Components/WelderComponent.cs @@ -1,58 +1,76 @@ -using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Tools.Systems; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Tools.Components; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(SharedToolSystem))] +/// +/// Handles fuel consumption for the tool and allows it to explode welding fuel tanks. +/// +/// +/// TODO: De-hardcode welder bombing. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] +[Access(typeof(SharedToolSystem))] public sealed partial class WelderComponent : Component { + /// + /// Is the welder currently enabled? + /// [DataField, AutoNetworkedField] public bool Enabled; - [DataField] - public float WelderTimer; + /// + /// Timestamp for the next update loop update. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextUpdate; /// - /// Name of . + /// Delay between updates. + /// + [DataField] + public TimeSpan WelderUpdateTimer = TimeSpan.FromSeconds(1); + + /// + /// Name of the fuel solution. /// [DataField] public string FuelSolutionName = "Welder"; /// - /// Reagent that will be used as fuel for welding. + /// Reagent that will be used as fuel for welding. /// [DataField] public ProtoId FuelReagent = "WeldingFuel"; /// - /// Fuel consumption per second while the welder is active. + /// Fuel consumption per second while the welder is active. + /// In u/s /// [DataField, AutoNetworkedField] public FixedPoint2 FuelConsumption = FixedPoint2.New(1.0f); /// - /// A fuel amount to be consumed when the welder goes from being unlit to being lit. + /// A fuel amount to be consumed when the welder goes from being unlit to being lit. /// [DataField, AutoNetworkedField] public FixedPoint2 FuelLitCost = FixedPoint2.New(0.5f); /// - /// Sound played when refilling the welder. + /// Sound played when refilling the welder. /// [DataField] public SoundSpecifier WelderRefill = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); /// - /// Whether the item is safe to refill while lit without exploding the tank. + /// Whether the item is safe to refill while lit without exploding the tank. /// [DataField] public bool TankSafe; - - [DataField] - public float WelderUpdateTimer = 1f; } diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs b/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs index af1dc85137..1507b1d6e8 100644 --- a/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs +++ b/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs @@ -17,13 +17,16 @@ public abstract partial class SharedToolSystem public void InitializeWelder() { + SubscribeLocalEvent(OnWelderInit); SubscribeLocalEvent(OnWelderExamine); SubscribeLocalEvent(OnWelderAfterInteract); - SubscribeLocalEvent((uid, comp, ev) => { + SubscribeLocalEvent((uid, comp, ev) => + { CanCancelWelderUse((uid, comp), ev.User, ev.Fuel, ev); }); - SubscribeLocalEvent>((uid, comp, ev) => { + SubscribeLocalEvent>((uid, comp, ev) => + { CanCancelWelderUse((uid, comp), ev.Event.User, ev.Event.Fuel, ev); }); SubscribeLocalEvent(OnWelderDoAfter); @@ -71,6 +74,12 @@ public abstract partial class SharedToolSystem return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume); } + private void OnWelderInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.WelderUpdateTimer; + Dirty(ent); + } + private void OnWelderExamine(Entity entity, ref ExaminedEvent args) { using (args.PushGroup(nameof(WelderComponent))) @@ -169,7 +178,8 @@ public abstract partial class SharedToolSystem private void OnActivateAttempt(Entity entity, ref ItemToggleActivateAttemptEvent args) { - if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value)) { + if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value)) + { args.Cancelled = true; return; } @@ -191,9 +201,34 @@ public abstract partial class SharedToolSystem private void OnDeactivateAttempt(Entity entity, ref ItemToggleDeactivateAttemptEvent args) { - if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value)) { + if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value)) + { args.Cancelled = true; - return; + } + } + + private void UpdateWelders() + { + var query = EntityQueryEnumerator(); + var curTime = _timing.CurTime; + while (query.MoveNext(out var uid, out var welder, out var solutionContainer)) + { + if (curTime < welder.NextUpdate) + continue; + + welder.NextUpdate += welder.WelderUpdateTimer; + Dirty(uid, welder); + + if (!welder.Enabled) + continue; + + if (!SolutionContainerSystem.TryGetSolution((uid, solutionContainer), welder.FuelSolutionName, out var solutionComp, out var solution)) + continue; + + SolutionContainerSystem.RemoveReagent(solutionComp.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderUpdateTimer.TotalSeconds); + + if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero) + ItemToggle.Toggle(uid); } } } diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.cs b/Content.Shared/Tools/Systems/SharedToolSystem.cs index bf98a365e7..7051cfea00 100644 --- a/Content.Shared/Tools/Systems/SharedToolSystem.cs +++ b/Content.Shared/Tools/Systems/SharedToolSystem.cs @@ -12,12 +12,14 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Shared.Tools.Systems; public abstract partial class SharedToolSystem : EntitySystem { + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!; @@ -263,6 +265,13 @@ public abstract partial class SharedToolSystem : EntitySystem return !beforeAttempt.Cancelled; } + public override void Update(float frameTime) + { + base.Update(frameTime); + + UpdateWelders(); + } + #region DoAfterEvents [Serializable, NetSerializable]