diff --git a/Content.Client/GameObjects/Components/Rotatable/RotatableComponent.cs b/Content.Client/GameObjects/Components/Rotatable/RotatableComponent.cs new file mode 100644 index 0000000000..462d360709 --- /dev/null +++ b/Content.Client/GameObjects/Components/Rotatable/RotatableComponent.cs @@ -0,0 +1,12 @@ +#nullable enable +using Content.Shared.GameObjects.Components.Rotatable; +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components.Rotatable +{ + [RegisterComponent] + [ComponentReference(typeof(SharedRotatableComponent))] + public class RotatableComponent : SharedRotatableComponent + { + } +} diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index cee1503a1f..f1ef10650e 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -56,7 +56,6 @@ namespace Content.Client "Drink", "Food", "FoodContainer", - "Rotatable", "MagicMirror", "FloorTile", "ShuttleController", diff --git a/Content.Server/GameObjects/Components/Rotatable/RotatableComponent.cs b/Content.Server/GameObjects/Components/Rotatable/RotatableComponent.cs index 380b7935a8..33aa7243e3 100644 --- a/Content.Server/GameObjects/Components/Rotatable/RotatableComponent.cs +++ b/Content.Server/GameObjects/Components/Rotatable/RotatableComponent.cs @@ -1,27 +1,19 @@ -using Content.Shared.GameObjects.EntitySystems.ActionBlocker; +#nullable enable +using Content.Shared.GameObjects.Components.Rotatable; +using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.Verbs; using Content.Shared.Interfaces; using Robust.Shared.GameObjects; using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.Physics; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Rotatable { [RegisterComponent] - public class RotatableComponent : Component + [ComponentReference(typeof(SharedRotatableComponent))] + public class RotatableComponent : SharedRotatableComponent { - public override string Name => "Rotatable"; - - /// - /// If true, this entity can be rotated even while anchored. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("rotateWhileAnchored")] - public bool RotateWhileAnchored { get; private set; } - private void TryRotate(IEntity user, Angle angle) { if (!RotateWhileAnchored && Owner.TryGetComponent(out IPhysBody? physics)) diff --git a/Content.Shared/GameObjects/Components/Rotatable/SharedRotatableComponent.cs b/Content.Shared/GameObjects/Components/Rotatable/SharedRotatableComponent.cs new file mode 100644 index 0000000000..cad3c89985 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Rotatable/SharedRotatableComponent.cs @@ -0,0 +1,26 @@ +#nullable enable +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.GameObjects.Components.Rotatable +{ + public abstract class SharedRotatableComponent : Component + { + public override string Name => "Rotatable"; + + /// + /// If true, this entity can be rotated even while anchored. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("rotateWhileAnchored")] + public bool RotateWhileAnchored { get; protected set; } + + /// + /// If true, will rotate entity in players direction when pulled + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("rotateWhilePulling")] + public bool RotateWhilePulling { get; protected set; } = true; + } +} diff --git a/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs index c89d510046..1e4aa4328c 100644 --- a/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/SharedPullingSystem.cs @@ -1,7 +1,9 @@ #nullable enable +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Content.Shared.GameObjects.Components.Pulling; +using Content.Shared.GameObjects.Components.Rotatable; using Content.Shared.GameObjects.EntitySystemMessages.Pulling; using Content.Shared.GameTicking; using Content.Shared.Input; @@ -11,6 +13,7 @@ using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.Input.Binding; using Robust.Shared.Map; +using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Physics.Dynamics.Joints; using Robust.Shared.Players; @@ -29,6 +32,20 @@ namespace Content.Shared.GameObjects.EntitySystems private readonly HashSet _moving = new(); private readonly HashSet _stoppedMoving = new(); + /// + /// If distance between puller and pulled entity lower that this threshold, + /// pulled entity will not change its rotation. + /// Helps with small distance jittering + /// + private const float ThresholdRotDistance = 1; + + /// + /// If difference between puller and pulled angle lower that this threshold, + /// pulled entity will not change its rotation. + /// Helps with diagonal movement jittering + /// + private const float ThresholdRotAngle = 30; + public IReadOnlySet Moving => _moving; public override void Initialize() @@ -89,6 +106,7 @@ namespace Content.Shared.GameObjects.EntitySystems private void PullerMoved(MoveEvent ev) { + var puller = ev.Sender; if (!TryGetPulled(ev.Sender, out var pulled)) { return; @@ -99,6 +117,8 @@ namespace Content.Shared.GameObjects.EntitySystems return; } + UpdatePulledRotation(puller, pulled); + physics.WakeBody(); if (pulled.TryGetComponent(out SharedPullableComponent? pullable)) @@ -198,5 +218,26 @@ namespace Content.Shared.GameObjects.EntitySystems { return _pullers.ContainsKey(puller); } + + private void UpdatePulledRotation(IEntity puller, IEntity pulled) + { + // TODO: update once ComponentReference works with directed event bus. + if (!pulled.TryGetComponent(out SharedRotatableComponent? rotatable)) + return; + + if (!rotatable.RotateWhilePulling) + return; + + var dir = puller.Transform.WorldPosition - pulled.Transform.WorldPosition; + if (dir.LengthSquared > ThresholdRotDistance * ThresholdRotDistance) + { + var oldAngle = pulled.Transform.WorldRotation; + var newAngle = Angle.FromWorldVec(dir); + + var diff = newAngle - oldAngle; + if (Math.Abs(diff.Degrees) > ThresholdRotAngle) + pulled.Transform.WorldRotation = newAngle; + } + } } }