Run grid traversal on entity spawn (#4796)

* Run grid traversal on entity spawn

* Add test

* Fix tests
This commit is contained in:
Leon Friedrich
2024-01-02 01:25:13 -05:00
committed by GitHub
parent 97d03c6954
commit f4faa1ad3d
8 changed files with 138 additions and 23 deletions

View File

@@ -25,9 +25,15 @@ internal sealed class SharedGridTraversalSystem : EntitySystem
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TransformStartupEvent>(OnStartup);
_transform.OnGlobalMoveEvent += OnMove;
}
private void OnStartup(ref TransformStartupEvent ev)
{
CheckTraverse(ev.Entity.Owner, ev.Entity.Comp);
}
public override void Shutdown()
{
_transform.OnGlobalMoveEvent -= OnMove;
@@ -92,7 +98,7 @@ internal sealed class SharedGridTraversalSystem : EntitySystem
: Transform(xform.ParentUid).LocalMatrix.Transform(xform.LocalPosition);
// Change parent if necessary
if (_mapManager.TryFindGridAt(xform.MapID, mapPos, out var gridUid, out _))
if (_mapManager.TryFindGridAt(map, mapPos, out var gridUid, out _))
{
// Some minor duplication here with AttachParent but only happens when going on/off grid so not a big deal ATM.
if (gridUid != xform.GridUid)

View File

@@ -332,7 +332,7 @@ public abstract partial class SharedTransformSystem
var parentEv = new EntParentChangedMessage(uid, null, MapId.Nullspace, xform);
RaiseLocalEvent(uid, ref parentEv, true);
var ev = new TransformStartupEvent(xform);
var ev = new TransformStartupEvent((uid, xform));
RaiseLocalEvent(uid, ref ev, true);
DebugTools.Assert(!xform.NoLocalRotation || xform.LocalRotation == 0, $"NoRot entity has a non-zero local rotation. entity: {ToPrettyString(uid)}");
@@ -1334,22 +1334,15 @@ public abstract partial class SharedTransformSystem
if (!xform.ParentUid.IsValid())
return false;
EntityUid newParent;
var oldPos = GetWorldPosition(xform, XformQuery);
if (_mapManager.TryFindGridAt(xform.MapID, oldPos, XformQuery, out var gridUid, out _))
{
newParent = gridUid;
}
else if (_mapManager.GetMapEntityId(xform.MapID) is { Valid: true } mapEnt)
{
newParent = mapEnt;
}
else
{
if (xform.MapUid is not { } map)
return false;
}
coordinates = new(newParent, GetInvWorldMatrix(newParent, XformQuery).Transform(oldPos));
var newParent = map;
var oldPos = GetWorldPosition(xform);
if (_mapManager.TryFindGridAt(map, oldPos, out var gridUid, out _))
newParent = gridUid;
coordinates = new(newParent, GetInvWorldMatrix(newParent).Transform(oldPos));
return true;
}
#endregion

View File

@@ -256,14 +256,10 @@ namespace Robust.Shared.GameObjects
}
[ByRefEvent]
public readonly struct TransformStartupEvent
public readonly struct TransformStartupEvent(Entity<TransformComponent> entity)
{
public readonly TransformComponent Component;
public TransformStartupEvent(TransformComponent component)
{
Component = component;
}
public readonly Entity<TransformComponent> Entity = entity;
public TransformComponent Component => Entity.Comp;
}
/// <summary>

View File

@@ -114,6 +114,18 @@ namespace Robust.Shared.Map
/// <returns>Returns true when a grid was found under the location.</returns>
bool TryFindGridAt(MapId mapId, Vector2 worldPos, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid);
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>
/// <remarks>
/// This method will never return the map's default grid.
/// </remarks>
/// <param name="mapId">Map to search.</param>
/// <param name="worldPos">Location on the map to check for a grid.</param>
/// <param name="grid">Grid that was found, if any.</param>
/// <returns>Returns true when a grid was found under the location.</returns>
bool TryFindGridAt(EntityUid mapId, Vector2 worldPos, out EntityUid uid, [NotNullWhen(true)] out MapGridComponent? grid);
/// <summary>
/// Attempts to find the map grid under the map location.
/// </summary>

View File

@@ -97,6 +97,8 @@ entities:
entMan.EnsureComponent<PhysicsMapComponent>(mapUid);
entMan.EnsureComponent<BroadphaseComponent>(mapUid);
var traversal = entMan.System<SharedGridTraversalSystem>();
traversal.Enabled = false;
var mapLoad = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
if (!mapLoad.TryLoad(mapId, "/TestMap.yml", out var root)
|| root.FirstOrDefault() is not { Valid:true } geid)
@@ -107,6 +109,7 @@ entities:
var entity = entMan.GetComponent<TransformComponent>(geid)._children.Single();
var c = entMan.GetComponent<MapDeserializeTestComponent>(entity);
traversal.Enabled = true;
Assert.That(c.Bar, Is.EqualTo(2));
Assert.That(c.Foo, Is.EqualTo(3));

View File

@@ -157,6 +157,9 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems
var grid = mapMan.GetGrid(gridId);
grid.SetTile(grid.TileIndicesFor(coordinates), new Tile(1));
var traversal = entMan.System<SharedGridTraversalSystem>();
traversal.Enabled = false;
var subscriber = new Subscriber();
int calledCount = 0;
var ent1 = entMan.SpawnEntity(null, coordinates); // this raises MoveEvent, subscribe after
@@ -171,7 +174,9 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems
{
Assert.That(ev.Entity, Is.EqualTo(ent1));
calledCount++;
}
traversal.Enabled = true;
}
/// <summary>
@@ -510,6 +515,9 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems
var grid = mapMan.GetGrid(gridId);
grid.SetTile(grid.TileIndicesFor(coordinates), new Tile(1));
var traversal = entMan.System<SharedGridTraversalSystem>();
traversal.Enabled = false;
var subscriber = new Subscriber();
int calledCount = 0;
var ent1 = entMan.SpawnEntity(null, coordinates); // this raises MoveEvent, subscribe after
@@ -525,6 +533,7 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems
Assert.That(ev.Entity, Is.EqualTo(ent1));
calledCount++;
}
traversal.Enabled = true;
}
/// <summary>

