diff --git a/Content.Client/Disposal/Components/DisposalUnitComponent.cs b/Content.Client/Disposal/Components/DisposalUnitComponent.cs index 5a45cbf677..4ef25aa185 100644 --- a/Content.Client/Disposal/Components/DisposalUnitComponent.cs +++ b/Content.Client/Disposal/Components/DisposalUnitComponent.cs @@ -17,10 +17,5 @@ namespace Content.Client.Disposal.Components RecentlyEjected = state.RecentlyEjected; } - - public override bool DragDropOn(DragDropEvent eventArgs) - { - return false; - } } } diff --git a/Content.Client/DragDrop/DragDropSystem.cs b/Content.Client/DragDrop/DragDropSystem.cs index ac01fda1ed..7c772ff698 100644 --- a/Content.Client/DragDrop/DragDropSystem.cs +++ b/Content.Client/DragDrop/DragDropSystem.cs @@ -30,7 +30,7 @@ namespace Content.Client.DragDrop /// Handles clientside drag and drop logic /// [UsedImplicitly] - public class DragDropSystem : EntitySystem + public class DragDropSystem : SharedDragDropSystem { [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IInputManager _inputManager = default!; @@ -433,7 +433,7 @@ namespace Content.Client.DragDrop return false; } - bool? valid = null; + var valid = CheckDragDropOn(eventArgs); foreach (var comp in EntityManager.GetComponents(eventArgs.Target)) { diff --git a/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs b/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs index 6625179a59..e1779682ae 100644 --- a/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs +++ b/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs @@ -53,7 +53,7 @@ namespace Content.IntegrationTests.Tests.Disposal { foreach (var entity in entities) { - Assert.That(unit.ContainedEntities.Contains(entity), Is.EqualTo(result)); + Assert.That(unit.Container.ContainedEntities.Contains(entity), Is.EqualTo(result)); } } @@ -65,11 +65,11 @@ namespace Content.IntegrationTests.Tests.Disposal private void Flush(DisposalUnitComponent unit, bool result, params EntityUid[] entities) { - Assert.That(unit.ContainedEntities, Is.SupersetOf(entities)); - Assert.That(entities.Length, Is.EqualTo(unit.ContainedEntities.Count)); + Assert.That(unit.Container.ContainedEntities, Is.SupersetOf(entities)); + Assert.That(entities.Length, Is.EqualTo(unit.Container.ContainedEntities.Count)); Assert.That(result, Is.EqualTo(EntitySystem.Get().TryFlush(unit))); - Assert.That(result || entities.Length == 0, Is.EqualTo(unit.ContainedEntities.Count == 0)); + Assert.That(result || entities.Length == 0, Is.EqualTo(unit.Container.ContainedEntities.Count == 0)); } private const string Prototypes = @" @@ -194,7 +194,7 @@ namespace Content.IntegrationTests.Tests.Disposal // Remove power need Assert.True(entityManager.TryGetComponent(disposalUnit, out ApcPowerReceiverComponent power)); power!.NeedsPower = false; - Assert.True(unit.Powered); + unit.Powered = true;//Power state changed event doesn't get fired smh // Flush with a mob and an item Flush(unit, true, human, wrench); diff --git a/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs b/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs index aaf9be47dd..9eaaafd90e 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs +++ b/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs @@ -26,7 +26,7 @@ namespace Content.Server.Disposal.Tube.Components var holder = _entMan.SpawnEntity(HolderPrototypeId, _entMan.GetComponent(Owner).MapPosition); var holderComponent = _entMan.GetComponent(holder); - foreach (var entity in from.ContainedEntities.ToArray()) + foreach (var entity in from.Container.ContainedEntities.ToArray()) { holderComponent.TryInsert(entity); } diff --git a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs index d450081d1e..cb94b72041 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs @@ -2,20 +2,12 @@ using System; using System.Collections.Generic; using System.Threading; using Content.Server.Atmos; -using Content.Server.Disposal.Unit.EntitySystems; -using Content.Server.Power.Components; using Content.Server.UserInterface; -using Content.Shared.ActionBlocker; -using Content.Shared.Acts; using Content.Shared.Atmos; using Content.Shared.Disposal.Components; -using Content.Shared.DragDrop; using Robust.Server.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Player; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -23,7 +15,7 @@ namespace Content.Server.Disposal.Unit.Components { [RegisterComponent] [ComponentReference(typeof(SharedDisposalUnitComponent))] - public class DisposalUnitComponent : SharedDisposalUnitComponent, IGasMixtureHolder, IDestroyAct + public class DisposalUnitComponent : SharedDisposalUnitComponent, IGasMixtureHolder { /// /// Last time that an entity tried to exit this disposal unit. @@ -41,7 +33,7 @@ namespace Content.Server.Disposal.Unit.Components [ViewVariables(VVAccess.ReadWrite)] [DataField("autoEngageTime")] - public readonly TimeSpan _automaticEngageTime = TimeSpan.FromSeconds(30); + public readonly TimeSpan AutomaticEngageTime = TimeSpan.FromSeconds(30); [ViewVariables(VVAccess.ReadWrite)] [DataField("flushDelay")] @@ -71,86 +63,14 @@ namespace Content.Server.Disposal.Unit.Components /// [ViewVariables] public Container Container = default!; - [ViewVariables] public IReadOnlyList ContainedEntities => Container.ContainedEntities; + [ViewVariables] public bool Powered = false; - [ViewVariables] - public bool Powered => - !IoCManager.Resolve().TryGetComponent(Owner, out ApcPowerReceiverComponent? receiver) || - receiver.Powered; - - [ViewVariables] public PressureState State => Pressure >= 1 ? PressureState.Ready : PressureState.Pressurizing; + [ViewVariables] public PressureState State = PressureState.Ready; [ViewVariables(VVAccess.ReadWrite)] public bool Engaged { get; set; } - [ViewVariables] public BoundUserInterface? UserInterface => Owner.GetUIOrNull(DisposalUnitUiKey.Key); - [DataField("air")] public GasMixture Air { get; set; } = new(Atmospherics.CellVolume); - - private bool PlayerCanUse(EntityUid player) - { - var actionBlocker = EntitySystem.Get(); - - if (!actionBlocker.CanInteract(player) || - !actionBlocker.CanUse(player)) - { - return false; - } - - return true; - } - - public void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) - { - if (obj.Session.AttachedEntity is not {Valid: true} player) - { - return; - } - - if (!PlayerCanUse(player)) - { - return; - } - - if (obj.Message is not UiButtonPressedMessage message) - { - return; - } - - switch (message.Button) - { - case UiButton.Eject: - EntitySystem.Get().TryEjectContents(this); - break; - case UiButton.Engage: - EntitySystem.Get().ToggleEngage(this); - break; - case UiButton.Power: - EntitySystem.Get().TogglePower(this); - SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f)); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - public override bool CanDragDropOn(DragDropEvent eventArgs) - { - // Base is redundant given this already calls the base CanInsert - // If that changes then update this - return EntitySystem.Get().CanInsert(this, eventArgs.Dragged); - } - - public override bool DragDropOn(DragDropEvent eventArgs) - { - EntitySystem.Get().TryInsert(Owner, eventArgs.Dragged, eventArgs.User); - return true; - } - - void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs) - { - EntitySystem.Get().TryEjectContents(this); - } } } diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index 0f4ea80077..fcc2154a66 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -9,10 +9,13 @@ using Content.Server.Disposal.Unit.Components; using Content.Server.DoAfter; using Content.Server.Hands.Components; using Content.Server.Power.Components; +using Content.Server.UserInterface; using Content.Shared.ActionBlocker; +using Content.Shared.Acts; using Content.Shared.Atmos; using Content.Shared.Disposal; using Content.Shared.Disposal.Components; +using Content.Shared.DragDrop; using Content.Shared.Interaction; using Content.Shared.Item; using Content.Shared.Movement; @@ -20,6 +23,7 @@ using Content.Shared.Popups; using Content.Shared.Throwing; using Content.Shared.Verbs; using Robust.Server.GameObjects; +using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -27,6 +31,7 @@ using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; +using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.Disposal.Unit.EntitySystems @@ -60,6 +65,8 @@ namespace Content.Server.Disposal.Unit.EntitySystems SubscribeLocalEvent(HandleActivate); SubscribeLocalEvent(HandleInteractHand); SubscribeLocalEvent(HandleInteractUsing); + SubscribeLocalEvent(HandleDragDropOn); + SubscribeLocalEvent(HandleDestruction); // Verbs SubscribeLocalEvent(AddFlushEjectVerbs); @@ -67,11 +74,14 @@ namespace Content.Server.Disposal.Unit.EntitySystems // Units SubscribeLocalEvent(DoInsertDisposalUnit); + + //UI + SubscribeLocalEvent(OnUiButtonPressed); } private void AddFlushEjectVerbs(EntityUid uid, DisposalUnitComponent component, GetAlternativeVerbsEvent args) { - if (!args.CanAccess || !args.CanInteract || component.ContainedEntities.Count == 0) + if (!args.CanAccess || !args.CanInteract || component.Container.ContainedEntities.Count == 0) return; // Verbs to flush the unit @@ -96,7 +106,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems // unwilling to accept that this is where they belong and don't want to accidentally climb inside. if (!args.CanAccess || !args.CanInteract || - component.ContainedEntities.Contains(args.User) || + component.Container.ContainedEntities.Contains(args.User) || !_actionBlockerSystem.CanMove(args.User)) return; @@ -142,6 +152,35 @@ namespace Content.Server.Disposal.Unit.EntitySystems } #region UI Handlers + private void OnUiButtonPressed(EntityUid uid, DisposalUnitComponent component, SharedDisposalUnitComponent.UiButtonPressedMessage args) + { + if (args.Session.AttachedEntity is not {Valid: true} player) + { + return; + } + + if (!_actionBlockerSystem.CanInteract(player) || !_actionBlockerSystem.CanUse(player)) + { + return; + } + + switch (args.Button) + { + case SharedDisposalUnitComponent.UiButton.Eject: + TryEjectContents(component); + break; + case SharedDisposalUnitComponent.UiButton.Engage: + ToggleEngage(component); + break; + case SharedDisposalUnitComponent.UiButton.Power: + TogglePower(component); + SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/machine_switch.ogg", component.Owner, AudioParams.Default.WithVolume(-2f)); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + public void ToggleEngage(DisposalUnitComponent component) { component.Engaged ^= true; @@ -180,7 +219,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems if (IsValidInteraction(args)) { - component.UserInterface?.Open(actor.PlayerSession); + component.Owner.GetUIOrNull(SharedDisposalUnitComponent.DisposalUnitUiKey.Key)?.Open(actor.PlayerSession); } } @@ -191,7 +230,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems // Duplicated code here, not sure how else to get actor inside to make UserInterface happy. if (!IsValidInteraction(args)) return; - component.UserInterface?.Open(actor.PlayerSession); + component.Owner.GetUIOrNull(SharedDisposalUnitComponent.DisposalUnitUiKey.Key)?.Open(actor.PlayerSession); args.Handled = true; } @@ -230,11 +269,6 @@ namespace Content.Server.Disposal.Unit.EntitySystems { component.Container = component.Owner.EnsureContainer(component.Name); - if (component.UserInterface != null) - { - component.UserInterface.OnReceiveMessage += component.OnUiReceiveMessage; - } - UpdateInterface(component, component.Powered); if (!EntityManager.HasComponent(component.Owner)) @@ -250,7 +284,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems component.Container.ForceRemove(entity); } - component.UserInterface?.CloseAll(); + component.Owner.GetUIOrNull(SharedDisposalUnitComponent.DisposalUnitUiKey.Key)?.CloseAll(); component.AutomaticEngageToken?.Cancel(); component.AutomaticEngageToken = null; @@ -264,6 +298,8 @@ namespace Content.Server.Disposal.Unit.EntitySystems if (!component.Running) return; + component.Powered = args.Powered; + // TODO: Need to check the other stuff. if (!args.Powered) { @@ -318,6 +354,16 @@ namespace Content.Server.Disposal.Unit.EntitySystems if (!args.Anchored) TryEjectContents(component); } + + private void HandleDestruction(EntityUid uid, DisposalUnitComponent component, DestructionEventArgs args) + { + TryEjectContents(component); + } + + private void HandleDragDropOn(EntityUid uid, DisposalUnitComponent component, DragDropEvent args) + { + args.Handled = TryInsert(component.Owner, args.Dragged, args.User); + } #endregion /// @@ -328,6 +374,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems var oldPressure = component.Pressure; component.Pressure = MathF.Min(1.0f, component.Pressure + PressurePerSecond * frameTime); + component.State = component.Pressure >= 1 ? SharedDisposalUnitComponent.PressureState.Ready : SharedDisposalUnitComponent.PressureState.Pressurizing; var state = component.State; @@ -399,13 +446,13 @@ namespace Content.Server.Disposal.Unit.EntitySystems return true; } - public void TryInsert(EntityUid unitId, EntityUid toInsertId, EntityUid userId, DisposalUnitComponent? unit = null) + public bool TryInsert(EntityUid unitId, EntityUid toInsertId, EntityUid userId, DisposalUnitComponent? unit = null) { if (!Resolve(unitId, ref unit)) - return; + return false; if (!CanInsert(unit, toInsertId)) - return; + return false; var delay = userId == toInsertId ? unit.EntryDelay : unit.DraggedEntryDelay; var ev = new DoInsertDisposalUnitEvent(userId, toInsertId, unitId); @@ -413,7 +460,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems if (delay <= 0) { DoInsertDisposalUnit(ev); - return; + return true; } // Can't check if our target AND disposals moves currently so we'll just check target. @@ -429,6 +476,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems }; _doAfterSystem.DoAfter(doAfterArgs); + return true; } @@ -465,6 +513,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems component.AutomaticEngageToken = null; component.Pressure = 0; + component.State = component.Pressure >= 1 ? SharedDisposalUnitComponent.PressureState.Ready : SharedDisposalUnitComponent.PressureState.Pressurizing; component.Engaged = false; @@ -479,7 +528,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems { var stateString = Loc.GetString($"{component.State}"); var state = new SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState(EntityManager.GetComponent(component.Owner).EntityName, stateString, EstimatedFullPressure(component), powered, component.Engaged); - component.UserInterface?.SetState(state); + component.Owner.GetUIOrNull(SharedDisposalUnitComponent.DisposalUnitUiKey.Key)?.SetState(state); } private TimeSpan EstimatedFullPressure(DisposalUnitComponent component) @@ -531,7 +580,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems return; } - if (component.ContainedEntities.Count > 0) + if (component.Container.ContainedEntities.Count > 0) { appearance.SetData(SharedDisposalUnitComponent.Visuals.Light, SharedDisposalUnitComponent.LightState.Full); return; @@ -546,7 +595,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems { component.Container.Remove(entity); - if (component.ContainedEntities.Count == 0) + if (component.Container.ContainedEntities.Count == 0) { component.AutomaticEngageToken?.Cancel(); component.AutomaticEngageToken = null; @@ -608,14 +657,14 @@ namespace Content.Server.Disposal.Unit.EntitySystems /// public void TryQueueEngage(DisposalUnitComponent component) { - if (component.Deleted || !component.Powered && component.ContainedEntities.Count == 0) + if (component.Deleted || !component.Powered && component.Container.ContainedEntities.Count == 0) { return; } component.AutomaticEngageToken = new CancellationTokenSource(); - component.Owner.SpawnTimer(component._automaticEngageTime, () => + component.Owner.SpawnTimer(component.AutomaticEngageTime, () => { if (!TryFlush(component)) { @@ -630,7 +679,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems if (EntityManager.TryGetComponent(entity, out ActorComponent? actor)) { - component.UserInterface?.Close(actor.PlayerSession); + component.Owner.GetUIOrNull(SharedDisposalUnitComponent.DisposalUnitUiKey.Key)?.Close(actor.PlayerSession); } UpdateVisualState(component); diff --git a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs index 0dd87f7de7..3a17228039 100644 --- a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs +++ b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs @@ -9,7 +9,7 @@ using Robust.Shared.Serialization; namespace Content.Shared.Disposal.Components { [NetworkedComponent] - public abstract class SharedDisposalUnitComponent : Component, IDragDropOn + public abstract class SharedDisposalUnitComponent : Component { public override string Name => "DisposalUnit"; @@ -134,13 +134,5 @@ namespace Content.Shared.Disposal.Components { Key } - - // TODO: Unfortunately these aren't really ECS yet so soontm - public virtual bool CanDragDropOn(DragDropEvent eventArgs) - { - return EntitySystem.Get().CanInsert(this, eventArgs.Dragged); - } - - public abstract bool DragDropOn(DragDropEvent eventArgs); } } diff --git a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs index 8a62badacf..acdb396ac2 100644 --- a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs +++ b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs @@ -1,6 +1,7 @@ using System; using Content.Shared.Body.Components; using Content.Shared.Disposal.Components; +using Content.Shared.DragDrop; using Content.Shared.Item; using Content.Shared.MobState.Components; using Content.Shared.Throwing; @@ -26,10 +27,11 @@ namespace Content.Shared.Disposal public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(HandlePreventCollide); + SubscribeLocalEvent(OnPreventCollide); + SubscribeLocalEvent(OnCanDragDropOn); } - private void HandlePreventCollide(EntityUid uid, SharedDisposalUnitComponent component, PreventCollideEvent args) + private void OnPreventCollide(EntityUid uid, SharedDisposalUnitComponent component, PreventCollideEvent args) { var otherBody = args.BodyB.Owner; @@ -47,6 +49,14 @@ namespace Content.Shared.Disposal } } + private void OnCanDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, CanDragDropOnEvent args) + { + if (args.Handled) return; + + args.CanDrop = CanInsert(component, args.Dragged); + args.Handled = true; + } + public virtual bool CanInsert(SharedDisposalUnitComponent component, EntityUid entity) { if (!EntityManager.GetComponent(component.Owner).Anchored) diff --git a/Content.Shared/DragDrop/CanDragDropOnEvent.cs b/Content.Shared/DragDrop/CanDragDropOnEvent.cs new file mode 100644 index 0000000000..02c5aa95cb --- /dev/null +++ b/Content.Shared/DragDrop/CanDragDropOnEvent.cs @@ -0,0 +1,38 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.DragDrop; + +/// +/// Event that gets send to the target of a drag drop action +/// Mark this event as handled to specify that the entity can be dropped on +/// and set CanDrop to true or false, depending on whether dropping the entity onto the target is actually possible. +/// +public class CanDragDropOnEvent : HandledEntityEventArgs +{ + /// + /// Entity doing the drag and drop. + /// + public EntityUid User { get; } + + /// + /// Entity that is being dragged. + /// + public EntityUid Dragged { get; } + + /// + /// Entity that is being dropped on. + /// + public EntityUid Target { get; } + + /// + /// If the dragged entity can be dropped on the target. + /// + public bool CanDrop { get; set; } = false; + + public CanDragDropOnEvent(EntityUid user, EntityUid dragged, EntityUid target) + { + User = user; + Dragged = dragged; + Target = target; + } +} diff --git a/Content.Shared/DragDrop/SharedDragDropSystem.cs b/Content.Shared/DragDrop/SharedDragDropSystem.cs new file mode 100644 index 0000000000..f75218e280 --- /dev/null +++ b/Content.Shared/DragDrop/SharedDragDropSystem.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.DragDrop; + +public abstract class SharedDragDropSystem : EntitySystem +{ + protected bool? CheckDragDropOn(DragDropEvent eventArgs) + { + var canDragDropOnEvent = new CanDragDropOnEvent(eventArgs.User, eventArgs.Dragged, eventArgs.Target); + + RaiseLocalEvent(eventArgs.Target, canDragDropOnEvent, false); + + return canDragDropOnEvent.Handled ? canDragDropOnEvent.CanDrop : null; + } +}