]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Travelling pointing arrows, brains can no longer point (#24864)
authorKrunklehorn <42424291+Krunklehorn@users.noreply.github.com>
Sat, 3 Feb 2024 08:09:20 +0000 (03:09 -0500)
committerGitHub <noreply@github.com>
Sat, 3 Feb 2024 08:09:20 +0000 (19:09 +1100)
* Decoupled from gravity, constant animation time, manual networking, cubic interpolation

* Reduced overshoot

* Implemented PointAttemptEvent, reacts with mobstate & sleeping

* Brains can no longer point, PBs must be inside a chassis

* Removed chassis check, made callback more obvious

Content.Client/Pointing/Components/PointingArrowComponent.cs
Content.Client/Pointing/PointingSystem.Visualizer.cs [new file with mode: 0644]
Content.Client/Pointing/PointingSystem.cs
Content.Server/Body/Systems/BrainSystem.cs
Content.Server/Pointing/EntitySystems/PointingSystem.cs
Content.Server/Silicons/Borgs/BorgSystem.cs
Content.Shared/Bed/Sleep/SharedSleepingSystem.cs
Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
Content.Shared/Pointing/Components/SharedPointingArrowComponent.cs
Content.Shared/Pointing/SharedPointingSystem.cs

index 0d3bc4a5cc2350475653256fcf63998e998a4334..4156f84aac75aa7193919214dbf5b65f3dbe506a 100644 (file)
@@ -1,19 +1,12 @@
-using System.Numerics;
 using Content.Shared.Pointing.Components;
+using System.Numerics;
 
 namespace Content.Client.Pointing.Components;
 [RegisterComponent]
 public sealed partial class PointingArrowComponent : SharedPointingArrowComponent
 {
     /// <summary>
-    /// How long it takes to go from the bottom of the animation to the top.
-    /// </summary>
-    [ViewVariables(VVAccess.ReadWrite)]
-    [DataField("animationTime")]
-    public float AnimationTime = 0.5f;
-
-    /// <summary>
-    /// How far it goes in any direction.
+    /// How far the arrow moves up and down during the floating phase.
     /// </summary>
     [ViewVariables(VVAccess.ReadWrite)]
     [DataField("offset")]
diff --git a/Content.Client/Pointing/PointingSystem.Visualizer.cs b/Content.Client/Pointing/PointingSystem.Visualizer.cs
new file mode 100644 (file)
index 0000000..63ce882
--- /dev/null
@@ -0,0 +1,62 @@
+using Content.Client.Pointing.Components;
+using Content.Shared.Pointing;
+using Robust.Client.GameObjects;
+using Robust.Client.Animations;
+using Robust.Shared.Animations;
+using System.Numerics;
+
+namespace Content.Client.Pointing;
+
+public sealed partial class PointingSystem : SharedPointingSystem
+{
+    [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
+
+    public void InitializeVisualizer()
+    {
+        SubscribeLocalEvent<PointingArrowComponent, AnimationCompletedEvent>(OnAnimationCompleted);
+    }
+
+    private void OnAnimationCompleted(EntityUid uid, PointingArrowComponent component, AnimationCompletedEvent args)
+    {
+        if (args.Key == component.AnimationKey)
+            _animationPlayer.Stop(uid, component.AnimationKey);
+    }
+
+    private void BeginPointAnimation(EntityUid uid, Vector2 startPosition, Vector2 offset, string animationKey)
+    {
+        if (_animationPlayer.HasRunningAnimation(uid, animationKey))
+            return;
+
+        var animation = new Animation
+        {
+            Length = PointDuration,
+            AnimationTracks =
+            {
+                new AnimationTrackComponentProperty
+                {
+                    ComponentType = typeof(SpriteComponent),
+                    Property = nameof(SpriteComponent.Offset),
+                    InterpolationMode = AnimationInterpolationMode.Cubic,
+                    KeyFrames =
+                    {
+                        // We pad here to prevent improper looping and tighten the overshoot, just a touch
+                        new AnimationTrackProperty.KeyFrame(startPosition, 0f),
+                        new AnimationTrackProperty.KeyFrame(Vector2.Lerp(startPosition, offset, 0.9f), PointKeyTimeMove),
+                        new AnimationTrackProperty.KeyFrame(offset, PointKeyTimeMove),
+                        new AnimationTrackProperty.KeyFrame(Vector2.Zero, PointKeyTimeMove),
+                        new AnimationTrackProperty.KeyFrame(offset, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(Vector2.Zero, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(offset, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(Vector2.Zero, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(offset, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(Vector2.Zero, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(offset, PointKeyTimeHover),
+                        new AnimationTrackProperty.KeyFrame(Vector2.Zero, PointKeyTimeHover),
+                    }
+                }
+            }
+        };
+
+        _animationPlayer.Play(uid, animation, animationKey);
+    }
+}
index 82b12fbf36a69176498e7b8664ca722b7d6ceb0e..a86b6e21b52261fe167ac169a40613af609a8300 100644 (file)
@@ -1,32 +1,25 @@
 using Content.Client.Pointing.Components;
-using Content.Client.Gravity;
-using Content.Shared.Mobs.Systems;
 using Content.Shared.Pointing;
 using Content.Shared.Verbs;
 using Robust.Client.GameObjects;
+using Robust.Shared.GameStates;
 using Robust.Shared.Utility;
 using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
 
 namespace Content.Client.Pointing;
 
-public sealed class PointingSystem : SharedPointingSystem
+public sealed partial class PointingSystem : SharedPointingSystem
 {
-    [Dependency] private readonly MobStateSystem _mobState = default!;
-    [Dependency] private readonly FloatingVisualizerSystem _floatingSystem = default!;
-
     public override void Initialize()
     {
         base.Initialize();
 
         SubscribeLocalEvent<GetVerbsEvent<Verb>>(AddPointingVerb);
         SubscribeLocalEvent<PointingArrowComponent, ComponentStartup>(OnArrowStartup);
-        SubscribeLocalEvent<PointingArrowComponent, AnimationCompletedEvent>(OnArrowAnimation);
         SubscribeLocalEvent<RoguePointingArrowComponent, ComponentStartup>(OnRogueArrowStartup);
-    }
+        SubscribeLocalEvent<PointingArrowComponent, ComponentHandleState>(HandleCompState);
 
-    private void OnArrowAnimation(EntityUid uid, PointingArrowComponent component, AnimationCompletedEvent args)
-    {
-        _floatingSystem.FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
+        InitializeVisualizer();
     }
 
     private void AddPointingVerb(GetVerbsEvent<Verb> args)
@@ -38,15 +31,11 @@ public sealed class PointingSystem : SharedPointingSystem
         // I'm just adding this verb exclusively to clients so that the verb-loading pop-in on the verb menu isn't
         // as bad. Important for this verb seeing as its usually an option on just about any entity.
 
+        // this is a pointing arrow. no pointing here...
         if (HasComp<PointingArrowComponent>(args.Target))
-        {
-            // this is a pointing arrow. no pointing here...
             return;
-        }
 
-        // Can the user point? Checking mob state directly instead of some action blocker, as many action blockers are blocked for
-        // ghosts and there is no obvious choice for pointing (unless ghosts CanEmote?).
-        if (_mobState.IsIncapacitated(args.User))
+        if (!CanPoint(args.User))
             return;
 
         // We won't check in range or visibility, as this verb is currently only executable via the context menu,
@@ -66,11 +55,9 @@ public sealed class PointingSystem : SharedPointingSystem
     private void OnArrowStartup(EntityUid uid, PointingArrowComponent component, ComponentStartup args)
     {
         if (TryComp<SpriteComponent>(uid, out var sprite))
-        {
             sprite.DrawDepth = (int) DrawDepth.Overlays;
-        }
 
-        _floatingSystem.FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime);
+        BeginPointAnimation(uid, component.StartPosition, component.Offset, component.AnimationKey);
     }
 
     private void OnRogueArrowStartup(EntityUid uid, RoguePointingArrowComponent arrow, ComponentStartup args)
@@ -81,4 +68,13 @@ public sealed class PointingSystem : SharedPointingSystem
             sprite.NoRotation = false;
         }
     }
+
+    private void HandleCompState(Entity<PointingArrowComponent> entity, ref ComponentHandleState args)
+    {
+        if (args.Current is not SharedPointingArrowComponentState state)
+            return;
+
+        entity.Comp.StartPosition = state.StartPosition;
+        entity.Comp.EndTime = state.EndTime;
+    }
 }
index b55274808d76c173dd1ed406e097bdc14fae969e..abb54971209229cc0dfa06f553fd2d9c598c8ed8 100644 (file)
@@ -4,6 +4,7 @@ using Content.Shared.Body.Components;
 using Content.Shared.Body.Events;
 using Content.Shared.Mind;
 using Content.Shared.Mind.Components;
+using Content.Shared.Pointing;
 
 namespace Content.Server.Body.Systems
 {
@@ -17,6 +18,7 @@ namespace Content.Server.Body.Systems
 
             SubscribeLocalEvent<BrainComponent, AddedToPartInBodyEvent>((uid, _, args) => HandleMind(args.Body, uid));
             SubscribeLocalEvent<BrainComponent, RemovedFromPartInBodyEvent>((uid, _, args) => HandleMind(uid, args.OldBody));
+            SubscribeLocalEvent<BrainComponent, PointAttemptEvent>(OnPointAttempt);
         }
 
         private void HandleMind(EntityUid newEntity, EntityUid oldEntity)
@@ -36,5 +38,10 @@ namespace Content.Server.Body.Systems
 
             _mindSystem.TransferTo(mindId, newEntity, mind: mind);
         }
+
+        private void OnPointAttempt(EntityUid uid, BrainComponent component, PointAttemptEvent args)
+        {
+            args.Cancel();
+        }
     }
 }
index 6fcdfcf994b2f6949d9d19b96717273efe4d1dc8..a7c455e6a5d3c89e317ad64c0f5fc38343dda8c9 100644 (file)
@@ -1,7 +1,6 @@
 using System.Linq;
 using Content.Server.Administration.Logs;
 using Content.Server.Pointing.Components;
-using Content.Shared.Bed.Sleep;
 using Content.Shared.Database;
 using Content.Shared.Examine;
 using Content.Shared.Eye;
@@ -10,13 +9,13 @@ using Content.Shared.IdentityManagement;
 using Content.Shared.Input;
 using Content.Shared.Interaction;
 using Content.Shared.Mind;
-using Content.Shared.Mobs.Systems;
 using Content.Shared.Pointing;
 using Content.Shared.Popups;
 using JetBrains.Annotations;
 using Robust.Server.GameObjects;
 using Robust.Server.Player;
 using Robust.Shared.Enums;
+using Robust.Shared.GameStates;
 using Robust.Shared.Input.Binding;
 using Robust.Shared.Map;
 using Robust.Shared.Player;
@@ -34,7 +33,6 @@ namespace Content.Server.Pointing.EntitySystems
         [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
         [Dependency] private readonly IGameTiming _gameTiming = default!;
         [Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
-        [Dependency] private readonly MobStateSystem _mobState = default!;
         [Dependency] private readonly SharedPopupSystem _popup = default!;
         [Dependency] private readonly VisibilitySystem _visibilitySystem = default!;
         [Dependency] private readonly SharedMindSystem _minds = default!;
@@ -50,6 +48,15 @@ namespace Content.Server.Pointing.EntitySystems
 
         private const float PointingRange = 15f;
 
+        private void GetCompState(Entity<PointingArrowComponent> entity, ref ComponentGetState args)
+        {
+            args.State = new SharedPointingArrowComponentState
+            {
+                StartPosition = entity.Comp.StartPosition,
+                EndTime = entity.Comp.EndTime
+            };
+        }
+
         private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
         {
             if (e.NewStatus != SessionStatus.Disconnected)
@@ -97,7 +104,7 @@ namespace Content.Server.Pointing.EntitySystems
             }
         }
 
-        public bool TryPoint(ICommonSession? session, EntityCoordinates coords, EntityUid pointed)
+        public bool TryPoint(ICommonSession? session, EntityCoordinates coordsPointed, EntityUid pointed)
         {
             if (session?.AttachedEntity is not { } player)
             {
@@ -105,9 +112,9 @@ namespace Content.Server.Pointing.EntitySystems
                 return false;
             }
 
-            if (!coords.IsValid(EntityManager))
+            if (!coordsPointed.IsValid(EntityManager))
             {
-                Log.Warning($"Player {ToPrettyString(player)} attempted to point at invalid coordinates: {coords}");
+                Log.Warning($"Player {ToPrettyString(player)} attempted to point at invalid coordinates: {coordsPointed}");
                 return false;
             }
 
@@ -123,33 +130,30 @@ namespace Content.Server.Pointing.EntitySystems
                 return false;
             }
 
-            // Checking mob state directly instead of some action blocker, as many action blockers are blocked for
-            // ghosts and there is no obvious choice for pointing.
-            if (_mobState.IsIncapacitated(player))
-            {
-                return false;
-            }
-
-            if (HasComp<SleepingComponent>(player))
+            if (!CanPoint(player))
             {
                 return false;
             }
 
-            if (!InRange(player, coords))
+            if (!InRange(player, coordsPointed))
             {
                 _popup.PopupEntity(Loc.GetString("pointing-system-try-point-cannot-reach"), player, player);
                 return false;
             }
 
+            var mapCoordsPointed = coordsPointed.ToMap(EntityManager);
+            _rotateToFaceSystem.TryFaceCoordinates(player, mapCoordsPointed.Position);
 
-            var mapCoords = coords.ToMap(EntityManager);
-            _rotateToFaceSystem.TryFaceCoordinates(player, mapCoords.Position);
-
-            var arrow = EntityManager.SpawnEntity("PointingArrow", coords);
+            var arrow = EntityManager.SpawnEntity("PointingArrow", coordsPointed);
 
             if (TryComp<PointingArrowComponent>(arrow, out var pointing))
             {
-                pointing.EndTime = _gameTiming.CurTime + TimeSpan.FromSeconds(4);
+                if (TryComp(player, out TransformComponent? xformPlayer))
+                    pointing.StartPosition = EntityCoordinates.FromMap(arrow, xformPlayer.Coordinates.ToMap(EntityManager)).Position;
+
+                pointing.EndTime = _gameTiming.CurTime + PointDuration;
+
+                Dirty(arrow, pointing);
             }
 
             if (EntityQuery<PointingArrowAngeringComponent>().FirstOrDefault() != null)
@@ -215,10 +219,10 @@ namespace Content.Server.Pointing.EntitySystems
                 TileRef? tileRef = null;
                 string? position = null;
 
-                if (_mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid))
+                if (_mapManager.TryFindGridAt(mapCoordsPointed, out var gridUid, out var grid))
                 {
-                    position = $"EntId={gridUid} {grid.WorldToTile(mapCoords.Position)}";
-                    tileRef = grid.GetTileRef(grid.WorldToTile(mapCoords.Position));
+                    position = $"EntId={gridUid} {grid.WorldToTile(mapCoordsPointed.Position)}";
+                    tileRef = grid.GetTileRef(grid.WorldToTile(mapCoordsPointed.Position));
                 }
 
                 var tileDef = _tileDefinitionManager[tileRef?.Tile.TypeId ?? 0];
@@ -228,7 +232,7 @@ namespace Content.Server.Pointing.EntitySystems
 
                 viewerMessage = Loc.GetString("pointing-system-other-point-at-tile", ("otherName", playerName), ("tileName", name));
 
-                _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):user} pointed at {name} {(position == null ? mapCoords : position)}");
+                _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):user} pointed at {name} {(position == null ? mapCoordsPointed : position)}");
             }
 
             _pointers[session] = _gameTiming.CurTime;