View File

@@ -38,6 +38,8 @@ namespace Robust.UnitTesting.Shared.Physics
var system = entityManager.EntitySysManager;
var physicsSys = system.GetEntitySystem<SharedPhysicsSystem>();
var xformSystem = system.GetEntitySystem<SharedTransformSystem>();
var traversal = entityManager.System<SharedGridTraversalSystem>();
traversal.Enabled = false;
await server.WaitAssertion(() =>
{
@@ -93,6 +95,7 @@ namespace Robust.UnitTesting.Shared.Physics
Assert.That(velocities.Item1, Is.Approximately(linearVelocity, 1e-6));
Assert.That(velocities.Item2, Is.Approximately(angularVelocity, 1e-6));
});
traversal.Enabled = true;
}
// Check that if something has more than one parent, the velocities are properly added
@@ -107,6 +110,8 @@ namespace Robust.UnitTesting.Shared.Physics
var system = entityManager.EntitySysManager;
var physicsSys = system.GetEntitySystem<SharedPhysicsSystem>();
var xformSystem = system.GetEntitySystem<SharedTransformSystem>();
var traversal = entityManager.System<SharedGridTraversalSystem>();
traversal.Enabled = false;
await server.WaitAssertion(() =>
{
@@ -166,6 +171,7 @@ namespace Robust.UnitTesting.Shared.Physics
Assert.That(velocities.Item1, Is.Approximately(linearVelocity, 1e-6));
Assert.That(velocities.Item2, Is.Approximately(angularVelocity, 1e-6));
});
traversal.Enabled = true;
}
}
}

View File

@@ -0,0 +1,90 @@
using System.Numerics;
using System.Threading.Tasks;
using NUnit.Framework;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Robust.UnitTesting.Shared.TransformTests;
public sealed class GridTraversalTest : RobustIntegrationTest
{
[Test]
public async Task TestSpawnTraversal()
{
var server = StartServer();
await server.WaitIdleAsync();
var mapMan = server.ResolveDependency<IMapManager>();
var sEntMan = server.ResolveDependency<IEntityManager>();
var xforms = sEntMan.System<SharedTransformSystem>();
var mapSys = sEntMan.System<MapSystem>();
// Set up entities
MapId mapId = default!;
EntityUid map = default;
EntityUid grid = default;
Vector2 gridMapPos = default;
await server.WaitPost(() =>
{
mapId = mapMan.CreateMap();
map = mapMan.GetMapEntityId(mapId);
var gridComp = mapMan.CreateGridEntity(mapId);
grid = gridComp.Owner;
mapSys.SetTile(grid, gridComp, Vector2i.Zero, new Tile(1));
var gridCentre = new EntityCoordinates(grid, .5f, .5f);
gridMapPos = gridCentre.ToMap(sEntMan, xforms).Position;
});
for (int i = 0; i < 10; i++)
{
await server.WaitRunTicks(1);
}
await server.WaitPost(() =>
{
// Spawn an entity using map coordinates will get parented to the grid when spawning on the grid.
var entity = sEntMan.SpawnEntity(null, new MapCoordinates(gridMapPos, mapId));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).MapUid, Is.EqualTo(map));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).GridUid, Is.EqualTo(grid));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).ParentUid, Is.EqualTo(grid));
sEntMan.Deleted(entity);
// Spawning using map entity coords will still parent to the grid when spawning on the grid.
entity = sEntMan.SpawnEntity(null, new EntityCoordinates(map, gridMapPos));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).MapUid, Is.EqualTo(map));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).GridUid, Is.EqualTo(grid));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).ParentUid, Is.EqualTo(grid));
sEntMan.Deleted(entity);
// and using local grid coords also works.
entity = sEntMan.SpawnEntity(null, new EntityCoordinates(grid, 0.5f, 0.5f));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).MapUid, Is.EqualTo(map));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).GridUid, Is.EqualTo(grid));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).ParentUid, Is.EqualTo(grid));
sEntMan.Deleted(entity);
// Spawning an entity far away from the grid will leave it parented to the map.
entity = sEntMan.SpawnEntity(null, new MapCoordinates(new Vector2(100f, 100f), mapId));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).MapUid, Is.EqualTo(map));
Assert.Null(sEntMan.GetComponent<TransformComponent>(entity).GridUid);
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).ParentUid, Is.EqualTo(map));
sEntMan.Deleted(entity);
entity = sEntMan.SpawnEntity(null, new EntityCoordinates(map, new Vector2(100f, 100f)));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).MapUid, Is.EqualTo(map));
Assert.Null(sEntMan.GetComponent<TransformComponent>(entity).GridUid);
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).ParentUid, Is.EqualTo(map));
sEntMan.Deleted(entity);
entity = sEntMan.SpawnEntity(null, new EntityCoordinates(grid, 100f, 100f));
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).MapUid, Is.EqualTo(map));
Assert.Null(sEntMan.GetComponent<TransformComponent>(entity).GridUid);
Assert.That(sEntMan.GetComponent<TransformComponent>(entity).ParentUid, Is.EqualTo(map));
sEntMan.Deleted(entity);
});
}
}