diff --git a/Robust.Client/GameObjects/EntitySystems/TransformSystem.Component.cs b/Robust.Client/GameObjects/EntitySystems/TransformSystem.Component.cs new file mode 100644 index 0000000000..5c0ed9f71c --- /dev/null +++ b/Robust.Client/GameObjects/EntitySystems/TransformSystem.Component.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Maths; + +namespace Robust.Client.GameObjects; + +public sealed partial class TransformSystem +{ + public override void SetLocalPosition(TransformComponent xform, Vector2 value) + { + xform._prevPosition = xform._localPosition; + xform._nextPosition = value; + xform.LerpParent = xform.ParentUid; + base.SetLocalPosition(xform, value); + ActivateLerp(xform); + } +} diff --git a/Robust.Client/GameObjects/EntitySystems/TransformSystem.cs b/Robust.Client/GameObjects/EntitySystems/TransformSystem.cs index f67d4dcfb2..6733e956de 100644 --- a/Robust.Client/GameObjects/EntitySystems/TransformSystem.cs +++ b/Robust.Client/GameObjects/EntitySystems/TransformSystem.cs @@ -14,12 +14,20 @@ namespace Robust.Client.GameObjects /// Handles interpolation of transform positions. /// [UsedImplicitly] - public sealed class TransformSystem : SharedTransformSystem + public sealed partial class TransformSystem : SharedTransformSystem { // Max distance per tick how far an entity can move before it is considered teleporting. // TODO: Make these values somehow dependent on server TPS. private const float MaxInterpolationDistance = 2.0f; - private const double MaxInterpolationAngle = Math.PI / 4; // 45 degrees. + private const float MaxInterpolationDistanceSquared = MaxInterpolationDistance * MaxInterpolationDistance; + + private const float MinInterpolationDistance = 0.001f; + private const float MinInterpolationDistanceSquared = MinInterpolationDistance * MinInterpolationDistance; + + private const double MinInterpolationAngle = Math.PI / 720; + + // 45 degrees. + private const double MaxInterpolationAngle = Math.PI / 4; [Dependency] private readonly IGameTiming _gameTiming = default!; @@ -59,7 +67,9 @@ namespace Robust.Client.GameObjects { var lerpDest = transform.LerpDestination.Value; var lerpSource = transform.LerpSource; - if ((lerpDest - lerpSource).LengthSquared < MaxInterpolationDistance * MaxInterpolationDistance) + var distance = (lerpDest - lerpSource).LengthSquared; + + if (distance is > MinInterpolationDistanceSquared and < MaxInterpolationDistanceSquared) { transform.LocalPosition = Vector2.Lerp(lerpSource, lerpDest, step); // Setting LocalPosition clears LerpPosition so fix that. @@ -72,7 +82,9 @@ namespace Robust.Client.GameObjects { var lerpDest = transform.LerpAngle.Value; var lerpSource = transform.LerpSourceAngle; - if (Math.Abs(Angle.ShortestDistance(lerpDest, lerpSource)) < MaxInterpolationAngle) + var distance = Math.Abs(Angle.ShortestDistance(lerpDest, lerpSource)); + + if (distance is > MinInterpolationAngle and < MaxInterpolationAngle) { transform.LocalRotation = Angle.Lerp(lerpSource, lerpDest, step); // Setting LocalRotation clears LerpAngle so fix that. diff --git a/Robust.Client/GameObjects/EntitySystems/VelocityDebugSystem.cs b/Robust.Client/GameObjects/EntitySystems/VelocityDebugSystem.cs index 4e76d7d218..c2be188c24 100644 --- a/Robust.Client/GameObjects/EntitySystems/VelocityDebugSystem.cs +++ b/Robust.Client/GameObjects/EntitySystems/VelocityDebugSystem.cs @@ -45,7 +45,7 @@ namespace Robust.Client.GameObjects LayoutContainer.SetPosition(_label, screenPos + new Vector2(0, 50)); _label.Visible = true; - _label.Text = $"Speed: {body.LinearVelocity.Length}\nLinear: {body.LinearVelocity.X:0.00}, {body.LinearVelocity.Y:0.00}\nAngular:{body.AngularVelocity}"; + _label.Text = $"Speed: {body.LinearVelocity.Length:0.00}\nLinear: {body.LinearVelocity.X:0.00}, {body.LinearVelocity.Y:0.00}\nAngular: {body.AngularVelocity}"; } } } diff --git a/Robust.Client/Physics/PhysicsSystem.cs b/Robust.Client/Physics/PhysicsSystem.cs index 18e767c81b..2e395fac63 100644 --- a/Robust.Client/Physics/PhysicsSystem.cs +++ b/Robust.Client/Physics/PhysicsSystem.cs @@ -1,6 +1,4 @@ -using System; using JetBrains.Annotations; -using Robust.Client.GameStates; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -12,31 +10,12 @@ namespace Robust.Client.Physics public sealed class PhysicsSystem : SharedPhysicsSystem { [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IClientGameStateManager _gameState = default!; - - private TimeSpan _lastRem; public override void Update(float frameTime) { - _lastRem = _gameTiming.CurTime; SimulateWorld(frameTime, _gameTiming.InPrediction); } - public override void FrameUpdate(float frameTime) - { - if (!_gameState.IsPredictionEnabled) - return; - - if (_lastRem > _gameTiming.TickRemainder) - { - _lastRem = TimeSpan.Zero; - } - - var diff = _gameTiming.TickRemainder - _lastRem; - _lastRem = _gameTiming.TickRemainder; - SimulateWorld((float) diff.TotalSeconds, true); - } - protected override void HandleMapCreated(MapChangedEvent eventArgs) { if (eventArgs.Map == MapId.Nullspace) return; diff --git a/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs b/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs index 6893cebeab..15e500e735 100644 --- a/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs +++ b/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs @@ -33,6 +33,8 @@ namespace Robust.Shared.GameObjects private Matrix3 _localMatrix = Matrix3.Identity; private Matrix3 _invLocalMatrix = Matrix3.Identity; + // used for lerping + internal Vector2? _nextPosition; internal Angle? _nextRotation; @@ -410,9 +412,6 @@ namespace Robust.Shared.GameObjects if (_localPosition.EqualsApprox(value)) return; - // Set _nextPosition to null to break any on-going lerps if this is done in a client side prediction. - _nextPosition = null; - var oldGridPos = Coordinates; _localPosition = value; Dirty(_entMan); diff --git a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs index f0ba335180..001b4ac9e4 100644 --- a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs +++ b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs @@ -268,6 +268,21 @@ public abstract partial class SharedTransformSystem #endregion + #region Local Position + + public void SetLocalPosition(EntityUid uid, Vector2 value, TransformComponent? xform = null) + { + if (!Resolve(uid, ref xform)) return; + SetLocalPosition(xform, value); + } + + public virtual void SetLocalPosition(TransformComponent xform, Vector2 value) + { + xform.LocalPosition = value; + } + + #endregion + #region Parent public TransformComponent? GetParent(EntityUid uid) @@ -320,12 +335,10 @@ public abstract partial class SharedTransformSystem #region States - private void ActivateLerp(TransformComponent xform) + protected void ActivateLerp(TransformComponent xform) { if (xform.ActivelyLerping) - { return; - } xform.ActivelyLerping = true; RaiseLocalEvent(xform.Owner, new TransformStartLerpMessage(xform), true); @@ -436,13 +449,18 @@ public abstract partial class SharedTransformSystem } else { - // this should cause the lerp to do nothing - component._nextPosition = null; - component._nextRotation = null; - component.LerpParent = EntityUid.Invalid; + DeactivateLerp(component); } } + private void DeactivateLerp(TransformComponent component) + { + // this should cause the lerp to do nothing + component._nextPosition = null; + component._nextRotation = null; + component.LerpParent = EntityUid.Invalid; + } + #endregion #region World Matrix @@ -514,12 +532,20 @@ public abstract partial class SharedTransformSystem return component.GetWorldPositionRotation(xformQuery); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetWorldPosition(EntityUid uid, Vector2 worldPos) { var xform = Transform(uid); SetWorldPosition(xform, worldPos); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetWorldPosition(EntityUid uid, Vector2 worldPos, EntityQuery xformQuery) + { + var component = xformQuery.GetComponent(uid); + SetWorldPosition(component, worldPos, xformQuery); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetWorldPosition(TransformComponent component, Vector2 worldPos) { @@ -531,14 +557,7 @@ public abstract partial class SharedTransformSystem // world coords to parent coords var newPos = component.Parent!.InvWorldMatrix.Transform(worldPos); - component.LocalPosition = newPos; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetWorldPosition(EntityUid uid, Vector2 worldPos, EntityQuery xformQuery) - { - var component = xformQuery.GetComponent(uid); - SetWorldPosition(component, worldPos, xformQuery); + SetLocalPosition(component, newPos); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -552,7 +571,7 @@ public abstract partial class SharedTransformSystem // world coords to parent coords var newPos = GetInvWorldMatrix(component._parent, xformQuery).Transform(worldPos); - component.LocalPosition = newPos; + SetLocalPosition(component, newPos); } #endregion