]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Predict ReactionMixerSystem (#41218)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Fri, 5 Dec 2025 20:46:38 +0000 (21:46 +0100)
committerGitHub <noreply@github.com>
Fri, 5 Dec 2025 20:46:38 +0000 (20:46 +0000)
* predict

* documentation

* review

Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs [deleted file]
Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs
Content.Shared/Chemistry/Reaction/ReactionMixerSystem.cs [new file with mode: 0644]

diff --git a/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs b/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs
deleted file mode 100644 (file)
index ee99418..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Reaction;
-using Content.Shared.DoAfter;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Interaction;
-using Content.Shared.Nutrition.EntitySystems;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Server.Popups;
-
-namespace Content.Server.Chemistry.EntitySystems;
-
-public sealed partial class ReactionMixerSystem : EntitySystem
-{
-    [Dependency] private readonly PopupSystem _popup = default!;
-    [Dependency] private readonly SharedSolutionContainerSystem _solutionContainers = default!;
-    [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
-
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<ReactionMixerComponent, AfterInteractEvent>(OnAfterInteract, before: [typeof(IngestionSystem)]);
-        SubscribeLocalEvent<ReactionMixerComponent, ShakeEvent>(OnShake);
-        SubscribeLocalEvent<ReactionMixerComponent, ReactionMixDoAfterEvent>(OnDoAfter);
-    }
-
-    private void OnAfterInteract(Entity<ReactionMixerComponent> entity, ref AfterInteractEvent args)
-    {
-        if (!args.Target.HasValue || !args.CanReach || !entity.Comp.MixOnInteract)
-            return;
-
-        if (!MixAttempt(entity, args.Target.Value, out _))
-            return;
-
-        var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.TimeToMix, new ReactionMixDoAfterEvent(), entity, args.Target.Value, entity);
-
-        _doAfterSystem.TryStartDoAfter(doAfterArgs);
-        args.Handled = true;
-    }
-
-    private void OnDoAfter(Entity<ReactionMixerComponent> entity, ref ReactionMixDoAfterEvent args)
-    {
-        //Do again to get the solution again
-        if (!MixAttempt(entity, args.Target!.Value, out var solution))
-            return;
-
-        _popup.PopupEntity(Loc.GetString(entity.Comp.MixMessage, ("mixed", Identity.Entity(args.Target!.Value, EntityManager)), ("mixer", Identity.Entity(entity.Owner, EntityManager))), args.User, args.User);
-
-        _solutionContainers.UpdateChemicals(solution!.Value, true, entity.Comp);
-
-        var afterMixingEvent = new AfterMixingEvent(entity, args.Target!.Value);
-        RaiseLocalEvent(entity, afterMixingEvent);
-    }
-
-    private void OnShake(Entity<ReactionMixerComponent> entity, ref ShakeEvent args)
-    {
-        if (!MixAttempt(entity, entity, out var solution))
-            return;
-
-        _solutionContainers.UpdateChemicals(solution!.Value, true, entity.Comp);
-
-        var afterMixingEvent = new AfterMixingEvent(entity, entity);
-        RaiseLocalEvent(entity, afterMixingEvent);
-    }
-
-    private bool MixAttempt(EntityUid ent, EntityUid target, out Entity<SolutionComponent>? solution)
-    {
-        solution = null;
-        var mixAttemptEvent = new MixingAttemptEvent(ent);
-        RaiseLocalEvent(ent, ref mixAttemptEvent);
-        if (mixAttemptEvent.Cancelled)
-        {
-            return false;
-        }
-
-        if (!_solutionContainers.TryGetMixableSolution(target, out solution, out _))
-            return false;
-
-        return true;
-    }
-}
index 8edfa44ce850ebb4328b0c1969a8da817665146b..25fda2560777fe031f19296e390edbd7287e1662 100644 (file)
@@ -1,48 +1,43 @@
-using Content.Shared.Chemistry.Components;
 using Content.Shared.DoAfter;
+using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Chemistry.Reaction;
 
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
 public sealed partial class ReactionMixerComponent : Component
 {
     /// <summary>
-    ///     A list of IDs for categories of reactions that can be mixed (i.e. HOLY for a bible, DRINK for a spoon)
+    /// A list of IDs for categories of reactions that can be mixed (i.e. HOLY for a bible, DRINK for a spoon).
     /// </summary>
-    [ViewVariables]
-    [DataField]
-    public List<ProtoId<MixingCategoryPrototype>> ReactionTypes = default!;
+    [DataField, AutoNetworkedField]
+    public List<ProtoId<MixingCategoryPrototype>> ReactionTypes = new();
 
     /// <summary>
-    ///     A string which identifies the string to be sent when successfully mixing a solution
+    /// The popup message when successfully mixing a solution.
     /// </summary>
-    [ViewVariables]
-    [DataField]
+    [DataField, AutoNetworkedField]
     public LocId MixMessage = "default-mixing-success";
 
     /// <summary>
-    ///     Defines if interacting is enough to mix with this component
+    /// Defines if interacting is enough to mix with this component.
     /// </summary>
-    [ViewVariables]
-    [DataField]
+    [DataField, AutoNetworkedField]
     public bool MixOnInteract = true;
 
     /// <summary>
-    ///     How long it takes to mix with this
+    /// How long it takes to mix with this.
     /// </summary>
-    [ViewVariables]
-    [DataField]
+    [DataField, AutoNetworkedField]
     public TimeSpan TimeToMix = TimeSpan.Zero;
 }
 
 [ByRefEvent]
 public record struct MixingAttemptEvent(EntityUid Mixed, bool Cancelled = false);
 
