diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 97198b19c..e7dd59f5d 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -36,6 +36,8 @@ END TEMPLATE--> ### Breaking changes * Remove the duplicate serialization copy of components kept on ComponentRegistryEntry; now it only stores the deserialized component. To get the raw MappingDataNode for EntityPrototypes use PrototypeManager. This is expected to significantly reduce memory usage. +* Obsolete LocalRotation in favor of the system method. The angle is now also normalized to 2PI and no longer grows indefinitely. +* Removed the obsolete TransformComponent methods. The remaining methods have been marked as obsolete and are subject to removal in future. ### New features diff --git a/Robust.Server.IntegrationTests/GameObjects/Components/Transform_Test.cs b/Robust.Server.IntegrationTests/GameObjects/Components/Transform_Test.cs index 95b857bb9..14f54d464 100644 --- a/Robust.Server.IntegrationTests/GameObjects/Components/Transform_Test.cs +++ b/Robust.Server.IntegrationTests/GameObjects/Components/Transform_Test.cs @@ -439,6 +439,21 @@ public void WorldRotationTest() Assert.That(result, new ApproxEqualityConstraint(Angle.FromDegrees(225))); } + [Test] + public void LocalRotationNormalizesTest() + { + var entity = EntityManager.SpawnEntity(null, InitialPos); + var transform = EntityManager.GetComponent(entity); + + XformSystem.SetLocalRotation(entity, Angle.FromDegrees(90), transform); + + Assert.That(transform.LocalRotation, NUnit.Framework.Is.EqualTo(Angle.FromDegrees(90))); + + XformSystem.SetWorldRotation(transform, Angle.FromDegrees(810)); + + Assert.That(transform.LocalRotation, NUnit.Framework.Is.EqualTo(Angle.FromDegrees(90))); + } + /// /// Test that, in a chain A -> B -> C, if A is moved C's world position correctly updates. /// diff --git a/Robust.Shared.IntegrationTests/GameObjects/Systems/AnchoredSystemTests.cs b/Robust.Shared.IntegrationTests/GameObjects/Systems/AnchoredSystemTests.cs index 9f04c1f2d..0764307f2 100644 --- a/Robust.Shared.IntegrationTests/GameObjects/Systems/AnchoredSystemTests.cs +++ b/Robust.Shared.IntegrationTests/GameObjects/Systems/AnchoredSystemTests.cs @@ -264,8 +264,7 @@ public void Anchored_SetPosition_Nop() sim.System().FailOnMove = true; // Act - sim.Transform(ent1).WorldPosition = new Vector2(99, 99); - sim.Transform(ent1).LocalPosition = new Vector2(99, 99); + xformSys.SetLocalPosition(ent1, new Vector2(99, 99)); Assert.That(xformSys.GetMapCoordinates(ent1), Is.EqualTo(coordinates)); sim.System().FailOnMove = false; diff --git a/Robust.Shared/Containers/SharedContainerSystem.Insert.cs b/Robust.Shared/Containers/SharedContainerSystem.Insert.cs index caf462d85..3ee421ce3 100644 --- a/Robust.Shared/Containers/SharedContainerSystem.Insert.cs +++ b/Robust.Shared/Containers/SharedContainerSystem.Insert.cs @@ -110,7 +110,7 @@ public bool Insert(Entity _noLocalRotation; - set - { - if (value) - LocalRotation = Angle.Zero; - - _noLocalRotation = value; - _entMan.Dirty(Owner, this); - } + [Obsolete("Use SharedTransformSystem.SetNoLocalRotation instead.")] + set => _entMan.System().SetNoLocalRotation(Owner, value, this); } /// @@ -153,11 +147,14 @@ public bool NoLocalRotation public Angle LocalRotation { get => _localRotation; + [Obsolete("Use SharedTransformSystem.SetLocalRotation")] set { if(_noLocalRotation) return; + value = SharedTransformSystem.NormalizeRotation(value); + if (_localRotation.EqualsApprox(value)) return; @@ -216,94 +213,6 @@ public Angle WorldRotation /// public EntityUid ParentUid => _parent; - /// - /// Matrix for transforming points from local to world space. - /// - [Obsolete("Use the system method instead")] - public Matrix3x2 WorldMatrix - { - get - { - var xformQuery = _entMan.GetEntityQuery(); - var parent = _parent; - var myMatrix = LocalMatrix; - - while (parent.IsValid()) - { - var parentXform = xformQuery.GetComponent(parent); - var parentMatrix = parentXform.LocalMatrix; - parent = parentXform.ParentUid; - - var result = Matrix3x2.Multiply(myMatrix, parentMatrix); - myMatrix = result; - } - - return myMatrix; - } - } - - /// - /// Matrix for transforming points from world to local space. - /// - [Obsolete("Use the system method instead")] - public Matrix3x2 InvWorldMatrix - { - get - { - var xformQuery = _entMan.GetEntityQuery(); - var parent = _parent; - var myMatrix = InvLocalMatrix; - - while (parent.IsValid()) - { - var parentXform = xformQuery.GetComponent(parent); - var parentMatrix = parentXform.InvLocalMatrix; - parent = parentXform.ParentUid; - - var result = Matrix3x2.Multiply(parentMatrix, myMatrix); - myMatrix = result; - } - - return myMatrix; - } - } - - /// - /// Current position offset of the entity relative to the world. - /// Can de-parent from its parent if the parent is a grid. - /// - [Animatable] - [ViewVariables(VVAccess.ReadWrite)] - [Obsolete("Use the system method instead")] - public Vector2 WorldPosition - { - get - { - if (_parent.IsValid()) - { - // parent coords to world coords - return Vector2.Transform(_localPosition, _entMan.GetComponent(ParentUid).WorldMatrix); - } - else - { - return Vector2.Zero; - } - } - set - { - if (!_parent.IsValid()) - { - DebugTools.Assert("Parent is invalid while attempting to set WorldPosition - did you try to move root node?"); - return; - } - - // world coords to parent coords - var newPos = Vector2.Transform(value, _entMan.GetComponent(ParentUid).InvWorldMatrix); - - LocalPosition = newPos; - } - } - /// /// Position offset of this entity relative to its parent. /// @@ -319,45 +228,14 @@ public EntityCoordinates Coordinates set => _entMan.EntitySysManager.GetEntitySystem().SetCoordinates(Owner, this, value); } - /// - /// Current position offset of the entity relative to the world. - /// This is effectively a more complete version of - /// - [ViewVariables(VVAccess.ReadWrite)] - [Obsolete("Use TransformSystem.GetMapCoordinates")] - public MapCoordinates MapPosition => new(WorldPosition, MapID); - /// /// Local offset of this entity relative to its parent /// ( if it's not null, to otherwise). /// - [Animatable] - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables] public Vector2 LocalPosition { get => _localPosition; - [Obsolete("Use the system method instead")] - set - { - if(Anchored) - return; - - if (_localPosition.EqualsApprox(value)) - return; - - var oldParent = _parent; - var oldPos = _localPosition; - - _localPosition = value; - var meta = _entMan.GetComponent(Owner); - _entMan.Dirty(Owner, this, meta); - MatricesDirty = true; - - if (!Initialized) - return; - - _entMan.System().RaiseMoveEvent((Owner, this, meta), oldParent, oldPos, _localRotation, MapUid); - } } /// @@ -375,7 +253,7 @@ public bool Anchored { _anchored = value; } - else if (value && !_anchored && _mapManager.TryFindGridAt(MapPosition, out _, out var grid)) + else if (value && !_anchored && _mapManager.TryFindGridAt(_entMan.System().GetMapCoordinates(this), out _, out var grid)) { _anchored = _entMan.EntitySysManager.GetEntitySystem().AnchorEntity(Owner, this, grid); } @@ -396,122 +274,7 @@ public bool Anchored [ViewVariables] public EntityUid LerpParent; public bool PredictedLerp; - /// - /// Detaches this entity from its parent. - /// - [Obsolete("Use the system's method instead.")] - public void AttachToGridOrMap() - { - _entMan.EntitySysManager.GetEntitySystem().AttachToGridOrMap(Owner, this); - } - - [Obsolete("Use TransformSystem.SetParent() instead")] - public void AttachParent(EntityUid parent) - { - _entMan.EntitySysManager.GetEntitySystem().SetParent(Owner, this, parent, _entMan.GetEntityQuery()); - } - - /// - /// Get the WorldPosition and WorldRotation of this entity faster than each individually. - /// - [Obsolete("Use the system method instead")] - public (Vector2 WorldPosition, Angle WorldRotation) GetWorldPositionRotation() - { - // Worldmatrix needs calculating anyway for worldpos so we'll just drop it. - var (worldPos, worldRot, _) = GetWorldPositionRotationMatrix(); - return (worldPos, worldRot); - } - - /// - /// Get the WorldPosition, WorldRotation, and WorldMatrix of this entity faster than each individually. - /// - [Obsolete("Use the system method instead")] - public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix) GetWorldPositionRotationMatrix(EntityQuery xforms) - { - var parent = _parent; - var worldRot = _localRotation; - var worldMatrix = LocalMatrix; - - // By doing these all at once we can elide multiple IsValid + GetComponent calls - while (parent.IsValid()) - { - var xform = xforms.GetComponent(parent); - worldRot += xform.LocalRotation; - var parentMatrix = xform.LocalMatrix; - var result = Matrix3x2.Multiply(worldMatrix, parentMatrix); - worldMatrix = result; - parent = xform.ParentUid; - } - - var worldPosition = worldMatrix.Translation; - - return (worldPosition, worldRot, worldMatrix); - } - - /// - /// Get the WorldPosition, WorldRotation, and WorldMatrix of this entity faster than each individually. - /// - [Obsolete("Use the system method instead")] - public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix) GetWorldPositionRotationMatrix() - { - var xforms = _entMan.GetEntityQuery(); - return GetWorldPositionRotationMatrix(xforms); - } - - /// - /// Get the WorldPosition, WorldRotation, and InvWorldMatrix of this entity faster than each individually. - /// - [Obsolete("Use the system method instead")] - public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationInvMatrix(EntityQuery xformQuery) - { - var (worldPos, worldRot, _, invWorldMatrix) = GetWorldPositionRotationMatrixWithInv(xformQuery); - return (worldPos, worldRot, invWorldMatrix); - } - - /// - /// Get the WorldPosition, WorldRotation, WorldMatrix, and InvWorldMatrix of this entity faster than each individually. - /// - [Obsolete("Use the system method instead")] - public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationMatrixWithInv() - { - var xformQuery = _entMan.GetEntityQuery(); - return GetWorldPositionRotationMatrixWithInv(xformQuery); - } - - /// - /// Get the WorldPosition, WorldRotation, WorldMatrix, and InvWorldMatrix of this entity faster than each individually. - /// - [Obsolete("Use the system method instead")] - public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationMatrixWithInv(EntityQuery xformQuery) - { - var parent = _parent; - var worldRot = _localRotation; - var invMatrix = InvLocalMatrix; - var worldMatrix = LocalMatrix; - - // By doing these all at once we can avoid multiple IsValid + GetComponent calls - while (parent.IsValid()) - { - var xform = xformQuery.GetComponent(parent); - worldRot += xform.LocalRotation; - - var parentMatrix = xform.LocalMatrix; - var result = Matrix3x2.Multiply(worldMatrix, parentMatrix); - worldMatrix = result; - - var parentInvMatrix = xform.InvLocalMatrix; - var invResult = Matrix3x2.Multiply(parentInvMatrix, invMatrix); - invMatrix = invResult; - - parent = xform.ParentUid; - } - - var worldPosition = worldMatrix.Translation; - - return (worldPosition, worldRot, worldMatrix, invMatrix); - } - - public void RebuildMatrices() + private void RebuildMatrices() { MatricesDirty = false; @@ -527,7 +290,8 @@ public void RebuildMatrices() public string GetDebugString() { - return $"pos/rot/wpos/wrot: {Coordinates}/{LocalRotation}/{WorldPosition}/{WorldRotation}"; + var xform = _entMan.System(); + return $"pos/rot/wpos/wrot: {Coordinates}/{LocalRotation}/{xform.GetWorldPosition(this)}/{xform.GetWorldRotation(this)}"; } } diff --git a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs index 2fa10c984..52320b593 100644 --- a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs +++ b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs @@ -45,7 +45,7 @@ internal void ReAnchor( var oldRot = xform._localRotation; var oldMap = xform.MapUid; xform._localPosition = tilePos + newGrid.TileSizeHalfVector; - xform._localRotation += rotation; + xform._localRotation = NormalizeRotation(xform._localRotation + rotation); var meta = MetaData(uid); SetGridId((uid, xform, meta), newGridUid); @@ -428,15 +428,35 @@ public void SetLocalPositionNoLerp(EntityUid uid, Vector2 value, TransformCompon if (!XformQuery.Resolve(uid, ref xform)) return; -#pragma warning disable CS0618 - xform.LocalPosition = value; -#pragma warning restore CS0618 + if (xform.Anchored) + return; + + if (xform._localPosition.EqualsApprox(value)) + return; + + var oldParent = xform._parent; + var oldPos = xform._localPosition; + + xform._localPosition = value; + var meta = MetaData(uid); + Dirty(uid, xform, meta); + xform.MatricesDirty = true; + + if (!xform.Initialized) + return; + + RaiseMoveEvent((uid, xform, meta), oldParent, oldPos, xform._localRotation, xform.MapUid); } #endregion #region Local Rotation + internal static Angle NormalizeRotation(Angle rotation) + { + return rotation.Reduced(); + } + public void SetLocalRotationNoLerp(EntityUid uid, Angle value, TransformComponent? xform = null) { if (!XformQuery.Resolve(uid, ref xform)) @@ -457,6 +477,27 @@ public void SetLocalRotation(TransformComponent xform, Angle value) #endregion + #region No Local Rotation + + public void SetNoLocalRotation(EntityUid uid, bool value, TransformComponent? xform = null) + { + if (!XformQuery.Resolve(uid, ref xform)) + return; + + SetNoLocalRotation((uid, xform), value); + } + + public void SetNoLocalRotation(Entity entity, bool value) + { + if (value) + SetLocalRotation(entity.Owner, Angle.Zero, entity.Comp); + + entity.Comp._noLocalRotation = value; + Dirty(entity); + } + + #endregion + #region Coordinates public void SetCoordinates(EntityUid uid, EntityCoordinates value) @@ -519,7 +560,7 @@ public void SetCoordinates( xform._localPosition = value.Position; if (rotation != null && !xform.NoLocalRotation) - xform._localRotation = rotation.Value; + xform._localRotation = NormalizeRotation(rotation.Value); DebugTools.Assert(!xform.NoLocalRotation || xform.LocalRotation == 0); @@ -621,7 +662,7 @@ public void SetCoordinates( { // preserve world rotation if (rotation == null && oldParent != null && newParent != null && !xform.NoLocalRotation) - xform._localRotation += GetWorldRotation(oldParent) - GetWorldRotation(newParent); + xform._localRotation = NormalizeRotation(xform._localRotation + GetWorldRotation(oldParent) - GetWorldRotation(newParent)); DebugTools.Assert(!xform.NoLocalRotation || xform.LocalRotation == 0); } @@ -1277,7 +1318,7 @@ public virtual void SetLocalPositionRotation(EntityUid uid, Vector2 pos, Angle r xform._localPosition = pos; if (!xform.NoLocalRotation) - xform._localRotation = rot; + xform._localRotation = NormalizeRotation(rot); DebugTools.Assert(!xform.NoLocalRotation || xform.LocalRotation == 0); diff --git a/Robust.Shared/Map/MapManager.GridCollection.cs b/Robust.Shared/Map/MapManager.GridCollection.cs index cf23be33c..43cba4db4 100644 --- a/Robust.Shared/Map/MapManager.GridCollection.cs +++ b/Robust.Shared/Map/MapManager.GridCollection.cs @@ -118,7 +118,8 @@ protected Entity CreateGrid(EntityUid map, ushort chunkSize, E //are applied. After they are applied the parent may be different, but the MapId will //be the same. This causes TransformComponent.ParentUid of a grid to be unsafe to //use in transform states anytime before the state parent is properly set. - EntityManager.GetComponent(gridEnt).AttachParent(map); + var transform = EntityManager.GetComponent(gridEnt); + EntityManager.System().SetParent(gridEnt, transform, map); var meta = EntityManager.GetComponent(gridEnt); EntityManager.System().SetEntityName(gridEnt, $"grid", meta);