diff --git a/Content.Server/Physics/Controllers/ConveyorController.cs b/Content.Server/Physics/Controllers/ConveyorController.cs index b3508025cb94..db4307f6de58 100644 --- a/Content.Server/Physics/Controllers/ConveyorController.cs +++ b/Content.Server/Physics/Controllers/ConveyorController.cs @@ -55,8 +55,6 @@ private void OnConveyorShutdown(EntityUid uid, ConveyorComponent component, Comp if (MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating) return; - RemComp(uid); - if (!TryComp(uid, out var physics)) return; diff --git a/Content.Shared/Conveyor/ActiveConveyorComponent.cs b/Content.Shared/Conveyor/ActiveConveyorComponent.cs deleted file mode 100644 index 1c94be97642e..000000000000 --- a/Content.Shared/Conveyor/ActiveConveyorComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Conveyor; - -/// -/// Used to track which conveyors are relevant in case there's a lot of them. -/// -[RegisterComponent] -public sealed partial class ActiveConveyorComponent : Component -{ - -} diff --git a/Content.Shared/Conveyor/ConveyedComponent.cs b/Content.Shared/Conveyor/ConveyedComponent.cs new file mode 100644 index 000000000000..25189d2182a5 --- /dev/null +++ b/Content.Shared/Conveyor/ConveyedComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Conveyor; + +/// +/// Indicates this entity is currently being conveyed. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ConveyedComponent : Component +{ + [ViewVariables, AutoNetworkedField] + public List Colliding = new(); +} diff --git a/Content.Shared/Conveyor/ConveyorComponent.cs b/Content.Shared/Conveyor/ConveyorComponent.cs index 6c95d68c9824..797fefa58557 100644 --- a/Content.Shared/Conveyor/ConveyorComponent.cs +++ b/Content.Shared/Conveyor/ConveyorComponent.cs @@ -39,9 +39,6 @@ public sealed partial class ConveyorComponent : Component [DataField] public ProtoId OffPort = "Off"; - - [ViewVariables] - public readonly HashSet Intersecting = new(); } [Serializable, NetSerializable] diff --git a/Content.Shared/Physics/Controllers/SharedConveyorController.cs b/Content.Shared/Physics/Controllers/SharedConveyorController.cs index e3b22d84319e..abcd2bc4a211 100644 --- a/Content.Shared/Physics/Controllers/SharedConveyorController.cs +++ b/Content.Shared/Physics/Controllers/SharedConveyorController.cs @@ -1,7 +1,9 @@ using System.Numerics; using Content.Shared.Conveyor; using Content.Shared.Gravity; +using Content.Shared.Magic; using Content.Shared.Movement.Systems; +using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics; @@ -9,6 +11,7 @@ using Robust.Shared.Physics.Controllers; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; +using Robust.Shared.Utility; namespace Content.Shared.Physics.Controllers; @@ -16,15 +19,23 @@ public abstract class SharedConveyorController : VirtualController { [Dependency] protected readonly IMapManager MapManager = default!; [Dependency] protected readonly EntityLookupSystem Lookup = default!; + [Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] protected readonly SharedPhysicsSystem Physics = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!; protected const string ConveyorFixture = "conveyor"; - private static readonly Vector2 _expansion = new Vector2(0.1f, 0.1f); + private EntityQuery _gridQuery; + private EntityQuery _xformQuery; + + private ValueList _ents = new(); + private HashSet> _conveyors = new(); public override void Initialize() { + _gridQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + UpdatesAfter.Add(typeof(SharedMoverController)); SubscribeLocalEvent(OnConveyorStartCollide); @@ -37,74 +48,125 @@ private void OnConveyorStartCollide(EntityUid uid, ConveyorComponent component, { var otherUid = args.OtherEntity; - if (args.OtherBody.BodyType == BodyType.Static || component.State == ConveyorState.Off) + if (!args.OtherFixture.Hard || args.OtherBody.BodyType == BodyType.Static || component.State == ConveyorState.Off) + return; + + var conveyed = EnsureComp(otherUid); + + if (conveyed.Colliding.Contains(uid)) return; - component.Intersecting.Add(otherUid); - EnsureComp(uid); + conveyed.Colliding.Add(uid); + Dirty(otherUid, conveyed); } - private void OnConveyorEndCollide(EntityUid uid, ConveyorComponent component, ref EndCollideEvent args) + private void OnConveyorEndCollide(Entity ent, ref EndCollideEvent args) { - component.Intersecting.Remove(args.OtherEntity); + if (!TryComp(args.OtherEntity, out ConveyedComponent? conveyed)) + return; - if (component.Intersecting.Count == 0) - RemComp(uid); + if (!conveyed.Colliding.Remove(ent.Owner)) + return; + + Dirty(args.OtherEntity, conveyed); } 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(); - var query = EntityQueryEnumerator(); + var query = EntityQueryEnumerator(); + _ents.Clear(); - while (query.MoveNext(out var uid, out var _, out var comp)) + while (query.MoveNext(out var uid, out var comp, out var xform, out var physics)) { - Convey(uid, comp, xformQuery, bodyQuery, conveyed, frameTime, prediction); + if (TryConvey((uid, comp, physics, xform), prediction, frameTime)) + continue; + + _ents.Add(uid); + } + + foreach (var ent in _ents) + { + RemComp(ent); } } - private void Convey(EntityUid uid, ConveyorComponent comp, EntityQuery xformQuery, EntityQuery bodyQuery, HashSet conveyed, float frameTime, bool prediction) + private bool TryConvey(Entity entity, bool prediction, float frameTime) { - // Use an event for conveyors to know what needs to run - if (!CanRun(comp)) - return; + var physics = entity.Comp2; + var xform = entity.Comp3; + var contacting = entity.Comp1.Colliding.Count > 0; - var speed = comp.Speed; + if (!contacting) + return false; - if (speed <= 0f || !xformQuery.TryGetComponent(uid, out var xform) || xform.GridUid == null) - return; + // Client moment + if (!physics.Predict && prediction) + return true; + + if (physics.BodyType == BodyType.Static) + return false; + + if (!_gridQuery.TryComp(xform.GridUid, out var grid)) + return true; + + var gridTile = _maps.TileIndicesFor(xform.GridUid.Value, grid, xform.Coordinates); + _conveyors.Clear(); - var conveyorPos = xform.LocalPosition; - var conveyorRot = xform.LocalRotation; + // Check for any conveyors on the attached tile. + Lookup.GetLocalEntitiesIntersecting(xform.GridUid.Value, gridTile, _conveyors); + DebugTools.Assert(_conveyors.Count <= 1); - conveyorRot += comp.Angle; + // No more conveyors. + if (_conveyors.Count == 0) + return true; + + if (physics.BodyStatus == BodyStatus.InAir || + _gravity.IsWeightless(entity, physics, xform)) + { + return true; + } + + Entity bestConveyor = default; + var bestSpeed = 0f; + + foreach (var conveyor in _conveyors) + { + if (conveyor.Comp.Speed > bestSpeed && CanRun(conveyor)) + { + bestSpeed = conveyor.Comp.Speed; + bestConveyor = conveyor; + } + } + + if (bestSpeed == 0f || bestConveyor == default) + return true; + + var comp = bestConveyor.Comp!; + var conveyorXform = _xformQuery.GetComponent(bestConveyor.Owner); + var conveyorPos = conveyorXform.LocalPosition; + var conveyorRot = conveyorXform.LocalRotation; + + conveyorRot += bestConveyor.Comp!.Angle; if (comp.State == ConveyorState.Reverse) conveyorRot += MathF.PI; var direction = conveyorRot.ToWorldVec(); - foreach (var (entity, transform, body) in GetEntitiesToMove(comp, xform, xformQuery, bodyQuery)) - { - if (!conveyed.Add(entity) || prediction && !body.Predict) - continue; + var localPos = xform.LocalPosition; + var itemRelative = conveyorPos - localPos; - var localPos = transform.LocalPosition; - var itemRelative = conveyorPos - localPos; + localPos += Convey(direction, bestSpeed, frameTime, itemRelative); - localPos += Convey(direction, speed, frameTime, itemRelative); - transform.LocalPosition = localPos; + TransformSystem.SetLocalPosition(entity, localPos, xform); - // Force it awake for collisionwake reasons. - Physics.SetAwake((entity, body), true); - Physics.SetSleepTime(body, 0f); - } - Dirty(uid, comp); + // Force it awake for collisionwake reasons. + Physics.SetAwake((entity, physics), true); + Physics.SetSleepTime(physics, 0f); + + return true; } private static Vector2 Convey(Vector2 direction, float speed, float frameTime, Vector2 itemRelative) @@ -140,36 +202,6 @@ private static Vector2 Convey(Vector2 direction, float speed, float frameTime, V } } - private IEnumerable<(EntityUid, TransformComponent, PhysicsComponent)> GetEntitiesToMove( - ConveyorComponent comp, - TransformComponent xform, - EntityQuery xformQuery, - EntityQuery bodyQuery) - { - // Check if the thing's centre overlaps the grid tile. - var grid = Comp(xform.GridUid!.Value); - var tile = grid.GetTileRef(xform.Coordinates); - var conveyorBounds = Lookup.GetLocalBounds(tile, grid.TileSize); - - foreach (var entity in comp.Intersecting) - { - if (!xformQuery.TryGetComponent(entity, out var entityXform) || entityXform.ParentUid != xform.GridUid!.Value) - continue; - - 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 gridAABB = new Box2(entityXform.LocalPosition - _expansion, entityXform.LocalPosition + _expansion); - - if (!conveyorBounds.Intersects(gridAABB)) - continue; - - yield return (entity, entityXform, physics); - } - } - public bool CanRun(ConveyorComponent component) { return component.State != ConveyorState.Off && component.Powered; diff --git a/Resources/Maps/origin.yml b/Resources/Maps/origin.yml index dcd961e34ea6..376719da61ce 100644 --- a/Resources/Maps/origin.yml +++ b/Resources/Maps/origin.yml @@ -81416,7 +81416,6 @@ entities: - type: DeviceLinkSink links: - 26152 - - type: ActiveConveyor - uid: 12943 components: - type: Transform diff --git a/Resources/Prototypes/Entities/Structures/conveyor.yml b/Resources/Prototypes/Entities/Structures/conveyor.yml index 4dc879b0f6a3..d82370ba0d6c 100644 --- a/Resources/Prototypes/Entities/Structures/conveyor.yml +++ b/Resources/Prototypes/Entities/Structures/conveyor.yml @@ -24,10 +24,10 @@ conveyor: shape: !type:PolygonShape vertices: - - -0.55,-0.55 - - 0.55,-0.55 - - 0.55,0.55 - - -0.55,0.55 + - -0.49,-0.49 + - 0.49,-0.49 + - 0.49,0.49 + - -0.49,0.49 layer: - Impassable - MidImpassable