+[ByRefEvent]
 public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer);
 
 [Serializable, NetSerializable]
-public sealed partial class ReactionMixDoAfterEvent : SimpleDoAfterEvent
-{
-}
+public sealed partial class ReactionMixDoAfterEvent : SimpleDoAfterEvent;
diff --git a/Content.Shared/Chemistry/Reaction/ReactionMixerSystem.cs b/Content.Shared/Chemistry/Reaction/ReactionMixerSystem.cs
new file mode 100644 (file)
index 0000000..4bc878a
--- /dev/null
@@ -0,0 +1,109 @@
+using Content.Shared.Chemistry.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Interaction;
+using Content.Shared.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Popups;
+
+namespace Content.Shared.Chemistry.Reaction;
+
+public sealed partial class ReactionMixerSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+    [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<ReactionMixerComponent, AfterInteractEvent>(OnAfterInteract, before: [typeof(IngestionSystem)]);
+        SubscribeLocalEvent<ReactionMixerComponent, ShakeEvent>(OnShake);
+        SubscribeLocalEvent<ReactionMixerComponent, ReactionMixDoAfterEvent>(OnDoAfter);
+    }
+
+    private void OnAfterInteract(Entity<ReactionMixerComponent> ent, ref AfterInteractEvent args)
+    {
+        if (!args.Target.HasValue || !args.CanReach || !ent.Comp.MixOnInteract)
+            return;
+
+        if (!CanMix(ent.AsNullable(), args.Target.Value))
+            return;
+
+        var doAfterArgs = new DoAfterArgs(EntityManager, args.User, ent.Comp.TimeToMix, new ReactionMixDoAfterEvent(), ent, args.Target.Value, ent);
+
+        _doAfter.TryStartDoAfter(doAfterArgs);
+        args.Handled = true;
+    }
+
+    private void OnDoAfter(Entity<ReactionMixerComponent> ent, ref ReactionMixDoAfterEvent args)
+    {
+        if (args.Target == null)
+            return;
+
+        if (!TryMix(ent.AsNullable(), args.Target.Value))
+            return;
+
+        _popup.PopupClient(
+            Loc.GetString(
+                ent.Comp.MixMessage,
+                ("mixed", Identity.Entity(args.Target.Value, EntityManager)),
+                ("mixer", Identity.Entity(ent.Owner, EntityManager))),
+            args.User,
+            args.User);
+    }
+
+    private void OnShake(Entity<ReactionMixerComponent> ent, ref ShakeEvent args)
+    {
+        TryMix(ent.AsNullable(), ent);
+    }
+
+    /// <summary>
+    /// Returns true if given reaction mixer is able to mix the solution inside the target entity, false otherwise.
+    /// </summary>
+    /// <param name="ent">The reaction mixer used to cause the reaction.</param>
+    /// <param name="target">The target solution container with a <see cref="MixableSolutionComponent"/>.</param>
+    public bool CanMix(Entity<ReactionMixerComponent?> ent, EntityUid target)
+    {
+        if (!Resolve(ent, ref ent.Comp, false)) // The used entity needs the component to be able to mix a solution
+            return false;
+
+        var mixAttemptEvent = new MixingAttemptEvent(ent);
+        RaiseLocalEvent(ent, ref mixAttemptEvent);
+        if (mixAttemptEvent.Cancelled)
+            return false;
+
+        if (!_solutionContainer.TryGetMixableSolution(target, out _, out _))
+            return false;
+
+        return true;
+    }
+
+    /// <summary>
+    /// Attempts to mix the solution inside the target entity using the given reaction mixer.
+    /// </summary>
+    /// <param name="ent">The reaction mixer used to cause the reaction.</param>
+    /// <param name="target">The target solution container with a <see cref="MixableSolutionComponent"/>.</param>
+    /// <returns>If the reaction mixer was able to mix the solution. This does not necessarily mean a reaction took place.</returns>
+    public bool TryMix(Entity<ReactionMixerComponent?> ent, EntityUid target)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return false;
+
+        var mixAttemptEvent = new MixingAttemptEvent(ent);
+        RaiseLocalEvent(ent, ref mixAttemptEvent);
+        if (mixAttemptEvent.Cancelled)
+            return false;
+
+        if (!_solutionContainer.TryGetMixableSolution(target, out var solutionEnt, out _))
+            return false;
+
+        _solutionContainer.UpdateChemicals(solutionEnt.Value, true, ent.Comp);
+
+        var afterMixingEvent = new AfterMixingEvent(ent, target);
+        RaiseLocalEvent(ent, ref afterMixingEvent);
+
+        return true;
+    }
+}