@@ -242,6 +246,8 @@ namespace Content.Server.Pointing.EntitySystems
         {
             base.Initialize();
 
+            SubscribeLocalEvent<PointingArrowComponent, ComponentGetState>(GetCompState);
+
             SubscribeNetworkEvent<PointingAttemptEvent>(OnPointAttempt);
 
             _playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
@@ -255,8 +261,8 @@ namespace Content.Server.Pointing.EntitySystems
         {
             var target = GetEntity(ev.Target);
 
-            if (TryComp(target, out TransformComponent? xform))
-                TryPoint(args.SenderSession, xform.Coordinates, target);
+            if (TryComp(target, out TransformComponent? xformTarget))
+                TryPoint(args.SenderSession, xformTarget.Coordinates, target);
             else
                 Log.Warning($"User {args.SenderSession} attempted to point at a non-existent entity uid: {ev.Target}");
         }
index 0efbe1a40ab7e52d5088e880b4588dc7ea71fb70..869c2797047ddf8c623f24d36643a219b52e9de1 100644 (file)
@@ -14,6 +14,7 @@ using Content.Shared.Mind.Components;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Systems;
 using Content.Shared.Movement.Systems;
+using Content.Shared.Pointing;
 using Content.Shared.PowerCell;
 using Content.Shared.PowerCell.Components;
 using Content.Shared.Roles;
@@ -67,6 +68,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
         SubscribeLocalEvent<BorgChassisComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
 
         SubscribeLocalEvent<BorgBrainComponent, MindAddedMessage>(OnBrainMindAdded);
+        SubscribeLocalEvent<BorgBrainComponent, PointAttemptEvent>(OnBrainPointAttempt);
 
         InitializeModules();
         InitializeMMI();
@@ -242,6 +244,11 @@ public sealed partial class BorgSystem : SharedBorgSystem
         _mind.TransferTo(mindId, containerEnt, mind: mind);
     }
 
