Revert "Move physics fixtures to its own component (#2220)"

This reverts commit ebc0fc9c60.
This commit is contained in:
metalgearsloth
2021-12-01 13:54:32 +11:00
parent 1dec0dd980
commit f812eb1e27
30 changed files with 534 additions and 615 deletions

View File

@@ -130,7 +130,7 @@ namespace Robust.Server.Console.Commands
Hard = true
};
var broadphase = EntitySystem.Get<FixtureSystem>();
var broadphase = EntitySystem.Get<SharedBroadphaseSystem>();
broadphase.CreateFixture(ground, horizontalFixture);
@@ -194,7 +194,7 @@ namespace Robust.Server.Console.Commands
Hard = true
};
var broadphase = EntitySystem.Get<FixtureSystem>();
var broadphase = EntitySystem.Get<SharedBroadphaseSystem>();
broadphase.CreateFixture(ground, horizontalFixture);
var vertical = new EdgeShape(new Vector2(10, 0), new Vector2(10, 10));
@@ -258,7 +258,7 @@ namespace Robust.Server.Console.Commands
Hard = true
};
var broadphase = EntitySystem.Get<FixtureSystem>();
var broadphase = EntitySystem.Get<SharedBroadphaseSystem>();
broadphase.CreateFixture(ground, horizontalFixture);
// Setup boxes
@@ -296,7 +296,7 @@ namespace Robust.Server.Console.Commands
private void CreateTumbler(MapId mapId)
{
var broadphaseSystem = EntitySystem.Get<FixtureSystem>();
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
var entityManager = IoCManager.Resolve<IEntityManager>();
var groundUid = entityManager.SpawnEntity(null, new MapCoordinates(0f, 0f, mapId)).Uid;

View File

@@ -51,11 +51,11 @@ namespace Robust.Server.Map
// TODO: Like MapManager injecting this is a PITA so need to work out an easy way to do it.
// Maybe just add like a PostInject method that gets called way later?
var fixtureSystem = EntitySystem.Get<FixtureSystem>();
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
foreach (var fixture in chunk.Fixtures)
{
fixtureSystem.DestroyFixture(body, fixture);
broadphaseSystem.DestroyFixture(body, fixture);
}
}

View File

@@ -441,21 +441,19 @@ namespace Robust.Server.Maps
{
var entManager = IoCManager.Resolve<IEntityManager>();
var gridFixtures = EntitySystem.Get<GridFixtureSystem>();
var fixtureSystem = EntitySystem.Get<FixtureSystem>();
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
foreach (var grid in Grids)
{
var gridInternal = (IMapGridInternal) grid;
var body = entManager.EnsureComponent<PhysicsComponent>(grid.GridEntityId);
body.Broadphase = _mapManager.GetMapEntity(grid.ParentMapId).GetComponent<BroadphaseComponent>();
var fixtures = entManager.EnsureComponent<FixturesComponent>(grid.GridEntityId);
var body = entManager.EnsureComponent<PhysicsComponent>(entManager.GetEntity(grid.GridEntityId));
gridFixtures.ProcessGrid(gridInternal);
// Need to go through and double-check we don't have any hanging-on fixtures that
// no longer apply (e.g. due to an update in GridFixtureSystem)
var toRemove = new RemQueue<Fixture>();
var toRemove = new List<Fixture>();
foreach (var (_, fixture) in fixtures.Fixtures)
foreach (var fixture in body.Fixtures)
{
var found = false;
@@ -479,10 +477,8 @@ namespace Robust.Server.Maps
foreach (var fixture in toRemove)
{
fixtureSystem.DestroyFixture(body, fixture, false, fixtures);
broadphaseSystem.DestroyFixture(fixture);
}
fixtureSystem.FixtureUpdate(fixtures, body);
}
}

View File

@@ -24,4 +24,17 @@ namespace Robust.Shared.GameObjects
Component = component;
}
}
public sealed class FixtureUpdateMessage : EntityEventArgs
{
public PhysicsComponent Body { get; }
public Fixture Fixture { get; }
public FixtureUpdateMessage(PhysicsComponent body, Fixture fixture)
{
Body = body;
Fixture = fixture;
}
}
}

View File

