diff --git a/Robust.Client/GameStates/ClientGameStateManager.cs b/Robust.Client/GameStates/ClientGameStateManager.cs index c79613724..0be731915 100644 --- a/Robust.Client/GameStates/ClientGameStateManager.cs +++ b/Robust.Client/GameStates/ClientGameStateManager.cs @@ -783,7 +783,7 @@ namespace Robust.Client.GameStates { foreach (var (uid, xform) in queuedBroadphaseUpdates) { - lookupSys.FindAndAddToEntityTree(uid, xform, xforms, metas, contQuery, physicsQuery, fixturesQuery, broadQuery); + lookupSys.FindAndAddToEntityTree(uid, true, xform); } } catch (Exception e) @@ -869,13 +869,13 @@ namespace Robust.Client.GameStates // This entity is going to get deleted, but maybe some if its children won't be, so lets detach them to // null. First we will detach the parent in order to reduce the number of broadphase/lookup updates. - xformSys.DetachParentToNull(ent, xform, xforms, metas); + xformSys.DetachParentToNull(ent, xform); // Then detach all children. var childEnumerator = xform.ChildEnumerator; while (childEnumerator.MoveNext(out var child)) { - xformSys.DetachParentToNull(child.Value, xforms.GetComponent(child.Value), xforms, metas, xform); + xformSys.DetachParentToNull(child.Value, xforms.GetComponent(child.Value), xform); if (deleteClientChildren && !deleteClientEntities // don't add duplicates @@ -917,13 +917,13 @@ namespace Robust.Client.GameStates continue; // Already deleted? or never sent to us? // First, a single recursive map change - xformSys.DetachParentToNull(id, xform, xforms, metas); + xformSys.DetachParentToNull(id, xform); // Then detach all children. var childEnumerator = xform.ChildEnumerator; while (childEnumerator.MoveNext(out var child)) { - xformSys.DetachParentToNull(child.Value, xforms.GetComponent(child.Value), xforms, metas, xform); + xformSys.DetachParentToNull(child.Value, xforms.GetComponent(child.Value), xform); } // Finally, delete the entity. @@ -1002,7 +1002,7 @@ namespace Robust.Client.GameStates var xform = xforms.GetComponent(ent); if (xform.ParentUid.IsValid()) { - lookupSys.RemoveFromEntityTree(ent, xform, xforms); + lookupSys.RemoveFromEntityTree(ent, xform); xform.Broadphase = BroadphaseData.Invalid; // In some cursed scenarios an entity inside of a container can leave PVS without the container itself leaving PVS. @@ -1017,7 +1017,7 @@ namespace Robust.Client.GameStates } meta._flags |= MetaDataFlags.Detached; - xformSys.DetachParentToNull(ent, xform, xforms, metas); + xformSys.DetachParentToNull(ent, xform); DebugTools.Assert((meta.Flags & MetaDataFlags.InContainer) == 0); if (container != null) diff --git a/Robust.Server/GameStates/PvsSystem.Dirty.cs b/Robust.Server/GameStates/PvsSystem.Dirty.cs index b14fc08df..f88ddc7aa 100644 --- a/Robust.Server/GameStates/PvsSystem.Dirty.cs +++ b/Robust.Server/GameStates/PvsSystem.Dirty.cs @@ -94,9 +94,7 @@ namespace Robust.Server.GameStates /// internal void MarkDirty(EntityUid uid) { - var query = GetEntityQuery(); - var xform = query.GetComponent(uid); - var coordinates = _transform.GetMoverCoordinates(xform, query); + var coordinates = _transform.GetMoverCoordinates(uid); _entityPvsCollection.MarkDirty(_entityPvsCollection.GetChunkIndex(coordinates)); } } diff --git a/Robust.Server/GameStates/PvsSystem.cs b/Robust.Server/GameStates/PvsSystem.cs index 470ee1598..90c6b3828 100644 --- a/Robust.Server/GameStates/PvsSystem.cs +++ b/Robust.Server/GameStates/PvsSystem.cs @@ -103,12 +103,17 @@ internal sealed partial class PvsSystem : EntitySystem private readonly List<(uint, IChunkIndexLocation)> _chunkList = new(64); internal readonly HashSet PendingAcks = new(); + private EntityQuery _eyeQuery; + private EntityQuery _xformQuery; + private ISawmill _sawmill = default!; public override void Initialize() { base.Initialize(); + _eyeQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); _sawmill = Logger.GetSawmill("PVS"); _entityPvsCollection = RegisterPVSCollection(); @@ -255,7 +260,7 @@ internal sealed partial class PvsSystem : EntitySystem { // GriddUid is only set after init. if (!ev.Component._gridInitialized) - _transform.InitializeGridUid(ev.Sender, ev.Component, GetEntityQuery(), GetEntityQuery()); + _transform.InitializeGridUid(ev.Sender, ev.Component); // since elements are cached grid-/map-relative, we dont need to update a given grids/maps children if (ev.Component.GridUid == ev.Sender) @@ -274,9 +279,8 @@ internal sealed partial class PvsSystem : EntitySystem DebugTools.Assert(!_mapManager.IsMap(ev.Sender)); - var xformQuery = GetEntityQuery(); - var coordinates = _transform.GetMoverCoordinates(ev.Component, xformQuery); - UpdateEntityRecursive(ev.Sender, ev.Component, coordinates, xformQuery, false, ev.ParentChanged); + var coordinates = _transform.GetMoverCoordinates(ev.Sender, ev.Component); + UpdateEntityRecursive(ev.Sender, ev.Component, coordinates, false, ev.ParentChanged); } private void OnTransformStartup(EntityUid uid, TransformComponent component, ref TransformStartupEvent args) @@ -292,16 +296,15 @@ internal sealed partial class PvsSystem : EntitySystem return; DebugTools.Assert(!_mapManager.IsMap(uid)); - var xformQuery = GetEntityQuery(); - var coordinates = _transform.GetMoverCoordinates(component, xformQuery); - UpdateEntityRecursive(uid, component, coordinates, xformQuery, false, false); + var coordinates = _transform.GetMoverCoordinates(uid, component); + UpdateEntityRecursive(uid, component, coordinates, false, false); } - private void UpdateEntityRecursive(EntityUid uid, TransformComponent xform, EntityCoordinates coordinates, EntityQuery xformQuery, bool mover, bool forceDirty) + private void UpdateEntityRecursive(EntityUid uid, TransformComponent xform, EntityCoordinates coordinates, bool mover, bool forceDirty) { if (mover && !xform.LocalPosition.Equals(Vector2.Zero)) { - coordinates = _transform.GetMoverCoordinates(xform, xformQuery); + coordinates = _transform.GetMoverCoordinates(uid, xform); } // since elements are cached grid-/map-relative, we don't need to update a given grids/maps children @@ -321,7 +324,7 @@ internal sealed partial class PvsSystem : EntitySystem // directly. while (children.MoveNext(out var child)) { - UpdateEntityRecursive(child.Value, xformQuery.GetComponent(child.Value), coordinates, xformQuery, true, forceDirty); + UpdateEntityRecursive(child.Value, _xformQuery.GetComponent(child.Value), coordinates, true, forceDirty); } } @@ -413,8 +416,6 @@ internal sealed partial class PvsSystem : EntitySystem public (List<(uint, IChunkIndexLocation)> , HashSet[], EntityUid[][] viewers) GetChunks(IPlayerSession[] sessions) { var playerChunks = new HashSet[sessions.Length]; - var eyeQuery = EntityManager.GetEntityQuery(); - var transformQuery = EntityManager.GetEntityQuery(); var viewerEntities = new EntityUid[sessions.Length][]; _chunkList.Clear(); @@ -444,12 +445,12 @@ internal sealed partial class PvsSystem : EntitySystem for (var j = 0; j < viewers.Length; j++) { var eyeEuid = viewers[j]; - var (viewPos, range, mapId) = CalcViewBounds(in eyeEuid, transformQuery); + var (viewPos, range, mapId) = CalcViewBounds(in eyeEuid); if (mapId == MapId.Nullspace) continue; uint visMask = EyeComponent.DefaultVisibilityMask; - if (eyeQuery.TryGetComponent(eyeEuid, out var eyeComp)) + if (_eyeQuery.TryGetComponent(eyeEuid, out var eyeComp)) visMask = eyeComp.VisibilityMask; // Get the nyoom dictionary for index lookups. @@ -485,7 +486,7 @@ internal sealed partial class PvsSystem : EntitySystem _gridIndices[visMask] = gridDict; } - var state = (i, transformQuery, viewPos, range, visMask, gridDict, playerChunks, _chunkList, _transform); + var state = (i, _xformQuery, viewPos, range, visMask, gridDict, playerChunks, _chunkList, _transform); _mapManager.FindGridsIntersecting(mapId, new Box2(viewPos - range, viewPos + range), ref state, static ( @@ -1205,10 +1206,10 @@ internal sealed partial class PvsSystem : EntitySystem } // Read Safe - private (Vector2 worldPos, float range, MapId mapId) CalcViewBounds(in EntityUid euid, EntityQuery transformQuery) + private (Vector2 worldPos, float range, MapId mapId) CalcViewBounds(in EntityUid euid) { - var xform = transformQuery.GetComponent(euid); - return (_transform.GetWorldPosition(xform, transformQuery), _viewSize / 2f, xform.MapID); + var xform = _xformQuery.GetComponent(euid); + return (_transform.GetWorldPosition(xform, _xformQuery), _viewSize / 2f, xform.MapID); } public sealed class TreePolicy : PooledObjectPolicy> where T : notnull diff --git a/Robust.Shared/Console/Commands/MapCommands.cs b/Robust.Shared/Console/Commands/MapCommands.cs index c8c9896ab..225808a4c 100644 --- a/Robust.Shared/Console/Commands/MapCommands.cs +++ b/Robust.Shared/Console/Commands/MapCommands.cs @@ -4,6 +4,7 @@ using System.Text; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Robust.Shared.Console.Commands; @@ -156,7 +157,6 @@ internal sealed class ListMapsCommand : LocalizedCommands internal sealed class ListGridsCommand : LocalizedCommands { [Dependency] private readonly IEntityManager _ent = default!; - [Dependency] private readonly IMapManager _map = default!; public override string Command => "lsgrid"; @@ -166,15 +166,18 @@ internal sealed class ListGridsCommand : LocalizedCommands public override void Execute(IConsoleShell shell, string argStr, string[] args) { var msg = new StringBuilder(); + var xformSystem = _ent.System(); var xformQuery = _ent.GetEntityQuery(); + var grids = _ent.AllComponentsList(); + grids.Sort((x, y) => x.Uid.CompareTo(y.Uid)); - foreach (var grid in _map.GetAllGrids().OrderBy(grid => grid.Owner)) + foreach (var (uid, grid) in grids) { - var xform = xformQuery.GetComponent(grid.Owner); - var worldPos = xform.WorldPosition; + var xform = xformQuery.GetComponent(uid); + var worldPos = xformSystem.GetWorldPosition(xform); msg.AppendFormat("{0}: map: {1}, ent: {2}, pos: {3:0.0},{4:0.0} \n", - grid.Owner, xform.MapID, grid.Owner, worldPos.X, worldPos.Y); + uid, xform.MapID, uid, worldPos.X, worldPos.Y); } shell.WriteLine(msg.ToString()); diff --git a/Robust.Shared/Containers/BaseContainer.cs b/Robust.Shared/Containers/BaseContainer.cs index 733ee4a48..599ef23df 100644 --- a/Robust.Shared/Containers/BaseContainer.cs +++ b/Robust.Shared/Containers/BaseContainer.cs @@ -115,7 +115,7 @@ namespace Robust.Shared.Containers // Remove the entity and any children from broadphases. // This is done before changing can collide to avoid unecceary updates. // TODO maybe combine with RecursivelyUpdatePhysics to avoid fetching components and iterating parents twice? - lookupSys.RemoveFromEntityTree(toinsert, transform, transformQuery); + lookupSys.RemoveFromEntityTree(toinsert, transform); DebugTools.Assert(transform.Broadphase == null || !transform.Broadphase.Value.IsValid()); // Avoid unnecessary broadphase updates while unanchoring, changing physics collision, and re-parenting. @@ -313,7 +313,7 @@ namespace Robust.Shared.Containers if (xform.ParentUid == oldParent // move event should already have handled it && xform.Broadphase == null) // broadphase explicitly invalid? { - entMan.EntitySysManager.GetEntitySystem().FindAndAddToEntityTree(toRemove, xform); + entMan.EntitySysManager.GetEntitySystem().FindAndAddToEntityTree(toRemove, xform: xform); } if (entMan.TryGetComponent(toRemove, out var jointComp)) diff --git a/Robust.Shared/Containers/SharedContainerSystem.Validation.cs b/Robust.Shared/Containers/SharedContainerSystem.Validation.cs index ca5c0e006..3ea0a6f23 100644 --- a/Robust.Shared/Containers/SharedContainerSystem.Validation.cs +++ b/Robust.Shared/Containers/SharedContainerSystem.Validation.cs @@ -45,7 +45,7 @@ public abstract partial class SharedContainerSystem : EntitySystem // CBF updating all maps. meta-data flags now get saved, eventually we should be able to just initialize // entities in containers without having to "re-insert" them. meta.Flags |= MetaDataFlags.InContainer; - _lookup.RemoveFromEntityTree(ent, xform, xformQuery); + _lookup.RemoveFromEntityTree(ent, xform); ((BaseContainer)cont).RecursivelyUpdatePhysics(ent, xform, physics, _physics, physicsQuery, xformQuery); // assert children have correct properties diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index ce4bdfa5c..d8a19f856 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -962,6 +962,34 @@ namespace Robust.Shared.GameObjects #region Join Functions + public (EntityUid Uid, T Component)[] AllComponents() where T : Component + { + var query = AllEntityQueryEnumerator(); + var comps = new (EntityUid Uid, T Component)[Count()]; + var i = 0; + + while (query.MoveNext(out var uid, out var comp)) + { + comps[i] = (uid, comp); + i++; + } + + return comps; + } + + public List<(EntityUid Uid, T Component)> AllComponentsList() where T : Component + { + var query = AllEntityQueryEnumerator(); + var comps = new List<(EntityUid Uid, T Component)>(Count()); + + while (query.MoveNext(out var uid, out var comp)) + { + comps.Add((uid, comp)); + } + + return comps; + } + public AllEntityQueryEnumerator AllEntityQueryEnumerator() where TComp1 : Component { diff --git a/Robust.Shared/GameObjects/EntityManager.cs b/Robust.Shared/GameObjects/EntityManager.cs index 8f9348f35..e2c3f09f5 100644 --- a/Robust.Shared/GameObjects/EntityManager.cs +++ b/Robust.Shared/GameObjects/EntityManager.cs @@ -557,7 +557,7 @@ namespace Robust.Shared.GameObjects { try { - xformSys.DetachParentToNull(uid, transform, xformQuery, metaQuery); + xformSys.DetachParentToNull(uid, transform); } catch (Exception e) { diff --git a/Robust.Shared/GameObjects/IEntityManager.Components.cs b/Robust.Shared/GameObjects/IEntityManager.Components.cs index 748f2714e..6ce23652b 100644 --- a/Robust.Shared/GameObjects/IEntityManager.Components.cs +++ b/Robust.Shared/GameObjects/IEntityManager.Components.cs @@ -391,6 +391,18 @@ namespace Robust.Shared.GameObjects /// True if the player should get the component state. bool CanGetComponentState(IEventBus eventBus, IComponent component, ICommonSession player); + /// + /// Returns all instances of a component in an array. + /// Use sparingly. + /// + (EntityUid Uid, T Component)[] AllComponents() where T : Component; + + /// + /// Returns all instances of a component in a List. + /// Use sparingly. + /// + List<(EntityUid Uid, T Component)> AllComponentsList() where T : Component; + AllEntityQueryEnumerator AllEntityQueryEnumerator() where TComp1 : Component; diff --git a/Robust.Shared/GameObjects/Systems/EntityLookupSystem.cs b/Robust.Shared/GameObjects/Systems/EntityLookupSystem.cs index 737097cb7..a5c0d05c5 100644 --- a/Robust.Shared/GameObjects/Systems/EntityLookupSystem.cs +++ b/Robust.Shared/GameObjects/Systems/EntityLookupSystem.cs @@ -70,6 +70,14 @@ namespace Robust.Shared.GameObjects [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + private EntityQuery _broadQuery; + private EntityQuery _containerQuery; + private EntityQuery _fixturesQuery; + private EntityQuery _metaQuery; + private EntityQuery _physicsQuery; + private EntityQuery _mapQuery; + private EntityQuery _xformQuery; + /// /// Returns all non-grid entities. Consider using your own flags if you wish for a faster query. /// @@ -79,6 +87,14 @@ namespace Robust.Shared.GameObjects { base.Initialize(); + _broadQuery = GetEntityQuery(); + _containerQuery = GetEntityQuery(); + _fixturesQuery = GetEntityQuery(); + _metaQuery = GetEntityQuery(); + _physicsQuery = GetEntityQuery(); + _mapQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + SubscribeLocalEvent(OnBroadphaseTerminating); SubscribeLocalEvent(OnBroadphaseAdd); SubscribeLocalEvent(OnGridAdd); @@ -107,28 +123,22 @@ namespace Robust.Shared.GameObjects private void OnBroadphaseTerminating(EntityUid uid, BroadphaseComponent component, ref EntityTerminatingEvent args) { - var xformQuery = GetEntityQuery(); - var fixtureQuery = GetEntityQuery(); - var physicsMapQuery = GetEntityQuery(); - var xform = xformQuery.GetComponent(uid); + var xform = _xformQuery.GetComponent(uid); var map = xform.MapUid; - physicsMapQuery.TryGetComponent(map, out var physMap); - RemoveChildrenFromTerminatingBroadphase(xform, component, physMap, xformQuery, fixtureQuery, physicsMapQuery); + _mapQuery.TryGetComponent(map, out var physMap); + RemoveChildrenFromTerminatingBroadphase(xform, component, physMap); RemComp(uid, component); } private void RemoveChildrenFromTerminatingBroadphase(TransformComponent xform, BroadphaseComponent component, - PhysicsMapComponent? map, - EntityQuery xformQuery, - EntityQuery fixtureQuery, - EntityQuery physicsMapQuery) + PhysicsMapComponent? map) { var childEnum = xform.ChildEnumerator; while (childEnum.MoveNext(out var child)) { - if (!xformQuery.TryGetComponent(child.Value, out var childXform)) + if (!_xformQuery.TryGetComponent(child.Value, out var childXform)) continue; if (childXform.GridUid == child) @@ -140,10 +150,10 @@ namespace Robust.Shared.GameObjects DebugTools.Assert(childXform.Broadphase.Value.Uid == component.Owner); DebugTools.Assert(!_mapManager.IsGrid(child.Value)); - if (childXform.Broadphase.Value.CanCollide && fixtureQuery.TryGetComponent(child.Value, out var fixtures)) + if (childXform.Broadphase.Value.CanCollide && _fixturesQuery.TryGetComponent(child.Value, out var fixtures)) { if (map == null) - physicsMapQuery.TryGetComponent(childXform.Broadphase.Value.PhysicsMap, out map); + _mapQuery.TryGetComponent(childXform.Broadphase.Value.PhysicsMap, out map); DebugTools.Assert(map == null || childXform.Broadphase.Value.PhysicsMap == map.Owner); var tree = childXform.Broadphase.Value.Static ? component.StaticTree : component.DynamicTree; @@ -154,7 +164,7 @@ namespace Robust.Shared.GameObjects } childXform.Broadphase = null; - RemoveChildrenFromTerminatingBroadphase(childXform, component, map, xformQuery, fixtureQuery, physicsMapQuery); + RemoveChildrenFromTerminatingBroadphase(childXform, component, map); } } @@ -184,9 +194,7 @@ namespace Robust.Shared.GameObjects private Box2 GetTreeAABB(EntityUid entity, EntityUid tree) { - var xformQuery = GetEntityQuery(); - - if (!xformQuery.TryGetComponent(entity, out var xform)) + if (!_xformQuery.TryGetComponent(entity, out var xform)) { Log.Error($"Entity tree contains a deleted entity? Tree: {ToPrettyString(tree)}, entity: {entity}"); return default; @@ -195,13 +203,13 @@ namespace Robust.Shared.GameObjects if (xform.ParentUid == tree) return GetAABBNoContainer(entity, xform.LocalPosition, xform.LocalRotation); - if (!xformQuery.TryGetComponent(tree, out var treeXform)) + if (!_xformQuery.TryGetComponent(tree, out var treeXform)) { Log.Error($"Entity tree has no transform? Tree Uid: {tree}"); return default; } - return _transform.GetInvWorldMatrix(treeXform, xformQuery).TransformBox(GetWorldAABB(entity, xform)); + return _transform.GetInvWorldMatrix(treeXform).TransformBox(GetWorldAABB(entity, xform)); } internal void CreateProxies(EntityUid uid, TransformComponent xform, Fixture fixture, PhysicsComponent body) @@ -212,8 +220,7 @@ namespace Robust.Shared.GameObjects if (!TryComp(xform.MapUid, out PhysicsMapComponent? physMap)) throw new InvalidOperationException(); - var xformQuery = GetEntityQuery(); - var (worldPos, worldRot) = _transform.GetWorldPositionRotation(xform, xformQuery); + var (worldPos, worldRot) = _transform.GetWorldPositionRotation(xform); var mapTransform = new Transform(worldPos, worldRot); var (_, broadWorldRot, _, broadInvMatrix) = _transform.GetWorldPositionRotationMatrixWithInv(broadphase.Owner); @@ -530,10 +537,6 @@ namespace Robust.Shared.GameObjects private void UpdateParent(EntityUid uid, TransformComponent xform, EntityUid oldParent) { - var broadQuery = GetEntityQuery(); - var xformQuery = GetEntityQuery(); - var fixturesQuery = GetEntityQuery(); - BroadphaseComponent? oldBroadphase = null; PhysicsMapComponent? oldPhysMap = null; if (xform.Broadphase != null) @@ -543,13 +546,13 @@ namespace Robust.Shared.GameObjects TryComp(xform.Broadphase.Value.PhysicsMap, out oldPhysMap); - if (!broadQuery.TryGetComponent(xform.Broadphase.Value.Uid, out oldBroadphase)) + if (!_broadQuery.TryGetComponent(xform.Broadphase.Value.Uid, out oldBroadphase)) { DebugTools.Assert("Encountered deleted broadphase."); // broadphase was probably deleted. - if (fixturesQuery.TryGetComponent(uid, out var fixtures)) + if (_fixturesQuery.TryGetComponent(uid, out var fixtures)) { foreach (var fixture in fixtures.Fixtures.Values) { @@ -562,7 +565,7 @@ namespace Robust.Shared.GameObjects } } - if (oldBroadphase != null && xformQuery.GetComponent(oldParent).MapID == MapId.Nullspace) + if (oldBroadphase != null && _xformQuery.GetComponent(oldParent).MapID == MapId.Nullspace) { oldBroadphase = null; // Note that the parentXform.MapID != MapId.Nullspace is required because currently grids are not allowed to @@ -574,21 +577,17 @@ namespace Robust.Shared.GameObjects // generally save a component lookup. } - TryFindBroadphase(xform, broadQuery, xformQuery, out var newBroadphase); + TryFindBroadphase(xform, out var newBroadphase); - var physicsQuery = GetEntityQuery(); if (oldBroadphase != null && oldBroadphase != newBroadphase) { - RemoveFromEntityTree(oldBroadphase.Owner, oldBroadphase, ref oldPhysMap, uid, xform, xformQuery, fixturesQuery); + RemoveFromEntityTree(oldBroadphase.Owner, oldBroadphase, ref oldPhysMap, uid, xform); } if (newBroadphase == null) return; - var metaQuery = GetEntityQuery(); - var contQuery = GetEntityQuery(); - - var newBroadphaseXform = xformQuery.GetComponent(newBroadphase.Owner); + var newBroadphaseXform = _xformQuery.GetComponent(newBroadphase.Owner); if (!TryComp(newBroadphaseXform.MapUid, out PhysicsMapComponent? physMap)) { throw new InvalidOperationException( @@ -601,36 +600,16 @@ namespace Robust.Shared.GameObjects newBroadphaseXform, physMap, uid, - xform, - xformQuery, - metaQuery, - contQuery, - physicsQuery, - fixturesQuery); + xform); } - public void FindAndAddToEntityTree(EntityUid uid, TransformComponent? xform = null) + public void FindAndAddToEntityTree(EntityUid uid, bool recursive = false, TransformComponent? xform = null) { - var xformQuery = GetEntityQuery(); - if (!xformQuery.Resolve(uid, ref xform)) + if (!_xformQuery.Resolve(uid, ref xform)) return; - var broadQuery = GetEntityQuery(); - if (TryFindBroadphase(xform, broadQuery, xformQuery, out var broadphase)) - AddOrUpdateEntityTree(broadphase, uid, xform, xformQuery); - } - - public void FindAndAddToEntityTree(EntityUid uid, - TransformComponent xform, - EntityQuery xformQuery, - EntityQuery metaQuery, - EntityQuery contQuery, - EntityQuery physicsQuery, - EntityQuery fixturesQuery, - EntityQuery broadQuery) - { - if (TryFindBroadphase(xform, broadQuery, xformQuery, out var broadphase)) - AddOrUpdateEntityTree(broadphase.Owner, broadphase, uid, xform, xformQuery, metaQuery, contQuery, physicsQuery, fixturesQuery, true); + if (TryFindBroadphase(xform, out var broadphase)) + AddOrUpdateEntityTree(broadphase.Owner, broadphase, uid, xform, recursive); } /// @@ -638,43 +617,22 @@ namespace Robust.Shared.GameObjects /// public void UpdateEntityTree(EntityUid uid, TransformComponent? xform = null) { - var xformQuery = GetEntityQuery(); - if (!xformQuery.Resolve(uid, ref xform)) + if (!_xformQuery.Resolve(uid, ref xform)) return; if (!TryGetCurrentBroadphase(xform, out var broadphase)) return; - AddOrUpdateEntityTree(broadphase, uid, xform, xformQuery); - } - - private void AddOrUpdateEntityTree( - BroadphaseComponent broadphase, - EntityUid uid, - TransformComponent xform, - EntityQuery xformQuery, - bool recursive = true) - { - var metaQuery = GetEntityQuery(); - var contQuery = GetEntityQuery(); - var physicsQuery = GetEntityQuery(); - var fixturesQuery = GetEntityQuery(); - - AddOrUpdateEntityTree(broadphase.Owner, broadphase, uid, xform, xformQuery, metaQuery, contQuery, physicsQuery, fixturesQuery, recursive); + AddOrUpdateEntityTree(broadphase.Owner, broadphase, uid, xform); } private void AddOrUpdateEntityTree(EntityUid broadUid, BroadphaseComponent broadphase, EntityUid uid, TransformComponent xform, - EntityQuery xformQuery, - EntityQuery metaQuery, - EntityQuery contQuery, - EntityQuery physicsQuery, - EntityQuery fixturesQuery, - bool recursive) + bool recursive = false) { - var broadphaseXform = xformQuery.GetComponent(broadphase.Owner); + var broadphaseXform = _xformQuery.GetComponent(broadphase.Owner); if (!TryComp(broadphaseXform.MapUid, out PhysicsMapComponent? physMap)) { throw new InvalidOperationException( @@ -688,11 +646,6 @@ namespace Robust.Shared.GameObjects physMap, uid, xform, - xformQuery, - metaQuery, - contQuery, - physicsQuery, - fixturesQuery, recursive); } @@ -703,11 +656,6 @@ namespace Robust.Shared.GameObjects PhysicsMapComponent physicsMap, EntityUid uid, TransformComponent xform, - EntityQuery xformQuery, - EntityQuery metaQuery, - EntityQuery contQuery, - EntityQuery physicsQuery, - EntityQuery fixturesQuery, bool recursive = true) { if (xform.Broadphase != null && !xform.Broadphase.Value.IsValid()) @@ -717,20 +665,20 @@ namespace Robust.Shared.GameObjects return; } - if (!physicsQuery.TryGetComponent(uid, out var body) || !body.CanCollide) + if (!_physicsQuery.TryGetComponent(uid, out var body) || !body.CanCollide) { // TOOD optimize this. This function iterates UP through parents, while we are currently iterating down. - var (coordinates, rotation) = _transform.GetMoverCoordinateRotation(uid, xform, xformQuery); + var (coordinates, rotation) = _transform.GetMoverCoordinateRotation(uid, xform); // TODO BROADPHASE PARENTING this just assumes local = world var relativeRotation = rotation - broadphaseXform.LocalRotation; - var aabb = GetAABBNoContainer(uid, coordinates.Position, relativeRotation, fixturesQuery); + var aabb = GetAABBNoContainer(uid, coordinates.Position, relativeRotation); AddOrUpdateSundriesTree(broadUid, broadphase, uid, xform, body?.BodyType == BodyType.Static, aabb); } else { - AddOrUpdatePhysicsTree(uid, broadUid, broadphase, broadphaseXform, physicsMap, xform, body, fixturesQuery.GetComponent(uid), xformQuery); + AddOrUpdatePhysicsTree(uid, broadUid, broadphase, broadphaseXform, physicsMap, xform, body, _fixturesQuery.GetComponent(uid), _xformQuery); } var childEnumerator = xform.ChildEnumerator; @@ -739,37 +687,34 @@ namespace Robust.Shared.GameObjects // TODO can this be removed? // AFAIK the separate container check is redundant now that we check for an invalid broadphase at the beginning of this function. - if (!contQuery.HasComponent(xform.Owner)) + if (!_containerQuery.HasComponent(uid)) { while (childEnumerator.MoveNext(out var child)) { - var childXform = xformQuery.GetComponent(child.Value); - AddOrUpdateEntityTree(broadUid, broadphase, broadphaseXform, physicsMap, child.Value, childXform, xformQuery, metaQuery, contQuery, physicsQuery, fixturesQuery); + var childXform = _xformQuery.GetComponent(child.Value); + AddOrUpdateEntityTree(broadUid, broadphase, broadphaseXform, physicsMap, child.Value, childXform); } return; } while (childEnumerator.MoveNext(out var child)) { - if ((metaQuery.GetComponent(child.Value).Flags & MetaDataFlags.InContainer) != 0x0) + if ((_metaQuery.GetComponent(child.Value).Flags & MetaDataFlags.InContainer) != 0x0) continue; - var childXform = xformQuery.GetComponent(child.Value); - AddOrUpdateEntityTree(broadUid, broadphase, broadphaseXform, physicsMap, child.Value, childXform, xformQuery, metaQuery, contQuery, physicsQuery, fixturesQuery); + var childXform = _xformQuery.GetComponent(child.Value); + AddOrUpdateEntityTree(broadUid, broadphase, broadphaseXform, physicsMap, child.Value, childXform); } } /// /// Recursively iterates through this entity's children and removes them from the BroadphaseComponent. /// - public void RemoveFromEntityTree(EntityUid uid, TransformComponent xform, EntityQuery xformQuery) + public void RemoveFromEntityTree(EntityUid uid, TransformComponent xform) { if (!TryGetCurrentBroadphase(xform, out var broadphase)) return; - var physicsQuery = GetEntityQuery(); - var fixturesQuery = GetEntityQuery(); - PhysicsMapComponent? physMap = null; if (xform.Broadphase!.Value.PhysicsMap is { Valid: true } map && !TryComp(map, out physMap)) { @@ -777,7 +722,7 @@ namespace Robust.Shared.GameObjects $"Broadphase's map is missing a physics map comp. Broadphase: {ToPrettyString(broadphase.Owner)}"); } - RemoveFromEntityTree(broadphase.Owner, broadphase, ref physMap, uid, xform, xformQuery, fixturesQuery); + RemoveFromEntityTree(broadphase.Owner, broadphase, ref physMap, uid, xform); } /// @@ -789,8 +734,6 @@ namespace Robust.Shared.GameObjects ref PhysicsMapComponent? physicsMap, EntityUid uid, TransformComponent xform, - EntityQuery xformQuery, - EntityQuery fixturesQuery, bool recursive = true) { if (xform.Broadphase is not { Valid: true } old) @@ -818,7 +761,7 @@ namespace Robust.Shared.GameObjects if (old.CanCollide) { DebugTools.Assert(old.PhysicsMap == (physicsMap?.Owner ?? default)); - RemoveBroadTree(broadphase, fixturesQuery.GetComponent(uid), old.Static, physicsMap); + RemoveBroadTree(broadphase, _fixturesQuery.GetComponent(uid), old.Static, physicsMap); } else if (old.Static) broadphase.StaticSundriesTree.Remove(uid); @@ -837,9 +780,7 @@ namespace Robust.Shared.GameObjects broadphase, ref physicsMap, child.Value, - xformQuery.GetComponent(child.Value), - xformQuery, - fixturesQuery); + _xformQuery.GetComponent(child.Value)); } } @@ -884,18 +825,14 @@ namespace Robust.Shared.GameObjects public bool TryFindBroadphase(EntityUid uid, [NotNullWhen(true)] out BroadphaseComponent? broadphase) { - var broadQuery = GetEntityQuery(); - var xformQuery = GetEntityQuery(); - return TryFindBroadphase(xformQuery.GetComponent(uid), broadQuery, xformQuery, out broadphase); + return TryFindBroadphase(_xformQuery.GetComponent(uid), out broadphase); } public bool TryFindBroadphase( TransformComponent xform, - EntityQuery broadQuery, - EntityQuery xformQuery, [NotNullWhen(true)] out BroadphaseComponent? broadphase) { - if (xform.MapID == MapId.Nullspace || _container.IsEntityOrParentInContainer(xform.Owner, null, xform, null, xformQuery)) + if (xform.MapID == MapId.Nullspace || _container.IsEntityOrParentInContainer(xform.Owner, null, xform, null, _xformQuery)) { broadphase = null; return false; @@ -906,10 +843,10 @@ namespace Robust.Shared.GameObjects // TODO provide variant that also returns world rotation (and maybe position). Avoids having to iterate though parents twice. while (parent.IsValid()) { - if (broadQuery.TryGetComponent(parent, out broadphase)) + if (_broadQuery.TryGetComponent(parent, out broadphase)) return true; - parent = xformQuery.GetComponent(parent).ParentUid; + parent = _xformQuery.GetComponent(parent).ParentUid; } broadphase = null; @@ -938,15 +875,7 @@ namespace Robust.Shared.GameObjects /// public Box2 GetAABBNoContainer(EntityUid uid, Vector2 position, Angle angle) { - return GetAABBNoContainer(uid, position, angle, GetEntityQuery()); - } - - /// - /// Get the AABB of an entity with the supplied position and angle without considering containers. - /// - public Box2 GetAABBNoContainer(EntityUid uid, Vector2 position, Angle angle, EntityQuery fixturesQuery) - { - if (fixturesQuery.TryGetComponent(uid, out var fixtures)) + if (_fixturesQuery.TryGetComponent(uid, out var fixtures)) { var transform = new Transform(position, angle); diff --git a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs index c99289277..3c0c0e235 100644 --- a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs +++ b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs @@ -255,7 +255,7 @@ public abstract partial class SharedTransformSystem parentXform._children.Add(uid); } - InitializeGridUid(uid, component, xformQuery, GetEntityQuery()); + InitializeGridUid(uid, component); component.MatricesDirty = true; DebugTools.Assert(component._gridUid == uid || !HasComp(uid)); @@ -289,9 +289,7 @@ public abstract partial class SharedTransformSystem internal void InitializeGridUid( EntityUid uid, - TransformComponent xform, - EntityQuery xformQuery, - EntityQuery gridQuery) + TransformComponent xform) { // Dont set pre-init, as the map grid component might not have been added yet. if (xform._gridInitialized || xform.LifeStage < ComponentLifeStage.Initializing) @@ -299,7 +297,7 @@ public abstract partial class SharedTransformSystem xform._gridInitialized = true; DebugTools.Assert(xform.GridUid == null); - if (gridQuery.HasComponent(uid)) + if (_gridQuery.HasComponent(uid)) { xform._gridUid = uid; return; @@ -308,8 +306,8 @@ public abstract partial class SharedTransformSystem if (!xform._parent.IsValid()) return; - var parentXform = xformQuery.GetComponent(xform._parent); - InitializeGridUid(xform._parent, parentXform, xformQuery, gridQuery); + var parentXform = _xformQuery.GetComponent(xform._parent); + InitializeGridUid(xform._parent, parentXform); xform._gridUid = parentXform._gridUid; } @@ -540,11 +538,11 @@ public abstract partial class SharedTransformSystem xform.ChangeMapId(newParent.MapID, xformQuery); if (!xform._gridInitialized) - InitializeGridUid(uid, xform, xformQuery, GetEntityQuery()); + InitializeGridUid(uid, xform); else { if (!newParent._gridInitialized) - InitializeGridUid(value.EntityId, newParent, xformQuery, GetEntityQuery()); + InitializeGridUid(value.EntityId, newParent); SetGridId(uid, xform, newParent.GridUid); } } @@ -552,7 +550,7 @@ public abstract partial class SharedTransformSystem { xform.ChangeMapId(MapId.Nullspace, xformQuery); if (!xform._gridInitialized) - InitializeGridUid(uid, xform, xformQuery, GetEntityQuery()); + InitializeGridUid(uid, xform); else SetGridId(uid, xform, null, xformQuery); } @@ -654,7 +652,7 @@ public abstract partial class SharedTransformSystem if (!parent.IsValid()) { - DetachParentToNull(uid, xform, xformQuery, GetEntityQuery()); + DetachParentToNull(uid, xform); return; } @@ -804,33 +802,19 @@ public abstract partial class SharedTransformSystem [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector2 GetWorldPosition(EntityUid uid) { - var query = GetEntityQuery(); - return GetWorldPosition(query.GetComponent(uid), query); + return GetWorldPosition(_xformQuery.GetComponent(uid)); } // Temporary until it's moved here [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector2 GetWorldPosition(TransformComponent component) - { - return GetWorldPosition(component, GetEntityQuery()); - } - - [Pure] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 GetWorldPosition(EntityUid uid, EntityQuery xformQuery) - { - return GetWorldPosition(xformQuery.GetComponent(uid), xformQuery); - } - - [Pure] - public Vector2 GetWorldPosition(TransformComponent component, EntityQuery xformQuery) { Vector2 pos = component._localPosition; while (component.ParentUid != component.MapUid && component.ParentUid.IsValid()) { - component = xformQuery.GetComponent(component.ParentUid); + component = _xformQuery.GetComponent(component.ParentUid); pos = component._localRotation.RotateVec(pos) + component._localPosition; } @@ -838,14 +822,27 @@ public abstract partial class SharedTransformSystem } [Pure] - public (Vector2 WorldPosition, Angle WorldRotation) GetWorldPositionRotation(TransformComponent component, EntityQuery xformQuery) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector2 GetWorldPosition(EntityUid uid, EntityQuery xformQuery) + { + return GetWorldPosition(xformQuery.GetComponent(uid)); + } + + [Pure] + public Vector2 GetWorldPosition(TransformComponent component, EntityQuery xformQuery) + { + return GetWorldPosition(component); + } + + [Pure] + public (Vector2 WorldPosition, Angle WorldRotation) GetWorldPositionRotation(TransformComponent component) { Vector2 pos = component._localPosition; Angle angle = component._localRotation; while (component.ParentUid != component.MapUid && component.ParentUid.IsValid()) { - component = xformQuery.GetComponent(component.ParentUid); + component = _xformQuery.GetComponent(component.ParentUid); pos = component._localRotation.RotateVec(pos) + component._localPosition; angle += component._localRotation; } @@ -853,6 +850,12 @@ public abstract partial class SharedTransformSystem return (pos, angle); } + [Pure] + public (Vector2 WorldPosition, Angle WorldRotation) GetWorldPositionRotation(TransformComponent component, EntityQuery xformQuery) + { + return GetWorldPositionRotation(component); + } + /// /// Returns the position and rotation relative to some entity higher up in the component's transform hierarchy. /// @@ -1297,46 +1300,51 @@ public abstract partial class SharedTransformSystem #endregion #region State Handling + public void DetachParentToNull(EntityUid uid, TransformComponent xform) + { + _xformQuery.TryGetComponent(xform.ParentUid, out var oldXform); + DetachParentToNull(uid, xform, oldXform); + } + + public void DetachParentToNull(EntityUid uid, TransformComponent xform, TransformComponent? oldXform) { if (xform._parent.IsValid()) - DetachParentToNull(uid, xform, GetEntityQuery(), GetEntityQuery()); + { + DebugTools.Assert(uid == xform.Owner); + var oldParent = xform._parent; + if (!oldParent.IsValid()) + { + DebugTools.Assert(!xform.Anchored); + DebugTools.Assert((MetaData(uid).Flags & MetaDataFlags.InContainer) == 0x0); + return; + } + + // Before making any changes to physics or transforms, remove from the current broadphase + _lookup.RemoveFromEntityTree(uid, xform); + + // Stop any active lerps + xform.NextPosition = null; + xform.NextRotation = null; + xform.LerpParent = EntityUid.Invalid; + + if (xform.Anchored && _metaQuery.TryGetComponent(xform.GridUid, out var meta) && meta.EntityLifeStage <= EntityLifeStage.MapInitialized) + { + var grid = Comp(xform.GridUid.Value); + var tileIndices = grid.TileIndicesFor(xform.Coordinates); + grid.RemoveFromSnapGridCell(tileIndices, uid); + xform._anchored = false; + var anchorStateChangedEvent = new AnchorStateChangedEvent(xform, true); + RaiseLocalEvent(uid, ref anchorStateChangedEvent, true); + } + + SetCoordinates(uid, xform, default, Angle.Zero, oldParent: oldXform); + DebugTools.Assert((MetaData(uid).Flags & MetaDataFlags.InContainer) == 0x0); + } else DebugTools.Assert(!xform.Anchored); } - public void DetachParentToNull(EntityUid uid, TransformComponent xform, EntityQuery xformQuery, EntityQuery metaQuery, TransformComponent? oldXform = null) - { - DebugTools.Assert(uid == xform.Owner); - var oldParent = xform._parent; - if (!oldParent.IsValid()) - { - DebugTools.Assert(!xform.Anchored); - DebugTools.Assert((MetaData(uid).Flags & MetaDataFlags.InContainer) == 0x0); - return; - } - - // Before making any changes to physics or transforms, remove from the current broadphase - _lookup.RemoveFromEntityTree(uid, xform, xformQuery); - - // Stop any active lerps - xform.NextPosition = null; - xform.NextRotation = null; - xform.LerpParent = EntityUid.Invalid; - - if (xform.Anchored && metaQuery.TryGetComponent(xform.GridUid, out var meta) && meta.EntityLifeStage <= EntityLifeStage.MapInitialized) - { - var grid = Comp(xform.GridUid.Value); - var tileIndices = grid.TileIndicesFor(xform.Coordinates); - grid.RemoveFromSnapGridCell(tileIndices, uid); - xform._anchored = false; - var anchorStateChangedEvent = new AnchorStateChangedEvent(xform, true); - RaiseLocalEvent(uid, ref anchorStateChangedEvent, true); - } - - SetCoordinates(uid, xform, default, Angle.Zero, oldParent: oldXform); - DebugTools.Assert((MetaData(uid).Flags & MetaDataFlags.InContainer) == 0x0); - } #endregion private void OnGridAdd(EntityUid uid, TransformComponent component, GridAddEvent args) diff --git a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.cs b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.cs index d1718b761..b3d99b82f 100644 --- a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.cs +++ b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.cs @@ -1,6 +1,5 @@ using Robust.Shared.GameStates; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Physics; @@ -21,6 +20,8 @@ namespace Robust.Shared.GameObjects [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + private EntityQuery _gridQuery; + private EntityQuery _metaQuery; private EntityQuery _xformQuery; private readonly Queue _gridMoves = new(); @@ -32,7 +33,10 @@ namespace Robust.Shared.GameObjects UpdatesOutsidePrediction = true; + _gridQuery = GetEntityQuery(); + _metaQuery = GetEntityQuery(); _xformQuery = GetEntityQuery(); + SubscribeLocalEvent(MapManagerOnTileChanged); SubscribeLocalEvent(OnCompInit); SubscribeLocalEvent(OnCompStartup); @@ -77,20 +81,17 @@ namespace Robust.Shared.GameObjects if (!TryComp(gridId, out BroadphaseComponent? lookup) || !_mapManager.TryGetGrid(gridId, out var grid)) return; - var xformQuery = GetEntityQuery(); - var metaQuery = GetEntityQuery(); - - if (!xformQuery.TryGetComponent(gridId, out var gridXform)) + if (!_xformQuery.TryGetComponent(gridId, out var gridXform)) return; - if (!xformQuery.TryGetComponent(gridXform.MapUid, out var mapTransform)) + if (!_xformQuery.TryGetComponent(gridXform.MapUid, out var mapTransform)) return; var aabb = _lookup.GetLocalBounds(tileIndices, grid.TileSize); foreach (var entity in _lookup.GetEntitiesIntersecting(lookup, aabb, LookupFlags.Uncontained | LookupFlags.Approximate)) { - if (!xformQuery.TryGetComponent(entity, out var xform) || xform.ParentUid != gridId) + if (!_xformQuery.TryGetComponent(entity, out var xform) || xform.ParentUid != gridId) continue; if (!aabb.Contains(xform.LocalPosition)) @@ -99,9 +100,9 @@ namespace Robust.Shared.GameObjects // If a tile is being removed due to an explosion or somesuch, some entities are likely being deleted. // Avoid unnecessary entity updates. if (EntityManager.IsQueuedForDeletion(entity)) - DetachParentToNull(entity, xform, xformQuery, metaQuery, gridXform); + DetachParentToNull(entity, xform, gridXform); else - SetParent(entity, xform, gridXform.MapUid.Value, xformQuery, mapTransform); + SetParent(entity, xform, gridXform.MapUid.Value, mapTransform); } } @@ -141,7 +142,12 @@ namespace Robust.Shared.GameObjects } } - public EntityCoordinates GetMoverCoordinates(TransformComponent xform, EntityQuery xformQuery) + public EntityCoordinates GetMoverCoordinates(EntityUid uid) + { + return GetMoverCoordinates(uid, _xformQuery.GetComponent(uid)); + } + + public EntityCoordinates GetMoverCoordinates(EntityUid uid, TransformComponent xform) { // Nullspace (or map) if (!xform.ParentUid.IsValid()) @@ -149,26 +155,31 @@ namespace Robust.Shared.GameObjects // GriddUid is only set after init. if (!xform._gridInitialized) - InitializeGridUid(xform.Owner, xform, xformQuery, GetEntityQuery()); + InitializeGridUid(uid, xform); // Is the entity directly parented to the grid? if (xform.GridUid == xform.ParentUid) return xform.Coordinates; - DebugTools.Assert(!_mapManager.IsGrid(xform.Owner) && !_mapManager.IsMap(xform.Owner)); + DebugTools.Assert(!_mapManager.IsGrid(uid) && !_mapManager.IsMap(uid)); // Not parented to grid so convert their pos back to the grid. - var worldPos = GetWorldPosition(xform, xformQuery); + var worldPos = GetWorldPosition(xform, _xformQuery); return xform.GridUid == null ? new EntityCoordinates(xform.MapUid ?? xform.ParentUid, worldPos) - : new EntityCoordinates(xform.GridUid.Value, xformQuery.GetComponent(xform.GridUid.Value).InvLocalMatrix.Transform(worldPos)); + : new EntityCoordinates(xform.GridUid.Value, _xformQuery.GetComponent(xform.GridUid.Value).InvLocalMatrix.Transform(worldPos)); + } + + public EntityCoordinates GetMoverCoordinates(EntityCoordinates coordinates, EntityQuery xformQuery) + { + return GetMoverCoordinates(coordinates); } /// /// Variant of that uses a entity coordinates, rather than an entity's transform. /// - public EntityCoordinates GetMoverCoordinates(EntityCoordinates coordinates, EntityQuery xformQuery) + public EntityCoordinates GetMoverCoordinates(EntityCoordinates coordinates) { var parentUid = coordinates.EntityId; @@ -176,11 +187,11 @@ namespace Robust.Shared.GameObjects if (!parentUid.IsValid()) return coordinates; - var parentXform = xformQuery.GetComponent(parentUid); + var parentXform = _xformQuery.GetComponent(parentUid); // GriddUid is only set after init. if (!parentXform._gridInitialized) - InitializeGridUid(parentUid, parentXform, xformQuery, GetEntityQuery()); + InitializeGridUid(parentUid, parentXform); // Is the entity directly parented to the grid? if (parentXform.GridUid == parentUid) @@ -194,17 +205,17 @@ namespace Robust.Shared.GameObjects DebugTools.Assert(!_mapManager.IsGrid(parentUid) && !_mapManager.IsMap(parentUid)); // Not parented to grid so convert their pos back to the grid. - var worldPos = GetWorldMatrix(parentXform, xformQuery).Transform(coordinates.Position); + var worldPos = GetWorldMatrix(parentXform, _xformQuery).Transform(coordinates.Position); return parentXform.GridUid == null ? new EntityCoordinates(mapId ?? parentUid, worldPos) - : new EntityCoordinates(parentXform.GridUid.Value, xformQuery.GetComponent(parentXform.GridUid.Value).InvLocalMatrix.Transform(worldPos)); + : new EntityCoordinates(parentXform.GridUid.Value, _xformQuery.GetComponent(parentXform.GridUid.Value).InvLocalMatrix.Transform(worldPos)); } /// /// Variant of that also returns the entity's world rotation /// - public (EntityCoordinates Coords, Angle worldRot) GetMoverCoordinateRotation(EntityUid uid, TransformComponent xform, EntityQuery xformQuery) + public (EntityCoordinates Coords, Angle worldRot) GetMoverCoordinateRotation(EntityUid uid, TransformComponent xform) { // Nullspace (or map) if (!xform.ParentUid.IsValid()) @@ -212,19 +223,19 @@ namespace Robust.Shared.GameObjects // GriddUid is only set after init. if (!xform._gridInitialized) - InitializeGridUid(uid, xform, xformQuery, GetEntityQuery()); + InitializeGridUid(uid, xform); // Is the entity directly parented to the grid? if (xform.GridUid == xform.ParentUid) - return (xform.Coordinates, GetWorldRotation(xform, xformQuery)); + return (xform.Coordinates, GetWorldRotation(xform, _xformQuery)); DebugTools.Assert(!_mapManager.IsGrid(uid) && !_mapManager.IsMap(uid)); - var (pos, worldRot) = GetWorldPositionRotation(xform, xformQuery); + var (pos, worldRot) = GetWorldPositionRotation(xform, _xformQuery); var coords = xform.GridUid == null ? new EntityCoordinates(xform.MapUid ?? xform.ParentUid, pos) - : new EntityCoordinates(xform.GridUid.Value, xformQuery.GetComponent(xform.GridUid.Value).InvLocalMatrix.Transform(pos)); + : new EntityCoordinates(xform.GridUid.Value, _xformQuery.GetComponent(xform.GridUid.Value).InvLocalMatrix.Transform(pos)); return (coords, worldRot); } diff --git a/Robust.Shared/Physics/Dynamics/PhysicsMapComponent.cs b/Robust.Shared/Physics/Dynamics/PhysicsMapComponent.cs index 4a0e9ba61..ba6edec60 100644 --- a/Robust.Shared/Physics/Dynamics/PhysicsMapComponent.cs +++ b/Robust.Shared/Physics/Dynamics/PhysicsMapComponent.cs @@ -23,104 +23,67 @@ using System.Collections.Generic; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; -using Robust.Shared.IoC; -using Robust.Shared.Log; -using Robust.Shared.Map; using Robust.Shared.Maths; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Utility; using Robust.Shared.ViewVariables; using PhysicsComponent = Robust.Shared.Physics.Components.PhysicsComponent; -namespace Robust.Shared.Physics.Dynamics +namespace Robust.Shared.Physics.Dynamics; + +[RegisterComponent, NetworkedComponent] +public sealed class PhysicsMapComponent : Component { - [RegisterComponent, NetworkedComponent] - public sealed class PhysicsMapComponent : Component + public bool AutoClearForces; + + /// + /// When substepping the client needs to know about the first position to use for lerping. + /// + public readonly Dictionary + LerpData = new(); + + /// + /// Keep a buffer of everything that moved in a tick. This will be used to check for physics contacts. + /// + [ViewVariables] + public readonly Dictionary MoveBuffer = new(); + + /// + /// All awake bodies on this map. + /// + [ViewVariables] + public readonly HashSet AwakeBodies = new(); + + /// + /// Store last tick's invDT + /// + internal float _invDt0; +} + +[ByRefEvent] +public readonly struct PhysicsUpdateBeforeMapSolveEvent +{ + public readonly bool Prediction; + public readonly PhysicsMapComponent MapComponent; + public readonly float DeltaTime; + + public PhysicsUpdateBeforeMapSolveEvent(bool prediction, PhysicsMapComponent mapComponent, float deltaTime) { - [Dependency] private readonly IEntityManager _entityManager = default!; - - public bool AutoClearForces; - - /// - /// When substepping the client needs to know about the first position to use for lerping. - /// - public readonly Dictionary - LerpData = new(); - - /// - /// Keep a buffer of everything that moved in a tick. This will be used to check for physics contacts. - /// - [ViewVariables] - public readonly Dictionary MoveBuffer = new(); - - /// - /// All awake bodies on this map. - /// - [ViewVariables] - public readonly HashSet AwakeBodies = new(); - - /// - /// Store last tick's invDT - /// - internal float _invDt0; - - #region AddRemove - - public void AddAwakeBody(PhysicsComponent body) - { - if (!body.CanCollide) - { - Logger.ErrorS("physics", $"Tried to add non-colliding {_entityManager.ToPrettyString(body.Owner)} as an awake body to map!"); - DebugTools.Assert(false); - return; - } - - if (body.BodyType == BodyType.Static) - { - Logger.ErrorS("physics", $"Tried to add static body {_entityManager.ToPrettyString(body.Owner)} as an awake body to map!"); - DebugTools.Assert(false); - return; - } - - DebugTools.Assert(body.Awake); - AwakeBodies.Add(body); - } - - public void RemoveSleepBody(PhysicsComponent body) - { - AwakeBodies.Remove(body); - } - - #endregion - } - - [ByRefEvent] - public readonly struct PhysicsUpdateBeforeMapSolveEvent - { - public readonly bool Prediction; - public readonly PhysicsMapComponent MapComponent; - public readonly float DeltaTime; - - public PhysicsUpdateBeforeMapSolveEvent(bool prediction, PhysicsMapComponent mapComponent, float deltaTime) - { - Prediction = prediction; - MapComponent = mapComponent; - DeltaTime = deltaTime; - } - } - - [ByRefEvent] - public readonly struct PhysicsUpdateAfterMapSolveEvent - { - public readonly bool Prediction; - public readonly PhysicsMapComponent MapComponent; - public readonly float DeltaTime; - - public PhysicsUpdateAfterMapSolveEvent(bool prediction, PhysicsMapComponent mapComponent, float deltaTime) - { - Prediction = prediction; - MapComponent = mapComponent; - DeltaTime = deltaTime; - } + Prediction = prediction; + MapComponent = mapComponent; + DeltaTime = deltaTime; + } +} + +[ByRefEvent] +public readonly struct PhysicsUpdateAfterMapSolveEvent +{ + public readonly bool Prediction; + public readonly PhysicsMapComponent MapComponent; + public readonly float DeltaTime; + + public PhysicsUpdateAfterMapSolveEvent(bool prediction, PhysicsMapComponent mapComponent, float deltaTime) + { + Prediction = prediction; + MapComponent = mapComponent; + DeltaTime = deltaTime; } } diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs index 22e4cbc2b..0aa28568f 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Island.cs @@ -278,13 +278,13 @@ public abstract partial class SharedPhysicsSystem /// /// Where the magic happens. /// - public void Step(PhysicsMapComponent component, float frameTime, bool prediction) + public void Step(EntityUid uid, PhysicsMapComponent component, float frameTime, bool prediction) { var invDt = frameTime > 0.0f ? 1.0f / frameTime : 0.0f; var dtRatio = component._invDt0 * frameTime; // Integrate velocities, solve velocity constraints, and do integration. - Solve(component, frameTime, dtRatio, invDt, prediction); + Solve(uid, component, frameTime, dtRatio, invDt, prediction); // TODO: SolveTOI @@ -308,7 +308,7 @@ public abstract partial class SharedPhysicsSystem } } - private void Solve(PhysicsMapComponent component, float frameTime, float dtRatio, float invDt, bool prediction) + private void Solve(EntityUid uid, PhysicsMapComponent component, float frameTime, float dtRatio, float invDt, bool prediction) { // Build and simulated islands from awake bodies. _bodyStack.EnsureCapacity(component.AwakeBodies.Count); @@ -339,10 +339,12 @@ public abstract partial class SharedPhysicsSystem // when contact broke so if you want to try that then GOOD LUCK. if (seed.Island) continue; - if (!metaQuery.TryGetComponent(seed.Owner, out var metadata)) + var seedUid = seed.Owner; + + if (!metaQuery.TryGetComponent(seedUid, out var metadata)) { - _sawmill.Error($"Found deleted entity {ToPrettyString(seed.Owner)} on map!"); - component.RemoveSleepBody(seed); + _sawmill.Error($"Found deleted entity {ToPrettyString(seedUid)} on map!"); + RemoveSleepBody(seedUid, seed, component); continue; } @@ -536,7 +538,7 @@ public abstract partial class SharedPhysicsSystem ReturnIsland(loneIsland); } - SolveIslands(component, islands, frameTime, dtRatio, invDt, prediction); + SolveIslands(uid, component, islands, frameTime, dtRatio, invDt, prediction); foreach (var island in islands) { @@ -591,10 +593,10 @@ public abstract partial class SharedPhysicsSystem _awakeBodyList.Clear(); } - private void SolveIslands(PhysicsMapComponent component, List islands, float frameTime, float dtRatio, float invDt, bool prediction) + private void SolveIslands(EntityUid uid, PhysicsMapComponent component, List islands, float frameTime, float dtRatio, float invDt, bool prediction) { var iBegin = 0; - var gravity = _gravity.GetGravity(component.Owner); + var gravity = _gravity.GetGravity(uid); var data = new SolverData( frameTime, diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs new file mode 100644 index 000000000..0d06372a4 --- /dev/null +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.Map.cs @@ -0,0 +1,53 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Dynamics; +using Robust.Shared.Utility; + +namespace Robust.Shared.Physics.Systems; + +public partial class SharedPhysicsSystem +{ + #region AddRemove + + internal void AddAwakeBody(EntityUid uid, PhysicsComponent body, PhysicsMapComponent? map = null) + { + if (map == null) + return; + + if (!body.CanCollide) + { + Log.Error($"Tried to add non-colliding {ToPrettyString(uid)} as an awake body to map!"); + DebugTools.Assert(false); + return; + } + + if (body.BodyType == BodyType.Static) + { + Log.Error($"Tried to add static body {ToPrettyString(uid)} as an awake body to map!"); + DebugTools.Assert(false); + return; + } + + DebugTools.Assert(body.Awake); + map.AwakeBodies.Add(body); + } + + internal void AddAwakeBody(EntityUid uid, PhysicsComponent body, EntityUid mapUid, PhysicsMapComponent? map = null) + { + Resolve(mapUid, ref map, false); + AddAwakeBody(uid, body, map); + } + + internal void RemoveSleepBody(EntityUid uid, PhysicsComponent body, PhysicsMapComponent? map = null) + { + map?.AwakeBodies.Remove(body); + } + + internal void RemoveSleepBody(EntityUid uid, PhysicsComponent body, EntityUid mapUid, PhysicsMapComponent? map = null) + { + Resolve(mapUid, ref map, false); + RemoveSleepBody(uid, body, map); + } + + #endregion +} diff --git a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs index c57552d42..c33f84127 100644 --- a/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs +++ b/Robust.Shared/Physics/Systems/SharedPhysicsSystem.cs @@ -205,8 +205,8 @@ namespace Robust.Shared.Physics.Systems { if (body.Awake) { - oldMap?.RemoveSleepBody(body); - newMap?.AddAwakeBody(body); + RemoveSleepBody(uid, body, oldMap); + AddAwakeBody(uid, body, newMap); DebugTools.Assert(body.Awake); } else @@ -252,24 +252,24 @@ namespace Robust.Shared.Physics.Systems private void OnWake(ref PhysicsWakeEvent @event) { - var mapId = EntityManager.GetComponent(@event.Body.Owner).MapID; + var mapId = EntityManager.GetComponent(@event.Entity).MapID; if (mapId == MapId.Nullspace) return; - EntityUid tempQualifier = _mapManager.GetMapEntityId(mapId); - EntityManager.GetComponent(tempQualifier).AddAwakeBody(@event.Body); + var tempQualifier = _mapManager.GetMapEntityId(mapId); + AddAwakeBody(@event.Entity, @event.Body, tempQualifier); } private void OnSleep(ref PhysicsSleepEvent @event) { - var mapId = EntityManager.GetComponent(@event.Body.Owner).MapID; + var mapId = EntityManager.GetComponent(@event.Entity).MapID; if (mapId == MapId.Nullspace) return; - EntityUid tempQualifier = _mapManager.GetMapEntityId(mapId); - EntityManager.GetComponent(tempQualifier).RemoveSleepBody(@event.Body); + var tempQualifier = _mapManager.GetMapEntityId(mapId); + RemoveSleepBody(@event.Entity, @event.Body, tempQualifier); } private void HandleContainerRemoved(EntityUid uid, PhysicsComponent physics, EntGotRemovedFromContainerMessage message) @@ -314,9 +314,9 @@ namespace Robust.Shared.Physics.Systems CollideContacts(); var enumerator = AllEntityQuery(); - while (enumerator.MoveNext(out var comp)) + while (enumerator.MoveNext(out var uid, out var comp)) { - Step(comp, frameTime, prediction); + Step(uid, comp, frameTime, prediction); } var updateAfterSolve = new PhysicsUpdateAfterSolveEvent(prediction, frameTime); diff --git a/Robust.UnitTesting/RobustUnitTest.cs b/Robust.UnitTesting/RobustUnitTest.cs index 582726e72..3493430aa 100644 --- a/Robust.UnitTesting/RobustUnitTest.cs +++ b/Robust.UnitTesting/RobustUnitTest.cs @@ -26,6 +26,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Reflection; using Robust.Shared.Utility; +using EyeComponent = Robust.Server.GameObjects.EyeComponent; namespace Robust.UnitTesting { @@ -127,6 +128,11 @@ namespace Robust.UnitTesting // Why are we still here? Just to suffer? Why can't we just use [RegisterComponent] magic? var compFactory = deps.Resolve(); + if (!compFactory.AllRegisteredTypes.Contains(typeof(EyeComponent))) + { + compFactory.RegisterClass(); + } + if (!compFactory.AllRegisteredTypes.Contains(typeof(MapComponent))) { compFactory.RegisterClass(); diff --git a/Robust.UnitTesting/Server/RobustServerSimulation.cs b/Robust.UnitTesting/Server/RobustServerSimulation.cs index f3272c982..be63fc664 100644 --- a/Robust.UnitTesting/Server/RobustServerSimulation.cs +++ b/Robust.UnitTesting/Server/RobustServerSimulation.cs @@ -269,6 +269,7 @@ namespace Robust.UnitTesting.Server compFactory.RegisterClass(); compFactory.RegisterClass(); compFactory.RegisterClass(); + compFactory.RegisterClass(); compFactory.RegisterClass(); compFactory.RegisterClass(); compFactory.RegisterClass(); diff --git a/Robust.UnitTesting/Shared/GameObjects/Systems/TransformSystemTests.cs b/Robust.UnitTesting/Shared/GameObjects/Systems/TransformSystemTests.cs index 4f3afaac0..eaa286214 100644 --- a/Robust.UnitTesting/Shared/GameObjects/Systems/TransformSystemTests.cs +++ b/Robust.UnitTesting/Shared/GameObjects/Systems/TransformSystemTests.cs @@ -70,10 +70,8 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems xformSystem.SetParent(child1, child1Xform, parent, parentXform: parentXform); xformSystem.SetParent(child2, child2Xform, parent, parentXform: parentXform); - var query = entManager.GetEntityQuery(); - - var mover1 = xformSystem.GetMoverCoordinates(child1Xform, query); - var mover2 = xformSystem.GetMoverCoordinates(child2Xform, query); + var mover1 = xformSystem.GetMoverCoordinates(child1, child1Xform); + var mover2 = xformSystem.GetMoverCoordinates(child2, child2Xform); Assert.That(mover1.Position, Is.EqualTo(Vector2.One)); Assert.That(mover2.Position, Is.EqualTo(new Vector2(10f, 10f))); @@ -82,7 +80,7 @@ namespace Robust.UnitTesting.Shared.GameObjects.Systems var child3Xform = entManager.GetComponent(child3); xformSystem.SetParent(child3, child3Xform, child2, parentXform: child2Xform); - Assert.That(xformSystem.GetMoverCoordinates(child3Xform, query).Position, Is.EqualTo(Vector2.One)); + Assert.That(xformSystem.GetMoverCoordinates(child3, child3Xform).Position, Is.EqualTo(Vector2.One)); } ///