+    private void OnBrainPointAttempt(EntityUid uid, BorgBrainComponent component, PointAttemptEvent args)
+    {
+        args.Cancel();
+    }
+
     private void UpdateBatteryAlert(EntityUid uid, PowerCellSlotComponent? slotComponent = null)
     {
         if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery, slotComponent))
index 2ac1c372ca6754d91e368a51423da566edc7e9b6..505b2a18e7b96ab170ff3ac97416a9edb12f322d 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Actions;
 using Content.Shared.Bed.Sleep;
 using Content.Shared.Damage.ForceSay;
 using Content.Shared.Eye.Blinding.Systems;
+using Content.Shared.Pointing;
 using Content.Shared.Speech;
 using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
@@ -25,6 +26,7 @@ namespace Content.Server.Bed.Sleep
             SubscribeLocalEvent<SleepingComponent, ComponentShutdown>(OnShutdown);
             SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
             SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
+            SubscribeLocalEvent<SleepingComponent, PointAttemptEvent>(OnPointAttempt);
             SubscribeLocalEvent<SleepingComponent, EntityUnpausedEvent>(OnSleepUnpaused);
         }
 
@@ -70,6 +72,11 @@ namespace Content.Server.Bed.Sleep
             if (component.LifeStage <= ComponentLifeStage.Running)
                 args.Cancel();
         }