@@ -28,9 +28,13 @@ using System.Linq;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Dynamics.Contacts;
using Robust.Shared.Players;
@@ -73,13 +77,6 @@ namespace Robust.Shared.GameObjects
public bool IgnoreCCD { get; set; }
// TODO: Placeholder; look it's disgusting but my main concern is stopping fixtures being serialized every tick
// on physics bodies for massive shuttle perf savings.
[Obsolete("Use FixturesComponent instead.")]
public IReadOnlyList<Fixture> Fixtures => Owner.EntityManager.GetComponent<FixturesComponent>(OwnerUid).Fixtures.Values.ToList();
public int FixtureCount => Owner.EntityManager.GetComponent<FixturesComponent>(OwnerUid).Fixtures.Count;
[ViewVariables]
public int ContactCount
{
@@ -97,6 +94,47 @@ namespace Robust.Shared.GameObjects
}
}
[ViewVariables]
public Box2 LocalAABB
{
get
{
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
var broadphase = broadphaseSystem.GetBroadphase(this);
if (broadphase == null) return new Box2();
var worldPos = Owner.Transform.WorldPosition;
var aabb = new Box2(worldPos, worldPos);
foreach (var fixture in Fixtures)
{
foreach (var proxy in fixture.Proxies)
{
aabb = aabb.Union(proxy.AABB);
}
}
return aabb;
}
}
[ViewVariables]
public Box2 WorldAABB
{
get
{
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
var broadphase = broadphaseSystem.GetBroadphase(this);
if (broadphase == null) return new Box2();
var localAABB = LocalAABB;
var center = broadphase.Owner.Transform.WorldMatrix.Transform(localAABB.Center);
return new Box2Rotated(localAABB.Translated(center), broadphase.Owner.Transform.WorldRotation, center).CalcBoundingBox();
}
}
public IEnumerable<Contact> Contacts
{
get
@@ -256,10 +294,29 @@ namespace Robust.Shared.GameObjects
Awake = true;
}
void ISerializationHooks.AfterDeserialization()
{
FixtureCount = _fixtures.Count;
foreach (var fixture in _fixtures)
{
fixture.Body = this;
fixture.ComputeProperties();
fixture.ID = GetFixtureName(fixture);
}
ResetMassData();
if (_mass > 0f && (BodyType & (BodyType.Dynamic | BodyType.KinematicController)) != 0)
{
_invMass = 1.0f / _mass;
}
}
/// <inheritdoc />
public override ComponentState GetComponentState()
{
return new PhysicsComponentState(_canCollide, _sleepingAllowed, _fixedRotation, _bodyStatus, _linVelocity, _angVelocity, _bodyType);
return new PhysicsComponentState(_canCollide, _sleepingAllowed, _fixedRotation, _bodyStatus, _fixtures, LinearVelocity, AngularVelocity, BodyType);
}
/// <inheritdoc />
@@ -276,7 +333,95 @@ namespace Robust.Shared.GameObjects
// So transform doesn't apply MapId in the HandleComponentState because ??? so MapId can still be 0.
// Fucking kill me, please. You have no idea deep the rabbit hole of shitcode goes to make this work.
/*
* -- Fixtures --
*/
var toAddFixtures = new List<Fixture>();
var toRemoveFixtures = new List<Fixture>();
var computeProperties = false;
// Given a bunch of data isn't serialized need to sort of re-initialise it
var newFixtures = new List<Fixture>(newState.Fixtures.Count);
foreach (var fixture in newState.Fixtures)
{
var newFixture = new Fixture();
fixture.CopyTo(newFixture);
newFixture.Body = this;
newFixtures.Add(newFixture);
}
// Add / update new fixtures
foreach (var fixture in newFixtures)
{
var found = false;
foreach (var existing in _fixtures)
{
if (!fixture.ID.Equals(existing.ID)) continue;
if (!fixture.Equals(existing))
{
toAddFixtures.Add(fixture);
toRemoveFixtures.Add(existing);
}
found = true;
break;
}
if (!found)
{
toAddFixtures.Add(fixture);
}
}
// Remove old fixtures
foreach (var existing in _fixtures)
{
var found = false;
foreach (var fixture in newFixtures)
{
if (fixture.ID.Equals(existing.ID))
{
found = true;
break;
}
}
if (!found)
{
toRemoveFixtures.Add(existing);
}
}
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
foreach (var fixture in toRemoveFixtures)
{
computeProperties = true;
broadphaseSystem.DestroyFixture(this, fixture);
}
// TODO: We also still need event listeners for shapes (Probably need C# events)
foreach (var fixture in toAddFixtures)
{
computeProperties = true;
broadphaseSystem.CreateFixture(this, fixture);
fixture.Shape.ApplyState();
}
/*
* -- Sundries --
*/
Dirty();
if (computeProperties)
{
ResetMassData();
}
LinearVelocity = newState.LinearVelocity;
// Logger.Debug($"{IGameTiming.TickStampStatic}: [{Owner}] {LinearVelocity}");
AngularVelocity = newState.AngularVelocity;
@@ -284,6 +429,24 @@ namespace Robust.Shared.GameObjects
Predict = false;
}
public Fixture? GetFixture(string name)
{
// Sooo I'd rather have fixtures as a list in serialization but there's not really an easy way to have it as a
// temporary value on deserialization so we can store it as a dictionary of <name, fixture>
// given 100% of bodies have 1-2 fixtures this isn't really a performance problem right now but
// should probably be done at some stage
// If we really need it then you just deserialize onto a dummy field that then just never gets used again.
foreach (var fixture in _fixtures)
{
if (fixture.ID.Equals(name))
{
return fixture;
}
}
return null;
}
/// <summary>
/// Resets the dynamics of this body.
/// Sets torque, force and linear/angular velocity to 0
@@ -305,7 +468,7 @@ namespace Robust.Shared.GameObjects
var bounds = new Box2(transform.Position, transform.Position);
foreach (var fixture in Fixtures)
foreach (var fixture in _fixtures)
{
for (var i = 0; i < fixture.Shape.ChildCount; i++)
{
@@ -317,6 +480,17 @@ namespace Robust.Shared.GameObjects
return bounds;
}
[ViewVariables]
public int FixtureCount { get; internal set; }
/// <inheritdoc />
[ViewVariables]
public IReadOnlyList<Fixture> Fixtures => _fixtures;
[DataField("fixtures")]
[NeverPushInheritance]
internal List<Fixture> _fixtures = new();
/// <summary>
/// Enables or disabled collision processing of this component.
/// </summary>
@@ -351,19 +525,57 @@ namespace Robust.Shared.GameObjects
/// This is useful for triggers or such to detect collision without actually causing a blockage.
/// </remarks>
[ViewVariables(VVAccess.ReadWrite)]
public bool Hard { get; internal set; }
public bool Hard
{
get
{
foreach (var fixture in Fixtures)
{
if (fixture.Hard) return true;
}
return false;
}
set
{
foreach (var fixture in Fixtures)
{
fixture.Hard = value;
}
}
}
/// <summary>
/// Bitmask of the collision layers this component is a part of.
/// </summary>
[ViewVariables]
public int CollisionLayer { get; internal set; }
[ViewVariables(VVAccess.ReadWrite)]
public int CollisionLayer
{
get
{
var layers = 0x0;
foreach (var fixture in Fixtures)
layers |= fixture.CollisionLayer;
return layers;
}
}
/// <summary>
/// Bitmask of the layers this component collides with.
/// </summary>
[ViewVariables]
public int CollisionMask { get; internal set; }
[ViewVariables(VVAccess.ReadWrite)]
public int CollisionMask
{
get
{
var mask = 0x0;
foreach (var fixture in Fixtures)
mask |= fixture.CollisionMask;
return mask;
}
}
// I made Mass read-only just because overwriting it doesn't touch inertia.
/// <summary>
@@ -761,6 +973,41 @@ namespace Robust.Shared.GameObjects
return Transform.MulT(new Quaternion2D((float) Owner.EntityManager.GetComponent<TransformComponent>(OwnerUid).WorldRotation.Theta), worldVector);
}
public void FixtureChanged(Fixture fixture)
{
// TODO: Optimise this a LOT
Dirty();
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new FixtureUpdateMessage(this, fixture));
}
public string GetFixtureName(Fixture fixture)
{
if (!string.IsNullOrEmpty(fixture.ID)) return fixture.ID;
var i = 0;
while (true)
{
var found = false;
++i;
var name = $"fixture_{i}";
foreach (var existing in _fixtures)
{
if (existing.ID.Equals(name))
{
found = true;
break;
}
}
if (!found)
{
return name;
}
}
}
public Transform GetTransform()
{
var (worldPos, worldRot) = Owner.Transform.GetWorldPositionRotation();
@@ -874,11 +1121,16 @@ namespace Robust.Shared.GameObjects
{
_awake = false;
}
}
var startup = new PhysicsInitializedEvent(Owner.Uid);
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, ref startup);
ResetMassData();
protected override void OnRemove()
{
base.OnRemove();
// Need to do these immediately in case collision behaviors deleted the body
// TODO: Could be more optimal as currently broadphase will call this ANYWAY
DestroyContacts();
EntitySystem.Get<SharedBroadphaseSystem>().RemoveBody(this);
CanCollide = false;
}
public void ResetMassData()
@@ -895,9 +1147,9 @@ namespace Robust.Shared.GameObjects
}
var localCenter = Vector2.Zero;
var shapeManager = EntitySystem.Get<FixtureSystem>();
var shapeManager = IoCManager.Resolve<IShapeManager>();
foreach (var fixture in Fixtures)
foreach (var fixture in _fixtures)
{
if (fixture.Mass <= 0.0f) continue;

View File

@@ -15,6 +15,7 @@ namespace Robust.Shared.GameObjects
public readonly bool SleepingAllowed;
public readonly bool FixedRotation;
public readonly BodyStatus Status;
public readonly List<Fixture> Fixtures;
public readonly Vector2 LinearVelocity;
public readonly float AngularVelocity;
@@ -27,6 +28,8 @@ namespace Robust.Shared.GameObjects
/// <param name="sleepingAllowed"></param>
/// <param name="fixedRotation"></param>
/// <param name="status"></param>
/// <param name="fixtures"></param>
/// <param name="joints"></param>
/// <param name="linearVelocity">Current linear velocity of the entity in meters per second.</param>
/// <param name="angularVelocity">Current angular velocity of the entity in radians per sec.</param>
/// <param name="bodyType"></param>
@@ -35,6 +38,7 @@ namespace Robust.Shared.GameObjects
bool sleepingAllowed,
bool fixedRotation,
BodyStatus status,
List<Fixture> fixtures,
Vector2 linearVelocity,
float angularVelocity,
BodyType bodyType)
@@ -43,6 +47,7 @@ namespace Robust.Shared.GameObjects
SleepingAllowed = sleepingAllowed;
FixedRotation = fixedRotation;
Status = status;
Fixtures = fixtures;
LinearVelocity = linearVelocity;
AngularVelocity = angularVelocity;

