]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
ReagentGrinder Comp and API to shared (#41956)
authorScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Sat, 27 Dec 2025 17:09:33 +0000 (18:09 +0100)
committerGitHub <noreply@github.com>
Sat, 27 Dec 2025 17:09:33 +0000 (17:09 +0000)
* init

* API

* review

* return

* review

* I tend to be stupid

Content.Client/Kitchen/EntitySystems/ReagentGrinderSystem.cs [new file with mode: 0644]
Content.Server/Kitchen/Components/ReagentGrinderComponent.cs [deleted file]
Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
Content.Shared/Kitchen/Components/ReagentGrinderComponent.cs [new file with mode: 0644]
Content.Shared/Kitchen/EntitySystems/SharedReagentGrinderSystem.cs [new file with mode: 0644]
Content.Shared/Kitchen/SharedReagentGrinder.cs

diff --git a/Content.Client/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Client/Kitchen/EntitySystems/ReagentGrinderSystem.cs
new file mode 100644 (file)
index 0000000..5eebd4a
--- /dev/null
@@ -0,0 +1,8 @@
+using Content.Shared.Kitchen.EntitySystems;
+using JetBrains.Annotations;
+
+namespace Content.Client.Kitchen.EntitySystems;
+
+[UsedImplicitly]
+public sealed class ReagentGrinderSystem : SharedReagentGrinderSystem;
+
diff --git a/Content.Server/Kitchen/Components/ReagentGrinderComponent.cs b/Content.Server/Kitchen/Components/ReagentGrinderComponent.cs
deleted file mode 100644 (file)
index 5bbbe2d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-using Content.Shared.Kitchen;
-using Content.Server.Kitchen.EntitySystems;
-using Robust.Shared.Audio;
-
-namespace Content.Server.Kitchen.Components
-{
-    /// <summary>
-    /// The combo reagent grinder/juicer. The reason why grinding and juicing are seperate is simple,
-    /// think of grinding as a utility to break an object down into its reagents. Think of juicing as
-    /// converting something into its single juice form. E.g, grind an apple and get the nutriment and sugar
-    /// it contained, juice an apple and get "apple juice".
-    /// </summary>
-    [Access(typeof(ReagentGrinderSystem)), RegisterComponent]
-    public sealed partial class ReagentGrinderComponent : Component
-    {
-        [DataField]
-        public int StorageMaxEntities = 6;
-
-        [DataField]
-        public TimeSpan WorkTime = TimeSpan.FromSeconds(3.5); // Roughly matches the grind/juice sounds.
-
-        [DataField]
-        public float WorkTimeMultiplier = 1;
-
-        [DataField]
-        public SoundSpecifier ClickSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
-
-        [DataField]
-        public SoundSpecifier GrindSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/blender.ogg");
-
-        [DataField]
-        public SoundSpecifier JuiceSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/juicer.ogg");
-
-        [DataField]
-        public GrinderAutoMode AutoMode = GrinderAutoMode.Off;
-
-        public EntityUid? AudioStream;
-    }
-
-    [Access(typeof(ReagentGrinderSystem)), RegisterComponent]
-    public sealed partial class ActiveReagentGrinderComponent : Component
-    {
-        /// <summary>
-        /// Remaining time until the grinder finishes grinding/juicing.
-        /// </summary>
-        [ViewVariables]
-        public TimeSpan EndTime;
-
-        [ViewVariables]
-        public GrinderProgram Program;
-    }
-}
index b850bc87fa4f0ed47740657ac0e715e511e124c4..a709f4b8d98e244647ab691c0f13d8edcb40fc5b 100644 (file)
@@ -1,5 +1,3 @@
-using Content.Server.Kitchen.Components;
-using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Server.Stack;
 using Content.Shared.Chemistry.EntitySystems;
@@ -20,15 +18,15 @@ using Robust.Shared.Audio.Systems;
 using Robust.Shared.Containers;
 using Robust.Shared.Timing;
 using System.Linq;
-using Content.Server.Construction.Completions;
 using Content.Server.Jittering;
 using Content.Shared.Jittering;
+using Content.Shared.Kitchen.EntitySystems;
 using Content.Shared.Power;
 
 namespace Content.Server.Kitchen.EntitySystems
 {
     [UsedImplicitly]
-    internal sealed class ReagentGrinderSystem : EntitySystem
+    internal sealed class ReagentGrinderSystem : SharedReagentGrinderSystem
     {
         [Dependency] private readonly IGameTiming _timing = default!;
         [Dependency] private readonly SharedSolutionContainerSystem _solutionContainersSystem = default!;
@@ -67,6 +65,8 @@ namespace Content.Server.Kitchen.EntitySystems
         {
             entity.Comp.AutoMode = (GrinderAutoMode) (((byte) entity.Comp.AutoMode + 1) % Enum.GetValues(typeof(GrinderAutoMode)).Length);
 
+            Dirty(entity);
+
             UpdateUiState(entity);
         }
 
@@ -90,12 +90,7 @@ namespace Content.Server.Kitchen.EntitySystems
 
                 foreach (var item in inputContainer.ContainedEntities.ToList())
                 {
-                    var solution = active.Program switch
-                    {
-                        GrinderProgram.Grind => GetGrindSolution(item),
-                        GrinderProgram.Juice => CompOrNull<ExtractableComponent>(item)?.JuiceSolution,
-                        _ => null,
-                    };
+                    var solution = GetGrinderSolution(item, active.Program);
 
                     if (solution is null)
                         continue;
@@ -218,8 +213,8 @@ namespace Content.Server.Kitchen.EntitySystems
                 && _solutionContainersSystem.TryGetFitsInDispenser(outputContainer.Value, out _, out containerSolution)
                 && inputContainer.ContainedEntities.Count > 0)
             {
-                canGrind = inputContainer.ContainedEntities.All(CanGrind);
-                canJuice = inputContainer.ContainedEntities.All(CanJuice);
+                canGrind = inputContainer.ContainedEntities.All(x => CanGrind(x));
+                canJuice = inputContainer.ContainedEntities.All(x => CanJuice(x));
             }
 
             var state = new ReagentGrinderInterfaceState(
@@ -293,10 +288,10 @@ namespace Content.Server.Kitchen.EntitySystems
             SoundSpecifier? sound;
             switch (program)
             {
-                case GrinderProgram.Grind when inputContainer.ContainedEntities.All(CanGrind):
+                case GrinderProgram.Grind when inputContainer.ContainedEntities.All(x => CanGrind(x)):
                     sound = reagentGrinder.GrindSound;
                     break;
-                case GrinderProgram.Juice when inputContainer.ContainedEntities.All(CanJuice):
+                case GrinderProgram.Juice when inputContainer.ContainedEntities.All(x => CanJuice(x)):
                     sound = reagentGrinder.JuiceSound;
                     break;
                 default:
@@ -317,29 +312,5 @@ namespace Content.Server.Kitchen.EntitySystems
         {
             _audioSystem.PlayPvs(reagentGrinder.Comp.ClickSound, reagentGrinder.Owner, AudioParams.Default.WithVolume(-2f));
         }
-
-        private Solution? GetGrindSolution(EntityUid uid)
-        {
-            if (TryComp<ExtractableComponent>(uid, out var extractable)
-                && extractable.GrindableSolution is not null
-                && _solutionContainersSystem.TryGetSolution(uid, extractable.GrindableSolution, out _, out var solution))
-            {
-                return solution;
-            }
-            else
-                return null;
-        }
-
-        private bool CanGrind(EntityUid uid)
-        {
-            var solutionName = CompOrNull<ExtractableComponent>(uid)?.GrindableSolution;
-
-            return solutionName is not null && _solutionContainersSystem.TryGetSolution(uid, solutionName, out _, out _);
-        }
-
-        private bool CanJuice(EntityUid uid)
-        {
-            return CompOrNull<ExtractableComponent>(uid)?.JuiceSolution is not null;
-        }
     }
 }
diff --git a/Content.Shared/Kitchen/Components/ReagentGrinderComponent.cs b/Content.Shared/Kitchen/Components/ReagentGrinderComponent.cs
new file mode 100644 (file)
index 0000000..6b8eb6f
--- /dev/null
@@ -0,0 +1,54 @@
+using Content.Shared.Kitchen.EntitySystems;
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Kitchen.Components;
+
+/// <summary>
+/// The combo reagent grinder/juicer. The reason why grinding and juicing are seperate is simple,
+/// think of grinding as a utility to break an object down into its reagents. Think of juicing as
+/// converting something into its single juice form. E.g, grind an apple and get the nutriment and sugar
+/// it contained, juice an apple and get "apple juice".
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[Access(typeof(SharedReagentGrinderSystem))]
+public sealed partial class ReagentGrinderComponent : Component
+{
+    [DataField, AutoNetworkedField]
+    public int StorageMaxEntities = 6;
+
+    [DataField, AutoNetworkedField]
+    public TimeSpan WorkTime = TimeSpan.FromSeconds(3.5); // Roughly matches the grind/juice sounds.
+
+    [DataField, AutoNetworkedField]
+    public float WorkTimeMultiplier = 1;
+
+    [DataField]
+    public SoundSpecifier ClickSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
+
+    [DataField]
+    public SoundSpecifier GrindSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/blender.ogg");
+
+    [DataField]
+    public SoundSpecifier JuiceSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/juicer.ogg");
+
+    [DataField, AutoNetworkedField]
+    public GrinderAutoMode AutoMode = GrinderAutoMode.Off;
+
+    public EntityUid? AudioStream;
+}
+
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(SharedReagentGrinderSystem))]
+public sealed partial class ActiveReagentGrinderComponent : Component
+{
+    /// <summary>
+    /// Remaining time until the grinder finishes grinding/juicing.
+    /// </summary>
+    [ViewVariables]
+    public TimeSpan EndTime;
+
+    [ViewVariables]
+    public GrinderProgram Program;
+}
+
diff --git a/Content.Shared/Kitchen/EntitySystems/SharedReagentGrinderSystem.cs b/Content.Shared/Kitchen/EntitySystems/SharedReagentGrinderSystem.cs
new file mode 100644 (file)
index 0000000..b54fd1d
--- /dev/null
@@ -0,0 +1,68 @@
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Kitchen.Components;
+using JetBrains.Annotations;
+
+namespace Content.Shared.Kitchen.EntitySystems;
+
+[UsedImplicitly]
+public abstract class SharedReagentGrinderSystem : EntitySystem
+{
+    [Dependency] private readonly SharedSolutionContainerSystem _solutionContainersSystem = default!;
+
+    /// <summary>
+    /// Gets the solutions from an entity using the specified Grinder program.
+    /// </summary>
+    /// <param name="ent">The entity which we check for solutions.</param>
+    /// <param name="program">The grinder program.</param>
+    /// <returns>The solution received, or null if none.</returns>
+    public Solution? GetGrinderSolution(Entity<ExtractableComponent?> ent, GrinderProgram program)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return null;
+
+        switch (program)
+        {
+            case GrinderProgram.Grind:
+                if (_solutionContainersSystem.TryGetSolution(ent.Owner, ent.Comp.GrindableSolution, out _, out var solution))
+                {
+                    return solution;
+                }
+                break;
+            case GrinderProgram.Juice:
+                return ent.Comp.JuiceSolution;
+        }
+
+        return null;
+    }
+
+    /// <summary>
+    /// Checks whether the entity can be ground using a ReagentGrinder.
+    /// </summary>
+    /// <param name="ent">The entity to check.</param>
+    /// <returns>True if it can be ground, otherwise false.</returns>
+    public bool CanGrind(Entity<ExtractableComponent?> ent)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return false;
+
+        if (ent.Comp.GrindableSolution == null)
+            return false;
+
+        return _solutionContainersSystem.TryGetSolution(ent.Owner, ent.Comp.GrindableSolution, out _, out _);
+    }
+
+    /// <summary>
+    /// Checks whether the entity can be juiced using a ReagentGrinder.
+    /// </summary>
+    /// <param name="ent">The entity to check.</param>
+    /// <returns>True if it can be juiced, otherwise false.</returns>
+    public bool CanJuice(Entity<ExtractableComponent?> ent)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return false;
+
+        return ent.Comp.JuiceSolution is not null;
+    }
+}
+
index 579db239c800ab7490043c742da23aeb1c346879..83088555da6f75470693d2fcab663aeb88a21fd2 100644 (file)
@@ -81,6 +81,7 @@ namespace Content.Shared.Kitchen
         Key
     }
 
+    [Serializable, NetSerializable]
     public enum GrinderAutoMode : byte
     {
         Off,