+
+        private void OnPointAttempt(EntityUid uid, SleepingComponent component, PointAttemptEvent args)
+        {
+            args.Cancel();
+        }
     }
 }
 
index 8ce12db51838cb4486823be5f81e5e9b226dd9f4..51991332539e57597a3784d0ddff1612191cd594 100644 (file)
@@ -9,6 +9,7 @@ using Content.Shared.Inventory.Events;
 using Content.Shared.Item;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Movement.Events;
+using Content.Shared.Pointing;
 using Content.Shared.Pulling.Events;
 using Content.Shared.Speech;
 using Content.Shared.Standing;
@@ -38,6 +39,7 @@ public partial class MobStateSystem
         SubscribeLocalEvent<MobStateComponent, StartPullAttemptEvent>(CheckAct);
         SubscribeLocalEvent<MobStateComponent, UpdateCanMoveEvent>(CheckAct);
         SubscribeLocalEvent<MobStateComponent, StandAttemptEvent>(CheckAct);
+        SubscribeLocalEvent<MobStateComponent, PointAttemptEvent>(CheckAct);
         SubscribeLocalEvent<MobStateComponent, TryingToSleepEvent>(OnSleepAttempt);
         SubscribeLocalEvent<MobStateComponent, CombatModeShouldHandInteractEvent>(OnCombatModeShouldHandInteract);
         SubscribeLocalEvent<MobStateComponent, AttemptPacifiedAttackEvent>(OnAttemptPacifiedAttack);