View File

@@ -1,12 +0,0 @@
namespace Robust.Shared.GameObjects
{
public readonly struct PhysicsInitializedEvent
{
public readonly EntityUid Uid;
public PhysicsInitializedEvent(EntityUid uid)
{
Uid = uid;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Robust.Shared.GameObjects
public abstract class SharedGridFixtureSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly FixtureSystem _fixtures = default!;
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
private bool _enabled;
@@ -59,12 +59,6 @@ namespace Robust.Shared.GameObjects
return;
}
if (!gridEnt.TryGetComponent(out FixturesComponent? fixturesComponent))
{
Logger.ErrorS("physics", $"Trying to regenerate collision for {gridEnt} that doesn't have {nameof(fixturesComponent)}");
return;
}
var origin = chunk.Indices * chunk.ChunkSize;
// So we store a reference to the fixture on the chunk because it's easier to cross-reference it.
@@ -129,7 +123,7 @@ namespace Robust.Shared.GameObjects
foreach (var fixture in toRemove)
{
chunk.Fixtures.Remove(fixture);
_fixtures.DestroyFixture(fixture, false, fixturesComponent);
_broadphase.DestroyFixture(fixture);
}
if (newFixtures.Count > 0 || toRemove.List?.Count > 0)
@@ -140,7 +134,7 @@ namespace Robust.Shared.GameObjects
// Anything remaining is a new fixture (or at least, may have not serialized onto the chunk yet).
foreach (var fixture in newFixtures)
{
var existingFixture = _fixtures.GetFixtureOrNull(physicsComponent, fixture.ID);
var existingFixture = physicsComponent.GetFixture(fixture.ID);
// Check if it's the same (otherwise remove anyway).
if (existingFixture?.Shape is PolygonShape poly &&
poly.EqualsApprox((PolygonShape) fixture.Shape))
@@ -150,14 +144,11 @@ namespace Robust.Shared.GameObjects
}
chunk.Fixtures.Add(fixture);
_fixtures.CreateFixture(physicsComponent, fixture, false, fixturesComponent);
_broadphase.CreateFixture(physicsComponent, fixture);
}
if (updated)
{
_fixtures.FixtureUpdate(fixturesComponent, physicsComponent);
EntityManager.EventBus.RaiseLocalEvent(gridEnt.Uid,new GridFixtureChangeEvent {NewFixtures = chunk.Fixtures});
}
}
}

View File

@@ -73,7 +73,7 @@ namespace Robust.Shared.GameObjects
var state = (body, entities);
foreach (var fixture in body.Fixtures)
foreach (var fixture in body._fixtures)
{
foreach (var proxy in fixture.Proxies)
{
@@ -165,7 +165,7 @@ namespace Robust.Shared.GameObjects
var localTransform = new Transform(broadInvMatrix.Transform(transform.Position), transform.Quaternion2D.Angle - broadRot);
foreach (var fixture in body.Fixtures)
foreach (var fixture in body._fixtures)
{
var collisionMask = fixture.CollisionMask;
var collisionLayer = fixture.CollisionLayer;

View File

@@ -160,5 +160,10 @@ namespace Robust.Shared.Physics.Collision.Shapes
// It's a line
return 0f;
}
public void ApplyState()
{
return;
}
}
}

View File

@@ -39,5 +39,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
/// Calculate the AABB of the shape.
/// </summary>
Box2 ComputeAABB(Transform transform, int childIndex);
void ApplyState();
}
}

View File

