]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Make trays clientside (#14826)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Fri, 31 Mar 2023 03:40:38 +0000 (14:40 +1100)
committerGitHub <noreply@github.com>
Fri, 31 Mar 2023 03:40:38 +0000 (14:40 +1100)
Content.Client/SubFloor/SubFloorHideSystem.cs
Content.Client/SubFloor/TrayRevealedComponent.cs [new file with mode: 0644]
Content.Client/SubFloor/TrayScannerSystem.cs [new file with mode: 0644]
Content.Server/SubFloor/TrayScannerSystem.cs [new file with mode: 0644]
Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
Content.Shared/SubFloor/SharedTrayScannerSystem.cs [new file with mode: 0644]
Content.Shared/SubFloor/SubFloorHideComponent.cs
Content.Shared/SubFloor/TrayScannerComponent.cs
Content.Shared/SubFloor/TrayScannerSystem.cs [deleted file]

index 0532f177decf22793fc2c6bee331083ba289934f..1d47f93a5a455c295928eafbd8837bb4040aecbc 100644 (file)
@@ -40,16 +40,12 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
         scannerRevealed &= !ShowAll; // no transparency for show-subfloor mode.
 
         var revealed = !covered || ShowAll || scannerRevealed;
-        var transparency = scannerRevealed ? component.ScannerTransparency : 1f;
 
         // set visibility & color of each layer
         foreach (var layer in args.Sprite.AllLayers)
         {
             // pipe connection visuals are updated AFTER this, and may re-hide some layers
             layer.Visible = revealed;
-
-            if (layer.Visible)
-                layer.Color = layer.Color.WithAlpha(transparency);
         }
 
         // Is there some layer that is always visible?
diff --git a/Content.Client/SubFloor/TrayRevealedComponent.cs b/Content.Client/SubFloor/TrayRevealedComponent.cs
new file mode 100644 (file)
index 0000000..e1a8b0c
--- /dev/null
@@ -0,0 +1,10 @@
+namespace Content.Client.SubFloor;
+
+/// <summary>
+/// Added clientside if an entity is revealed for TRay.
+/// </summary>
+[RegisterComponent]
+public sealed class TrayRevealedComponent : Component
+{
+
+}
diff --git a/Content.Client/SubFloor/TrayScannerSystem.cs b/Content.Client/SubFloor/TrayScannerSystem.cs
new file mode 100644 (file)
index 0000000..2f53226
--- /dev/null
@@ -0,0 +1,144 @@
+using Content.Client.Hands;
+using Content.Shared.SubFloor;
+using Robust.Client.Animations;
+using Robust.Client.GameObjects;
+using Robust.Client.Player;
+using Robust.Shared.Map;
+using Robust.Shared.Timing;
+
+namespace Content.Client.SubFloor;
+
+public sealed class TrayScannerSystem : SharedTrayScannerSystem
+{
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly IPlayerManager _player = default!;
+    [Dependency] private readonly AnimationPlayerSystem _animation = default!;
+    [Dependency] private readonly EntityLookupSystem _lookup = default!;
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly SharedTransformSystem _transform = default!;
+
+    private const string TRayAnimationKey = "trays";
+    private const double AnimationLength = 0.5;
+
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        if (!_timing.IsFirstTimePredicted)
+            return;
+
+        // TODO: Multiple viewports or w/e
+        var player = _player.LocalPlayer?.ControlledEntity;
+        var xformQuery = GetEntityQuery<TransformComponent>();
+
+        if (!xformQuery.TryGetComponent(player, out var playerXform))
+            return;
+
+        var playerPos = _transform.GetWorldPosition(playerXform, xformQuery);
+        var playerMap = playerXform.MapID;
+        var range = 0f;
+
+        if (TryComp<HandsComponent>(player, out var playerHands) &&
+            TryComp<TrayScannerComponent>(playerHands.ActiveHandEntity, out var scanner) && scanner.Enabled)
+        {
+            range = scanner.Range;
+
+            foreach (var comp in _lookup.GetComponentsInRange<SubFloorHideComponent>(playerMap, playerPos, range))
+            {
+                var uid = comp.Owner;
+                if (!comp.IsUnderCover || !comp.BlockAmbience | !comp.BlockInteractions)
+                    continue;
+
+                EnsureComp<TrayRevealedComponent>(uid);
+            }
+        }
+
+        var revealedQuery = AllEntityQuery<TrayRevealedComponent, SpriteComponent, TransformComponent>();
+        var subfloorQuery = GetEntityQuery<SubFloorHideComponent>();
+
+        while (revealedQuery.MoveNext(out var uid, out _, out var sprite, out var xform))
+        {
+            var worldPos = _transform.GetWorldPosition(xform, xformQuery);
+
+            // Revealing
+            // Add buffer range to avoid flickers.
+            if (subfloorQuery.HasComponent(uid) &&
+                xform.MapID != MapId.Nullspace &&
+                xform.MapID == playerMap &&
+                xform.Anchored &&
+                range != 0f &&
+                (playerPos - worldPos).Length <= range + 0.5f)
+            {
+                // Due to the fact client is predicting this server states will reset it constantly
+                if ((!_appearance.TryGetData(uid, SubFloorVisuals.ScannerRevealed, out bool value) || !value) &&
+                    sprite.Color.A > SubfloorRevealAlpha)
+                {
+                    sprite.Color = sprite.Color.WithAlpha(0f);
+                }
+
+                SetRevealed(uid, true);
+
+                if (sprite.Color.A >= SubfloorRevealAlpha || _animation.HasRunningAnimation(uid, TRayAnimationKey))
+                    continue;
+
+                _animation.Play(uid, new Animation()
+                {
+                    Length = TimeSpan.FromSeconds(AnimationLength),
+                    AnimationTracks =
+                    {
+                        new AnimationTrackComponentProperty()
+                        {
+                            ComponentType = typeof(SpriteComponent),
+                            Property = nameof(SpriteComponent.Color),
+                            KeyFrames =
+                            {
+                                new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), 0f),
+                                new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(SubfloorRevealAlpha), (float) AnimationLength)
+                            }
+                        }
+                    }
+                }, TRayAnimationKey);
+            }
+            // Hiding
+            else
+            {
+                // Hidden completely so unreveal and reset the alpha.
+                if (sprite.Color.A <= 0f)
+                {
+                    SetRevealed(uid, false);
+                    RemCompDeferred<TrayRevealedComponent>(uid);
+                    sprite.Color = sprite.Color.WithAlpha(1f);
+                    continue;
+                }
+
+                SetRevealed(uid, true);
+
+                if (_animation.HasRunningAnimation(uid, TRayAnimationKey))
+                    continue;
+
+                _animation.Play(uid, new Animation()
+                {
+                    Length = TimeSpan.FromSeconds(AnimationLength),
+                    AnimationTracks =
+                    {
+                        new AnimationTrackComponentProperty()
+                        {
+                            ComponentType = typeof(SpriteComponent),
+                            Property = nameof(SpriteComponent.Color),
+                            KeyFrames =
+                            {
+                                new AnimationTrackProperty.KeyFrame(sprite.Color, 0f),
+                                new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), (float) AnimationLength)
+                            }
+                        }
+                    }
+                }, TRayAnimationKey);
+            }
+        }
+    }
+
+    private void SetRevealed(EntityUid uid, bool value)
+    {
+        _appearance.SetData(uid, SubFloorVisuals.ScannerRevealed, value);
+    }
+}
diff --git a/Content.Server/SubFloor/TrayScannerSystem.cs b/Content.Server/SubFloor/TrayScannerSystem.cs
new file mode 100644 (file)
index 0000000..f93d656
--- /dev/null
@@ -0,0 +1,8 @@
+using Content.Shared.SubFloor;
+
+namespace Content.Server.SubFloor;
+
+public sealed class TrayScannerSystem : SharedTrayScannerSystem
+{
+
+}
index f726827b470ee92d68a929ad086304cd276a32c4..9d2eb3de695907f5c9616b4223537518e9e3865e 100644 (file)
@@ -16,7 +16,6 @@ namespace Content.Shared.SubFloor
     {
         [Dependency] protected readonly IMapManager MapManager = default!;
         [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
-        [Dependency] private readonly TrayScannerSystem _trayScannerSystem = default!;
         [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
         [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
 
@@ -70,7 +69,6 @@ namespace Content.Shared.SubFloor
             if (args.Anchored)
             {
                 var xform = Transform(uid);
-                _trayScannerSystem.OnSubfloorAnchored(uid, component, xform);
                 UpdateFloorCover(uid, component, xform);
             }
             else if (component.IsUnderCover)
@@ -139,37 +137,6 @@ namespace Content.Shared.SubFloor
             }
         }
 
-        /// <summary>
-        ///     This function is used by T-Ray scanners or other sub-floor revealing entities to toggle visibility.
-        /// </summary>
-        public void SetEntitiesRevealed(IEnumerable<EntityUid> entities, EntityUid revealer, bool visible)
-        {
-            foreach (var uid in entities)
-            {
-                SetEntityRevealed(uid, revealer, visible);
-            }
-        }
-
-        /// <summary>
-        ///     This function is used by T-Ray scanners or other sub-floor revealing entities to toggle visibility.
-        /// </summary>
-        public void SetEntityRevealed(EntityUid uid, EntityUid revealer, bool visible, SubFloorHideComponent? hideComp = null)
-        {
-            if (!Resolve(uid, ref hideComp, false))
-                return;
-
-            if (visible)
-            {
-                if (hideComp.RevealedBy.Add(revealer) && hideComp.RevealedBy.Count == 1)
-                    UpdateAppearance(uid, hideComp);
-
-                return;
-            }
-
-            if (hideComp.RevealedBy.Remove(revealer) && hideComp.RevealedBy.Count == 0)
-                UpdateAppearance(uid, hideComp);
-        }
-
         public void UpdateAppearance(
             EntityUid uid,
             SubFloorHideComponent? hideComp = null,
@@ -186,7 +153,6 @@ namespace Content.Shared.SubFloor
             if (Resolve(uid, ref appearance, false))
             {
                 Appearance.SetData(uid, SubFloorVisuals.Covered, hideComp.IsUnderCover, appearance);
-                Appearance.SetData(uid, SubFloorVisuals.ScannerRevealed, hideComp.RevealedBy.Count != 0, appearance);
             }
         }
     }
@@ -194,8 +160,15 @@ namespace Content.Shared.SubFloor
     [Serializable, NetSerializable]
     public enum SubFloorVisuals : byte
     {
-        Covered, // is there a floor tile over this entity
-        ScannerRevealed, // is this entity revealed by a scanner or some other entity?
+        /// <summary>
+        /// Is there a floor tile over this entity
+        /// </summary>
+        Covered,
+
+        /// <summary>
+        /// Is this entity revealed by a scanner or some other entity?
+        /// </summary>
+        ScannerRevealed,
     }
 
     public enum SubfloorLayers : byte
diff --git a/Content.Shared/SubFloor/SharedTrayScannerSystem.cs b/Content.Shared/SubFloor/SharedTrayScannerSystem.cs
new file mode 100644 (file)
index 0000000..1ba88c5
--- /dev/null
@@ -0,0 +1,69 @@
+using Content.Shared.Interaction;
+using Robust.Shared.Containers;
+using Robust.Shared.GameStates;
+using Robust.Shared.Map;
+using Robust.Shared.Serialization;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+using System.Linq;
+
+namespace Content.Shared.SubFloor;
+
+public abstract class SharedTrayScannerSystem : EntitySystem
+{
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+    public const float SubfloorRevealAlpha = 0.8f;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<TrayScannerComponent, ComponentGetState>(OnTrayScannerGetState);
+        SubscribeLocalEvent<TrayScannerComponent, ComponentHandleState>(OnTrayScannerHandleState);
+        SubscribeLocalEvent<TrayScannerComponent, ActivateInWorldEvent>(OnTrayScannerActivate);
+    }
+
+    private void OnTrayScannerActivate(EntityUid uid, TrayScannerComponent scanner, ActivateInWorldEvent args)
+    {
+        SetScannerEnabled(uid, !scanner.Enabled, scanner);
+    }
+
+    private void SetScannerEnabled(EntityUid uid, bool enabled, TrayScannerComponent? scanner = null)
+    {
+        if (!Resolve(uid, ref scanner) || scanner.Enabled == enabled)
+            return;
+
+        scanner.Enabled = enabled;
+        Dirty(scanner);
+
+        // We don't remove from _activeScanners on disabled, because the update function will handle that, as well as
+        // managing the revealed subfloor entities
+
+        if (TryComp<AppearanceComponent>(uid, out var appearance))
+        {
+            _appearance.SetData(uid, TrayScannerVisual.Visual, scanner.Enabled ? TrayScannerVisual.On : TrayScannerVisual.Off, appearance);
+        }
+    }
+
+    private void OnTrayScannerGetState(EntityUid uid, TrayScannerComponent scanner, ref ComponentGetState args)
+    {
+        args.State = new TrayScannerState(scanner.Enabled);
+    }
+
+    private void OnTrayScannerHandleState(EntityUid uid, TrayScannerComponent scanner, ref ComponentHandleState args)
+    {
+        if (args.Current is not TrayScannerState state)
+            return;
+
+        SetScannerEnabled(uid, state.Enabled, scanner);
+    }
+}
+
+[Serializable, NetSerializable]
+public enum TrayScannerVisual : sbyte
+{
+    Visual,
+    On,
+    Off
+}
index e3a170b89d19a694ac23b2e6052e58eb6793c1e1..415b2127e97e94518cd02725fbcaec50d5fbce75 100644 (file)
@@ -39,24 +39,11 @@ namespace Content.Shared.SubFloor
         [DataField("blockAmbience")]
         public bool BlockAmbience { get; set; } = true;
 