index 07613c77463bc772edcf85624602fe804bc6f4bd..66cca50c2ed0c22db83e2784bdc1809221b2c4e3 100644 (file)
@@ -1,13 +1,22 @@
 using Robust.Shared.GameStates;
+using System.Numerics;
 
 namespace Content.Shared.Pointing.Components;
 
 [NetworkedComponent]
 public abstract partial class SharedPointingArrowComponent : Component
 {
+    /// <summary>
+    /// The position of the sender when the point began.
+    /// </summary>
+    [DataField]
+    [ViewVariables(VVAccess.ReadWrite)]
+    public Vector2 StartPosition;
+
     /// <summary>
     /// When the pointing arrow ends
     /// </summary>
-    [ViewVariables(VVAccess.ReadWrite), DataField("endTime")]
+    [DataField]
+    [ViewVariables(VVAccess.ReadWrite)]
     public TimeSpan EndTime;
 }
index 05e4b4aa27a1b593c2aafb6761e756f6fd433770..bb3436a14b5d924e60405d180f7419e2a4ea6dc8 100644 (file)
@@ -1,17 +1,36 @@
 using Robust.Shared.Serialization;
+using System.Numerics;
 
 namespace Content.Shared.Pointing;
 
 public abstract class SharedPointingSystem : EntitySystem
 {
+    protected readonly TimeSpan PointDuration = TimeSpan.FromSeconds(4);
+    protected readonly float PointKeyTimeMove = 0.1f;
+    protected readonly float PointKeyTimeHover = 0.5f;
+
     [Serializable, NetSerializable]
-    protected sealed class PointingArrowComponentState : ComponentState
+    public sealed class SharedPointingArrowComponentState : ComponentState
     {
-        public TimeSpan EndTime;
+        public Vector2 StartPosition { get; init; }
+        public TimeSpan EndTime { get; init; }
+    }
+
+    public bool CanPoint(EntityUid uid)
+    {
+        var ev = new PointAttemptEvent(uid);
+        RaiseLocalEvent(uid, ev, true);
+
+        return !ev.Cancelled;
+    }
+}
 
-        public PointingArrowComponentState(TimeSpan endTime)
-        {
-            EndTime = endTime;
-        }
+public sealed class PointAttemptEvent : CancellableEntityEventArgs
+{
+    public PointAttemptEvent(EntityUid uid)
+    {
+        Uid = uid;
     }
+
+    public EntityUid Uid { get; }
 }