@@ -32,6 +32,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
{
if (MathHelper.CloseToPercent(_radius, value)) return;
_radius = value;
OnDataChanged?.Invoke();
}
}
@@ -57,6 +58,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
return;
_localBounds = value;
OnDataChanged?.Invoke();
}
}
@@ -75,6 +77,13 @@ namespace Robust.Shared.Physics.Collision.Shapes
return new Box2Rotated(_localBounds.Translated(transform.Position), transform.Quaternion2D.Angle, transform.Position).CalcBoundingBox().Enlarged(_radius);
}
/// <inheritdoc />
public void ApplyState() { }
// TODO
[field: NonSerialized]
public event Action? OnDataChanged;
[Pure]
internal List<Vector2> GetVertices()
{

View File

@@ -72,6 +72,9 @@ namespace Robust.Shared.Physics.Collision.Shapes
return new Box2(p.X - _radius, p.Y - _radius, p.X + _radius, p.Y + _radius);
}
/// <inheritdoc />
public void ApplyState() { }
public bool Equals(IPhysShape? other)
{
if (other is not PhysShapeCircle otherCircle) return false;

View File

@@ -128,7 +128,9 @@ namespace Robust.Shared.Physics.Collision.Shapes
Normals[i] = temp.Normalized;
}
// TODO: Updates (network etc)
// Compute the polygon mass data
// TODO: Update fixture. Maybe use events for it? Who tf knows.
// If we get grid polys then we'll actually need runtime updating of bbs.
}
public ShapeType ShapeType => ShapeType.Polygon;
@@ -245,6 +247,11 @@ namespace Robust.Shared.Physics.Collision.Shapes
return new Box2(lower - r, upper + r);
}
public void ApplyState()
{
return;
}
public static explicit operator PolygonShape(PhysShapeAabb aabb)
{
// TODO: Need a test for this probably, if there is no AABB manifold generator done at least.

View File

@@ -82,8 +82,7 @@ namespace Robust.Shared.Physics.Dynamics
if (MathHelper.CloseToPercent(value, _friction)) return;
_friction = value;
// TODO: EntitySystem
// Body.FixtureChanged(this);
Body.FixtureChanged(this);
}
}
@@ -100,11 +99,10 @@ namespace Robust.Shared.Physics.Dynamics
get => _restitution;
set
{
if (MathHelper.CloseTo(value, _restitution)) return;
if (MathHelper.CloseToPercent(value, _restitution)) return;
// TODO: EntitySystem
_restitution = value;
// Body.FixtureChanged(this);
Body.FixtureChanged(this);
}
}
@@ -127,10 +125,9 @@ namespace Robust.Shared.Physics.Dynamics
if (_hard == value)
return;
// TODO: EntitySystem
_hard = value;
Body.Awake = true;
// Body.FixtureChanged(this);
Body.FixtureChanged(this);
}
}
@@ -156,9 +153,9 @@ namespace Robust.Shared.Physics.Dynamics
{
if (MathHelper.CloseToPercent(value, _mass)) return;
// TODO: EntitySystem
_mass = MathF.Max(0f, value);
// Body.FixtureChanged(this);
ComputeProperties();
Body.FixtureChanged(this);
Body.ResetMassData();
}
}
@@ -178,9 +175,8 @@ namespace Robust.Shared.Physics.Dynamics
if (_collisionLayer == value)
return;
// TODO: EntitySystem
_collisionLayer = value;
// Body.FixtureChanged(this);
Body.FixtureChanged(this);
EntitySystem.Get<SharedBroadphaseSystem>().Refilter(this);
}
}
@@ -200,9 +196,8 @@ namespace Robust.Shared.Physics.Dynamics
if (_collisionMask == value)
return;
// TODO: EntitySystem
_collisionMask = value;
// Body.FixtureChanged(this);
Body.FixtureChanged(this);
EntitySystem.Get<SharedBroadphaseSystem>().Refilter(this);
}
}
@@ -281,8 +276,47 @@ namespace Robust.Shared.Physics.Dynamics
fixture._mass = _mass;
}
#region ComputeProperties
// Moved from Shape because no MassData on Shape anymore (due to serv3 and physics ease-of-use etc etc.)
internal void ComputeProperties()
{
switch (Shape)
{
case EdgeShape edge:
ComputeEdge(edge);
break;
case PhysShapeAabb aabb:
ComputeAABB(aabb);
break;
case PhysShapeCircle circle:
ComputeCircle(circle);
break;
case PolygonShape poly:
ComputePoly(poly, out _);
break;
default:
throw new NotImplementedException();
}
}
#region ComputeProperties
private void ComputeAABB(PhysShapeAabb aabb)
{
var area = aabb.LocalBounds.Width * aabb.LocalBounds.Height;
float I = 0.0f;
//The area is too small for the engine to handle.
DebugTools.Assert(area > float.Epsilon);
// Total mass
// TODO: Do we need this?
var density = area > 0.0f ? Mass / area : 0.0f;
// Center of mass
aabb.Centroid = Vector2.Zero;
// Inertia tensor relative to the local origin (point s).
_inertia = density * I;
}
private void ComputePoly(PolygonShape poly, out float area)
{

View File

@@ -1,410 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Robust.Shared.Physics
{
/// <summary>
/// Manages physics fixtures.
/// </summary>
public sealed partial class FixtureSystem : EntitySystem
{
[Dependency] private readonly SharedBroadphaseSystem _broadphaseSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FixturesComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<FixturesComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<FixturesComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<FixturesComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<PhysicsInitializedEvent>(OnPhysicsInit);
SubscribeLocalEvent<PhysicsComponent, ComponentShutdown>(OnPhysicsShutdown);
}
private void OnShutdown(EntityUid uid, FixturesComponent component, ComponentShutdown args)
{
// TODO: Need a better solution to this because the only reason I don't throw is that allcomponents test
// Yes it is actively making the game buggier but I would essentially double the size of this PR trying to fix it
// my best solution rn is move the broadphase property onto FixturesComponent and then refactor
// SharedBroadphaseSystem a LOT.
if (!EntityManager.TryGetComponent(uid, out PhysicsComponent? body))
{
return;
}
// Can't just get physicscomp on shutdown as it may be touched completely independently.
body.DestroyContacts();
_broadphaseSystem.RemoveBody(body, component);
body.CanCollide = false;
}
private void OnInit(EntityUid uid, FixturesComponent component, ComponentInit args)
{
// Convert the serialized list to the dictionary format as it may not necessarily have an ID in YAML
// (probably change this someday for perf reasons?)
foreach (var fixture in component.SerializedFixtures)
{
fixture.ID = GetFixtureName(component, fixture);
if (component.Fixtures.TryAdd(fixture.ID, fixture)) continue;
Logger.DebugS("physics", $"Tried to deserialize fixture {fixture.ID} on {uid} which already exists.");
}
component.SerializedFixtures.Clear();
if (component.Fixtures.Count <= 0 ||
!EntityManager.TryGetComponent(uid, out PhysicsComponent? body) ||
!EntityManager.TryGetComponent(uid, out TransformComponent? xform)) return;
// Ordering issues man
var broadphase = _broadphaseSystem.GetBroadphase(body);
body.Broadphase = broadphase;
if (broadphase != null)
{
var worldPos = xform.WorldPosition;
var worldRot = xform.WorldRotation;
// Can't resolve in serialization so here we are.
// TODO: Support for large body DynamicTrees (i.e. 1 proxy for the entire body)
foreach (var (_, fixture) in component.Fixtures)
{
// It's possible that fixtures were added at some stage prior to this so we'll just check if they're on the broadphase
if (fixture.ProxyCount > 0) continue;
fixture.Body = body;
_broadphaseSystem.CreateProxies(fixture, worldPos, worldRot, false);
}
}
// Make sure all the right stuff is set on the body
FixtureUpdate(component);
}
#region Public
public void CreateFixture(PhysicsComponent body, Fixture fixture, bool updates = true, FixturesComponent? manager = null, TransformComponent? xform = null)
{
if (!Resolve(body.OwnerUid, ref manager, ref xform))
{
DebugTools.Assert(false);
return;
}
fixture.ID = GetFixtureName(manager, fixture);
manager.Fixtures.Add(fixture.ID, fixture);
fixture.Body = body;
// TODO: Assert world locked
// Broadphase should be set in the future TM
// Should only happen for nullspace / initializing entities
if (body.Broadphase != null)
{
var worldPos = xform.WorldPosition;
var worldRot = xform.WorldRotation;
_broadphaseSystem.UpdateBroadphaseCache(body.Broadphase);
_broadphaseSystem.CreateProxies(fixture, worldPos, worldRot, false);
}
// Supposed to be wrapped in density but eh
if (updates)
{
FixtureUpdate(manager, body);
body.ResetMassData();
manager.Dirty();
}
// TODO: Set newcontacts to true.
}
/// <summary>
/// Creates a <see cref="Fixture"/> from this shape and adds it to the specified <see cref="PhysicsComponent"/>
/// </summary>
public Fixture CreateFixture(PhysicsComponent body, IPhysShape shape)
{
var fixture = new Fixture(body, shape);
CreateFixture(body, fixture);
return fixture;
}
/// <summary>
/// Creates a <see cref="Fixture"/> from this shape and adds it to the specified <see cref="PhysicsComponent"/> with mass.
/// </summary>
public void CreateFixture(PhysicsComponent body, IPhysShape shape, float mass)
{
// TODO: Make it take in density instead?
var fixture = new Fixture(body, shape) {Mass = mass};
CreateFixture(body, fixture);
}
/// <summary>
/// Attempts to get the <see cref="Fixture"/> with the specified ID for this body.
/// </summary>
public Fixture? GetFixtureOrNull(PhysicsComponent body, string id, FixturesComponent? manager = null)
{
if (!Resolve(body.OwnerUid, ref manager))
{
return null;
}
return manager.Fixtures.TryGetValue(id, out var fixture) ? fixture : null;
}
/// <summary>
/// Destroys the specified <see cref="Fixture"/> attached to the body.
/// </summary>
/// <param name="body">The specified body</param>
/// <param name="id">The fixture ID</param>
/// <param name="updates">Whether to update mass etc. Set false if you're doing a bulk operation</param>
public void DestroyFixture(PhysicsComponent body, string id, bool updates = true)
{
var fixture = GetFixtureOrNull(body, id);
if (fixture == null) return;
DestroyFixture(body, fixture, updates);
}
/// <summary>
/// Destroys the specified <see cref="Fixture"/>
/// </summary>
/// <param name="fixture">The specified fixture</param>
/// <param name="updates">Whether to update mass etc. Set false if you're doing a bulk operation</param>
public void DestroyFixture(Fixture fixture, bool updates = true, FixturesComponent? manager = null)
{
DestroyFixture(fixture.Body, fixture, updates, manager);
}
/// <summary>
/// Destroys the specified <see cref="Fixture"/>
/// </summary>
/// <param name="updates">Whether to update mass etc. Set false if you're doing a bulk operation</param>
public void DestroyFixture(PhysicsComponent body, Fixture fixture, bool updates = true, FixturesComponent? manager = null)
{
if (!Resolve(body.OwnerUid, ref manager))
{
return;
}
// TODO: Assert world locked
DebugTools.Assert(fixture.Body == body);
DebugTools.Assert(manager.FixtureCount > 0);
if (!manager.Fixtures.Remove(fixture.ID))
{
Logger.ErrorS("fixtures", $"Tried to remove fixture from {body.Owner} that was already removed.");
return;
}
var edge = body.ContactEdges;
while (edge != null)
{
var contact = edge.Contact!;
edge = edge.Next;
var fixtureA = contact.FixtureA;
var fixtureB = contact.FixtureB;
if (fixture == fixtureA || fixture == fixtureB)
{
body.PhysicsMap?.ContactManager.Destroy(contact);
}
}
var broadphase = body.Broadphase;
if (broadphase != null)
{
_broadphaseSystem.DestroyProxies(broadphase, fixture);
}
if (updates)
{
FixtureUpdate(manager, body);
body.ResetMassData();
manager.Dirty();
}
}
#endregion
private void OnPhysicsShutdown(EntityUid uid, PhysicsComponent component, ComponentShutdown args)
{
if (EntityManager.GetComponent<MetaDataComponent>(uid).EntityLifeStage > EntityLifeStage.MapInitialized) return;
EntityManager.RemoveComponent<FixturesComponent>(uid);
}
private void OnPhysicsInit(ref PhysicsInitializedEvent ev)
{
EntityManager.EnsureComponent<FixturesComponent>(ev.Uid);
}
private void OnGetState(EntityUid uid, FixturesComponent component, ref ComponentGetState args)
{
args.State = new FixtureManagerComponentState
{
Fixtures = component.Fixtures.Values.ToList(),
};
}
private void OnHandleState(EntityUid uid, FixturesComponent component, ref ComponentHandleState args)
{
if (args.Current is not FixtureManagerComponentState state) return;
if (!EntityManager.TryGetComponent(uid, out PhysicsComponent? physics))
{
DebugTools.Assert(false);
Logger.ErrorS("physics", $"Tried to apply fixture state for {uid} which has name {nameof(PhysicsComponent)}");
return;
}
var toAddFixtures = new List<Fixture>();
var toRemoveFixtures = new List<Fixture>();
var computeProperties = false;
// Given a bunch of data isn't serialized need to sort of re-initialise it
var newFixtures = new List<Fixture>(state.Fixtures.Count);
foreach (var fixture in state.Fixtures)
{
var newFixture = new Fixture();
fixture.CopyTo(newFixture);
newFixture.Body = physics;
newFixtures.Add(newFixture);
}
// Add / update new fixtures
foreach (var fixture in newFixtures)
{
var found = false;
foreach (var (_, existing) in component.Fixtures)
{
if (!fixture.ID.Equals(existing.ID)) continue;
if (!fixture.Equals(existing))
{
toAddFixtures.Add(fixture);
toRemoveFixtures.Add(existing);
}
found = true;
break;
}
if (!found)
{
toAddFixtures.Add(fixture);
}
}
// Remove old fixtures
foreach (var (_, existing) in component.Fixtures)
{
var found = false;
foreach (var fixture in newFixtures)
{
if (fixture.ID.Equals(existing.ID))
{
found = true;
break;
}
}
if (!found)
{
toRemoveFixtures.Add(existing);
}
}
foreach (var fixture in toRemoveFixtures)
{
computeProperties = true;
DestroyFixture(physics, fixture);
}
// TODO: We also still need event listeners for shapes (Probably need C# events)
// Or we could just make it so shapes can only be updated via fixturesystem which handles it
// automagically (friends or something?)
foreach (var fixture in toAddFixtures)
{
computeProperties = true;
CreateFixture(physics, fixture);
}
if (computeProperties)
{
physics.ResetMassData();
}
}
private string GetFixtureName(FixturesComponent component, Fixture fixture)
{
if (!string.IsNullOrEmpty(fixture.ID)) return fixture.ID;
var i = 0;
while (true)
{
++i;
var name = $"fixture_{i}";
var found = component.Fixtures.ContainsKey(name);
if (!found)
{
return name;
}
}
}
/// <summary>
/// Updates all of the cached physics information on the body derived from fixtures.
/// </summary>
public void FixtureUpdate(FixturesComponent component, PhysicsComponent? body = null)
{
if (!Resolve(component.OwnerUid, ref body))
{
return;
}
var mask = 0;
var layer = 0;
var hard = false;
foreach (var (_, fixture) in component.Fixtures)
{
mask |= fixture.CollisionMask;
layer |= fixture.CollisionLayer;
hard |= fixture.Hard;
}
body.ResetMassData();
// Normally this method is called when fixtures need to be dirtied anyway so no point in returning early I think
body.CollisionMask = mask;
body.CollisionLayer = layer;
body.Hard = hard;
component.Dirty();
}
[Serializable, NetSerializable]
private sealed class FixtureManagerComponentState : ComponentState
{
public List<Fixture> Fixtures = default!;
}
}
}

