ReagentGrinder Comp and API to shared (#41956)

* init

* API

* review

* return

* review

* I tend to be stupid
This commit is contained in:
ScarKy0
2025-12-27 18:09:33 +01:00
committed by GitHub
parent cf25961186
commit 662d2ee964
6 changed files with 140 additions and 90 deletions

View File

@@ -0,0 +1,8 @@
using Content.Shared.Kitchen.EntitySystems;
using JetBrains.Annotations;
namespace Content.Client.Kitchen.EntitySystems;
[UsedImplicitly]
public sealed class ReagentGrinderSystem : SharedReagentGrinderSystem;

View File

@@ -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;
}
}

View 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;
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -81,6 +81,7 @@ namespace Content.Shared.Kitchen
Key
}
[Serializable, NetSerializable]
public enum GrinderAutoMode : byte
{
Off,