-        /// <summary>
-        ///     When revealed using some scanning tool, what transparency should be used to draw this item?
-        /// </summary>
-        [DataField("scannerTransparency")]
-        public float ScannerTransparency = 0.8f;
-
         /// <summary>
         ///     Sprite layer keys for the layers that are always visible, even if the entity is below a floor tile. E.g.,
         ///     the vent part of a vent is always visible, even though the piping is hidden.
         /// </summary>
         [DataField("visibleLayers")]
         public HashSet<Enum> VisibleLayers = new() { SubfloorLayers.FirstLayer };
-
-        /// <summary>
-        ///     The entities this subfloor is revealed by.
-        /// </summary>
-        [ViewVariables]
-        [Access(typeof(SharedSubFloorHideSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends
-        public HashSet<EntityUid> RevealedBy { get; set; } = new();
     }
 }
index c6bc3d46f31889412d4ab2129de0dc652852a3a5..811d120a1daf8b7d57fc79ee41bc2984268bc20f 100644 (file)
@@ -3,33 +3,19 @@ using Robust.Shared.Serialization;
 
 namespace Content.Shared.SubFloor;
 
-[RegisterComponent]
-[NetworkedComponent]
+[RegisterComponent, NetworkedComponent]
 public sealed class TrayScannerComponent : Component
 {
     /// <summary>
     ///     Whether the scanner is currently on.
     /// </summary>
-    [ViewVariables]
-    public bool Enabled { get; set; }
-
-    /// <summary>
-    ///     Last position of the scanner. Rounded to integers to avoid excessive entity lookups when moving.
-    /// </summary>
-    [ViewVariables]
-    public Vector2i? LastLocation { get; set; }
+    [ViewVariables, DataField("enabled")] public bool Enabled;
 
     /// <summary>
     ///     Radius in which the scanner will reveal entities. Centered on the <see cref="LastLocation"/>.
     /// </summary>
-    [DataField("range")]
-    public float Range { get; set; } = 2.5f;
-
-    /// <summary>
-    ///     The sub-floor entities that this scanner is currently revealing.
-    /// </summary>
-    [ViewVariables]
-    public HashSet<EntityUid> RevealedSubfloors = new();
+    [ViewVariables(VVAccess.ReadWrite), DataField("range")]
+    public float Range = 4f;
 }
 
 [Serializable, NetSerializable]
diff --git a/Content.Shared/SubFloor/TrayScannerSystem.cs b/Content.Shared/SubFloor/TrayScannerSystem.cs
deleted file mode 100644 (file)
index c9eecb3..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-using Content.Shared.Interaction;
-using Robust.Shared.Containers;
-using Robust.Shared.GameStates;
-using Robust.Shared.Map;
-using Robust.Shared.Serialization;
-using Robust.Shared.Timing;
-using Robust.Shared.Utility;
-using System.Linq;
-
-namespace Content.Shared.SubFloor;
-
-public sealed class TrayScannerSystem : EntitySystem
-{
-    [Dependency] private readonly IMapManager _mapManager = default!;
-    [Dependency] private readonly IGameTiming _gameTiming = default!;
-    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
-    [Dependency] private readonly SharedSubFloorHideSystem _subfloorSystem = default!;
-    [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
-    [Dependency] private readonly SharedTransformSystem _transform = default!;
-
-    private HashSet<EntityUid> _activeScanners = new();
-    private RemQueue<EntityUid> _invalidScanners = new();
-
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<TrayScannerComponent, ComponentShutdown>(OnComponentShutdown);
-        SubscribeLocalEvent<TrayScannerComponent, ComponentGetState>(OnTrayScannerGetState);
-        SubscribeLocalEvent<TrayScannerComponent, ComponentHandleState>(OnTrayScannerHandleState);
-        SubscribeLocalEvent<TrayScannerComponent, ActivateInWorldEvent>(OnTrayScannerActivate);
-    }
-
-    private void OnTrayScannerActivate(EntityUid uid, TrayScannerComponent scanner, ActivateInWorldEvent args)
-    {
-        SetScannerEnabled(uid, !scanner.Enabled, scanner);
-    }
-
-    private void SetScannerEnabled(EntityUid uid, bool enabled, TrayScannerComponent? scanner = null)
-    {
-        if (!Resolve(uid, ref scanner))
-            return;
-
-        scanner.Enabled = enabled;
-        Dirty(scanner);
-
-        if (scanner.Enabled)
-            _activeScanners.Add(uid);
-
-        // We don't remove from _activeScanners on disabled, because the update function will handle that, as well as
-        // managing the revealed subfloor entities
-
-        if (EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
-        {
-            _appearance.SetData(uid, TrayScannerVisual.Visual, scanner.Enabled ? TrayScannerVisual.On : TrayScannerVisual.Off, appearance);
-        }
-    }
-
-    private void OnTrayScannerGetState(EntityUid uid, TrayScannerComponent scanner, ref ComponentGetState args)
-    {
-        args.State = new TrayScannerState(scanner.Enabled);
-    }
-
-    private void OnTrayScannerHandleState(EntityUid uid, TrayScannerComponent scanner, ref ComponentHandleState args)
-    {
-        if (args.Current is not TrayScannerState state)
-            return;
-
-        SetScannerEnabled(uid, state.Enabled, scanner);
-
-        // This is hacky and somewhat inefficient for the client. But when resetting predicted entities we have to unset
-        // last position. This is because appearance data gets reset, but if the position isn't reset the scanner won't
-        // re-reveal entities leading to odd visuals.
-        scanner.LastLocation = null;
-    }
-
-    public void OnComponentShutdown(EntityUid uid, TrayScannerComponent scanner, ComponentShutdown args)
-    {
-        _subfloorSystem.SetEntitiesRevealed(scanner.RevealedSubfloors, uid, false);
-        _activeScanners.Remove(uid);
-    }
-
-    public override void Update(float frameTime)
-    {
-        if (!_gameTiming.IsFirstTimePredicted)
-            return;
-
-        if (!_activeScanners.Any())
-            return;
-
-        foreach (var scanner in _activeScanners)
-        {
-            if (_invalidScanners.List != null
-                && _invalidScanners.List.Contains(scanner))
-                continue;
-
-            if (!UpdateTrayScanner(scanner))
-                _invalidScanners.Add(scanner);
-        }
-
-        foreach (var invalidScanner in _invalidScanners)
-        {
-            _activeScanners.Remove(invalidScanner);
-        }
-
-        _invalidScanners.List?.Clear();
-    }
-
-    /// <summary>
-    ///     When a subfloor entity gets anchored (which includes spawning & coming into PVS range), Check for nearby scanners.
-    /// </summary>
-    public void OnSubfloorAnchored(EntityUid uid, SubFloorHideComponent? hideComp = null, TransformComponent? xform = null)
-    {
-        if (!Resolve(uid, ref hideComp, ref xform))
-            return;
-
-        var pos = xform.MapPosition;
-
-        foreach (var entity in _activeScanners)
-        {
-            if (!TryComp(entity, out TrayScannerComponent? scanner))
-                continue;
-
-            if (!Transform(entity).MapPosition.InRange(pos, scanner.Range))
-                continue;
-
-            hideComp.RevealedBy.Add(entity);
-            scanner.RevealedSubfloors.Add(uid);
-        }
-    }
-
-    /// <summary>
-    ///     Updates a T-Ray scanner. Should be called on immediate
-    ///     state change (turned on/off), or during the update
-    ///     loop.
-    /// </summary>
-    /// <returns>true if the update was successful, false otherwise</returns>
-    private bool UpdateTrayScanner(EntityUid uid, TrayScannerComponent? scanner = null, TransformComponent? transform = null)
-    {
-        if (!Resolve(uid, ref scanner, ref transform))
-            return false;
-
-        // if the scanner was toggled off recently,
-        // set all the known subfloor to invisible,
-        // and return false so it's removed from
-        // the active scanner list
-        if (!scanner.Enabled || transform.MapID == MapId.Nullspace)
-        {
-            _subfloorSystem.SetEntitiesRevealed(scanner.RevealedSubfloors, uid, false);
-            scanner.LastLocation = null;
-            scanner.RevealedSubfloors.Clear();
-            return false;
-        }
-
-        var pos = transform.LocalPosition;
-        var parent = _transform.GetParent(transform);
-
-        // zero vector implies container
-        //
-        // this means we should get the entity transform's parent
-        if (pos == Vector2.Zero
-            && parent != null
-            && _containerSystem.ContainsEntity(transform.ParentUid, uid))
-        {
-            pos = parent.LocalPosition;
-
-            // if this is also zero, we can check one more time
-            //
-            // could recurse through fully but i think that's useless,
-            // just attempt to check through the gp's transform and if
-            // that doesn't work, just don't bother any further
-            if (pos == Vector2.Zero)
-            {
-                var gpTransform = _transform.GetParent(parent);
-                if (gpTransform != null
-                    && _containerSystem.ContainsEntity(gpTransform.Owner, transform.ParentUid))
-                {
-                    pos = gpTransform.LocalPosition;
-                }
-            }
-        }
-
-        // is the position still logically zero? just clear,
-        // but we need to keep it as 'true' since this t-ray
-        // is still technically on
-        if (pos == Vector2.Zero)
-        {
-            _subfloorSystem.SetEntitiesRevealed(scanner.RevealedSubfloors, uid, false);
-            scanner.RevealedSubfloors.Clear();
-            return true;
-        }
-
-        // get the rounded position so that small movements don't cause this to
-        // update every time
-        var flooredPos = (Vector2i) pos;
-
-        // MAYBE redo this. Currently different players can see different entities
-        //
-        // Here we avoid the entity lookup & return early if the scanner's position hasn't appreciably changed. However,
-        // if a new player enters PVS-range, they will update the in-range entities on their end and use that to set
-        // LastLocation. This means that different players can technically see different entities being revealed by the
-        // same scanner. The correct fix for this is probably just to network the revealed entity set.... But I CBF
-        // doing that right now....
-        if (flooredPos == scanner.LastLocation
-            || float.IsNaN(flooredPos.X) && float.IsNaN(flooredPos.Y))
-            return true;
-
-        scanner.LastLocation = flooredPos;
-
-        //  Update entities in Range
-        HashSet<EntityUid> nearby = new();
-        var coords = transform.MapPosition;
-        var worldBox = Box2.CenteredAround(coords.Position, (scanner.Range * 2, scanner.Range * 2));
-
-        // For now, limiting to the scanner's own grid. We could do a grid-lookup, but then what do we do if one grid
-        // flies away, while the scanner's local-position remains unchanged?
-        if (_mapManager.TryGetGrid(transform.GridUid, out var grid))
-        {
-            foreach (var entity in grid.GetAnchoredEntities(worldBox))
-            {
-                if (!Transform(entity).MapPosition.InRange(coords, scanner.Range))
-                    continue;
-
-                if (!TryComp(entity, out SubFloorHideComponent? hideComp))
-                    continue; // Not a hide-able entity.
-
-                nearby.Add(entity);
-
-                if (scanner.RevealedSubfloors.Add(entity))
-                    _subfloorSystem.SetEntityRevealed(entity, uid, true, hideComp);
-            }
-        }
-
-        // get all the old elements that are no longer detected
-        HashSet<EntityUid> missing = new(scanner.RevealedSubfloors.Except(nearby));
-
-        // remove those from the list
-        scanner.RevealedSubfloors.ExceptWith(missing);
-
-        // and hide them
-        _subfloorSystem.SetEntitiesRevealed(missing, uid, false);
-
-        return true;
-    }
-}
-
-[Serializable, NetSerializable]
-public enum TrayScannerVisual : sbyte
-{
-    Visual,
-    On,
-    Off
-}