View File

@@ -1,52 +0,0 @@
using System.Collections.Generic;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Shared.Physics
{
/// <summary>
/// Storage for physics fixtures
/// </summary>
/// <remarks>
/// In its own component to decrease physics comp state size significantly.
/// </remarks>
[RegisterComponent]
[NetworkedComponent]
[Friend(typeof(FixtureSystem))]
[ComponentProtoName("Fixtures")]
public sealed class FixturesComponent : Component, ISerializationHooks
{
// This is a snowflake component whose main job is making physics states smaller for massive bodies
// (e.g. grids)
// Content generally shouldn't care about its existence.
public override string Name => "Fixtures";
[ViewVariables]
public int FixtureCount => Fixtures.Count;
[ViewVariables]
public readonly Dictionary<string, Fixture> Fixtures = new();
[DataField("fixtures")]
[NeverPushInheritance]
internal List<Fixture> SerializedFixtures = new();
void ISerializationHooks.BeforeSerialization()
{
// Can't assert the count is 0 because it's possible it gets re-serialized before init!
if (SerializedFixtures.Count > 0) return;
foreach (var (_, fixture) in Fixtures)
{
SerializedFixtures.Add(fixture);
}
}
}
}

View File

@@ -54,6 +54,8 @@ namespace Robust.Shared.Physics
/// </summary>
void DestroyContacts();
IReadOnlyList<Fixture> Fixtures { get; }
/// <summary>
/// The type of the body, which determines how collisions effect this object.
/// </summary>
@@ -81,7 +83,7 @@ namespace Robust.Shared.Physics
/// <remarks>
/// This is useful for triggers or such to detect collision without actually causing a blockage.
/// </remarks>
bool Hard { get; }
bool Hard { get; set; }
/// <summary>
/// Inverse mass of the entity in kilograms (1 / Mass).

