diff --git a/Content.Server/Conveyor/ActiveConveyorComponent.cs b/Content.Server/Conveyor/ActiveConveyorComponent.cs new file mode 100644 index 0000000000..da18c7ef87 --- /dev/null +++ b/Content.Server/Conveyor/ActiveConveyorComponent.cs @@ -0,0 +1,10 @@ +namespace Content.Server.Conveyor; + +/// +/// Used to track which conveyors are relevant in case there's a lot of them. +/// +[RegisterComponent] +public sealed class ActiveConveyorComponent : Component +{ + +} diff --git a/Content.Server/Conveyor/ConveyorComponent.cs b/Content.Server/Conveyor/ConveyorComponent.cs index 1437c0e5a6..12cca3e261 100644 --- a/Content.Server/Conveyor/ConveyorComponent.cs +++ b/Content.Server/Conveyor/ConveyorComponent.cs @@ -1,11 +1,13 @@ +using Content.Server.Physics.Controllers; using Content.Shared.Conveyor; using Content.Shared.MachineLinking; +using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Conveyor { [RegisterComponent] - [Access(typeof(ConveyorSystem))] + [Access(typeof(ConveyorController))] public sealed class ConveyorComponent : Component { /// @@ -36,5 +38,8 @@ namespace Content.Server.Conveyor [DataField("offPort", customTypeSerializer: typeof(PrototypeIdSerializer))] public string OffPort = "Off"; + + [ViewVariables] + public readonly HashSet Intersecting = new(); } } diff --git a/Content.Server/Conveyor/ConveyorSystem.cs b/Content.Server/Conveyor/ConveyorSystem.cs deleted file mode 100644 index 32afa82395..0000000000 --- a/Content.Server/Conveyor/ConveyorSystem.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Content.Server.MachineLinking.Events; -using Content.Server.MachineLinking.System; -using Content.Server.Power.Components; -using Content.Server.Power.EntitySystems; -using Content.Server.Recycling; -using Content.Server.Recycling.Components; -using Content.Shared.Conveyor; -using Content.Shared.Item; - -namespace Content.Server.Conveyor -{ - public sealed class ConveyorSystem : EntitySystem - { - [Dependency] private RecyclerSystem _recycler = default!; - [Dependency] private readonly SignalLinkerSystem _signalSystem = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnSignalReceived); - SubscribeLocalEvent(OnPowerChanged); - } - - private void OnInit(EntityUid uid, ConveyorComponent component, ComponentInit args) - { - _signalSystem.EnsureReceiverPorts(uid, component.ReversePort, component.ForwardPort, component.OffPort); - } - - private void OnPowerChanged(EntityUid uid, ConveyorComponent component, PowerChangedEvent args) - { - UpdateAppearance(component); - } - - private void UpdateAppearance(ConveyorComponent component) - { - if (!EntityManager.TryGetComponent(component.Owner, out var appearance)) return; - var isPowered = this.IsPowered(component.Owner, EntityManager); - appearance.SetData(ConveyorVisuals.State, isPowered ? component.State : ConveyorState.Off); - } - - private void OnSignalReceived(EntityUid uid, ConveyorComponent component, SignalReceivedEvent args) - { - if (args.Port == component.OffPort) - SetState(component, ConveyorState.Off); - else if (args.Port == component.ForwardPort) - SetState(component, ConveyorState.Forward); - else if (args.Port == component.ReversePort) - SetState(component, ConveyorState.Reverse); - } - - private void SetState(ConveyorComponent component, ConveyorState state) - { - component.State = state; - - if (TryComp(component.Owner, out var recycler)) - { - if (component.State != ConveyorState.Off) - _recycler.EnableRecycler(recycler); - else - _recycler.DisableRecycler(recycler); - } - - UpdateAppearance(component); - } - - public bool CanRun(ConveyorComponent component) - { - return component.State != ConveyorState.Off && - !EntityManager.HasComponent(component.Owner) && - this.IsPowered(component.Owner, EntityManager); - } - } -} diff --git a/Content.Server/Physics/Controllers/ConveyorController.cs b/Content.Server/Physics/Controllers/ConveyorController.cs index 38d89914ec..d84922bf7b 100644 --- a/Content.Server/Physics/Controllers/ConveyorController.cs +++ b/Content.Server/Physics/Controllers/ConveyorController.cs @@ -1,53 +1,170 @@ using Content.Server.Conveyor; +using Content.Server.Gravity.EntitySystems; +using Content.Server.MachineLinking.Events; +using Content.Server.MachineLinking.System; +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Server.Recycling; +using Content.Server.Recycling.Components; using Content.Shared.Conveyor; +using Content.Shared.Item; using Content.Shared.Movement.Components; +using Content.Shared.Physics; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Physics; +using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Controllers; +using Robust.Shared.Physics.Dynamics; namespace Content.Server.Physics.Controllers { public sealed class ConveyorController : VirtualController { - [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly ConveyorSystem _conveyor = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly FixtureSystem _fixtures = default!; + [Dependency] private readonly GravitySystem _gravity = default!; + [Dependency] private readonly RecyclerSystem _recycler = default!; + [Dependency] private readonly SignalLinkerSystem _signalSystem = default!; + + public const string ConveyorFixture = "conveyor"; public override void Initialize() { UpdatesAfter.Add(typeof(MoverController)); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnConveyorShutdown); + SubscribeLocalEvent(OnSignalReceived); + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnConveyorStartCollide); + SubscribeLocalEvent(OnConveyorEndCollide); base.Initialize(); } + private void OnConveyorEndCollide(EntityUid uid, ConveyorComponent component, EndCollideEvent args) + { + component.Intersecting.Remove(args.OtherFixture.Body.Owner); + + if (component.Intersecting.Count == 0) + { + RemComp(uid); + } + } + + private void OnConveyorStartCollide(EntityUid uid, ConveyorComponent component, StartCollideEvent args) + { + var otherUid = args.OtherFixture.Body.Owner; + + if (args.OtherFixture.Body.BodyType == BodyType.Static) return; + + component.Intersecting.Add(otherUid); + EnsureComp(uid); + } + + private void OnInit(EntityUid uid, ConveyorComponent component, ComponentInit args) + { + _signalSystem.EnsureReceiverPorts(uid, component.ReversePort, component.ForwardPort, component.OffPort); + + if (TryComp(uid, out var body)) + { + var shape = new PolygonShape(); + shape.SetAsBox(0.55f, 0.55f); + + _fixtures.TryCreateFixture(body, new Fixture(body, shape) + { + ID = ConveyorFixture, + CollisionLayer = (int) (CollisionGroup.LowImpassable | CollisionGroup.MidImpassable | CollisionGroup.Impassable), + Hard = false, + }); + } + } + + private void OnPowerChanged(EntityUid uid, ConveyorComponent component, PowerChangedEvent args) + { + UpdateAppearance(component); + } + + private void UpdateAppearance(ConveyorComponent component) + { + if (!EntityManager.TryGetComponent(component.Owner, out var appearance)) return; + var isPowered = this.IsPowered(component.Owner, EntityManager); + appearance.SetData(ConveyorVisuals.State, isPowered ? component.State : ConveyorState.Off); + } + + private void OnSignalReceived(EntityUid uid, ConveyorComponent component, SignalReceivedEvent args) + { + if (args.Port == component.OffPort) + SetState(component, ConveyorState.Off); + else if (args.Port == component.ForwardPort) + SetState(component, ConveyorState.Forward); + else if (args.Port == component.ReversePort) + SetState(component, ConveyorState.Reverse); + } + + private void SetState(ConveyorComponent component, ConveyorState state) + { + component.State = state; + + if (TryComp(component.Owner, out var recycler)) + { + if (component.State != ConveyorState.Off) + _recycler.EnableRecycler(recycler); + else + _recycler.DisableRecycler(recycler); + } + + UpdateAppearance(component); + } + + public bool CanRun(ConveyorComponent component) + { + return component.State != ConveyorState.Off && this.IsPowered(component.Owner, EntityManager); + } + + private void OnConveyorShutdown(EntityUid uid, ConveyorComponent component, ComponentShutdown args) + { + RemComp(uid); + + if (!TryComp(uid, out var body)) + return; + + _fixtures.DestroyFixture(body, ConveyorFixture); + } + public override void UpdateBeforeSolve(bool prediction, float frameTime) { base.UpdateBeforeSolve(prediction, frameTime); var conveyed = new HashSet(); + // Don't use it directly in EntityQuery because we may be able to save getcomponents. + var xformQuery = GetEntityQuery(); + var bodyQuery = GetEntityQuery(); - // TODO: This won't work if someone wants a massive fuckoff conveyor so look at using StartCollide or something. - foreach (var (comp, xform) in EntityManager.EntityQuery()) + foreach (var (_, comp) in EntityQuery()) { - Convey(comp, xform, conveyed, frameTime); + Convey(comp, xformQuery, bodyQuery, conveyed, frameTime); } } - private void Convey(ConveyorComponent comp, TransformComponent xform, HashSet conveyed, float frameTime) + private void Convey(ConveyorComponent comp, EntityQuery xformQuery, EntityQuery bodyQuery, HashSet conveyed, float frameTime) { // Use an event for conveyors to know what needs to run - if (!_conveyor.CanRun(comp)) + if (!CanRun(comp)) { return; } var speed = comp.Speed; - if (speed <= 0f) return; + if (speed <= 0f || + !xformQuery.TryGetComponent(comp.Owner, out var xform) || + xform.GridUid == null) + return; - var (conveyorPos, conveyorRot) = xform.GetWorldPositionRotation(); + var conveyorPos = xform.LocalPosition; + var conveyorRot = xform.LocalRotation; conveyorRot += comp.Angle; @@ -58,18 +175,20 @@ namespace Content.Server.Physics.Controllers var direction = conveyorRot.ToWorldVec(); - foreach (var (entity, transform) in GetEntitiesToMove(comp, xform)) + foreach (var (entity, transform, body) in GetEntitiesToMove(comp, xform, xformQuery, bodyQuery)) { - if (!conveyed.Add(entity)) continue; + if (!conveyed.Add(entity)) + continue; - var worldPos = transform.WorldPosition; - var itemRelative = conveyorPos - worldPos; + var localPos = transform.LocalPosition; + var itemRelative = conveyorPos - localPos; - worldPos += Convey(direction, speed, frameTime, itemRelative); - transform.WorldPosition = worldPos; + localPos += Convey(direction, speed, frameTime, itemRelative); + transform.LocalPosition = localPos; - if (TryComp(entity, out var body)) - body.Awake = true; + // Force it awake for collisionwake reasons. + body.Awake = true; + body.SleepTime = 0f; } } @@ -102,42 +221,41 @@ namespace Content.Server.Physics.Controllers } } - public IEnumerable<(EntityUid, TransformComponent)> GetEntitiesToMove(ConveyorComponent comp, TransformComponent xform) + private IEnumerable<(EntityUid, TransformComponent, PhysicsComponent)> GetEntitiesToMove( + ConveyorComponent comp, + TransformComponent xform, + EntityQuery xformQuery, + EntityQuery bodyQuery) { - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid) || - !grid.TryGetTileRef(xform.Coordinates, out var tile)) yield break; + // Check if the thing's centre overlaps the grid tile. + var grid = _mapManager.GetGrid(xform.GridUid!.Value); + var tile = grid.GetTileRef(xform.Coordinates); + var conveyorBounds = _lookup.GetLocalBounds(tile, grid.TileSize); - var tileAABB = _lookup.GetLocalBounds(tile, grid.TileSize).Enlarged(0.01f); - var gridMatrix = Transform(grid.GridEntityId).InvWorldMatrix; - - foreach (var entity in _lookup.GetEntitiesIntersecting(tile)) + foreach (var entity in comp.Intersecting) { - if (entity == comp.Owner || - Deleted(entity) || - HasComp(entity)) continue; - - if (!TryComp(entity, out PhysicsComponent? physics) || - physics.BodyType == BodyType.Static || - physics.BodyStatus == BodyStatus.InAir || - entity.IsWeightless(physics, entityManager: EntityManager)) + if (!xformQuery.TryGetComponent(entity, out var entityXform) || + entityXform.ParentUid != grid.GridEntityId) { continue; } - if (_container.IsEntityInContainer(entity)) + if (!bodyQuery.TryGetComponent(entity, out var physics) || + physics.BodyType == BodyType.Static || + physics.BodyStatus == BodyStatus.InAir || + _gravity.IsWeightless(entity, physics, entityXform)) { continue; } // Yes there's still going to be the occasional rounding issue where it stops getting conveyed // When you fix the corner issue that will fix this anyway. - var transform = Transform(entity); - var gridPos = gridMatrix.Transform(transform.WorldPosition); - var gridAABB = new Box2(gridPos - 0.1f, gridPos + 0.1f); + var gridAABB = new Box2(entityXform.LocalPosition - 0.1f, entityXform.LocalPosition + 0.1f); - if (!tileAABB.Intersects(gridAABB)) continue; + if (!conveyorBounds.Intersects(gridAABB)) + continue; - yield return (entity, transform); + yield return (entity, entityXform, physics); } } } diff --git a/Resources/Prototypes/Entities/Structures/conveyor.yml b/Resources/Prototypes/Entities/Structures/conveyor.yml index b62236ca4f..b8c1ef18df 100644 --- a/Resources/Prototypes/Entities/Structures/conveyor.yml +++ b/Resources/Prototypes/Entities/Structures/conveyor.yml @@ -18,6 +18,9 @@ drawdepth: FloorObjects - type: ApcPowerReceiver - type: ExtensionCableReceiver + - type: Physics + bodyType: Static + - type: Fixtures - type: Conveyor - type: Appearance - type: GenericVisualizer