Files
Delta-v/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
T
c7077a388c Predict reagent grinder (#42815)
* prediction!!!

* fixes

* fixes and add debug logs

* fix prediction and cleanup

* raise event on client + comp access

* reapply power state changes

* Update Content.Client/Kitchen/EntitySystems/ReagentGrinderSystem.cs

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>

* Update Content.Shared/Kitchen/Components/ReagentGrinderComponent.cs

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>

* comments and prefilled grinder protos

* t

---------

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: ScarKy0 <scarky0@onet.eu>
2026-06-29 12:44:09 +02:00

129 lines
5.5 KiB
C#

using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Kitchen;
using Content.Shared.Kitchen.Components;
using Content.Shared.Kitchen.EntitySystems;
using Content.Shared.Power.EntitySystems;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Kitchen.UI;
[GenerateTypedNameReferences]
public sealed partial class GrinderMenu : FancyWindow
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly ItemSlotsSystem _slots = default!;
private readonly SharedPowerReceiverSystem _power = default!;
private readonly SharedReagentGrinderSystem _grinder = default!;
private readonly SharedSolutionContainerSystem _solutionContainer = default!;
private readonly Dictionary<int, EntityUid> _chamberVisualContents = new();
private EntityUid _owner;
public event Action? OnToggleAuto;
public event Action? OnGrind;
public event Action? OnJuice;
public event Action? OnEjectAll;
public event Action? OnEjectBeaker;
public event Action<EntityUid>? OnEjectChamber;
public GrinderMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_slots = _entityManager.System<ItemSlotsSystem>();
_power = _entityManager.System<SharedPowerReceiverSystem>();
_grinder = _entityManager.System<SharedReagentGrinderSystem>();
_solutionContainer = _entityManager.System<SharedSolutionContainerSystem>();
AutoModeButton.OnPressed += _ => OnToggleAuto?.Invoke();
GrindButton.OnPressed += _ => OnGrind?.Invoke();
JuiceButton.OnPressed += _ => OnJuice?.Invoke();
ChamberContentBox.EjectButton.OnPressed += _ => OnEjectAll?.Invoke();
BeakerContentBox.EjectButton.OnPressed += _ => OnEjectBeaker?.Invoke();
ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected;
BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None;
}
private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args)
{
OnEjectChamber?.Invoke(_chamberVisualContents[args.ItemIndex]);
}
public void SetEntity(EntityUid owner)
{
_owner = owner;
UpdateUi();
}
public void UpdateUi()
{
if (!_entityManager.TryGetComponent<ReagentGrinderComponent>(_owner, out var grinderComp))
return;
var active = _grinder.IsActive((_owner, grinderComp));
var beaker = _slots.GetItemOrNull(_owner, ReagentGrinderComponent.BeakerSlotId);
var powered = _power.IsPowered(_owner);
var hasInput = grinderComp.InputContainer.ContainedEntities.Any();
var canGrind = hasInput && grinderComp.InputContainer.ContainedEntities.All(x => _grinder.CanGrind(x));
var canJuice = hasInput && grinderComp.InputContainer.ContainedEntities.All(x => _grinder.CanJuice(x));
BeakerContentBox.EjectButton.Disabled = active || !beaker.HasValue;
ChamberContentBox.EjectButton.Disabled = active || !hasInput;
GrindButton.Disabled = active || !canGrind || !powered || !beaker.HasValue;
JuiceButton.Disabled = active || !canJuice || !powered || !beaker.HasValue;
GrindButton.Modulate = grinderComp.Program == GrinderProgram.Grind ? Color.Green : Color.White;
JuiceButton.Modulate = grinderComp.Program == GrinderProgram.Juice ? Color.Green : Color.White;
AutoModeButton.Text = grinderComp.AutoMode switch
{
GrinderAutoMode.Grind => Loc.GetString("grinder-menu-grind-button"),
GrinderAutoMode.Juice => Loc.GetString("grinder-menu-juice-button"),
_ => Loc.GetString("grinder-menu-auto-button-off"),
};
//Refresh chamber contents
_chamberVisualContents.Clear();
ChamberContentBox.BoxContents.Clear();
foreach (var entity in grinderComp.InputContainer.ContainedEntities)
{
// TODO: Replace with SpriteView
var texture = _entityManager.GetComponent<SpriteComponent>(entity).Icon?.Default;
var solidItem = ChamberContentBox.BoxContents.AddItem(_entityManager.GetComponent<MetaDataComponent>(entity).EntityName, texture);
var solidIndex = ChamberContentBox.BoxContents.IndexOf(solidItem);
_chamberVisualContents.Add(solidIndex, entity);
}
//Refresh beaker contents
BeakerContentBox.BoxContents.Clear();
//if no beaker is attached use this guard to prevent hitting a null reference.
if (!beaker.HasValue || !_solutionContainer.TryGetFitsInDispenser(beaker.Value, out _, out var reagents))
return;
//Looks like we have a beaker attached.
if (!reagents.Any())
{
BeakerContentBox.BoxContents.AddItem(Loc.GetString("grinder-menu-beaker-content-box-is-empty"));
}
else
{
foreach (var (reagent, quantity) in reagents)
{
var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto)
? $"{quantity} {proto.LocalizedName}"
: "???";
BeakerContentBox.BoxContents.AddItem(reagentName);
}
}
}
}