View File

@@ -6,11 +6,19 @@ using Robust.Shared.Utility;
namespace Robust.Shared.Physics
{
public partial class FixtureSystem
public interface IShapeManager
{
/// <summary>
/// Tests whether a particular point is contained in the shape.
/// Returns whether a particular point intersects the specified shape.
/// </summary>
bool TestPoint(IPhysShape shape, Transform xform, Vector2 worldPoint);
void GetMassData(IPhysShape shape, ref MassData data);
}
public class ShapeManager : IShapeManager
{
/// <inheritdoc />
public bool TestPoint(IPhysShape shape, Transform xform, Vector2 worldPoint)
{
switch (shape)

View File

@@ -183,7 +183,7 @@ namespace Robust.Shared.Physics
}
}
internal void UpdateBroadphaseCache(BroadphaseComponent broadphase)
private void UpdateBroadphaseCache(BroadphaseComponent broadphase)
{
var uid = broadphase.OwnerUid;
@@ -409,15 +409,14 @@ namespace Robust.Shared.Physics
/// <summary>
/// Remove all of our fixtures from the broadphase.
/// </summary>
private void DestroyProxies(PhysicsComponent body, FixturesComponent? manager = null)
/// <param name="body"></param>
private void DestroyProxies(PhysicsComponent body)
{
if (!Resolve(body.OwnerUid, ref manager)) return;
var broadphase = body.Broadphase;
if (broadphase == null) return;
foreach (var (_, fixture) in manager.Fixtures)
foreach (var fixture in body._fixtures)
{
DestroyProxies(broadphase, fixture);
}
@@ -441,15 +440,9 @@ namespace Robust.Shared.Physics
CreateProxies(body, true);
}
internal void RemoveBody(PhysicsComponent body, FixturesComponent? manager = null)
internal void RemoveBody(PhysicsComponent body)
{
// TODO: Would reaaalllyy like for this to not be false in future
if (!Resolve(body.OwnerUid, ref manager, false))
{
return;
}
DestroyProxies(body, manager);
DestroyProxies(body);
}
private void OnGridMove(EntityUid uid, MapGridComponent component, ref MoveEvent args)
@@ -565,6 +558,91 @@ namespace Robust.Shared.Physics
_queuedRotates.Enqueue(args);
}
public void CreateFixture(PhysicsComponent body, Fixture fixture)
{
fixture.ID = body.GetFixtureName(fixture);
body._fixtures.Add(fixture);
body.FixtureCount += 1;
fixture.Body = body;
// TODO: Assert world locked
// Broadphase should be set in the future TM
// Should only happen for nullspace / initializing entities
if (body.Broadphase != null)
{
UpdateBroadphaseCache(body.Broadphase);
CreateProxies(fixture, body.Owner.Transform.WorldPosition, false);
}
// Supposed to be wrapped in density but eh
body.ResetMassData();
body.Dirty();
// TODO: Set newcontacts to true.
}
public Fixture CreateFixture(PhysicsComponent body, IPhysShape shape)
{
var fixture = new Fixture(body, shape);
CreateFixture(body, fixture);
return fixture;
}
public void CreateFixture(PhysicsComponent body, IPhysShape shape, float mass)
{
// TODO: Make it take in density instead
var fixture = new Fixture(body, shape) {Mass = mass};
CreateFixture(body, fixture);
}
public void DestroyFixture(PhysicsComponent body, string id)
{
var fixture = body.GetFixture(id);
if (fixture == null) return;
DestroyFixture(body, fixture);
}
public void DestroyFixture(Fixture fixture)
{
DestroyFixture(fixture.Body, fixture);
}
public void DestroyFixture(PhysicsComponent body, Fixture fixture)
{
// TODO: Assert world locked
DebugTools.Assert(fixture.Body == body);
DebugTools.Assert(body.FixtureCount > 0);
if (!body._fixtures.Remove(fixture))
return;
var edge = body.ContactEdges;
while (edge != null)
{
var contact = edge.Contact!;
edge = edge.Next;
var fixtureA = contact.FixtureA;
var fixtureB = contact.FixtureB;
if (fixture == fixtureA || fixture == fixtureB)
{
body.PhysicsMap?.ContactManager.Destroy(contact);
}
}
var broadphase = GetBroadphase(fixture.Body);
if (broadphase != null)
{
DestroyProxies(broadphase, fixture);
}
body.FixtureCount -= 1;
body.ResetMassData();
body.Dirty();
}
private void SynchronizeFixtures(PhysicsComponent body, Vector2 worldPos, float worldRot)
{
// Logger.DebugS("physics", $"Synchronizing fixtures for {body.Owner}");
@@ -655,7 +733,6 @@ namespace Robust.Shared.Physics
if (body.Owner.Transform.MapID == MapId.Nullspace) return;
var worldPos = body.Owner.Transform.WorldPosition;
var worldRot = body.Owner.Transform.WorldRotation;
// Outside of PVS (TODO Remove when PVS is better)
if (float.IsNaN(worldPos.X) || float.IsNaN(worldPos.Y))
@@ -679,7 +756,7 @@ namespace Robust.Shared.Physics
foreach (var fixture in body.Fixtures)
{
CreateProxies(fixture, worldPos, worldRot, useCache);
CreateProxies(fixture, worldPos, useCache);
}
// Ensure cache remains up to date if the broadphase is moving.
@@ -696,7 +773,7 @@ namespace Robust.Shared.Physics
/// <summary>
/// Create the proxies for this fixture on the body's broadphase.
/// </summary>
internal void CreateProxies(Fixture fixture, Vector2 worldPos, Angle worldRot, bool useCache)
private void CreateProxies(Fixture fixture, Vector2 worldPos, bool useCache)
{
// Ideally we would always just defer this until Update / FrameUpdate but that will have to wait for a future
// PR for my own sanity.
@@ -723,7 +800,7 @@ namespace Robust.Shared.Physics
Matrix3 broadphaseInvMatrix;
(Vector2 Position, float Rotation) broadphaseTransform;
var xform = EntityManager.GetComponent<TransformComponent>(broadphase.OwnerUid);
var xform = broadphase.Owner.Transform;
if (useCache)
{
@@ -740,6 +817,7 @@ namespace Robust.Shared.Physics
broadphaseTransform = (wp, (float) wr.Theta);
}
var worldRot = fixture.Body.Owner.Transform.WorldRotation;
var localPos = broadphaseInvMatrix.Transform(worldPos);
var transform = new Transform(localPos, worldRot - broadphaseTransform.Rotation);
@@ -763,7 +841,7 @@ namespace Robust.Shared.Physics
/// <summary>
/// Destroy the proxies for this fixture on the broadphase.
/// </summary>
internal void DestroyProxies(BroadphaseComponent broadphase, Fixture fixture)
private void DestroyProxies(BroadphaseComponent broadphase, Fixture fixture)
{
if (broadphase == null)
{
@@ -800,22 +878,12 @@ namespace Robust.Shared.Physics
physicsComponent.Awake = true;
}
public override void Shutdown()
{
base.Shutdown();
var configManager = IoCManager.Resolve<IConfigurationManager>();
configManager.UnsubValueChanged(CVars.BroadphaseExpand, SetBroadphaseExpand);
_mapManager.MapCreated -= OnMapCreated;
_mapManager.MapDestroyed -= OnMapDestroyed;
}
#region Broadphase management
private void OnMapCreated(object? sender, MapEventArgs e)
{
if (e.Map == MapId.Nullspace) return;
EntityManager.EnsureComponent<BroadphaseComponent>(_mapManager.GetMapEntityId(e.Map));
var mapEnt = _mapManager.GetMapEntity(e.Map);
mapEnt.EnsureComponent<BroadphaseComponent>();
_moveBuffer[e.Map] = new Dictionary<FixtureProxy, Box2>(64);
}
@@ -825,9 +893,19 @@ namespace Robust.Shared.Physics
_movedGrids.Remove(e.Map);
}
public override void Shutdown()
{
base.Shutdown();
var configManager = IoCManager.Resolve<IConfigurationManager>();
configManager.UnsubValueChanged(CVars.BroadphaseExpand, SetBroadphaseExpand);
_mapManager.MapCreated -= OnMapCreated;
_mapManager.MapDestroyed -= OnMapDestroyed;
}
private void HandleGridInit(GridInitializeEvent ev)
{
EntityManager.EnsureComponent<BroadphaseComponent>(ev.EntityUid);
var grid = EntityManager.GetEntity(ev.EntityUid);
grid.EnsureComponent<BroadphaseComponent>();
}
private void HandleBroadphaseInit(EntityUid uid, BroadphaseComponent component, ComponentInit args)
@@ -836,8 +914,6 @@ namespace Robust.Shared.Physics
component.Tree = new DynamicTreeBroadPhase(capacity);
}
#endregion
internal BroadphaseComponent? GetBroadphase(PhysicsComponent body)
{
return GetBroadphase(body.Owner);
@@ -908,6 +984,11 @@ namespace Robust.Shared.Physics
}
}
internal IEnumerable<BroadphaseComponent> GetBroadphases(MapId mapId, Vector2 worldPos)
{
return GetBroadphases(mapId, new Box2(worldPos, worldPos));
}
private sealed class InvalidBroadphaseException : Exception
{
public InvalidBroadphaseException() {}

View File

@@ -48,6 +48,7 @@ namespace Robust.Shared
IoCManager.Register<IManifoldManager, CollisionManager>();
IoCManager.Register<IIslandManager, IslandManager>();
IoCManager.Register<IVerticesSimplifier, RamerDouglasPeuckerSimplifier>();
IoCManager.Register<IShapeManager, ShapeManager>();
}
}
}

