Disposals refactor (#17803)
This commit is contained in:
@@ -1,26 +0,0 @@
|
|||||||
using Content.Shared.Disposal.Components;
|
|
||||||
using Robust.Client.Animations;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
|
|
||||||
namespace Content.Client.Disposal.Components
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(SharedDisposalUnitComponent))]
|
|
||||||
public sealed class DisposalUnitComponent : SharedDisposalUnitComponent
|
|
||||||
{
|
|
||||||
[DataField("flushSound")]
|
|
||||||
public readonly SoundSpecifier? FlushSound;
|
|
||||||
|
|
||||||
public Animation FlushAnimation = default!;
|
|
||||||
|
|
||||||
public DisposalUnitBoundUserInterfaceState? UiState;
|
|
||||||
|
|
||||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
|
||||||
{
|
|
||||||
base.HandleComponentState(curState, nextState);
|
|
||||||
if (curState is not DisposalUnitComponentState state) return;
|
|
||||||
|
|
||||||
RecentlyEjected = state.RecentlyEjected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9
Content.Client/Disposal/DisposalUnitComponent.cs
Normal file
9
Content.Client/Disposal/DisposalUnitComponent.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Shared.Disposal.Components;
|
||||||
|
|
||||||
|
namespace Content.Client.Disposal;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DisposalUnitComponent : SharedDisposalUnitComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
using Content.Client.Disposal.Components;
|
|
||||||
using Content.Client.Disposal.UI;
|
|
||||||
using Content.Shared.Disposal;
|
using Content.Shared.Disposal;
|
||||||
|
using Content.Shared.Disposal.Components;
|
||||||
|
using Content.Shared.DragDrop;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Physics.Events;
|
||||||
using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent;
|
using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent;
|
||||||
|
|
||||||
namespace Content.Client.Disposal.Systems;
|
namespace Content.Client.Disposal.Systems;
|
||||||
@@ -12,131 +16,65 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
|
|||||||
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
|
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
|
||||||
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
|
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
private const string AnimationKey = "disposal_unit_animation";
|
|
||||||
|
|
||||||
private readonly List<EntityUid> _pressuringDisposals = new();
|
private const string AnimationKey = "disposal_unit_animation";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, ComponentHandleState>(OnHandleState);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, PreventCollideEvent>(OnPreventCollide);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, CanDropTargetEvent>(OnCanDragDropOn);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, ComponentInit>(OnComponentInit);
|
SubscribeLocalEvent<DisposalUnitComponent, ComponentInit>(OnComponentInit);
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
SubscribeLocalEvent<DisposalUnitComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateActive(EntityUid disposalEntity, bool active)
|
private void OnHandleState(EntityUid uid, DisposalUnitComponent component, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
if (active)
|
if (args.Current is not DisposalUnitComponentState state)
|
||||||
{
|
|
||||||
if (!_pressuringDisposals.Contains(disposalEntity))
|
|
||||||
_pressuringDisposals.Add(disposalEntity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pressuringDisposals.Remove(disposalEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void FrameUpdate(float frameTime)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(frameTime);
|
|
||||||
for (var i = _pressuringDisposals.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
var disposal = _pressuringDisposals[i];
|
|
||||||
if (!UpdateInterface(disposal))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_pressuringDisposals.RemoveAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool UpdateInterface(EntityUid disposalUnit)
|
|
||||||
{
|
|
||||||
if (!TryComp(disposalUnit, out DisposalUnitComponent? component) || component.Deleted)
|
|
||||||
return true;
|
|
||||||
if (component.Deleted)
|
|
||||||
return true;
|
|
||||||
if (!TryComp(disposalUnit, out ClientUserInterfaceComponent? userInterface))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var state = component.UiState;
|
|
||||||
if (state == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (var inter in userInterface.Interfaces)
|
|
||||||
{
|
|
||||||
if (inter is DisposalUnitBoundUserInterface boundInterface)
|
|
||||||
{
|
|
||||||
return boundInterface.UpdateWindowState(state) != false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, DisposalUnitComponent disposalUnit, ComponentInit args)
|
|
||||||
{
|
|
||||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!sprite.LayerMapTryGet(DisposalUnitVisualLayers.Base, out var baseLayerIdx))
|
component.FlushSound = state.FlushSound;
|
||||||
return; // Couldn't find the "normal" layer to return to after flush animation
|
component.State = state.State;
|
||||||
|
component.NextPressurized = state.NextPressurized;
|
||||||
|
component.AutomaticEngageTime = state.AutomaticEngageTime;
|
||||||
|
component.NextFlush = state.NextFlush;
|
||||||
|
component.Powered = state.Powered;
|
||||||
|
component.Engaged = state.Engaged;
|
||||||
|
component.RecentlyEjected.Clear();
|
||||||
|
component.RecentlyEjected.AddRange(state.RecentlyEjected);
|
||||||
|
}
|
||||||
|
|
||||||
if (!sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseFlush, out var flushLayerIdx))
|
public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null)
|
||||||
return; // Couldn't find the flush animation layer
|
|
||||||
|
|
||||||
var originalBaseState = sprite.LayerGetState(baseLayerIdx);
|
|
||||||
var flushState = sprite.LayerGetState(flushLayerIdx);
|
|
||||||
|
|
||||||
// Setup the flush animation to play
|
|
||||||
disposalUnit.FlushAnimation = new Animation
|
|
||||||
{
|
{
|
||||||
Length = TimeSpan.FromSeconds(disposalUnit.FlushTime),
|
return;
|
||||||
AnimationTracks = {
|
|
||||||
new AnimationTrackSpriteFlick {
|
|
||||||
LayerKey = DisposalUnitVisualLayers.BaseFlush,
|
|
||||||
KeyFrames = {
|
|
||||||
// Play the flush animation
|
|
||||||
new AnimationTrackSpriteFlick.KeyFrame(flushState, 0),
|
|
||||||
// Return to base state (though, depending on how the unit is
|
|
||||||
// configured we might get an appearence change event telling
|
|
||||||
// us to go to charging state)
|
|
||||||
new AnimationTrackSpriteFlick.KeyFrame(originalBaseState, disposalUnit.FlushTime)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (disposalUnit.FlushSound != null)
|
private void OnComponentInit(EntityUid uid, SharedDisposalUnitComponent sharedDisposalUnit, ComponentInit args)
|
||||||
{
|
{
|
||||||
disposalUnit.FlushAnimation.AnimationTracks.Add(
|
if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp<AppearanceComponent>(uid, out var appearance))
|
||||||
new AnimationTrackPlaySound
|
return;
|
||||||
{
|
|
||||||
KeyFrames = {
|
UpdateState(uid, sharedDisposalUnit, sprite, appearance);
|
||||||
new AnimationTrackPlaySound.KeyFrame(_audioSystem.GetSound(disposalUnit.FlushSound), 0)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureComp<AnimationPlayerComponent>(uid);
|
private void OnAppearanceChange(EntityUid uid, SharedDisposalUnitComponent unit, ref AppearanceChangeEvent args)
|
||||||
|
|
||||||
UpdateState(uid, disposalUnit, sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAppearanceChange(EntityUid uid, DisposalUnitComponent unit, ref AppearanceChangeEvent args)
|
|
||||||
{
|
{
|
||||||
if (args.Sprite == null)
|
if (args.Sprite == null)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
UpdateState(uid, unit, args.Sprite, args.Component);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateState(uid, unit, args.Sprite);
|
/// <summary>
|
||||||
}
|
/// Update visuals and tick animation
|
||||||
|
/// </summary>
|
||||||
// Update visuals and tick animation
|
private void UpdateState(EntityUid uid, SharedDisposalUnitComponent unit, SpriteComponent sprite, AppearanceComponent appearance)
|
||||||
private void UpdateState(EntityUid uid, DisposalUnitComponent unit, SpriteComponent sprite)
|
|
||||||
{
|
{
|
||||||
if (!_appearanceSystem.TryGetData<VisualState>(uid, Visuals.VisualState, out var state))
|
if (!_appearanceSystem.TryGetData<VisualState>(uid, Visuals.VisualState, out var state, appearance))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -144,24 +82,69 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
|
|||||||
sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == VisualState.UnAnchored);
|
sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == VisualState.UnAnchored);
|
||||||
sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == VisualState.Anchored);
|
sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == VisualState.Anchored);
|
||||||
sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseCharging, state == VisualState.Charging);
|
sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseCharging, state == VisualState.Charging);
|
||||||
sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseFlush, state == VisualState.Flushing);
|
sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseFlush, state is VisualState.Flushing or VisualState.Charging);
|
||||||
|
|
||||||
|
// This is a transient state so not too worried about replaying in range.
|
||||||
if (state == VisualState.Flushing)
|
if (state == VisualState.Flushing)
|
||||||
{
|
{
|
||||||
if (!_animationSystem.HasRunningAnimation(uid, AnimationKey))
|
if (!_animationSystem.HasRunningAnimation(uid, AnimationKey))
|
||||||
{
|
{
|
||||||
_animationSystem.Play(uid, unit.FlushAnimation, AnimationKey);
|
var flushState = new RSI.StateId("disposal-flush");
|
||||||
|
|
||||||
|
// Setup the flush animation to play
|
||||||
|
var anim = new Animation
|
||||||
|
{
|
||||||
|
Length = unit.FlushDelay,
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackSpriteFlick
|
||||||
|
{
|
||||||
|
LayerKey = DisposalUnitVisualLayers.BaseFlush,
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
// Play the flush animation
|
||||||
|
new AnimationTrackSpriteFlick.KeyFrame(flushState, 0),
|
||||||
|
// Return to base state (though, depending on how the unit is
|
||||||
|
// configured we might get an appearance change event telling
|
||||||
|
// us to go to charging state)
|
||||||
|
new AnimationTrackSpriteFlick.KeyFrame("disposal-charging", (float) unit.FlushDelay.TotalSeconds)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (unit.FlushSound != null)
|
||||||
|
{
|
||||||
|
anim.AnimationTracks.Add(
|
||||||
|
new AnimationTrackPlaySound
|
||||||
|
{
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackPlaySound.KeyFrame(_audioSystem.GetSound(unit.FlushSound), 0)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_appearanceSystem.TryGetData<HandleState>(uid, Visuals.Handle, out var handleState))
|
_animationSystem.Play(uid, anim, AnimationKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state == VisualState.Charging)
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(DisposalUnitVisualLayers.BaseFlush, new RSI.StateId("disposal-charging"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_animationSystem.Stop(uid, AnimationKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_appearanceSystem.TryGetData<HandleState>(uid, Visuals.Handle, out var handleState, appearance))
|
||||||
{
|
{
|
||||||
handleState = HandleState.Normal;
|
handleState = HandleState.Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != HandleState.Normal);
|
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != HandleState.Normal);
|
||||||
|
|
||||||
if (!_appearanceSystem.TryGetData<LightStates>(uid, Visuals.Light, out var lightState))
|
if (!_appearanceSystem.TryGetData<LightStates>(uid, Visuals.Light, out var lightState, appearance))
|
||||||
{
|
{
|
||||||
lightState = LightStates.Off;
|
lightState = LightStates.Off;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Client.Disposal.Components;
|
|
||||||
using Content.Client.Disposal.Systems;
|
using Content.Client.Disposal.Systems;
|
||||||
using Content.Shared.Disposal;
|
using Content.Shared.Disposal;
|
||||||
|
using Content.Shared.Disposal.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
@@ -16,7 +16,9 @@ namespace Content.Client.Disposal.UI
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
// What are you doing here
|
||||||
public MailingUnitWindow? MailingUnitWindow;
|
public MailingUnitWindow? MailingUnitWindow;
|
||||||
|
|
||||||
public DisposalUnitWindow? DisposalUnitWindow;
|
public DisposalUnitWindow? DisposalUnitWindow;
|
||||||
|
|
||||||
public DisposalUnitBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
|
public DisposalUnitBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
|
||||||
@@ -76,41 +78,27 @@ namespace Content.Client.Disposal.UI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entityId = Owner.Owner;
|
|
||||||
if (!_entityManager.TryGetComponent(entityId, out DisposalUnitComponent? component))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case MailingUnitBoundUserInterfaceState mailingUnitState:
|
case MailingUnitBoundUserInterfaceState mailingUnitState:
|
||||||
MailingUnitWindow?.UpdateState(mailingUnitState);
|
MailingUnitWindow?.UpdateState(mailingUnitState);
|
||||||
component.UiState = mailingUnitState.DisposalState;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisposalUnitBoundUserInterfaceState disposalUnitState:
|
case DisposalUnitBoundUserInterfaceState disposalUnitState:
|
||||||
DisposalUnitWindow?.UpdateState(disposalUnitState);
|
DisposalUnitWindow?.UpdateState(disposalUnitState);
|
||||||
component.UiState = disposalUnitState;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_entityManager.System<DisposalUnitSystem>().UpdateActive(entityId, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
if (!disposing) return;
|
if (!disposing)
|
||||||
|
return;
|
||||||
|
|
||||||
MailingUnitWindow?.Dispose();
|
MailingUnitWindow?.Dispose();
|
||||||
DisposalUnitWindow?.Dispose();
|
DisposalUnitWindow?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool? UpdateWindowState(DisposalUnitBoundUserInterfaceState state)
|
|
||||||
{
|
|
||||||
return UiKey is DisposalUnitUiKey
|
|
||||||
? DisposalUnitWindow?.UpdateState(state)
|
|
||||||
: MailingUnitWindow?.UpdatePressure(state.FullPressureTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Shared.Disposal.Components;
|
|||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent;
|
using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent;
|
||||||
|
|
||||||
namespace Content.Client.Disposal.UI
|
namespace Content.Client.Disposal.UI
|
||||||
@@ -12,6 +13,8 @@ namespace Content.Client.Disposal.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class DisposalUnitWindow : DefaultWindow
|
public sealed partial class DisposalUnitWindow : DefaultWindow
|
||||||
{
|
{
|
||||||
|
public TimeSpan FullPressure;
|
||||||
|
|
||||||
public DisposalUnitWindow()
|
public DisposalUnitWindow()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
@@ -22,14 +25,19 @@ namespace Content.Client.Disposal.UI
|
|||||||
/// Update the interface state for the disposals window.
|
/// Update the interface state for the disposals window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>true if we should stop updating every frame.</returns>
|
/// <returns>true if we should stop updating every frame.</returns>
|
||||||
public bool UpdateState(DisposalUnitBoundUserInterfaceState state)
|
public void UpdateState(DisposalUnitBoundUserInterfaceState state)
|
||||||
{
|
{
|
||||||
Title = state.UnitName;
|
Title = state.UnitName;
|
||||||
UnitState.Text = state.UnitState;
|
UnitState.Text = state.UnitState;
|
||||||
Power.Pressed = state.Powered;
|
Power.Pressed = state.Powered;
|
||||||
Engage.Pressed = state.Engaged;
|
Engage.Pressed = state.Engaged;
|
||||||
|
FullPressure = state.FullPressureTime;
|
||||||
|
}
|
||||||
|
|
||||||
return !state.Powered || PressureBar.UpdatePressure(state.FullPressureTime);
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
{
|
||||||
|
base.FrameUpdate(args);
|
||||||
|
PressureBar.UpdatePressure(FullPressure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Server.Disposal.Unit.Components;
|
|||||||
using Content.Server.Disposal.Unit.EntitySystems;
|
using Content.Server.Disposal.Unit.EntitySystems;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Shared.Disposal;
|
using Content.Shared.Disposal;
|
||||||
|
using Content.Shared.Disposal.Components;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Reflection;
|
using Robust.Shared.Reflection;
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.Disposal.Unit.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed class ActiveDisposalUnitComponent : Component
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,77 +1,13 @@
|
|||||||
using System.Threading;
|
|
||||||
using Content.Server.Atmos;
|
using Content.Server.Atmos;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Disposal.Components;
|
using Content.Shared.Disposal.Components;
|
||||||
using Robust.Shared.Containers;
|
|
||||||
|
|
||||||
namespace Content.Server.Disposal.Unit.Components
|
namespace Content.Server.Disposal.Unit.Components;
|
||||||
{
|
|
||||||
|
// GasMixture life.
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(SharedDisposalUnitComponent))]
|
public sealed class DisposalUnitComponent : SharedDisposalUnitComponent
|
||||||
public sealed class DisposalUnitComponent : SharedDisposalUnitComponent, IGasMixtureHolder
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Last time that an entity tried to exit this disposal unit.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public TimeSpan LastExitAttempt;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current pressure of this disposal unit.
|
|
||||||
/// Prevents it from flushing if it is not equal to or bigger than 1.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("pressure")]
|
|
||||||
public float Pressure = 1f;
|
|
||||||
|
|
||||||
[DataField("autoEngageEnabled")]
|
|
||||||
public bool AutomaticEngage = true;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("autoEngageTime")]
|
|
||||||
public readonly TimeSpan AutomaticEngageTime = TimeSpan.FromSeconds(30);
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("flushDelay")]
|
|
||||||
public readonly TimeSpan FlushDelay = TimeSpan.FromSeconds(3);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delay from trying to enter disposals ourselves.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
[DataField("entryDelay")]
|
|
||||||
public float EntryDelay = 0.5f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delay from trying to shove someone else into disposals.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float DraggedEntryDelay = 0.5f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Token used to cancel the automatic engage of a disposal unit
|
|
||||||
/// after an entity enters it.
|
|
||||||
/// </summary>
|
|
||||||
public CancellationTokenSource? AutomaticEngageToken;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Container of entities inside this disposal unit.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables] public Container Container = default!;
|
|
||||||
|
|
||||||
[ViewVariables] public bool Powered = false;
|
|
||||||
|
|
||||||
[ViewVariables] public PressureState State = PressureState.Ready;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool Engaged { get; set; }
|
|
||||||
|
|
||||||
[DataField("air")]
|
[DataField("air")]
|
||||||
public GasMixture Air { get; set; } = new(Atmospherics.CellVolume);
|
public GasMixture Air = new(Atmospherics.CellVolume);
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public TimeSpan NextFlush = TimeSpan.MaxValue;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public bool AutoFlushing = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Server.Disposal.Tube;
|
|||||||
using Content.Server.Disposal.Tube.Components;
|
using Content.Server.Disposal.Tube.Components;
|
||||||
using Content.Server.Disposal.Unit.Components;
|
using Content.Server.Disposal.Unit.Components;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
|
using Content.Shared.Disposal.Components;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
@@ -13,8 +14,7 @@ using Robust.Shared.Physics.Systems;
|
|||||||
|
|
||||||
namespace Content.Server.Disposal.Unit.EntitySystems
|
namespace Content.Server.Disposal.Unit.EntitySystems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
public sealed class DisposableSystem : EntitySystem
|
||||||
internal sealed class DisposableSystem : EntitySystem
|
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!;
|
[Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Disposal.Tube;
|
using Content.Server.Disposal.Tube;
|
||||||
@@ -10,13 +9,13 @@ using Content.Server.Power.Components;
|
|||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Construction.Components;
|
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.Disposal;
|
using Content.Shared.Disposal;
|
||||||
using Content.Shared.Disposal.Components;
|
using Content.Shared.Disposal.Components;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
@@ -27,68 +26,87 @@ using Content.Shared.Throwing;
|
|||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
|
using Robust.Shared.Physics.Events;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Disposal.Unit.EntitySystems
|
namespace Content.Server.Disposal.Unit.EntitySystems;
|
||||||
{
|
|
||||||
public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
|
public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly DisposalTubeSystem _disposalTubeSystem = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly PowerReceiverSystem _power = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||||
[Dependency] private readonly PowerReceiverSystem _power = default!;
|
|
||||||
[Dependency] private readonly DisposalTubeSystem _disposalTubeSystem = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
||||||
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, ComponentGetState>(OnGetState);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, PreventCollideEvent>(OnPreventCollide);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, CanDropTargetEvent>(OnCanDragDropOn);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
|
||||||
// Shouldn't need re-anchoring.
|
// Shouldn't need re-anchoring.
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
SubscribeLocalEvent<DisposalUnitComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
// TODO: Predict me when hands predicted
|
// TODO: Predict me when hands predicted
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, ContainerRelayMovementEntityEvent>(HandleMovement);
|
SubscribeLocalEvent<DisposalUnitComponent, ContainerRelayMovementEntityEvent>(OnMovement);
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, PowerChangedEvent>(HandlePowerChange);
|
SubscribeLocalEvent<DisposalUnitComponent, PowerChangedEvent>(OnPowerChange);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, ComponentInit>(OnDisposalInit);
|
||||||
|
|
||||||
// Component lifetime
|
SubscribeLocalEvent<DisposalUnitComponent, ThrowHitByEvent>(OnThrowCollide);
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, ComponentInit>(HandleDisposalInit);
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, ComponentRemove>(HandleDisposalRemove);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, ThrowHitByEvent>(HandleThrowCollide);
|
SubscribeLocalEvent<DisposalUnitComponent, ActivateInWorldEvent>(OnActivate);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, DragDropTargetEvent>(OnDragDropOn);
|
||||||
|
SubscribeLocalEvent<DisposalUnitComponent, DestructionEventArgs>(OnDestruction);
|
||||||
|
|
||||||
// Interactions
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, ActivateInWorldEvent>(HandleActivate);
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, AfterInteractUsingEvent>(HandleAfterInteractUsing);
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, DragDropTargetEvent>(HandleDragDropOn);
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, DestructionEventArgs>(HandleDestruction);
|
|
||||||
|
|
||||||
// Verbs
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, GetVerbsEvent<InteractionVerb>>(AddInsertVerb);
|
SubscribeLocalEvent<DisposalUnitComponent, GetVerbsEvent<InteractionVerb>>(AddInsertVerb);
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, GetVerbsEvent<AlternativeVerb>>(AddDisposalAltVerbs);
|
SubscribeLocalEvent<DisposalUnitComponent, GetVerbsEvent<AlternativeVerb>>(AddDisposalAltVerbs);
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, GetVerbsEvent<Verb>>(AddClimbInsideVerb);
|
SubscribeLocalEvent<DisposalUnitComponent, GetVerbsEvent<Verb>>(AddClimbInsideVerb);
|
||||||
|
|
||||||
// Units
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, DisposalDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<DisposalUnitComponent, DisposalDoAfterEvent>(OnDoAfter);
|
||||||
|
|
||||||
//UI
|
|
||||||
SubscribeLocalEvent<DisposalUnitComponent, SharedDisposalUnitComponent.UiButtonPressedMessage>(OnUiButtonPressed);
|
SubscribeLocalEvent<DisposalUnitComponent, SharedDisposalUnitComponent.UiButtonPressedMessage>(OnUiButtonPressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddDisposalAltVerbs(EntityUid uid, DisposalUnitComponent component, GetVerbsEvent<AlternativeVerb> args)
|
private void OnGetState(EntityUid uid, DisposalUnitComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new DisposalUnitComponentState(
|
||||||
|
component.FlushSound,
|
||||||
|
component.State,
|
||||||
|
component.NextPressurized,
|
||||||
|
component.AutomaticEngageTime,
|
||||||
|
component.NextFlush,
|
||||||
|
component.Powered,
|
||||||
|
component.Engaged,
|
||||||
|
component.RecentlyEjected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnpaused(EntityUid uid, SharedDisposalUnitComponent component, ref EntityUnpausedEvent args)
|
||||||
|
{
|
||||||
|
if (component.NextFlush != null)
|
||||||
|
component.NextFlush = component.NextFlush.Value + args.PausedTime;
|
||||||
|
|
||||||
|
component.NextPressurized += args.PausedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDisposalAltVerbs(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
if (!args.CanAccess || !args.CanInteract)
|
if (!args.CanAccess || !args.CanInteract)
|
||||||
return;
|
return;
|
||||||
@@ -99,7 +117,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
// Verbs to flush the unit
|
// Verbs to flush the unit
|
||||||
AlternativeVerb flushVerb = new()
|
AlternativeVerb flushVerb = new()
|
||||||
{
|
{
|
||||||
Act = () => Engage(uid, component),
|
Act = () => ManualEngage(uid, component),
|
||||||
Text = Loc.GetString("disposal-flush-verb-get-data-text"),
|
Text = Loc.GetString("disposal-flush-verb-get-data-text"),
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
|
||||||
Priority = 1,
|
Priority = 1,
|
||||||
@@ -117,7 +135,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddClimbInsideVerb(EntityUid uid, DisposalUnitComponent component, GetVerbsEvent<Verb> args)
|
private void AddClimbInsideVerb(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent<Verb> args)
|
||||||
{
|
{
|
||||||
// This is not an interaction, activation, or alternative verb type because unfortunately most users are
|
// This is not an interaction, activation, or alternative verb type because unfortunately most users are
|
||||||
// unwilling to accept that this is where they belong and don't want to accidentally climb inside.
|
// unwilling to accept that this is where they belong and don't want to accidentally climb inside.
|
||||||
@@ -126,7 +144,9 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
!args.CanInteract ||
|
!args.CanInteract ||
|
||||||
component.Container.ContainedEntities.Contains(args.User) ||
|
component.Container.ContainedEntities.Contains(args.User) ||
|
||||||
!_actionBlockerSystem.CanMove(args.User))
|
!_actionBlockerSystem.CanMove(args.User))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Add verb to climb inside of the unit,
|
// Add verb to climb inside of the unit,
|
||||||
Verb verb = new()
|
Verb verb = new()
|
||||||
@@ -142,7 +162,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddInsertVerb(EntityUid uid, DisposalUnitComponent component, GetVerbsEvent<InteractionVerb> args)
|
private void AddInsertVerb(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent<InteractionVerb> args)
|
||||||
{
|
{
|
||||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null || args.Using == null)
|
if (!args.CanAccess || !args.CanInteract || args.Hands == null || args.Using == null)
|
||||||
return;
|
return;
|
||||||
@@ -168,7 +188,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
args.Verbs.Add(insertVerb);
|
args.Verbs.Add(insertVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoAfter(EntityUid uid, DisposalUnitComponent component, DoAfterEvent args)
|
private void OnDoAfter(EntityUid uid, SharedDisposalUnitComponent component, DoAfterEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled || args.Cancelled || args.Args.Target == null || args.Args.Used == null)
|
if (args.Handled || args.Cancelled || args.Args.Target == null || args.Args.Used == null)
|
||||||
return;
|
return;
|
||||||
@@ -178,7 +198,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, DisposalUnitComponent? disposal = null)
|
public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref disposal))
|
if (!Resolve(uid, ref disposal))
|
||||||
return;
|
return;
|
||||||
@@ -194,18 +214,15 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<ActiveDisposalUnitComponent, DisposalUnitComponent>();
|
var query = EntityQueryEnumerator<DisposalUnitComponent, MetaDataComponent>();
|
||||||
while (query.MoveNext(out var uid, out var _, out var unit))
|
while (query.MoveNext(out var uid, out var unit, out var metadata))
|
||||||
{
|
{
|
||||||
if (!Update(uid, unit, frameTime))
|
Update(uid, unit, metadata, frameTime);
|
||||||
continue;
|
|
||||||
|
|
||||||
RemComp<ActiveDisposalUnitComponent>(uid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region UI Handlers
|
#region UI Handlers
|
||||||
private void OnUiButtonPressed(EntityUid uid, DisposalUnitComponent component, SharedDisposalUnitComponent.UiButtonPressedMessage args)
|
private void OnUiButtonPressed(EntityUid uid, SharedDisposalUnitComponent component, SharedDisposalUnitComponent.UiButtonPressedMessage args)
|
||||||
{
|
{
|
||||||
if (args.Session.AttachedEntity is not { Valid: true } player)
|
if (args.Session.AttachedEntity is not { Valid: true } player)
|
||||||
{
|
{
|
||||||
@@ -230,23 +247,25 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleEngage(EntityUid uid, DisposalUnitComponent component)
|
public void ToggleEngage(EntityUid uid, SharedDisposalUnitComponent component)
|
||||||
{
|
{
|
||||||
component.Engaged ^= true;
|
component.Engaged ^= true;
|
||||||
|
|
||||||
if (component.Engaged)
|
if (component.Engaged)
|
||||||
{
|
{
|
||||||
Engage(uid, component);
|
ManualEngage(uid, component);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Disengage(uid, component);
|
Disengage(uid, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Eventbus Handlers
|
#region Eventbus Handlers
|
||||||
private void HandleActivate(EntityUid uid, DisposalUnitComponent component, ActivateInWorldEvent args)
|
|
||||||
|
private void OnActivate(EntityUid uid, SharedDisposalUnitComponent component, ActivateInWorldEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp(args.User, out ActorComponent? actor))
|
if (!TryComp(args.User, out ActorComponent? actor))
|
||||||
{
|
{
|
||||||
@@ -257,7 +276,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
_ui.TryOpen(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession);
|
_ui.TryOpen(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleAfterInteractUsing(EntityUid uid, DisposalUnitComponent component, AfterInteractUsingEvent args)
|
private void OnAfterInteractUsing(EntityUid uid, SharedDisposalUnitComponent component, AfterInteractUsingEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled || !args.CanReach)
|
if (args.Handled || !args.CanReach)
|
||||||
return;
|
return;
|
||||||
@@ -280,7 +299,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thrown items have a chance of bouncing off the unit and not going in.
|
/// Thrown items have a chance of bouncing off the unit and not going in.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void HandleThrowCollide(EntityUid uid, DisposalUnitComponent component, ThrowHitByEvent args)
|
private void OnThrowCollide(EntityUid uid, SharedDisposalUnitComponent component, ThrowHitByEvent args)
|
||||||
{
|
{
|
||||||
if (!CanInsert(uid, component, args.Thrown) ||
|
if (!CanInsert(uid, component, args.Thrown) ||
|
||||||
_robustRandom.NextDouble() > 0.75 ||
|
_robustRandom.NextDouble() > 0.75 ||
|
||||||
@@ -292,74 +311,41 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
|
|
||||||
if (args.User != null)
|
if (args.User != null)
|
||||||
_adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.User.Value):player} landed in {ToPrettyString(uid)}");
|
_adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.User.Value):player} landed in {ToPrettyString(uid)}");
|
||||||
|
|
||||||
AfterInsert(uid, component, args.Thrown);
|
AfterInsert(uid, component, args.Thrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDisposalInit(EntityUid uid, DisposalUnitComponent component, ComponentInit args)
|
private void OnDisposalInit(EntityUid uid, SharedDisposalUnitComponent component, ComponentInit args)
|
||||||
{
|
{
|
||||||
component.Container = _containerSystem.EnsureContainer<Container>(uid, SharedDisposalUnitComponent.ContainerId);
|
component.Container = _containerSystem.EnsureContainer<Container>(uid, SharedDisposalUnitComponent.ContainerId);
|
||||||
|
|
||||||
UpdateInterface(uid, component, component.Powered);
|
UpdateInterface(uid, component, component.Powered);
|
||||||
|
|
||||||
if (!HasComp<AnchorableComponent>(uid))
|
|
||||||
{
|
|
||||||
Log.Warning($"Disposal unit {uid} is missing an {nameof(AnchorableComponent)}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDisposalRemove(EntityUid uid, DisposalUnitComponent component, ComponentRemove args)
|
private void OnPowerChange(EntityUid uid, SharedDisposalUnitComponent component, ref PowerChangedEvent args)
|
||||||
{
|
{
|
||||||
foreach (var entity in component.Container.ContainedEntities.ToArray())
|
if (!component.Running || args.Powered == component.Powered)
|
||||||
{
|
|
||||||
component.Container.Remove(entity, force: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ui.TryCloseAll(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key);
|
|
||||||
component.NextFlush = TimeSpan.MaxValue;
|
|
||||||
|
|
||||||
component.Container = null!;
|
|
||||||
RemComp<ActiveDisposalUnitComponent>(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandlePowerChange(EntityUid uid, DisposalUnitComponent component, ref PowerChangedEvent args)
|
|
||||||
{
|
|
||||||
if (!component.Running)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
component.Powered = args.Powered;
|
component.Powered = args.Powered;
|
||||||
|
|
||||||
// TODO: Need to check the other stuff.
|
|
||||||
if (!args.Powered)
|
|
||||||
{
|
|
||||||
component.NextFlush = TimeSpan.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleStateChange(uid, component, args.Powered && (component.State == SharedDisposalUnitComponent.PressureState.Pressurizing || component.NextFlush != TimeSpan.MaxValue));
|
|
||||||
UpdateVisualState(uid, component);
|
UpdateVisualState(uid, component);
|
||||||
UpdateInterface(uid, component, args.Powered);
|
UpdateInterface(uid, component, args.Powered);
|
||||||
|
|
||||||
|
if (!args.Powered)
|
||||||
|
{
|
||||||
|
component.NextFlush = null;
|
||||||
|
Dirty(component);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (component.Engaged && !TryFlush(uid, component))
|
if (component.Engaged && !TryFlush(uid, component))
|
||||||
{
|
{
|
||||||
TryQueueEngage(uid, component);
|
QueueAutomaticEngage(uid, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// TODO: This should just use the same thing as entity storage?
|
||||||
/// Add or remove this disposal from the active ones for updating.
|
private void OnMovement(EntityUid uid, SharedDisposalUnitComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||||
/// </summary>
|
|
||||||
public void HandleStateChange(EntityUid uid, DisposalUnitComponent _, bool active)
|
|
||||||
{
|
|
||||||
if (active)
|
|
||||||
{
|
|
||||||
EnsureComp<ActiveDisposalUnitComponent>(uid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RemComp<ActiveDisposalUnitComponent>(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleMovement(EntityUid uid, DisposalUnitComponent component, ref ContainerRelayMovementEntityEvent args)
|
|
||||||
{
|
{
|
||||||
var currentTime = GameTiming.CurTime;
|
var currentTime = GameTiming.CurTime;
|
||||||
|
|
||||||
@@ -374,7 +360,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
Remove(uid, component, args.Entity);
|
Remove(uid, component, args.Entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAnchorChanged(EntityUid uid, DisposalUnitComponent component, ref AnchorStateChangedEvent args)
|
private void OnAnchorChanged(EntityUid uid, SharedDisposalUnitComponent component, ref AnchorStateChangedEvent args)
|
||||||
{
|
{
|
||||||
if (Terminating(uid))
|
if (Terminating(uid))
|
||||||
return;
|
return;
|
||||||
@@ -384,58 +370,71 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
TryEjectContents(uid, component);
|
TryEjectContents(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDestruction(EntityUid uid, DisposalUnitComponent component, DestructionEventArgs args)
|
private void OnDestruction(EntityUid uid, SharedDisposalUnitComponent component, DestructionEventArgs args)
|
||||||
{
|
{
|
||||||
TryEjectContents(uid, component);
|
TryEjectContents(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDragDropOn(EntityUid uid, DisposalUnitComponent component, ref DragDropTargetEvent args)
|
private void OnDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, ref DragDropTargetEvent args)
|
||||||
{
|
{
|
||||||
args.Handled = TryInsert(uid, args.Dragged, args.User);
|
args.Handled = TryInsert(uid, args.Dragged, args.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void UpdateState(EntityUid uid, DisposalsPressureState state, SharedDisposalUnitComponent component, MetaDataComponent metadata)
|
||||||
|
{
|
||||||
|
if (component.State == state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.State = state;
|
||||||
|
UpdateVisualState(uid, component);
|
||||||
|
UpdateInterface(uid, component, component.Powered);
|
||||||
|
Dirty(component, metadata);
|
||||||
|
|
||||||
|
if (state == DisposalsPressureState.Ready)
|
||||||
|
{
|
||||||
|
component.NextPressurized = TimeSpan.Zero;
|
||||||
|
|
||||||
|
// Manually engaged
|
||||||
|
if (component.Engaged)
|
||||||
|
{
|
||||||
|
component.NextFlush = GameTiming.CurTime + component.ManualFlushTime;
|
||||||
|
}
|
||||||
|
else if (component.Container.ContainedEntities.Count > 0)
|
||||||
|
{
|
||||||
|
component.NextFlush = GameTiming.CurTime + component.AutomaticEngageTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
component.NextFlush = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Work out if we can stop updating this disposals component i.e. full pressure and nothing colliding.
|
/// Work out if we can stop updating this disposals component i.e. full pressure and nothing colliding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool Update(EntityUid uid, DisposalUnitComponent component, float frameTime)
|
private void Update(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent metadata, float frameTime)
|
||||||
{
|
{
|
||||||
var oldPressure = component.Pressure;
|
var state = GetState(uid, component, metadata);
|
||||||
|
|
||||||
component.Pressure = MathF.Min(1.0f, component.Pressure + PressurePerSecond * frameTime);
|
// Pressurizing, just check if we need a state update.
|
||||||
component.State = component.Pressure >= 1 ? SharedDisposalUnitComponent.PressureState.Ready : SharedDisposalUnitComponent.PressureState.Pressurizing;
|
if (component.NextPressurized > GameTiming.CurTime)
|
||||||
|
|
||||||
var state = component.State;
|
|
||||||
|
|
||||||
if (oldPressure < 1 && state == SharedDisposalUnitComponent.PressureState.Ready)
|
|
||||||
{
|
{
|
||||||
UpdateVisualState(uid, component);
|
UpdateState(uid, state, component, metadata);
|
||||||
UpdateInterface(uid, component, component.Powered);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (component.Engaged)
|
if (component.NextFlush != null)
|
||||||
|
{
|
||||||
|
if (component.NextFlush.Value < GameTiming.CurTime)
|
||||||
{
|
{
|
||||||
TryFlush(uid, component);
|
TryFlush(uid, component);
|
||||||
state = component.State;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.State == SharedDisposalUnitComponent.PressureState.Pressurizing)
|
UpdateState(uid, state, component, metadata);
|
||||||
{
|
|
||||||
var oldTimeElapsed = oldPressure / PressurePerSecond;
|
|
||||||
if (oldTimeElapsed < component.FlushTime && oldTimeElapsed + frameTime >= component.FlushTime)
|
|
||||||
{
|
|
||||||
// We've crossed over the amount of time it takes to flush. This will switch the
|
|
||||||
// visuals over to a 'Charging' state.
|
|
||||||
UpdateVisualState(uid, component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (component.State == SharedDisposalUnitComponent.PressureState.Ready && component.NextFlush < _gameTiming.CurTime)
|
|
||||||
{
|
|
||||||
if (!TryFlush(uid, component) && component.AutoFlushing)
|
|
||||||
TryQueueEngage(uid, component);
|
|
||||||
else
|
|
||||||
component.AutoFlushing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Box2? disposalsBounds = null;
|
Box2? disposalsBounds = null;
|
||||||
var count = component.RecentlyEjected.Count;
|
var count = component.RecentlyEjected.Count;
|
||||||
@@ -452,7 +451,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = component.RecentlyEjected.Count - 1; i >= 0; i--)
|
for (var i = 0; i < component.RecentlyEjected.Count; i++)
|
||||||
{
|
{
|
||||||
var ejectedId = component.RecentlyEjected[i];
|
var ejectedId = component.RecentlyEjected[i];
|
||||||
if (HasComp<PhysicsComponent>(ejectedId))
|
if (HasComp<PhysicsComponent>(ejectedId))
|
||||||
@@ -465,14 +464,14 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
component.RecentlyEjected.RemoveAt(i);
|
component.RecentlyEjected.RemoveAt(i);
|
||||||
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count != component.RecentlyEjected.Count)
|
if (count != component.RecentlyEjected.Count)
|
||||||
Dirty(component);
|
Dirty(component, metadata);
|
||||||
|
|
||||||
return state == SharedDisposalUnitComponent.PressureState.Ready && component.NextFlush == TimeSpan.MaxValue && component.RecentlyEjected.Count == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryInsert(EntityUid unitId, EntityUid toInsertId, EntityUid? userId, DisposalUnitComponent? unit = null)
|
public bool TryInsert(EntityUid unitId, EntityUid toInsertId, EntityUid? userId, DisposalUnitComponent? unit = null)
|
||||||
@@ -512,16 +511,16 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool TryFlush(EntityUid uid, DisposalUnitComponent component)
|
public bool TryFlush(EntityUid uid, SharedDisposalUnitComponent component)
|
||||||
{
|
{
|
||||||
if (component.Deleted || !CanFlush(uid, component))
|
if (!CanFlush(uid, component))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
component.NextFlush = TimeSpan.MaxValue;
|
if (component.NextFlush != null)
|
||||||
|
component.NextFlush = component.NextFlush.Value + component.AutomaticEngageTime;
|
||||||
|
|
||||||
//Allows the MailingUnitSystem to add tags or prevent flushing
|
|
||||||
var beforeFlushArgs = new BeforeDisposalFlushEvent();
|
var beforeFlushArgs = new BeforeDisposalFlushEvent();
|
||||||
RaiseLocalEvent(uid, beforeFlushArgs);
|
RaiseLocalEvent(uid, beforeFlushArgs);
|
||||||
|
|
||||||
@@ -537,15 +536,35 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
|
|
||||||
var coords = xform.Coordinates;
|
var coords = xform.Coordinates;
|
||||||
var entry = grid.GetLocal(coords)
|
var entry = grid.GetLocal(coords)
|
||||||
.FirstOrDefault(entity => HasComp<DisposalEntryComponent>(entity));
|
.FirstOrDefault(HasComp<DisposalEntryComponent>);
|
||||||
|
|
||||||
if (entry == default)
|
if (entry == default || component is not DisposalUnitComponent sDisposals)
|
||||||
{
|
{
|
||||||
|
component.Engaged = false;
|
||||||
|
Dirty(component);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HandleAir(uid, sDisposals, xform);
|
||||||
|
|
||||||
|
_disposalTubeSystem.TryInsert(entry, sDisposals, beforeFlushArgs.Tags);
|
||||||
|
|
||||||
|
component.NextPressurized = GameTiming.CurTime + TimeSpan.FromSeconds(1f / PressurePerSecond);
|
||||||
|
component.Engaged = false;
|
||||||
|
// stop queuing NOW
|
||||||
|
component.NextFlush = null;
|
||||||
|
|
||||||
|
UpdateVisualState(uid, component, true);
|
||||||
|
UpdateInterface(uid, component, component.Powered);
|
||||||
|
|
||||||
|
Dirty(component);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAir(EntityUid uid, DisposalUnitComponent component, TransformComponent xform)
|
||||||
|
{
|
||||||
var air = component.Air;
|
var air = component.Air;
|
||||||
var entryComponent = Comp<DisposalEntryComponent>(entry);
|
|
||||||
var indices = _transformSystem.GetGridOrMapTilePosition(uid, xform);
|
var indices = _transformSystem.GetGridOrMapTilePosition(uid, xform);
|
||||||
|
|
||||||
if (_atmosSystem.GetTileMixture(xform.GridUid, xform.MapUid, indices, true) is { Temperature: > 0f } environment)
|
if (_atmosSystem.GetTileMixture(xform.GridUid, xform.MapUid, indices, true) is { Temperature: > 0f } environment)
|
||||||
@@ -554,59 +573,38 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
|
|
||||||
component.Air = environment.Remove(transferMoles);
|
component.Air = environment.Remove(transferMoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
_disposalTubeSystem.TryInsert(entry, component, beforeFlushArgs.Tags);
|
|
||||||
|
|
||||||
component.NextFlush = TimeSpan.MaxValue;
|
|
||||||
|
|
||||||
if (!component.DisablePressure)
|
|
||||||
{
|
|
||||||
component.Pressure = 0;
|
|
||||||
component.State = SharedDisposalUnitComponent.PressureState.Pressurizing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
component.Engaged = false;
|
public void UpdateInterface(EntityUid uid, SharedDisposalUnitComponent component, bool powered)
|
||||||
|
|
||||||
HandleStateChange(uid, component, true);
|
|
||||||
UpdateVisualState(uid, component, true);
|
|
||||||
UpdateInterface(uid, component, component.Powered);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateInterface(EntityUid uid, DisposalUnitComponent component, bool powered)
|
|
||||||
{
|
{
|
||||||
var stateString = Loc.GetString($"disposal-unit-state-{component.State}");
|
var compState = GetState(uid, component);
|
||||||
var state = new SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState(Name(uid), stateString, EstimatedFullPressure(component), powered, component.Engaged);
|
var stateString = Loc.GetString($"disposal-unit-state-{compState}");
|
||||||
|
var state = new SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState(Name(uid), stateString, EstimatedFullPressure(uid, component), powered, component.Engaged);
|
||||||
_ui.TrySetUiState(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, state);
|
_ui.TrySetUiState(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, state);
|
||||||
|
|
||||||
var stateUpdatedEvent = new DisposalUnitUIStateUpdatedEvent(state);
|
var stateUpdatedEvent = new DisposalUnitUIStateUpdatedEvent(state);
|
||||||
RaiseLocalEvent(uid, stateUpdatedEvent);
|
RaiseLocalEvent(uid, stateUpdatedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeSpan EstimatedFullPressure(DisposalUnitComponent component)
|
/// <summary>
|
||||||
|
/// Returns the estimated time when the disposal unit will be back to full pressure.
|
||||||
|
/// </summary>
|
||||||
|
private TimeSpan EstimatedFullPressure(EntityUid uid, SharedDisposalUnitComponent component)
|
||||||
{
|
{
|
||||||
if (component.State == SharedDisposalUnitComponent.PressureState.Ready) return TimeSpan.Zero;
|
if (component.NextPressurized < GameTiming.CurTime)
|
||||||
|
return TimeSpan.Zero;
|
||||||
|
|
||||||
var currentTime = GameTiming.CurTime;
|
return component.NextPressurized;
|
||||||
var pressure = component.Pressure;
|
|
||||||
|
|
||||||
return TimeSpan.FromSeconds(currentTime.TotalSeconds + (1.0f - pressure) / PressurePerSecond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateVisualState(EntityUid uid, DisposalUnitComponent component)
|
public void UpdateVisualState(EntityUid uid, SharedDisposalUnitComponent component, bool flush = false)
|
||||||
{
|
|
||||||
UpdateVisualState(uid, component, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateVisualState(EntityUid uid, DisposalUnitComponent component, bool flush)
|
|
||||||
{
|
{
|
||||||
if (!TryComp(uid, out AppearanceComponent? appearance))
|
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Comp<TransformComponent>(uid).Anchored)
|
if (!Transform(uid).Anchored)
|
||||||
{
|
{
|
||||||
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.UnAnchored, appearance);
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.UnAnchored, appearance);
|
||||||
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Handle, SharedDisposalUnitComponent.HandleState.Normal, appearance);
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Handle, SharedDisposalUnitComponent.HandleState.Normal, appearance);
|
||||||
@@ -614,7 +612,20 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, component.Pressure < 1 ? SharedDisposalUnitComponent.VisualState.Charging : SharedDisposalUnitComponent.VisualState.Anchored, appearance);
|
var state = GetState(uid, component);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case DisposalsPressureState.Flushed:
|
||||||
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.Flushing, appearance);
|
||||||
|
break;
|
||||||
|
case DisposalsPressureState.Pressurizing:
|
||||||
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.Charging, appearance);
|
||||||
|
break;
|
||||||
|
case DisposalsPressureState.Ready:
|
||||||
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.Anchored, appearance);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Handle, component.Engaged
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Handle, component.Engaged
|
||||||
? SharedDisposalUnitComponent.HandleState.Engaged
|
? SharedDisposalUnitComponent.HandleState.Engaged
|
||||||
@@ -627,21 +638,17 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lightState = SharedDisposalUnitComponent.LightStates.Off;
|
var lightState = SharedDisposalUnitComponent.LightStates.Off;
|
||||||
if (flush)
|
|
||||||
{
|
|
||||||
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.Flushing, appearance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.Container.ContainedEntities.Count > 0)
|
if (component.Container.ContainedEntities.Count > 0)
|
||||||
{
|
{
|
||||||
lightState |= SharedDisposalUnitComponent.LightStates.Full;
|
lightState |= SharedDisposalUnitComponent.LightStates.Full;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.Pressure < 1)
|
if (state is DisposalsPressureState.Pressurizing or DisposalsPressureState.Flushed)
|
||||||
{
|
{
|
||||||
lightState |= SharedDisposalUnitComponent.LightStates.Charging;
|
lightState |= SharedDisposalUnitComponent.LightStates.Charging;
|
||||||
}
|
}
|
||||||
else if (!component.Engaged)
|
else
|
||||||
{
|
{
|
||||||
lightState |= SharedDisposalUnitComponent.LightStates.Ready;
|
lightState |= SharedDisposalUnitComponent.LightStates.Ready;
|
||||||
}
|
}
|
||||||
@@ -649,86 +656,109 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Light, lightState, appearance);
|
_appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Light, lightState, appearance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(EntityUid uid, DisposalUnitComponent component, EntityUid toRemove)
|
public void Remove(EntityUid uid, SharedDisposalUnitComponent component, EntityUid toRemove)
|
||||||
{
|
{
|
||||||
component.Container.Remove(toRemove);
|
component.Container.Remove(toRemove);
|
||||||
|
|
||||||
if (component.Container.ContainedEntities.Count == 0)
|
if (component.Container.ContainedEntities.Count == 0)
|
||||||
{
|
{
|
||||||
component.NextFlush = TimeSpan.MaxValue;
|
// If not manually engaged then reset the flushing entirely.
|
||||||
|
if (!component.Engaged)
|
||||||
|
{
|
||||||
|
component.NextFlush = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!component.RecentlyEjected.Contains(toRemove))
|
if (!component.RecentlyEjected.Contains(toRemove))
|
||||||
component.RecentlyEjected.Add(toRemove);
|
component.RecentlyEjected.Add(toRemove);
|
||||||
|
|
||||||
Dirty(component);
|
|
||||||
HandleStateChange(uid, component, active: true);
|
|
||||||
UpdateVisualState(uid, component);
|
UpdateVisualState(uid, component);
|
||||||
|
Dirty(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanFlush(EntityUid unit, DisposalUnitComponent component)
|
public bool CanFlush(EntityUid unit, SharedDisposalUnitComponent component)
|
||||||
{
|
{
|
||||||
return component.State == SharedDisposalUnitComponent.PressureState.Ready
|
return GetState(unit, component) == DisposalsPressureState.Ready
|
||||||
&& component.Powered
|
&& component.Powered
|
||||||
&& Comp<TransformComponent>(unit).Anchored;
|
&& Comp<TransformComponent>(unit).Anchored;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Engage(EntityUid uid, DisposalUnitComponent component)
|
public void ManualEngage(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null)
|
||||||
{
|
{
|
||||||
component.Engaged = true;
|
component.Engaged = true;
|
||||||
UpdateVisualState(uid, component);
|
UpdateVisualState(uid, component);
|
||||||
UpdateInterface(uid, component, component.Powered);
|
UpdateInterface(uid, component, component.Powered);
|
||||||
|
Dirty(component);
|
||||||
|
|
||||||
if (CanFlush(uid, component))
|
if (!CanFlush(uid, component))
|
||||||
{
|
return;
|
||||||
component.NextFlush = _gameTiming.CurTime + component.FlushDelay;
|
|
||||||
EnsureComp<ActiveDisposalUnitComponent>(uid);
|
if (!Resolve(uid, ref metadata))
|
||||||
}
|
return;
|
||||||
|
|
||||||
|
var pauseTime = Metadata.GetPauseTime(uid, metadata);
|
||||||
|
var nextEngage = GameTiming.CurTime - pauseTime + component.ManualFlushTime;
|
||||||
|
component.NextFlush = TimeSpan.FromSeconds(Math.Min((component.NextFlush ?? TimeSpan.MaxValue).TotalSeconds, nextEngage.TotalSeconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disengage(EntityUid uid, DisposalUnitComponent component)
|
public void Disengage(EntityUid uid, SharedDisposalUnitComponent component)
|
||||||
{
|
{
|
||||||
component.Engaged = false;
|
component.Engaged = false;
|
||||||
|
|
||||||
|
if (component.Container.ContainedEntities.Count == 0)
|
||||||
|
{
|
||||||
|
component.NextFlush = null;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateVisualState(uid, component);
|
UpdateVisualState(uid, component);
|
||||||
UpdateInterface(uid, component, component.Powered);
|
UpdateInterface(uid, component, component.Powered);
|
||||||
|
Dirty(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove all entities currently in the disposal unit.
|
/// Remove all entities currently in the disposal unit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TryEjectContents(EntityUid uid, DisposalUnitComponent component)
|
public void TryEjectContents(EntityUid uid, SharedDisposalUnitComponent component)
|
||||||
{
|
{
|
||||||
foreach (var entity in component.Container.ContainedEntities.ToArray())
|
foreach (var entity in component.Container.ContainedEntities.ToArray())
|
||||||
{
|
{
|
||||||
Remove(uid, component, entity);
|
Remove(uid, component, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!component.Engaged)
|
||||||
|
{
|
||||||
|
component.NextFlush = null;
|
||||||
|
Dirty(component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid entity)
|
public override bool CanInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid entity)
|
||||||
{
|
{
|
||||||
if (!base.CanInsert(uid, component, entity) || component is not DisposalUnitComponent serverComp)
|
if (!base.CanInsert(uid, component, entity) || component is not SharedDisposalUnitComponent serverComp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return serverComp.Container.CanInsert(entity);
|
return serverComp.Container.CanInsert(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If something is inserted (or the likes) then we'll queue up a flush in the future.
|
/// If something is inserted (or the likes) then we'll queue up an automatic flush in the future.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TryQueueEngage(EntityUid uid, DisposalUnitComponent component)
|
public void QueueAutomaticEngage(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null)
|
||||||
{
|
{
|
||||||
if (component.Deleted || !component.AutomaticEngage || !component.Powered && component.Container.ContainedEntities.Count == 0)
|
if (component.Deleted || !component.AutomaticEngage || !component.Powered && component.Container.ContainedEntities.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
component.NextFlush = _gameTiming.CurTime + component.AutomaticEngageTime;
|
var pauseTime = Metadata.GetPauseTime(uid, metadata);
|
||||||
component.AutoFlushing = true;
|
var automaticTime = GameTiming.CurTime + component.AutomaticEngageTime - pauseTime;
|
||||||
|
var flushTime = TimeSpan.FromSeconds(Math.Min((component.NextFlush ?? TimeSpan.MaxValue).TotalSeconds, automaticTime.TotalSeconds));
|
||||||
|
|
||||||
EnsureComp<ActiveDisposalUnitComponent>(uid);
|
component.NextFlush = flushTime;
|
||||||
|
Dirty(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AfterInsert(EntityUid uid, DisposalUnitComponent component, EntityUid inserted, EntityUid? user = null)
|
public void AfterInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid inserted, EntityUid? user = null)
|
||||||
{
|
{
|
||||||
if (!component.Container.Insert(inserted))
|
if (!component.Container.Insert(inserted))
|
||||||
return;
|
return;
|
||||||
@@ -736,13 +766,15 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
if (user != inserted && user != null)
|
if (user != inserted && user != null)
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user.Value):player} inserted {ToPrettyString(inserted)} into {ToPrettyString(uid)}");
|
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user.Value):player} inserted {ToPrettyString(inserted)} into {ToPrettyString(uid)}");
|
||||||
|
|
||||||
TryQueueEngage(uid, component);
|
QueueAutomaticEngage(uid, component);
|
||||||
|
|
||||||
if (TryComp(inserted, out ActorComponent? actor))
|
if (TryComp(inserted, out ActorComponent? actor))
|
||||||
{
|
{
|
||||||
_ui.TryClose(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession);
|
_ui.TryClose(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maybe do pullable instead? Eh still fine.
|
||||||
|
Joints.RecursiveClearJoints(inserted);
|
||||||
UpdateVisualState(uid, component);
|
UpdateVisualState(uid, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -769,4 +801,3 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
{
|
{
|
||||||
public readonly List<string> Tags = new();
|
public readonly List<string> Tags = new();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Server.Storage.Components;
|
|
||||||
using Content.Shared.Storage.Components;
|
|
||||||
using Content.Shared.Verbs;
|
|
||||||
using Content.Server.Disposal.Unit.Components;
|
|
||||||
using Content.Server.Disposal.Unit.EntitySystems;
|
|
||||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
|
|
||||||
using Content.Shared.DoAfter;
|
|
||||||
using Content.Shared.Placeable;
|
|
||||||
using Content.Shared.Storage;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Server.Storage.EntitySystems
|
|
||||||
{
|
|
||||||
public sealed class DumpableSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
|
||||||
[Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
SubscribeLocalEvent<DumpableComponent, AfterInteractEvent>(OnAfterInteract, after: new[]{ typeof(StorageSystem) });
|
|
||||||
SubscribeLocalEvent<DumpableComponent, GetVerbsEvent<AlternativeVerb>>(AddDumpVerb);
|
|
||||||
SubscribeLocalEvent<DumpableComponent, GetVerbsEvent<UtilityVerb>>(AddUtilityVerbs);
|
|
||||||
SubscribeLocalEvent<DumpableComponent, DumpableDoAfterEvent>(OnDoAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAfterInteract(EntityUid uid, DumpableComponent component, AfterInteractEvent args)
|
|
||||||
{
|
|
||||||
if (!args.CanReach || args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!HasComp<DisposalUnitComponent>(args.Target) && !HasComp<PlaceableSurfaceComponent>(args.Target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
StartDoAfter(uid, args.Target.Value, args.User, component);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddDumpVerb(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent<AlternativeVerb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanAccess || !args.CanInteract)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryComp<ServerStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AlternativeVerb verb = new()
|
|
||||||
{
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
StartDoAfter(uid, args.Target, args.User, dumpable);//Had multiplier of 0.6f
|
|
||||||
},
|
|
||||||
Text = Loc.GetString("dump-verb-name"),
|
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/drop.svg.192dpi.png")),
|
|
||||||
};
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddUtilityVerbs(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent<UtilityVerb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanAccess || !args.CanInteract)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryComp<ServerStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (HasComp<DisposalUnitComponent>(args.Target))
|
|
||||||
{
|
|
||||||
UtilityVerb verb = new()
|
|
||||||
{
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
StartDoAfter(uid, args.Target, args.User, dumpable);
|
|
||||||
},
|
|
||||||
Text = Loc.GetString("dump-disposal-verb-name", ("unit", args.Target)),
|
|
||||||
IconEntity = uid
|
|
||||||
};
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasComp<PlaceableSurfaceComponent>(args.Target))
|
|
||||||
{
|
|
||||||
UtilityVerb verb = new()
|
|
||||||
{
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
StartDoAfter(uid, args.Target, args.User, dumpable);
|
|
||||||
},
|
|
||||||
Text = Loc.GetString("dump-placeable-verb-name", ("surface", args.Target)),
|
|
||||||
IconEntity = uid
|
|
||||||
};
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid userUid, DumpableComponent dumpable)
|
|
||||||
{
|
|
||||||
if (!TryComp<SharedStorageComponent>(storageUid, out var storage) || storage.StoredEntities == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float delay = storage.StoredEntities.Count * (float) dumpable.DelayPerItem.TotalSeconds * dumpable.Multiplier;
|
|
||||||
|
|
||||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(userUid, delay, new DumpableDoAfterEvent(), storageUid, target: targetUid, used: storageUid)
|
|
||||||
{
|
|
||||||
BreakOnTargetMove = true,
|
|
||||||
BreakOnUserMove = true,
|
|
||||||
NeedHand = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDoAfter(EntityUid uid, DumpableComponent component, DoAfterEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled || args.Cancelled || !TryComp<SharedStorageComponent>(uid, out var storage) || storage.StoredEntities == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Queue<EntityUid> dumpQueue = new();
|
|
||||||
foreach (var entity in storage.StoredEntities)
|
|
||||||
{
|
|
||||||
dumpQueue.Enqueue(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var entity in dumpQueue)
|
|
||||||
{
|
|
||||||
var transform = Transform(entity);
|
|
||||||
_container.AttachParentToContainerOrGrid(transform);
|
|
||||||
transform.LocalPosition += _random.NextVector2Box() / 2;
|
|
||||||
transform.LocalRotation = _random.NextAngle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Args.Target == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (HasComp<DisposalUnitComponent>(args.Args.Target.Value))
|
|
||||||
{
|
|
||||||
foreach (var entity in dumpQueue)
|
|
||||||
{
|
|
||||||
_disposalUnitSystem.DoInsertDisposalUnit(args.Args.Target.Value, entity, args.Args.User);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasComp<PlaceableSurfaceComponent>(args.Args.Target.Value))
|
|
||||||
{
|
|
||||||
foreach (var entity in dumpQueue)
|
|
||||||
{
|
|
||||||
Transform(entity).LocalPosition = Transform(args.Args.Target.Value).LocalPosition + _random.NextVector2Box() / 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,6 +30,7 @@ using Robust.Server.Player;
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -52,10 +53,10 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
[Dependency] private readonly SharedInteractionSystem _sharedInteractionSystem = default!;
|
[Dependency] private readonly SharedInteractionSystem _sharedInteractionSystem = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
|
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
[Dependency] private readonly StackSystem _stack = default!;
|
[Dependency] private readonly StackSystem _stack = default!;
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||||
|
|
||||||
@@ -226,7 +227,9 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
|| !itemQuery.HasComponent(entity)
|
|| !itemQuery.HasComponent(entity)
|
||||||
|| !CanInsert(uid, entity, out _, storageComp)
|
|| !CanInsert(uid, entity, out _, storageComp)
|
||||||
|| !_interactionSystem.InRangeUnobstructed(args.User, entity))
|
|| !_interactionSystem.InRangeUnobstructed(args.User, entity))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
validStorables.Add(entity);
|
validStorables.Add(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,52 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
namespace Content.Shared.Disposal.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Disposal.Components
|
|
||||||
{
|
|
||||||
[NetworkedComponent]
|
[NetworkedComponent]
|
||||||
public abstract class SharedDisposalUnitComponent : Component
|
public abstract class SharedDisposalUnitComponent : Component
|
||||||
{
|
{
|
||||||
public const string ContainerId = "DisposalUnit";
|
public const string ContainerId = "disposals";
|
||||||
|
|
||||||
// TODO: Could maybe turn the contact off instead far more cheaply as farseer (though not box2d) had support for it?
|
/// <summary>
|
||||||
// Need to suss it out.
|
/// Sounds played upon the unit flushing.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("soundFlush")]
|
||||||
|
public SoundSpecifier? FlushSound = new SoundPathSpecifier("/Audio/Machines/disposalflush.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// State for this disposals unit.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("state")]
|
||||||
|
public DisposalsPressureState State;
|
||||||
|
|
||||||
|
// TODO: Just make this use vaulting.
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We'll track whatever just left disposals so we know what collision we need to ignore until they stop intersecting our BB.
|
/// We'll track whatever just left disposals so we know what collision we need to ignore until they stop intersecting our BB.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<EntityUid> RecentlyEjected = new();
|
[ViewVariables, DataField("recentlyEjected")]
|
||||||
|
public readonly List<EntityUid> RecentlyEjected = new();
|
||||||
|
|
||||||
[DataField("flushTime", required: true)]
|
/// <summary>
|
||||||
public readonly float FlushTime;
|
/// Next time the disposal unit will be pressurized.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("nextPressurized", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||||
|
public TimeSpan NextPressurized = TimeSpan.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes to flush a disposals unit manually.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("flushTime")]
|
||||||
|
public TimeSpan ManualFlushTime = TimeSpan.FromSeconds(2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes from the start of a flush animation to return the sprite to normal.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("flushDelay")]
|
||||||
|
public TimeSpan FlushDelay = TimeSpan.FromSeconds(3);
|
||||||
|
|
||||||
[DataField("mobsCanEnter")]
|
[DataField("mobsCanEnter")]
|
||||||
public bool MobsCanEnter = true;
|
public bool MobsCanEnter = true;
|
||||||
@@ -27,6 +57,53 @@ namespace Content.Shared.Disposal.Components
|
|||||||
[DataField("disablePressure"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("disablePressure"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool DisablePressure = false;
|
public bool DisablePressure = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Last time that an entity tried to exit this disposal unit.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public TimeSpan LastExitAttempt;
|
||||||
|
|
||||||
|
[DataField("autoEngageEnabled")]
|
||||||
|
public bool AutomaticEngage = true;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("autoEngageTime")]
|
||||||
|
public TimeSpan AutomaticEngageTime = TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delay from trying to enter disposals ourselves.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("entryDelay")]
|
||||||
|
public float EntryDelay = 0.5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delay from trying to shove someone else into disposals.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float DraggedEntryDelay = 0.5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Container of entities inside this disposal unit.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] public Container Container = default!;
|
||||||
|
|
||||||
|
// TODO: Network power shit instead fam.
|
||||||
|
[ViewVariables, DataField("powered")]
|
||||||
|
public bool Powered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Was the disposals unit engaged for a manual flush.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("engaged")]
|
||||||
|
public bool Engaged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Next time this unit will flush. Is the lesser of <see cref="FlushDelay"/> and <see cref="AutomaticEngageTime"/>
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables, DataField("nextFlush", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||||
|
public TimeSpan? NextFlush;
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum Visuals : byte
|
public enum Visuals : byte
|
||||||
{
|
{
|
||||||
@@ -52,6 +129,7 @@ namespace Content.Shared.Disposal.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
[Flags]
|
||||||
public enum LightStates : byte
|
public enum LightStates : byte
|
||||||
{
|
{
|
||||||
Off = 0,
|
Off = 0,
|
||||||
@@ -68,29 +146,6 @@ namespace Content.Shared.Disposal.Components
|
|||||||
Power
|
Power
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum PressureState : byte
|
|
||||||
{
|
|
||||||
Ready,
|
|
||||||
Pressurizing
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ComponentState GetComponentState()
|
|
||||||
{
|
|
||||||
return new DisposalUnitComponentState(RecentlyEjected);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
protected sealed class DisposalUnitComponentState : ComponentState
|
|
||||||
{
|
|
||||||
public List<EntityUid> RecentlyEjected;
|
|
||||||
|
|
||||||
public DisposalUnitComponentState(List<EntityUid> uids)
|
|
||||||
{
|
|
||||||
RecentlyEjected = uids;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class DisposalUnitBoundUserInterfaceState : BoundUserInterfaceState, IEquatable<DisposalUnitBoundUserInterfaceState>
|
public sealed class DisposalUnitBoundUserInterfaceState : BoundUserInterfaceState, IEquatable<DisposalUnitBoundUserInterfaceState>
|
||||||
{
|
{
|
||||||
@@ -142,4 +197,19 @@ namespace Content.Shared.Disposal.Components
|
|||||||
Key
|
Key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum DisposalsPressureState : byte
|
||||||
|
{
|
||||||
|
Ready,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Has been flushed recently within FlushDelay.
|
||||||
|
/// </summary>
|
||||||
|
Flushed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FlushDelay has elapsed and now we're transitioning back to Ready.
|
||||||
|
/// </summary>
|
||||||
|
Pressurizing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,38 +8,69 @@ using Content.Shared.Mobs.Components;
|
|||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Robust.Shared.Physics.Events;
|
using Robust.Shared.Physics.Events;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Disposal
|
namespace Content.Shared.Disposal;
|
||||||
{
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class DisposalDoAfterEvent : SimpleDoAfterEvent
|
public sealed class DisposalDoAfterEvent : SimpleDoAfterEvent
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[UsedImplicitly]
|
|
||||||
public abstract class SharedDisposalUnitSystem : EntitySystem
|
public abstract class SharedDisposalUnitSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] protected readonly IGameTiming GameTiming = default!;
|
[Dependency] protected readonly IGameTiming GameTiming = default!;
|
||||||
|
[Dependency] protected readonly MetaDataSystem Metadata = default!;
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
[Dependency] protected readonly SharedJointSystem Joints = default!;
|
||||||
|
|
||||||
protected static TimeSpan ExitAttemptDelay = TimeSpan.FromSeconds(0.5);
|
protected static TimeSpan ExitAttemptDelay = TimeSpan.FromSeconds(0.5);
|
||||||
|
|
||||||
// Percentage
|
// Percentage
|
||||||
public const float PressurePerSecond = 0.05f;
|
public const float PressurePerSecond = 0.05f;
|
||||||
|
|
||||||
public override void Initialize()
|
/// <summary>
|
||||||
|
/// Gets the current pressure state of a disposals unit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid"></param>
|
||||||
|
/// <param name="component"></param>
|
||||||
|
/// <param name="metadata"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public DisposalsPressureState GetState(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null)
|
||||||
{
|
{
|
||||||
base.Initialize();
|
var nextPressure = Metadata.GetPauseTime(uid, metadata) + component.NextPressurized - GameTiming.CurTime;
|
||||||
SubscribeLocalEvent<SharedDisposalUnitComponent, PreventCollideEvent>(OnPreventCollide);
|
var pressurizeTime = 1f / PressurePerSecond;
|
||||||
SubscribeLocalEvent<SharedDisposalUnitComponent, CanDropTargetEvent>(OnCanDragDropOn);
|
var pressurizeDuration = pressurizeTime - component.FlushDelay.TotalSeconds;
|
||||||
SubscribeLocalEvent<SharedDisposalUnitComponent, GotEmaggedEvent>(OnEmagged);
|
|
||||||
|
if (nextPressure.TotalSeconds > pressurizeDuration)
|
||||||
|
{
|
||||||
|
return DisposalsPressureState.Flushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPreventCollide(EntityUid uid, SharedDisposalUnitComponent component,
|
if (nextPressure > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
return DisposalsPressureState.Pressurizing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DisposalsPressureState.Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetPressure(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref metadata))
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
var pauseTime = Metadata.GetPauseTime(uid, metadata);
|
||||||
|
return MathF.Min(1f,
|
||||||
|
(float) (GameTiming.CurTime - pauseTime - component.NextPressurized).TotalSeconds / PressurePerSecond);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnPreventCollide(EntityUid uid, SharedDisposalUnitComponent component,
|
||||||
ref PreventCollideEvent args)
|
ref PreventCollideEvent args)
|
||||||
{
|
{
|
||||||
var otherBody = args.OtherEntity;
|
var otherBody = args.OtherEntity;
|
||||||
@@ -58,7 +89,7 @@ namespace Content.Shared.Disposal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCanDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, ref CanDropTargetEvent args)
|
protected void OnCanDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, ref CanDropTargetEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
@@ -67,7 +98,7 @@ namespace Content.Shared.Disposal
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(EntityUid uid, SharedDisposalUnitComponent component, ref GotEmaggedEvent args)
|
protected void OnEmagged(EntityUid uid, SharedDisposalUnitComponent component, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
component.DisablePressure = true;
|
component.DisablePressure = true;
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
@@ -97,5 +128,34 @@ namespace Content.Shared.Disposal
|
|||||||
|
|
||||||
return damageState != null && (!component.MobsCanEnter || _mobState.IsDead(entity, damageState));
|
return damageState != null && (!component.MobsCanEnter || _mobState.IsDead(entity, damageState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TODO: Proper prediction
|
||||||
|
/// </summary>
|
||||||
|
public abstract void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null);
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
protected sealed class DisposalUnitComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public SoundSpecifier? FlushSound;
|
||||||
|
public DisposalsPressureState State;
|
||||||
|
public TimeSpan NextPressurized;
|
||||||
|
public TimeSpan AutomaticEngageTime;
|
||||||
|
public TimeSpan? NextFlush;
|
||||||
|
public bool Powered;
|
||||||
|
public bool Engaged;
|
||||||
|
public List<EntityUid> RecentlyEjected;
|
||||||
|
|
||||||
|
public DisposalUnitComponentState(SoundSpecifier? flushSound, DisposalsPressureState state, TimeSpan nextPressurized, TimeSpan automaticEngageTime, TimeSpan? nextFlush, bool powered, bool engaged, List<EntityUid> recentlyEjected)
|
||||||
|
{
|
||||||
|
FlushSound = flushSound;
|
||||||
|
State = state;
|
||||||
|
NextPressurized = nextPressurized;
|
||||||
|
AutomaticEngageTime = automaticEngageTime;
|
||||||
|
NextFlush = nextFlush;
|
||||||
|
Powered = powered;
|
||||||
|
Engaged = engaged;
|
||||||
|
RecentlyEjected = recentlyEjected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Threading;
|
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Storage.Components
|
namespace Content.Shared.Storage.Components;
|
||||||
{
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class DumpableDoAfterEvent : SimpleDoAfterEvent
|
public sealed class DumpableDoAfterEvent : SimpleDoAfterEvent
|
||||||
{
|
{
|
||||||
@@ -13,17 +13,18 @@ namespace Content.Shared.Storage.Components
|
|||||||
/// Lets you dump this container on the ground using a verb,
|
/// Lets you dump this container on the ground using a verb,
|
||||||
/// or when interacting with it on a disposal unit or placeable surface.
|
/// or when interacting with it on a disposal unit or placeable surface.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
public sealed class DumpableComponent : Component
|
public sealed partial class DumpableComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How long each item adds to the doafter.
|
/// How long each item adds to the doafter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("delayPerItem")] public TimeSpan DelayPerItem = TimeSpan.FromSeconds(0.2);
|
[DataField("delayPerItem"), AutoNetworkedField]
|
||||||
|
public TimeSpan DelayPerItem = TimeSpan.FromSeconds(0.2);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The multiplier modifier
|
/// The multiplier modifier
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("multiplier")] public float Multiplier = 1.0f;
|
[DataField("multiplier"), AutoNetworkedField]
|
||||||
}
|
public float Multiplier = 1.0f;
|
||||||
}
|
}
|
||||||
|
|||||||
158
Content.Shared/Storage/EntitySystems/DumpableSystem.cs
Normal file
158
Content.Shared/Storage/EntitySystems/DumpableSystem.cs
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
using Content.Shared.Disposal;
|
||||||
|
using Content.Shared.Disposal.Components;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Placeable;
|
||||||
|
using Content.Shared.Storage.Components;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Storage.EntitySystems;
|
||||||
|
|
||||||
|
public sealed class DumpableSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly SharedDisposalUnitSystem _disposalUnitSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||||
|
|
||||||
|
private EntityQuery<TransformComponent> _xformQuery;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
SubscribeLocalEvent<DumpableComponent, AfterInteractEvent>(OnAfterInteract, after: new[]{ typeof(SharedEntityStorageSystem) });
|
||||||
|
SubscribeLocalEvent<DumpableComponent, GetVerbsEvent<AlternativeVerb>>(AddDumpVerb);
|
||||||
|
SubscribeLocalEvent<DumpableComponent, GetVerbsEvent<UtilityVerb>>(AddUtilityVerbs);
|
||||||
|
SubscribeLocalEvent<DumpableComponent, DumpableDoAfterEvent>(OnDoAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAfterInteract(EntityUid uid, DumpableComponent component, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (!args.CanReach || args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasComp<SharedDisposalUnitComponent>(args.Target) && !HasComp<PlaceableSurfaceComponent>(args.Target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
StartDoAfter(uid, args.Target.Value, args.User, component);
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDumpVerb(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent<AlternativeVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanAccess || !args.CanInteract)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<SharedStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AlternativeVerb verb = new()
|
||||||
|
{
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
StartDoAfter(uid, args.Target, args.User, dumpable);//Had multiplier of 0.6f
|
||||||
|
},
|
||||||
|
Text = Loc.GetString("dump-verb-name"),
|
||||||
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/drop.svg.192dpi.png")),
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddUtilityVerbs(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent<UtilityVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanAccess || !args.CanInteract)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<SharedStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HasComp<SharedDisposalUnitComponent>(args.Target))
|
||||||
|
{
|
||||||
|
UtilityVerb verb = new()
|
||||||
|
{
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
StartDoAfter(uid, args.Target, args.User, dumpable);
|
||||||
|
},
|
||||||
|
Text = Loc.GetString("dump-disposal-verb-name", ("unit", args.Target)),
|
||||||
|
IconEntity = uid
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasComp<PlaceableSurfaceComponent>(args.Target))
|
||||||
|
{
|
||||||
|
UtilityVerb verb = new()
|
||||||
|
{
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
StartDoAfter(uid, args.Target, args.User, dumpable);
|
||||||
|
},
|
||||||
|
Text = Loc.GetString("dump-placeable-verb-name", ("surface", args.Target)),
|
||||||
|
IconEntity = uid
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid userUid, DumpableComponent dumpable)
|
||||||
|
{
|
||||||
|
if (!TryComp<SharedStorageComponent>(storageUid, out var storage) || storage.StoredEntities == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float delay = storage.StoredEntities.Count * (float) dumpable.DelayPerItem.TotalSeconds * dumpable.Multiplier;
|
||||||
|
|
||||||
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(userUid, delay, new DumpableDoAfterEvent(), storageUid, target: targetUid, used: storageUid)
|
||||||
|
{
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
NeedHand = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoAfter(EntityUid uid, DumpableComponent component, DoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled || args.Cancelled || !TryComp<SharedStorageComponent>(uid, out var storage) || storage.StoredEntities == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Queue<EntityUid> dumpQueue = new();
|
||||||
|
foreach (var entity in storage.StoredEntities)
|
||||||
|
{
|
||||||
|
dumpQueue.Enqueue(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entity in dumpQueue)
|
||||||
|
{
|
||||||
|
var transform = Transform(entity);
|
||||||
|
_container.AttachParentToContainerOrGrid(transform);
|
||||||
|
_transformSystem.SetLocalPositionRotation(transform, transform.LocalPosition + _random.NextVector2Box() / 2, _random.NextAngle());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Args.Target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HasComp<SharedDisposalUnitComponent>(args.Args.Target.Value))
|
||||||
|
{
|
||||||
|
foreach (var entity in dumpQueue)
|
||||||
|
{
|
||||||
|
_disposalUnitSystem.DoInsertDisposalUnit(args.Args.Target.Value, entity, args.Args.User);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasComp<PlaceableSurfaceComponent>(args.Args.Target.Value))
|
||||||
|
{
|
||||||
|
var targetPos = _xformQuery.GetComponent(args.Args.Target.Value).LocalPosition;
|
||||||
|
|
||||||
|
foreach (var entity in dumpQueue)
|
||||||
|
{
|
||||||
|
_transformSystem.SetLocalPosition(entity, targetPos + _random.NextVector2Box() / 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||||
|
[Dependency] private readonly SharedJointSystem _joints = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
@@ -261,6 +262,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_joints.RecursiveClearJoints(toInsert);
|
||||||
var inside = EnsureComp<InsideEntityStorageComponent>(toInsert);
|
var inside = EnsureComp<InsideEntityStorageComponent>(toInsert);
|
||||||
inside.Storage = container;
|
inside.Storage = container;
|
||||||
return component.Contents.Insert(toInsert, EntityManager);
|
return component.Contents.Insert(toInsert, EntityManager);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<GrapplingProjectileComponent, ProjectileEmbedEvent>(OnGrappleCollide);
|
SubscribeLocalEvent<GrapplingProjectileComponent, ProjectileEmbedEvent>(OnGrappleCollide);
|
||||||
|
SubscribeLocalEvent<GrapplingProjectileComponent, JointRemovedEvent>(OnGrappleJointRemoved);
|
||||||
SubscribeLocalEvent<CanWeightlessMoveEvent>(OnWeightlessMove);
|
SubscribeLocalEvent<CanWeightlessMoveEvent>(OnWeightlessMove);
|
||||||
SubscribeAllEvent<RequestGrapplingReelMessage>(OnGrapplingReel);
|
SubscribeAllEvent<RequestGrapplingReelMessage>(OnGrapplingReel);
|
||||||
|
|
||||||
@@ -45,6 +46,11 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<GrapplingGunComponent, HandDeselectedEvent>(OnGrapplingDeselected);
|
SubscribeLocalEvent<GrapplingGunComponent, HandDeselectedEvent>(OnGrapplingDeselected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGrappleJointRemoved(EntityUid uid, GrapplingProjectileComponent component, JointRemovedEvent args)
|
||||||
|
{
|
||||||
|
QueueDel(uid);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGrapplingShot(EntityUid uid, GrapplingGunComponent component, ref GunShotEvent args)
|
private void OnGrapplingShot(EntityUid uid, GrapplingGunComponent component, ref GunShotEvent args)
|
||||||
{
|
{
|
||||||
foreach (var (shotUid, _) in args.Ammo)
|
foreach (var (shotUid, _) in args.Ammo)
|
||||||
|
|||||||
@@ -23,4 +23,6 @@ disposal-unit-thrown-missed = Missed!
|
|||||||
|
|
||||||
# state
|
# state
|
||||||
disposal-unit-state-Ready = Ready
|
disposal-unit-state-Ready = Ready
|
||||||
|
# Yes I want it to always say Pressurizing
|
||||||
|
disposal-unit-state-Flushed = Pressurizing
|
||||||
disposal-unit-state-Pressurizing = Pressurizing
|
disposal-unit-state-Pressurizing = Pressurizing
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ entities:
|
|||||||
parent: 37
|
parent: 37
|
||||||
type: Transform
|
type: Transform
|
||||||
- containers:
|
- containers:
|
||||||
DisposalUnit: !type:Container
|
disposals: !type:Container
|
||||||
showEnts: False
|
showEnts: False
|
||||||
occludes: True
|
occludes: True
|
||||||
ents:
|
ents:
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
map: [ "enum.DisposalUnitVisualLayers.Unanchored" ]
|
map: [ "enum.DisposalUnitVisualLayers.Unanchored" ]
|
||||||
- state: disposal
|
- state: disposal
|
||||||
map: [ "enum.DisposalUnitVisualLayers.Base" ]
|
map: [ "enum.DisposalUnitVisualLayers.Base" ]
|
||||||
- state: disposal-charging
|
|
||||||
map: [ "enum.DisposalUnitVisualLayers.BaseCharging" ]
|
|
||||||
- state: disposal-flush
|
- state: disposal-flush
|
||||||
map: [ "enum.DisposalUnitVisualLayers.BaseFlush" ]
|
map: [ "enum.DisposalUnitVisualLayers.BaseFlush" ]
|
||||||
- state: dispover-charge
|
- state: dispover-charge
|
||||||
@@ -70,7 +68,7 @@
|
|||||||
type: DisposalUnitBoundUserInterface
|
type: DisposalUnitBoundUserInterface
|
||||||
- type: ContainerContainer
|
- type: ContainerContainer
|
||||||
containers:
|
containers:
|
||||||
DisposalUnit: !type:Container
|
disposals: !type:Container
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 62
|
price: 62
|
||||||
- type: PowerSwitch
|
- type: PowerSwitch
|
||||||
@@ -84,9 +82,6 @@
|
|||||||
graph: DisposalMachine
|
graph: DisposalMachine
|
||||||
node: disposal_unit
|
node: disposal_unit
|
||||||
- type: DisposalUnit
|
- type: DisposalUnit
|
||||||
flushSound:
|
|
||||||
path: /Audio/Machines/disposalflush.ogg
|
|
||||||
flushTime: 2
|
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
interfaces:
|
interfaces:
|
||||||
- key: enum.DisposalUnitUiKey.Key
|
- key: enum.DisposalUnitUiKey.Key
|
||||||
@@ -123,9 +118,6 @@
|
|||||||
- type: DisposalUnit
|
- type: DisposalUnit
|
||||||
autoEngageEnabled: false
|
autoEngageEnabled: false
|
||||||
mobsCanEnter: false
|
mobsCanEnter: false
|
||||||
flushSound:
|
|
||||||
path: /Audio/Machines/disposalflush.ogg
|
|
||||||
flushTime: 2
|
|
||||||
- type: MailingUnit
|
- type: MailingUnit
|
||||||
- type: DeviceNetwork
|
- type: DeviceNetwork
|
||||||
deviceNetId: Wired
|
deviceNetId: Wired
|
||||||
|
|||||||
Reference in New Issue
Block a user