diff --git a/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs b/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs index c3e9dce150..3b30f4275b 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs +++ b/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs @@ -1,7 +1,9 @@ using System; using System.Linq; using Content.Server.Atmos.EntitySystems; +using Content.Server.Disposal.Tube; using Content.Server.Disposal.Unit.Components; +using Content.Server.Disposal.Unit.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Maths; @@ -13,8 +15,6 @@ namespace Content.Server.Disposal.Tube.Components [ComponentReference(typeof(IDisposalTubeComponent))] public class DisposalEntryComponent : DisposalTubeComponent { - [Dependency] private readonly IRobustRandom _random = default!; - private const string HolderPrototypeId = "DisposalHolder"; public override string Name => "DisposalEntry"; @@ -32,19 +32,7 @@ namespace Content.Server.Disposal.Tube.Components EntitySystem.Get().Merge(holderComponent.Air, from.Air); from.Air.Clear(); - return TryInsert(holderComponent); - } - - public bool TryInsert(DisposalHolderComponent holder) - { - if (!Contents.Insert(holder.Owner)) - { - return false; - } - - holder.EnterTube(this); - - return true; + return EntitySystem.Get().EnterTube(holderComponent.OwnerUid, OwnerUid, holderComponent, null, this); } protected override Direction[] ConnectableDirections() @@ -57,12 +45,9 @@ namespace Content.Server.Disposal.Tube.Components /// public override Direction NextDirection(DisposalHolderComponent holder) { - if (holder.PreviousDirectionFrom != Direction.Invalid && holder.PreviousDirectionFrom == ConnectableDirections()[0]) + if (holder.PreviousDirectionFrom != Direction.Invalid) { - var invalidDirections = new[] { ConnectableDirections()[0], Direction.Invalid }; - var directions = Enum.GetValues(typeof(Direction)) - .Cast().Except(invalidDirections).ToList(); - return _random.Pick(directions); + return Direction.Invalid; } return ConnectableDirections()[0]; diff --git a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs b/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs index 31ea796118..4c101fd752 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs +++ b/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using Content.Server.Construction.Components; using Content.Server.Disposal.Unit.Components; +using Content.Server.Disposal.Unit.EntitySystems; using Content.Shared.Acts; using Content.Shared.Disposal.Components; using Content.Shared.Popups; @@ -48,34 +49,6 @@ namespace Content.Server.Disposal.Tube.Components public abstract Direction NextDirection(DisposalHolderComponent holder); - public virtual Vector2 ExitVector(DisposalHolderComponent holder) - { - return NextDirection(holder).ToVec(); - } - - public bool Remove(DisposalHolderComponent holder) - { - var removed = Contents.Remove(holder.Owner); - holder.ExitDisposals(); - return removed; - } - - public bool TransferTo(DisposalHolderComponent holder, IDisposalTubeComponent to) - { - var position = holder.Owner.Transform.LocalPosition; - if (!to.Contents.Insert(holder.Owner)) - { - return false; - } - - holder.Owner.Transform.LocalPosition = position; - - Contents.Remove(holder.Owner); - holder.EnterTube(to); - - return true; - } - // TODO: Make disposal pipes extend the grid private void Connect() { @@ -123,7 +96,7 @@ namespace Content.Server.Disposal.Tube.Components continue; } - holder.ExitDisposals(); + EntitySystem.Get().ExitDisposals(holder.OwnerUid); } } diff --git a/Content.Server/Disposal/Tube/Components/IDisposalTubeComponent.cs b/Content.Server/Disposal/Tube/Components/IDisposalTubeComponent.cs index 82f30eca7f..8110acb798 100644 --- a/Content.Server/Disposal/Tube/Components/IDisposalTubeComponent.cs +++ b/Content.Server/Disposal/Tube/Components/IDisposalTubeComponent.cs @@ -10,9 +10,6 @@ namespace Content.Server.Disposal.Tube.Components Container Contents { get; } Direction NextDirection(DisposalHolderComponent holder); - Vector2 ExitVector(DisposalHolderComponent holder); - bool Remove(DisposalHolderComponent holder); - bool TransferTo(DisposalHolderComponent holder, IDisposalTubeComponent to); bool CanConnect(Direction direction, IDisposalTubeComponent with); void PopupDirections(IEntity entity); } diff --git a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs index a3129f4bfd..d85958a8fb 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs @@ -5,6 +5,7 @@ using Content.Server.Atmos; using Content.Server.Atmos.EntitySystems; using Content.Server.Disposal.Tube.Components; using Content.Server.Disposal.Tube; +using Content.Server.Disposal.Unit.EntitySystems; using Content.Server.Items; using Content.Shared.Atmos; using Content.Shared.Body.Components; @@ -24,36 +25,36 @@ namespace Content.Server.Disposal.Unit.Components { public override string Name => "DisposalHolder"; - private Container _contents = null!; + public Container Container = null!; /// /// The total amount of time that it will take for this entity to /// be pushed to the next tube /// [ViewVariables] - private float StartingTime { get; set; } + public float StartingTime { get; set; } /// /// Time left until the entity is pushed to the next tube /// [ViewVariables] - private float TimeLeft { get; set; } + public float TimeLeft { get; set; } [ViewVariables] public IDisposalTubeComponent? PreviousTube { get; set; } [ViewVariables] - public Direction PreviousDirection { get; private set; } = Direction.Invalid; + public Direction PreviousDirection { get; set; } = Direction.Invalid; [ViewVariables] public Direction PreviousDirectionFrom => (PreviousDirection == Direction.Invalid) ? Direction.Invalid : PreviousDirection.GetOpposite(); [ViewVariables] - public IDisposalTubeComponent? CurrentTube { get; private set; } + public IDisposalTubeComponent? CurrentTube { get; set; } // CurrentDirection is not null when CurrentTube isn't null. [ViewVariables] - public Direction CurrentDirection { get; private set; } = Direction.Invalid; + public Direction CurrentDirection { get; set; } = Direction.Invalid; /// /// A list of tags attached to the content, used for sorting @@ -69,18 +70,12 @@ namespace Content.Server.Disposal.Unit.Components { base.Initialize(); - _contents = ContainerHelpers.EnsureContainer(Owner, nameof(DisposalHolderComponent)); - } - - protected override void OnRemove() - { - base.OnRemove(); - ExitDisposals(); + Container = ContainerHelpers.EnsureContainer(Owner, nameof(DisposalHolderComponent)); } private bool CanInsert(IEntity entity) { - if (!_contents.CanInsert(entity)) + if (!Container.CanInsert(entity)) { return false; } @@ -91,7 +86,7 @@ namespace Content.Server.Disposal.Unit.Components public bool TryInsert(IEntity entity) { - if (!CanInsert(entity) || !_contents.Insert(entity)) + if (!CanInsert(entity) || !Container.Insert(entity)) { return false; } @@ -103,98 +98,5 @@ namespace Content.Server.Disposal.Unit.Components return true; } - - public void EnterTube(IDisposalTubeComponent tube) - { - if (CurrentTube != null) - { - PreviousTube = CurrentTube; - PreviousDirection = CurrentDirection; - } - - Owner.Transform.Coordinates = tube.Owner.Transform.Coordinates; - CurrentTube = tube; - CurrentDirection = tube.NextDirection(this); - StartingTime = 0.1f; - TimeLeft = 0.1f; - } - - public void ExitDisposals() - { - if (Deleted) - return; - - PreviousTube = null; - PreviousDirection = Direction.Invalid; - CurrentTube = null; - CurrentDirection = Direction.Invalid; - StartingTime = 0; - TimeLeft = 0; - - foreach (var entity in _contents.ContainedEntities.ToArray()) - { - if (entity.TryGetComponent(out IPhysBody? physics)) - { - physics.CanCollide = true; - } - - _contents.ForceRemove(entity); - - if (entity.Transform.Parent == Owner.Transform) - { - entity.Transform.AttachParentToContainerOrGrid(); - } - } - - var atmosphereSystem = EntitySystem.Get(); - - if (atmosphereSystem.GetTileMixture(Owner.Transform.Coordinates, true) is {} environment) - { - atmosphereSystem.Merge(environment, Air); - Air.Clear(); - } - - Owner.Delete(); - } - - public void Update(float frameTime) - { - while (frameTime > 0) - { - var time = frameTime; - if (time > TimeLeft) - { - time = TimeLeft; - } - - TimeLeft -= time; - frameTime -= time; - - if (CurrentTube == null || CurrentTube.Deleted) - { - ExitDisposals(); - break; - } - - if (TimeLeft > 0) - { - var progress = 1 - TimeLeft / StartingTime; - var origin = CurrentTube.Owner.Transform.Coordinates; - var destination = CurrentDirection.ToVec(); - var newPosition = destination * progress; - - Owner.Transform.Coordinates = origin.Offset(newPosition); - - continue; - } - - var nextTube = EntitySystem.Get().NextTubeFor(CurrentTube.Owner.Uid, CurrentDirection); - if (nextTube == null || nextTube.Deleted || !CurrentTube.TransferTo(this, nextTube)) - { - CurrentTube.Remove(this); - break; - } - } - } } } diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs index 720c97b047..494503097a 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs @@ -1,18 +1,181 @@ -using Content.Server.Disposal.Unit.Components; +using System.Linq; +using Content.Server.Atmos; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Disposal.Tube.Components; +using Content.Server.Disposal.Tube; +using Content.Server.Disposal.Unit.Components; using JetBrains.Annotations; +using Robust.Shared.Containers; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Map; +using Robust.Shared.Maths; +using Robust.Shared.Physics; namespace Content.Server.Disposal.Unit.EntitySystems { [UsedImplicitly] internal sealed class DisposableSystem : EntitySystem { + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!; + [Dependency] private readonly DisposalTubeSystem _disposalTubeSystem = default!; + + public void ExitDisposals(EntityUid uid, DisposalHolderComponent? holder = null, TransformComponent? holderTransform = null) + { + if (!Resolve(uid, ref holder, ref holderTransform)) + return; + + // Check for a disposal unit to throw them into and then eject them from it. + // *This ejection also makes the target not collide with the unit.* + // *This is on purpose.* + var grid = _mapManager.GetGrid(holderTransform.GridID); + var gridTileContents = grid.GetLocal(holderTransform.Coordinates); + DisposalUnitComponent? duc = null; + foreach (var contentUid in gridTileContents) + { + if (EntityManager.TryGetComponent(contentUid, out duc)) + break; + } + + foreach (var entity in holder.Container.ContainedEntities.ToArray()) + { + if (entity.TryGetComponent(out IPhysBody? physics)) + { + physics.CanCollide = true; + } + + holder.Container.ForceRemove(entity); + + if (entity.Transform.Parent == holderTransform) + { + if (duc != null) + { + // Insert into disposal unit + entity.Transform.Coordinates = new EntityCoordinates(duc.OwnerUid, Vector2.Zero); + duc.Container.Insert(entity); + } + else + { + entity.Transform.AttachParentToContainerOrGrid(); + } + } + } + + if (duc != null) + { + _disposalUnitSystem.TryEjectContents(duc); + } + + var atmosphereSystem = EntitySystem.Get(); + + if (atmosphereSystem.GetTileMixture(holderTransform.Coordinates, true) is {} environment) + { + atmosphereSystem.Merge(environment, holder.Air); + holder.Air.Clear(); + } + + EntityManager.DeleteEntity(uid); + } + + // Note: This function will cause an ExitDisposals on any failure that does not make an ExitDisposals impossible. + public bool EnterTube(EntityUid holderUid, EntityUid toUid, DisposalHolderComponent? holder = null, TransformComponent? holderTransform = null, IDisposalTubeComponent? to = null, TransformComponent? toTransform = null) + { + if (!Resolve(holderUid, ref holder, ref holderTransform)) + return false; + if (!Resolve(toUid, ref to, ref toTransform)) + { + ExitDisposals(holderUid, holder, holderTransform); + return false; + } + + // Insert into next tube + holderTransform.Coordinates = new EntityCoordinates(toUid, Vector2.Zero); + if (!to.Contents.Insert(holder.Owner)) + { + ExitDisposals(holderUid, holder, holderTransform); + return false; + } + + if (holder.CurrentTube != null) + { + holder.PreviousTube = holder.CurrentTube; + holder.PreviousDirection = holder.CurrentDirection; + } + var dir = to.NextDirection(holder); + // Invalid direction = exit now! + if (dir == Direction.Invalid) + { + ExitDisposals(holderUid, holder, holderTransform); + return false; + } + + holderTransform.Coordinates = toTransform.Coordinates; + holder.CurrentTube = to; + holder.CurrentDirection = dir; + holder.StartingTime = 0.1f; + holder.TimeLeft = 0.1f; + return true; + } public override void Update(float frameTime) { foreach (var comp in EntityManager.EntityQuery()) { - comp.Update(frameTime); + UpdateComp(comp, frameTime); + } + } + + private void UpdateComp(DisposalHolderComponent holder, float frameTime) + { + while (frameTime > 0) + { + var time = frameTime; + if (time > holder.TimeLeft) + { + time = holder.TimeLeft; + } + + holder.TimeLeft -= time; + frameTime -= time; + + var currentTube = holder.CurrentTube; + if (currentTube == null || currentTube.Deleted) + { + ExitDisposals(holder.OwnerUid); + break; + } + + if (holder.TimeLeft > 0) + { + var progress = 1 - holder.TimeLeft / holder.StartingTime; + var origin = currentTube.Owner.Transform.Coordinates; + var destination = holder.CurrentDirection.ToVec(); + var newPosition = destination * progress; + + holder.Owner.Transform.Coordinates = origin.Offset(newPosition); + + continue; + } + + // Past this point, we are performing inter-tube transfer! + // Remove current tube content + currentTube.Contents.ForceRemove(holder.Owner); + + // Find next tube + var nextTube = _disposalTubeSystem.NextTubeFor(currentTube.OwnerUid, holder.CurrentDirection); + if (nextTube == null || nextTube.Deleted) + { + ExitDisposals(holder.OwnerUid); + break; + } + + // Perform remainder of entry process + if (!EnterTube(holder.OwnerUid, nextTube.OwnerUid, holder, null, nextTube, null)) + { + ExitDisposals(holder.OwnerUid); + break; + } } } }