View File

@@ -113,16 +113,6 @@ namespace Robust.UnitTesting
compFactory.RegisterClass<PhysicsMapComponent>();
}
if (!compFactory.AllRegisteredTypes.Contains(typeof(BroadphaseComponent)))
{
compFactory.RegisterClass<BroadphaseComponent>();
}
if (!compFactory.AllRegisteredTypes.Contains(typeof(FixturesComponent)))
{
compFactory.RegisterClass<FixturesComponent>();
}
if(entMan.EventBus == null)
{
entMan.Startup();

View File

@@ -66,12 +66,9 @@ entities:
var broady = new BroadPhaseSystem();
var physics = new PhysicsSystem();
var gridFixtures = new GridFixtureSystem();
var fixtures = new FixtureSystem();
// MOCKS WHY
mock.Setup(m => m.GetEntitySystem<SharedBroadphaseSystem>()).Returns(broady);
mock.Setup(m => m.GetEntitySystem<SharedPhysicsSystem>()).Returns(physics);
mock.Setup(m => m.GetEntitySystem<GridFixtureSystem>()).Returns(gridFixtures);
mock.Setup(m => m.GetEntitySystem<FixtureSystem>()).Returns(fixtures);
IoCManager.RegisterInstance<IEntitySystemManager>(mock.Object, true);
//IoCManager.RegisterInstance<ICustomFormatManager>(mockFormat.Object, true);
@@ -106,11 +103,7 @@ entities:
var entMan = IoCManager.Resolve<IEntityManager>();
var mapId = map.CreateMap();
// Yay test bullshit
var mapUid = map.GetMapEntityId(mapId);
entMan.EnsureComponent<PhysicsMapComponent>(mapUid);
entMan.EnsureComponent<BroadphaseComponent>(mapUid);
map.GetMapEntity(mapId).EnsureComponent<PhysicsMapComponent>();
var mapLoad = IoCManager.Resolve<IMapLoader>();
var grid = mapLoad.LoadBlueprint(mapId, "/TestMap.yml");

View File

@@ -235,7 +235,6 @@ namespace Robust.UnitTesting.Server
compFactory.RegisterClass<BroadphaseComponent>();
compFactory.RegisterClass<ContainerManagerComponent>();
compFactory.RegisterClass<PhysicsMapComponent>();
compFactory.RegisterClass<FixturesComponent>();
_regDelegate?.Invoke(compFactory);
@@ -251,7 +250,6 @@ namespace Robust.UnitTesting.Server
entitySystemMan.LoadExtraSystemType<MapSystem>();
entitySystemMan.LoadExtraSystemType<DebugPhysicsSystem>();
entitySystemMan.LoadExtraSystemType<BroadPhaseSystem>();
entitySystemMan.LoadExtraSystemType<FixtureSystem>();
entitySystemMan.LoadExtraSystemType<GridFixtureSystem>();
entitySystemMan.LoadExtraSystemType<TransformSystem>();

View File

@@ -35,6 +35,10 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems
{
f.LoadString(Prototypes);
})
.RegisterDependencies(f =>
{
f.Register<IShapeManager, ShapeManager>();
})
.InitializeInstance();
var mapManager = sim.Resolve<IMapManager>();

