--- /dev/null
+using Content.Client.Fluids.UI;
+using Content.Client.Items;
+using Content.Shared.Fluids;
+using Robust.Client.UserInterface;
+
+namespace Content.Client.Fluids;
+
+public sealed class MoppingSystem : SharedMoppingSystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+ Subs.ItemStatus<AbsorbentComponent>(GetAbsorbent);
+ }
+
+ private Control GetAbsorbent(EntityUid arg)
+ {
+ return new AbsorbentItemStatus(arg, EntityManager);
+ }
+}
--- /dev/null
+<Control xmlns="https://spacestation14.io">
+ <BoxContainer Orientation="Horizontal">
+ <ProgressBar
+ HorizontalExpand="True"
+ Name="PercentBar"
+ MinSize="20 20"
+ VerticalAlignment="Center"
+ Margin="2 8 4 2"
+ MaxValue="1.0"
+ MinValue="0.0">
+ </ProgressBar>
+ </BoxContainer>
+</Control>
--- /dev/null
+using Content.Shared.Fluids;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Timing;
+
+namespace Content.Client.Fluids.UI
+{
+ [GenerateTypedNameReferences]
+ public sealed partial class AbsorbentItemStatus : Control
+ {
+ private readonly IEntityManager _entManager;
+ private readonly EntityUid _uid;
+
+ public AbsorbentItemStatus(EntityUid uid, IEntityManager entManager)
+ {
+ RobustXamlLoader.Load(this);
+ _uid = uid;
+ _entManager = entManager;
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ base.FrameUpdate(args);
+ if (!_entManager.TryGetComponent<AbsorbentComponent>(_uid, out var absorbent))
+ return;
+
+ PercentBar.Value = absorbent.Progress;
+ }
+ }
+}
+using System.Linq;
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.DoAfter;
using Content.Server.Popups;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
+using Content.Shared.Fluids;
using Content.Shared.Interaction;
using Content.Shared.Tag;
using JetBrains.Annotations;
namespace Content.Server.Fluids.EntitySystems;
[UsedImplicitly]
-public sealed class MoppingSystem : EntitySystem
+public sealed class MoppingSystem : SharedMoppingSystem
{
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly SpillableSystem _spillableSystem = default!;
public override void Initialize()
{
base.Initialize();
+ SubscribeLocalEvent<AbsorbentComponent, ComponentInit>(OnAbsorbentInit);
SubscribeLocalEvent<AbsorbentComponent, AfterInteractEvent>(OnAfterInteract);
+ SubscribeLocalEvent<AbsorbentComponent, SolutionChangedEvent>(OnAbsorbentSolutionChange);
SubscribeLocalEvent<TransferCancelledEvent>(OnTransferCancelled);
SubscribeLocalEvent<TransferCompleteEvent>(OnTransferComplete);
}
+ private void OnAbsorbentInit(EntityUid uid, AbsorbentComponent component, ComponentInit args)
+ {
+ // TODO: I know dirty on init but no prediction moment.
+ UpdateAbsorbent(uid, component);
+ }
+
+ private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, SolutionChangedEvent args)
+ {
+ UpdateAbsorbent(uid, component);
+ }
+
+ private void UpdateAbsorbent(EntityUid uid, AbsorbentComponent component)
+ {
+ if (!_solutionSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out var solution))
+ return;
+
+ var oldProgress = component.Progress;
+
+ component.Progress = (float) (solution.Volume / solution.MaxVolume);
+ if (component.Progress.Equals(oldProgress))
+ return;
+ Dirty(component);
+ }
+
private void OnAfterInteract(EntityUid uid, AbsorbentComponent component, AfterInteractEvent args)
{
if (!args.CanReach || args.Handled)
-using Content.Server.Fluids.EntitySystems;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
-namespace Content.Server.Fluids.Components;
+namespace Content.Shared.Fluids;
/// <summary>
/// For entities that can clean up puddles
/// </summary>
-[RegisterComponent, Access(typeof(MoppingSystem))]
+[RegisterComponent, NetworkedComponent]
public sealed class AbsorbentComponent : Component
{
+ // TODO: Predicted solutions my beloved.
+ public float Progress;
+
public const string SolutionName = "absorbed";
[DataField("pickupAmount")]
--- /dev/null
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Fluids;
+
+public abstract class SharedMoppingSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<AbsorbentComponent, ComponentGetState>(OnAbsorbentGetState);
+ SubscribeLocalEvent<AbsorbentComponent, ComponentHandleState>(OnAbsorbentHandleState);
+ }
+
+ private void OnAbsorbentHandleState(EntityUid uid, AbsorbentComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not AbsorbentComponentState state)
+ return;
+
+ if (component.Progress.Equals(state.Progress))
+ return;
+
+ component.Progress = state.Progress;
+ }
+
+ private void OnAbsorbentGetState(EntityUid uid, AbsorbentComponent component, ref ComponentGetState args)
+ {
+ args.State = new AbsorbentComponentState()
+ {
+ Progress = component.Progress,
+ };
+ }
+
+ [Serializable, NetSerializable]
+ protected sealed class AbsorbentComponentState : ComponentState
+ {
+ public float Progress;
+ }
+}