Skip to content

Commit

Permalink
Remove references to IComponent.Owner in physics island processing
Browse files Browse the repository at this point in the history
Basically just converts a bunch of places where PhysicsComponent is being stored to instead store Entity<PhysicsComponent> and fixes the resulting errors
  • Loading branch information
TemporalOroboros committed Feb 6, 2025
1 parent c4a5752 commit ebb697e
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 52 deletions.
2 changes: 1 addition & 1 deletion Robust.Client/Physics/DebugPhysicsIslandSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PhysicsComponent> Bodies)> IslandSolve = new();
public readonly Queue<(TimeSpan Time, List<Entity<PhysicsComponent>> Bodies)> IslandSolve = new();
public const float SolveDuration = 0.1f;

public override void Initialize()
Expand Down
10 changes: 5 additions & 5 deletions Robust.Client/Physics/PhysicsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PhysicsComponent>(body.Owner, body));
toRemove.Add(new Entity<PhysicsComponent>(uid, body));
}
}

Expand All @@ -49,19 +49,19 @@ protected override void Cleanup(PhysicsMapComponent component, float frameTime)
base.Cleanup(component, frameTime);
}

protected override void UpdateLerpData(PhysicsMapComponent component, List<PhysicsComponent> bodies, EntityQuery<TransformComponent> xformQuery)
protected override void UpdateLerpData(PhysicsMapComponent component, List<Entity<PhysicsComponent>> bodies, EntityQuery<TransformComponent> 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)
{
continue;
}

component.LerpData[xform.Owner] = (xform.ParentUid, xform.LocalPosition, xform.LocalRotation);
component.LerpData[body.Owner] = (xform.ParentUid, xform.LocalPosition, xform.LocalRotation);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Robust.Shared/Physics/Dynamics/PhysicsMapComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public sealed partial class PhysicsMapComponent : Component
/// All awake bodies on this map.
/// </summary>
[ViewVariables]
public readonly HashSet<PhysicsComponent> AwakeBodies = new();
public readonly HashSet<Entity<PhysicsComponent>> AwakeBodies = new();

/// <summary>
/// Store last tick's invDT
Expand Down
4 changes: 2 additions & 2 deletions Robust.Shared/Physics/IslandSolveMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace Robust.Shared.Physics
{
internal sealed class IslandSolveMessage : EntityEventArgs
{
public List<PhysicsComponent> Bodies { get; }
public List<Entity<PhysicsComponent>> Bodies { get; }

public IslandSolveMessage(List<PhysicsComponent> bodies)
public IslandSolveMessage(List<Entity<PhysicsComponent>> bodies)
{
Bodies = bodies;
}
Expand Down
80 changes: 42 additions & 38 deletions Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ public abstract partial class SharedPhysicsSystem
*/
private const int MaxIslands = 256;

private readonly ObjectPool<List<PhysicsComponent>> _islandBodyPool =
new DefaultObjectPool<List<PhysicsComponent>>(new ListPolicy<PhysicsComponent>(), MaxIslands);
private readonly ObjectPool<List<Entity<PhysicsComponent>>> _islandBodyPool =
new DefaultObjectPool<List<Entity<PhysicsComponent>>>(new ListPolicy<Entity<PhysicsComponent>>(), MaxIslands);

private readonly ObjectPool<List<Contact>> _islandContactPool =
new DefaultObjectPool<List<Contact>>(new ListPolicy<Contact>(), MaxIslands);
Expand All @@ -140,7 +140,7 @@ public abstract partial class SharedPhysicsSystem
internal record struct IslandData(
int Index,
bool LoneIsland,
List<PhysicsComponent> Bodies,
List<Entity<PhysicsComponent>> Bodies,
List<Contact> Contacts,
List<(Joint Original, Joint Joint)> Joints,
List<(Joint Joint, float Error)> BrokenJoints)
Expand All @@ -161,17 +161,17 @@ internal record struct IslandData(
/// </summary>
public int Offset = 0;

public readonly List<PhysicsComponent> Bodies = Bodies;
public readonly List<Entity<PhysicsComponent>> Bodies = Bodies;
public readonly List<Contact> Contacts = Contacts;
public readonly List<(Joint Original, Joint Joint)> Joints = Joints;
public bool PositionSolved = false;
public readonly List<(Joint Joint, float Error)> BrokenJoints = BrokenJoints;
}

// Caching for island generation.
private readonly HashSet<PhysicsComponent> _islandSet = new(64);
private readonly Stack<PhysicsComponent> _bodyStack = new(64);
private readonly List<PhysicsComponent> _awakeBodyList = new(256);
private readonly HashSet<Entity<PhysicsComponent>> _islandSet = new(64);
private readonly Stack<Entity<PhysicsComponent>> _bodyStack = new(64);
private readonly List<Entity<PhysicsComponent>> _awakeBodyList = new(256);

// Config
private bool _warmStarting;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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))
{
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -679,7 +681,7 @@ private void SolveIslands(EntityUid uid, PhysicsMapComponent component, List<Isl
/// If this is the first time a body has been updated this tick update its position for lerping.
/// Due to substepping we have to check it every time.
/// </summary>
protected virtual void UpdateLerpData(PhysicsMapComponent component, List<PhysicsComponent> bodies, EntityQuery<TransformComponent> xformQuery)
protected virtual void UpdateLerpData(PhysicsMapComponent component, List<Entity<PhysicsComponent>> bodies, EntityQuery<TransformComponent> xformQuery)
{

}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 ||
Expand Down Expand Up @@ -965,16 +968,16 @@ private void SolveIsland(
ArrayPool<ContactPositionConstraint>.Shared.Return(positionConstraints);
}

private void FinalisePositions(int start, int end, int offset, List<PhysicsComponent> bodies, EntityQuery<TransformComponent> xformQuery, Vector2[] positions, float[] angles, Vector2[] solvedPositions, float[] solvedAngles)
private void FinalisePositions(int start, int end, int offset, List<Entity<PhysicsComponent>> bodies, EntityQuery<TransformComponent> 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);
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -1048,7 +1052,7 @@ private void UpdateBodies(
}

if (physicsDirtied)
Dirty(uid, body);
Dirty(body);
}
}

Expand Down
4 changes: 2 additions & 2 deletions Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions Robust.UnitTesting/Shared/Physics/PhysicsMap_Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PhysicsComponent>(parent, parentBody)));

var child = entManager.SpawnEntity(null, new EntityCoordinates(parent, Vector2.Zero));
var childBody = entManager.AddComponent<PhysicsComponent>(child);
Expand All @@ -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<PhysicsComponent>(child, childBody)));

xformSystem.SetParent(parent, parentXform, mapUid2);

Expand Down

0 comments on commit ebb697e

Please sign in to comment.