View File

@@ -17,7 +17,6 @@ namespace Robust.UnitTesting.Shared.Physics
- type: Transform
- type: Physics
bodyType: Dynamic
- type: Fixtures
- type: CollisionWake
";

View File

@@ -18,7 +18,6 @@ namespace Robust.UnitTesting.Shared.Physics
components:
- type: Physics
bodyType: Dynamic
- type: Fixtures
";
[Test]

View File

@@ -30,8 +30,8 @@ namespace Robust.UnitTesting.Shared.Physics
{
await _server.WaitIdleAsync();
var entManager = _server.ResolveDependency<IEntityManager>();
var fixtureSystem = _server.ResolveDependency<IEntitySystemManager>()
.GetEntitySystem<FixtureSystem>();
var broadphaseSystem = _server.ResolveDependency<IEntitySystemManager>()
.GetEntitySystem<SharedBroadphaseSystem>();
await _server.WaitAssertion(() =>
{
@@ -39,7 +39,7 @@ namespace Robust.UnitTesting.Shared.Physics
var box = boxEnt.AddComponent<PhysicsComponent>();
var poly = new PolygonShape();
poly.SetAsBox(0.5f, 0.5f);
var fixture = fixtureSystem.CreateFixture(box, poly);
var fixture = broadphaseSystem.CreateFixture(box, poly);
fixture.Mass = 1f;
box.FixedRotation = false;
box.BodyType = BodyType.Dynamic;

View File

@@ -7,21 +7,21 @@ using Robust.Shared.Physics.Collision.Shapes;
namespace Robust.UnitTesting.Shared.Physics
{
[TestFixture]
[TestOf(typeof(FixtureSystem))]
public class FixtureShape_Test : RobustUnitTest
[TestOf(typeof(IShapeManager))]
public class ShapeManager_Test : RobustUnitTest
{
private FixtureSystem _shapeManager = default!;
private IShapeManager _shapeManager = default!;
[OneTimeSetUp]
public void Setup()
{
_shapeManager = new FixtureSystem();
_shapeManager = new ShapeManager();
}
[Test]
public void TestCirclePoint()
{
var circle = new PhysShapeCircle {Radius = 0.5f};
var circle = new PhysShapeCircle() {Radius = 0.5f};
var transform = new Transform(0f);
var posA = Vector2.One;
var posB = Vector2.Zero;

View File

@@ -49,11 +49,11 @@ namespace Robust.UnitTesting.Shared.Physics
var entityManager = server.ResolveDependency<IEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
var fixtureSystem = entitySystemManager.GetEntitySystem<FixtureSystem>();
var broadphaseSystem = entitySystemManager.GetEntitySystem<SharedBroadphaseSystem>();
MapId mapId;
const int columnCount = 1;
const int rowCount = 15;
var columnCount = 1;
var rowCount = 15;
PhysicsComponent[] bodies = new PhysicsComponent[columnCount * rowCount];
Vector2 firstPos = Vector2.Zero;
@@ -73,7 +73,7 @@ namespace Robust.UnitTesting.Shared.Physics
Hard = true
};
fixtureSystem.CreateFixture(ground, horizontalFixture);
broadphaseSystem.CreateFixture(ground, horizontalFixture);
var vertical = new EdgeShape(new Vector2(10, 0), new Vector2(10, 10));
var verticalFixture = new Fixture(ground, vertical)
@@ -83,7 +83,7 @@ namespace Robust.UnitTesting.Shared.Physics
Hard = true
};
fixtureSystem.CreateFixture(ground, verticalFixture);
broadphaseSystem.CreateFixture(ground, verticalFixture);
var xs = new[]
{
@@ -116,7 +116,7 @@ namespace Robust.UnitTesting.Shared.Physics
Hard = true,
};
fixtureSystem.CreateFixture(box, fixture);
broadphaseSystem.CreateFixture(box, fixture);
bodies[j * rowCount + i] = box;
}
@@ -164,7 +164,8 @@ namespace Robust.UnitTesting.Shared.Physics
var entityManager = server.ResolveDependency<IEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>();
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
var fixtureSystem = entitySystemManager.GetEntitySystem<FixtureSystem>();
var physicsSystem = entitySystemManager.GetEntitySystem<SharedPhysicsSystem>();
var broadphaseSystem = entitySystemManager.GetEntitySystem<SharedBroadphaseSystem>();
MapId mapId;
var columnCount = 1;
@@ -187,7 +188,7 @@ namespace Robust.UnitTesting.Shared.Physics
Hard = true
};
fixtureSystem.CreateFixture(ground, horizontalFixture);
broadphaseSystem.CreateFixture(ground, horizontalFixture);
var vertical = new EdgeShape(new Vector2(10, 0), new Vector2(10, 10));
var verticalFixture = new Fixture(ground, vertical)
@@ -197,7 +198,7 @@ namespace Robust.UnitTesting.Shared.Physics
Hard = true
};
fixtureSystem.CreateFixture(ground, verticalFixture);
broadphaseSystem.CreateFixture(ground, verticalFixture);
var xs = new[]
{
@@ -226,7 +227,7 @@ namespace Robust.UnitTesting.Shared.Physics
Hard = true,
};
fixtureSystem.CreateFixture(circle, fixture);
broadphaseSystem.CreateFixture(circle, fixture);
bodies[j * rowCount + i] = circle;
}