diff --git a/Robust.Client/Physics/DebugPhysicsIslandSystem.cs b/Robust.Client/Physics/DebugPhysicsIslandSystem.cs index 0d29b815ecc..e9684207c0e 100644 --- a/Robust.Client/Physics/DebugPhysicsIslandSystem.cs +++ b/Robust.Client/Physics/DebugPhysicsIslandSystem.cs @@ -47,7 +47,7 @@ internal sealed class DebugPhysicsIslandSystem : EntitySystem * This will draw above every body involved in a particular island solve. */ - public readonly Queue<(TimeSpan Time, List Bodies)> IslandSolve = new(); + public readonly Queue<(TimeSpan Time, List> Bodies)> IslandSolve = new(); public const float SolveDuration = 0.1f; public override void Initialize() diff --git a/Robust.Client/Physics/PhysicsSystem.cs b/Robust.Client/Physics/PhysicsSystem.cs index 0c756ebfc1c..6bcf647a821 100644 --- a/Robust.Client/Physics/PhysicsSystem.cs +++ b/Robust.Client/Physics/PhysicsSystem.cs @@ -31,13 +31,13 @@ protected override void Cleanup(PhysicsMapComponent component, float frameTime) // (and serializing it over the network isn't necessary?) // This is a client-only problem. // Also need to suss out having the client build the island anyway and just... not solving it? - foreach (var body in component.AwakeBodies) + foreach (var (uid, body) in component.AwakeBodies) { if (!body.SleepingAllowed || body.LinearVelocity.Length() > LinearToleranceSqr / 2f || body.AngularVelocity * body.AngularVelocity > AngularToleranceSqr / 2f) continue; body.SleepTime += frameTime; if (body.SleepTime > TimeToSleep) { - toRemove.Add(new Entity(body.Owner, body)); + toRemove.Add(new Entity(uid, body)); } } @@ -49,11 +49,11 @@ protected override void Cleanup(PhysicsMapComponent component, float frameTime) base.Cleanup(component, frameTime); } - protected override void UpdateLerpData(PhysicsMapComponent component, List bodies, EntityQuery xformQuery) + protected override void UpdateLerpData(PhysicsMapComponent component, List> bodies, EntityQuery xformQuery) { foreach (var body in bodies) { - if (body.BodyType == BodyType.Static || + if (body.Comp.BodyType == BodyType.Static || component.LerpData.TryGetValue(body.Owner, out var lerpData) || !xformQuery.TryGetComponent(body.Owner, out var xform) || lerpData.ParentUid == xform.ParentUid) @@ -61,7 +61,7 @@ protected override void UpdateLerpData(PhysicsMapComponent component, List [ViewVariables] - public readonly HashSet AwakeBodies = new(); + public readonly HashSet> AwakeBodies = new(); /// /// Store last tick's invDT diff --git a/Robust.Shared/Physics/IslandSolveMessage.cs b/Robust.Shared/Physics/IslandSolveMessage.cs index 26f00bea0b2..8b79afe8e7d 100644 --- a/Robust.Shared/Physics/IslandSolveMessage.cs +++ b/Robust.Shared/Physics/IslandSolveMessage.cs @@ -6,9 +6,9 @@ namespace Robust.Shared.Physics { internal sealed class IslandSolveMessage : EntityEventArgs { - public List Bodies { get; } + public List> Bodies { get; } - public IslandSolveMessage(List bodies) + public IslandSolveMessage(List> bodies) { Bodies = bodies; } diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs index b3fbc3b344c..57e63d8a33f 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs @@ -125,8 +125,8 @@ public abstract partial class SharedPhysicsSystem */ private const int MaxIslands = 256; - private readonly ObjectPool> _islandBodyPool = - new DefaultObjectPool>(new ListPolicy(), MaxIslands); + private readonly ObjectPool>> _islandBodyPool = + new DefaultObjectPool>>(new ListPolicy>(), MaxIslands); private readonly ObjectPool> _islandContactPool = new DefaultObjectPool>(new ListPolicy(), MaxIslands); @@ -140,7 +140,7 @@ public abstract partial class SharedPhysicsSystem internal record struct IslandData( int Index, bool LoneIsland, - List Bodies, + List> Bodies, List Contacts, List<(Joint Original, Joint Joint)> Joints, List<(Joint Joint, float Error)> BrokenJoints) @@ -161,7 +161,7 @@ internal record struct IslandData( /// public int Offset = 0; - public readonly List Bodies = Bodies; + public readonly List> Bodies = Bodies; public readonly List Contacts = Contacts; public readonly List<(Joint Original, Joint Joint)> Joints = Joints; public bool PositionSolved = false; @@ -169,9 +169,9 @@ internal record struct IslandData( } // Caching for island generation. - private readonly HashSet _islandSet = new(64); - private readonly Stack _bodyStack = new(64); - private readonly List _awakeBodyList = new(256); + private readonly HashSet> _islandSet = new(64); + private readonly Stack> _bodyStack = new(64); + private readonly List> _awakeBodyList = new(256); // Config private bool _warmStarting; @@ -282,7 +282,7 @@ public void Step(EntityUid uid, PhysicsMapComponent component, float frameTime, private void ClearForces(PhysicsMapComponent component) { - foreach (var body in component.AwakeBodies) + foreach (var (_, body) in component.AwakeBodies) { // TODO: Netsync body.Force = Vector2.Zero; @@ -315,13 +315,12 @@ private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime var islandJoints = new List<(Joint Original, Joint Joint)>(); // Build the relevant islands / graphs for all bodies. - foreach (var seed in _awakeBodyList) + foreach (var (seedUid, seed) in _awakeBodyList) { // I tried not running prediction for non-contacted entities but unfortunately it looked like shit // when contact broke so if you want to try that then GOOD LUCK. - if (seed.Island) continue; - - var seedUid = seed.Owner; + if (seed.Island) + continue; if (!metaQuery.TryGetComponent(seedUid, out var metadata)) { @@ -342,19 +341,21 @@ private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime var bodies = _islandBodyPool.Get(); var contacts = _islandContactPool.Get(); var joints = _islandJointPool.Get(); - _bodyStack.Push(seed); + _bodyStack.Push((seedUid, seed)); seed.Island = true; - while (_bodyStack.TryPop(out var body)) + while (_bodyStack.TryPop(out var bodyEnt)) { - var bodyUid = body.Owner; + var bodyUid = bodyEnt.Owner; + var body = bodyEnt.Comp; - bodies.Add(body); - _islandSet.Add(body); + bodies.Add(bodyEnt); + _islandSet.Add(bodyEnt); // Static bodies don't propagate islands - if (body.BodyType == BodyType.Static) continue; + if (body.BodyType == BodyType.Static) + continue; // As static bodies can never be awake (unlike Farseer) we'll set this after the check. SetAwake(bodyUid, body, true, updateSleepTime: false); @@ -383,9 +384,10 @@ private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime var other = bodyA == body ? bodyB : bodyA; // Was the other body already added to this island? - if (other.Island) continue; + if (other.Island) + continue; - _bodyStack.Push(other); + _bodyStack.Push(bodyEnt); other.Island = true; } @@ -468,13 +470,13 @@ private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime if (!bodyA.Island) { - _bodyStack.Push(bodyA); + _bodyStack.Push((joint.BodyAUid, bodyA)); bodyA.Island = true; } if (!bodyB.Island) { - _bodyStack.Push(bodyB); + _bodyStack.Push((joint.BodyBUid, bodyB)); bodyB.Island = true; } } @@ -487,7 +489,7 @@ private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime // Bodies not touching anything, hence we can just add it to the lone island. if (contacts.Count == 0 && joints.Count == 0) { - DebugTools.Assert(bodies.Count == 1 && bodies[0].BodyType != BodyType.Static); + DebugTools.Assert(bodies.Count == 1 && bodies[0].Comp.BodyType != BodyType.Static); loneIsland.Bodies.Add(bodies[0]); idx = loneIsland.Index; } @@ -501,7 +503,7 @@ private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime // Allow static bodies to be re-used in other islands for (var i = 0; i < bodies.Count; i++) { - var body = bodies[i]; + var body = bodies[i].Comp; // Static bodies can participate in other islands if (body.BodyType == BodyType.Static) @@ -537,8 +539,8 @@ private void ReturnIsland(IslandData island) { foreach (var body in island.Bodies) { - DebugTools.Assert(body.IslandIndex.ContainsKey(island.Index)); - body.IslandIndex.Remove(island.Index); + DebugTools.Assert(body.Comp.IslandIndex.ContainsKey(island.Index)); + body.Comp.IslandIndex.Remove(island.Index); } _islandBodyPool.Return(island.Bodies); @@ -561,7 +563,7 @@ private void ReturnIsland(IslandData island) protected virtual void Cleanup(PhysicsMapComponent component, float frameTime) { - foreach (var body in _islandSet) + foreach (var (_, body) in _islandSet) { if (!body.Island || body.Deleted) { @@ -679,7 +681,7 @@ private void SolveIslands(EntityUid uid, PhysicsMapComponent component, List - protected virtual void UpdateLerpData(PhysicsMapComponent component, List bodies, EntityQuery xformQuery) + protected virtual void UpdateLerpData(PhysicsMapComponent component, List> bodies, EntityQuery xformQuery) { } @@ -718,9 +720,9 @@ private void SolveIsland( for (var i = 0; i < island.Bodies.Count; i++) { - var body = island.Bodies[i]; + var (bodyUid, body) = island.Bodies[i]; var (worldPos, worldRot) = - _transform.GetWorldPositionRotation(xformQuery.GetComponent(body.Owner), xformQuery); + _transform.GetWorldPositionRotation(xformQuery.GetComponent(bodyUid), xformQuery); var transform = new Transform(worldPos, worldRot); var position = Physics.Transform.Mul(transform, body.LocalCenter); @@ -899,7 +901,7 @@ private void SolveIsland( { for (var i = 0; i < bodyCount; i++) { - var body = island.Bodies[i]; + var body = island.Bodies[i].Comp; if (body.BodyType == BodyType.Static) continue; @@ -930,9 +932,10 @@ private void SolveIsland( for (var i = 0; i < bodyCount; i++) { - var body = island.Bodies[i]; + var body = island.Bodies[i].Comp; - if (body.BodyType == BodyType.Static) continue; + if (body.BodyType == BodyType.Static) + continue; if (!body.SleepingAllowed || body.AngularVelocity * body.AngularVelocity > data.AngTolSqr || @@ -965,16 +968,16 @@ private void SolveIsland( ArrayPool.Shared.Return(positionConstraints); } - private void FinalisePositions(int start, int end, int offset, List bodies, EntityQuery xformQuery, Vector2[] positions, float[] angles, Vector2[] solvedPositions, float[] solvedAngles) + private void FinalisePositions(int start, int end, int offset, List> bodies, EntityQuery xformQuery, Vector2[] positions, float[] angles, Vector2[] solvedPositions, float[] solvedAngles) { for (var i = start; i < end; i++) { - var body = bodies[i]; + var (bodyUid, body) = bodies[i]; if (body.BodyType == BodyType.Static) continue; - var xform = xformQuery.GetComponent(body.Owner); + var xform = xformQuery.GetComponent(bodyUid); var parentXform = xformQuery.GetComponent(xform.ParentUid); var (_, parentRot, parentInvMatrix) = parentXform.GetWorldPositionRotationInvMatrix(xformQuery); var worldRot = (float) (parentRot + xform._localRotation); @@ -1019,7 +1022,8 @@ private void UpdateBodies( // So technically we don't /need/ to skip static bodies here but it saves us having to check for deferred updates so we'll do it anyway. // Plus calcing worldpos can be costly so we skip that too which is nice. - if (body.BodyType == BodyType.Static) continue; + if (body.Comp.BodyType == BodyType.Static) + continue; var uid = body.Owner; var position = positions[offset + i]; @@ -1048,7 +1052,7 @@ private void UpdateBodies( } if (physicsDirtied) - Dirty(uid, body); + Dirty(body); } } diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs index 14cae127fd2..631ba135aba 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs @@ -29,7 +29,7 @@ internal void AddAwakeBody(EntityUid uid, PhysicsComponent body, PhysicsMapCompo } DebugTools.Assert(body.Awake); - map.AwakeBodies.Add(body); + map.AwakeBodies.Add((uid, body)); } internal void AddAwakeBody(EntityUid uid, PhysicsComponent body, EntityUid mapUid, PhysicsMapComponent? map = null) @@ -40,7 +40,7 @@ internal void AddAwakeBody(EntityUid uid, PhysicsComponent body, EntityUid mapUi internal void RemoveSleepBody(EntityUid uid, PhysicsComponent body, PhysicsMapComponent? map = null) { - map?.AwakeBodies.Remove(body); + map?.AwakeBodies.Remove((uid, body)); } internal void RemoveSleepBody(EntityUid uid, PhysicsComponent body, EntityUid mapUid, PhysicsMapComponent? map = null) diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs index 0339d133401..3e9ab5e10fa 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs @@ -238,7 +238,7 @@ private void RecursiveMapUpdate( DebugTools.Assert(body.Awake); } else - DebugTools.Assert(oldMap?.AwakeBodies.Contains(body) != true); + DebugTools.Assert(oldMap?.AwakeBodies.Contains((uid, body)) != true); } _joints.ClearJoints(uid); diff --git a/Robust.UnitTesting/Shared/Physics/PhysicsMap_Test.cs b/Robust.UnitTesting/Shared/Physics/PhysicsMap_Test.cs index 5f3bbbb3572..741d6467158 100644 --- a/Robust.UnitTesting/Shared/Physics/PhysicsMap_Test.cs +++ b/Robust.UnitTesting/Shared/Physics/PhysicsMap_Test.cs @@ -45,7 +45,7 @@ public void RecursiveMapChange() physSystem.SetSleepingAllowed(parent, parentBody, false); fixtureSystem.CreateFixture(parent, "fix1", new Fixture(new PhysShapeCircle(0.5f), 0, 0, false), body: parentBody); physSystem.WakeBody(parent); - Assert.That(physicsMap.AwakeBodies, Does.Contain(parentBody)); + Assert.That(physicsMap.AwakeBodies, Does.Contain(new Entity(parent, parentBody))); var child = entManager.SpawnEntity(null, new EntityCoordinates(parent, Vector2.Zero)); var childBody = entManager.AddComponent(child); @@ -55,7 +55,7 @@ public void RecursiveMapChange() fixtureSystem.CreateFixture(child, "fix1", new Fixture(new PhysShapeCircle(0.5f), 0, 0, false), body: childBody); physSystem.WakeBody(child, body: childBody); - Assert.That(physicsMap.AwakeBodies, Does.Contain(childBody)); + Assert.That(physicsMap.AwakeBodies, Does.Contain(new Entity(child, childBody))); xformSystem.SetParent(parent, parentXform, mapUid2);