]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Sloth's subfloor vismask adventure (#35347)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Thu, 20 Mar 2025 13:57:04 +0000 (00:57 +1100)
committerGitHub <noreply@github.com>
Thu, 20 Mar 2025 13:57:04 +0000 (00:57 +1100)
* Add a subfloor vismask

Significantly cuts down on sent entity count.

* More optimisations

* Fix command

* Fixes

* namespace cleanup

* Review

* Vismasks

* Content update

* Bandaid

* awewa

* Revert these

* reh

* Update Content.Shared/SubFloor/TrayScannerComponent.cs

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
22 files changed:
Content.Client/SubFloor/SubFloorHideSystem.cs
Content.Client/UserInterface/Systems/Sandbox/SandboxUIController.cs
Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml.cs
Content.IntegrationTests/Tests/PrototypeSaveTest.cs
Content.Server/Ghost/GhostSystem.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.cs
Content.Server/SubFloor/SubFloorHideSystem.cs
Content.Shared/Eye/VisibilityFlags.cs
Content.Shared/Ghost/GhostComponent.cs
Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
Content.Shared/SubFloor/SharedTrayScannerSystem.cs
Content.Shared/SubFloor/SubFloorHideComponent.cs
Content.Shared/SubFloor/TrayScannerComponent.cs
Content.Shared/SubFloor/TrayScannerUserComponent.cs [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/trinary.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml
Resources/Prototypes/Entities/Structures/Power/cable_terminal.yml
Resources/Prototypes/Entities/Structures/Power/cables.yml

index df65717c40596fe1783585683526af8a8b10739c..997d375fbee62a1dd636de8bd15ef6b6e52ee596 100644 (file)
@@ -1,12 +1,15 @@
-using Content.Shared.DrawDepth;
+using Content.Client.UserInterface.Systems.Sandbox;
 using Content.Shared.SubFloor;
 using Robust.Client.GameObjects;
+using Robust.Client.UserInterface;
+using Robust.Shared.Player;
 
 namespace Content.Client.SubFloor;
 
 public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
 {
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly IUserInterfaceManager _ui = default!;
 
     private bool _showAll;
 
@@ -18,8 +21,13 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
         {
             if (_showAll == value) return;
             _showAll = value;
+            _ui.GetUIController<SandboxUIController>().SetToggleSubfloors(value);
 
-            UpdateAll();
+            var ev = new ShowSubfloorRequestEvent()
+            {
+                Value = value,
+            };
+            RaiseNetworkEvent(ev);
         }
     }
 
@@ -28,6 +36,20 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
         base.Initialize();
 
         SubscribeLocalEvent<SubFloorHideComponent, AppearanceChangeEvent>(OnAppearanceChanged);
+        SubscribeNetworkEvent<ShowSubfloorRequestEvent>(OnRequestReceived);
+        SubscribeLocalEvent<LocalPlayerDetachedEvent>(OnPlayerDetached);
+    }
+
+    private void OnPlayerDetached(LocalPlayerDetachedEvent ev)
+    {
+        // Vismask resets so need to reset this.
+        ShowAll = false;
+    }
+
+    private void OnRequestReceived(ShowSubfloorRequestEvent ev)
+    {
+        // When client receives request Queue an update on all vis.
+        UpdateAll();
     }
 
     private void OnAppearanceChanged(EntityUid uid, SubFloorHideComponent component, ref AppearanceChangeEvent args)
index 1924bf2b24c4883415771d4095c6bd2f530f3dda..037cc99754f6706695e3d8cce850b9d1dd18534d 100644 (file)
@@ -39,7 +39,6 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
     [UISystemDependency] private readonly DebugPhysicsSystem _debugPhysics = default!;
     [UISystemDependency] private readonly MarkerSystem _marker = default!;
     [UISystemDependency] private readonly SandboxSystem _sandbox = default!;
-    [UISystemDependency] private readonly SubFloorHideSystem _subfloorHide = default!;
 
     private SandboxWindow? _window;
 
@@ -117,10 +116,11 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
 
         _window.OnOpen += () => { SandboxButton!.Pressed = true; };
         _window.OnClose += () => { SandboxButton!.Pressed = false; };
+
+        // TODO: These need moving to opened so at least if they're not synced properly on open they work.
         _window.ToggleLightButton.Pressed = !_light.Enabled;
         _window.ToggleFovButton.Pressed = !_eye.CurrentEye.DrawFov;
         _window.ToggleShadowsButton.Pressed = !_light.DrawShadows;
-        _window.ToggleSubfloorButton.Pressed = _subfloorHide.ShowAll;
         _window.ShowMarkersButton.Pressed = _marker.MarkersVisible;
         _window.ShowBbButton.Pressed = (_debugPhysics.Flags & PhysicsDebugFlags.Shapes) != 0x0;
 
@@ -219,4 +219,16 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
             _window.Close();
         }
     }
+
+    #region Buttons
+
+    public void SetToggleSubfloors(bool value)
+    {
+        if (_window == null)
+            return;
+
+        _window.ToggleSubfloorButton.Pressed = value;
+    }
+
+    #endregion
 }
index 08431a29707689ba94bdda88a5466bf72ec15b24..5bbb791123476defd8df675a51c23cbe4e18a235 100644 (file)
@@ -1,4 +1,5 @@
-using Robust.Client.AutoGenerated;
+using Content.Client.SubFloor;
+using Robust.Client.AutoGenerated;
 using Robust.Client.UserInterface.CustomControls;
 using Robust.Client.UserInterface.XAML;
 
@@ -7,8 +8,18 @@ namespace Content.Client.UserInterface.Systems.Sandbox.Windows;
 [GenerateTypedNameReferences]
 public sealed partial class SandboxWindow : DefaultWindow
 {
+    [Dependency] private readonly IEntityManager _entManager = null!;
+
     public SandboxWindow()
     {
         RobustXamlLoader.Load(this);
+        IoCManager.InjectDependencies(this);
+    }
+
+    protected override void Opened()
+    {
+        base.Opened();
+        // Make sure state is up to date.
+        ToggleSubfloorButton.Pressed = _entManager.System<SubFloorHideSystem>().ShowAll;
     }
 }
index 1ef34365ea3d1a367c8bcddfe19237fe028628ff..9ff8ca290094b9579ce779b27ee0c3f471ef4d8b 100644 (file)
@@ -35,7 +35,6 @@ public sealed class PrototypeSaveTest
         await using var pair = await PoolManager.GetServerClient();
         var server = pair.Server;
 
-        var mapManager = server.ResolveDependency<IMapManager>();
         var entityMan = server.ResolveDependency<IEntityManager>();
         var prototypeMan = server.ResolveDependency<IPrototypeManager>();
         var seriMan = server.ResolveDependency<ISerializationManager>();
index 5bfa208b1c6c4a40701886b4225c4d81a58aa211..1ca96889cf783a55f5311d7369db27111a56b493 100644 (file)
@@ -100,6 +100,17 @@ namespace Content.Server.Ghost
 
             SubscribeLocalEvent<RoundEndTextAppendEvent>(_ => MakeVisible(true));
             SubscribeLocalEvent<ToggleGhostVisibilityToAllEvent>(OnToggleGhostVisibilityToAll);
+
+            SubscribeLocalEvent<GhostComponent, GetVisMaskEvent>(OnGhostVis);
+        }
+
+        private void OnGhostVis(Entity<GhostComponent> ent, ref GetVisMaskEvent args)
+        {
+            // If component not deleting they can see ghosts.
+            if (ent.Comp.LifeStage <= ComponentLifeStage.Running)
+            {
+                args.VisibilityMask |= (int)VisibilityFlags.Ghost;
+            }
         }
 
         private void OnGhostHearingAction(EntityUid uid, GhostComponent component, ToggleGhostHearingActionEvent args)
@@ -186,8 +197,7 @@ namespace Content.Server.Ghost
                 _visibilitySystem.RefreshVisibility(uid, visibilityComponent: visibility);
             }
 
-            SetCanSeeGhosts(uid, true);
-
+            _eye.RefreshVisibilityMask(uid);
             var time = _gameTiming.CurTime;
             component.TimeOfDeath = time;
         }
@@ -207,21 +217,10 @@ namespace Content.Server.Ghost
             }
 
             // Entity can't see ghosts anymore.
-            SetCanSeeGhosts(uid, false);
+            _eye.RefreshVisibilityMask(uid);
             _actions.RemoveAction(uid, component.BooActionEntity);
         }
 
-        private void SetCanSeeGhosts(EntityUid uid, bool canSee, EyeComponent? eyeComponent = null)
-        {
-            if (!Resolve(uid, ref eyeComponent, false))
-                return;
-
-            if (canSee)
-                _eye.SetVisibilityMask(uid, eyeComponent.VisibilityMask | (int) VisibilityFlags.Ghost, eyeComponent);
-            else
-                _eye.SetVisibilityMask(uid, eyeComponent.VisibilityMask & ~(int) VisibilityFlags.Ghost, eyeComponent);
-        }
-
         private void OnMapInit(EntityUid uid, GhostComponent component, MapInitEvent args)
         {
             _actions.AddAction(uid, ref component.BooActionEntity, component.BooAction);
index 4cfceaf2974777ebdde6e07d2b59a6508afef1d3..b319db09e0653a0fd30dcc9df599ad40495c4e14 100644 (file)
@@ -63,9 +63,16 @@ public sealed partial class RevenantSystem : EntitySystem
         SubscribeLocalEvent<RevenantComponent, StatusEffectEndedEvent>(OnStatusEnded);
         SubscribeLocalEvent<RoundEndTextAppendEvent>(_ => MakeVisible(true));
 
+        SubscribeLocalEvent<RevenantComponent, GetVisMaskEvent>(OnRevenantGetVis);
+
         InitializeAbilities();
     }
 
+    private void OnRevenantGetVis(Entity<RevenantComponent> ent, ref GetVisMaskEvent args)
+    {
+        args.VisibilityMask |= (int)VisibilityFlags.Ghost;
+    }
+
     private void OnStartup(EntityUid uid, RevenantComponent component, ComponentStartup args)
     {
         //update the icon
@@ -84,10 +91,7 @@ public sealed partial class RevenantSystem : EntitySystem
         }
 
         //ghost vision
-        if (TryComp(uid, out EyeComponent? eye))
-        {
-            _eye.SetVisibilityMask(uid, eye.VisibilityMask | (int) (VisibilityFlags.Ghost), eye);
-        }
+        _eye.RefreshVisibilityMask(uid);
     }
 
     private void OnMapInit(EntityUid uid, RevenantComponent component, MapInitEvent args)
index 497d7788d72c8e5c71ceefcfbdf605267f09846a..54f4be86a019fe89c9f86fbcb7285f9db66dbd16 100644 (file)
@@ -1,16 +1,76 @@
 using Content.Shared.Construction.Components;
+using Content.Shared.Eye;
 using Content.Shared.SubFloor;
+using Robust.Server.Player;
+using Robust.Shared.Enums;
 using Robust.Shared.Map.Components;
+using Robust.Shared.Player;
 
 namespace Content.Server.SubFloor;
 
 public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
 {
+    [Dependency] private readonly IPlayerManager _player = default!;
+    [Dependency] private readonly SharedEyeSystem _eye = default!;
+
+    private HashSet<ICommonSession> _showFloors = new();
+
     public override void Initialize()
     {
         base.Initialize();
         SubscribeLocalEvent<SubFloorHideComponent, AnchorAttemptEvent>(OnAnchorAttempt);
         SubscribeLocalEvent<SubFloorHideComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
+        SubscribeNetworkEvent<ShowSubfloorRequestEvent>(OnShowSubfloor);
+        SubscribeLocalEvent<GetVisMaskEvent>(OnGetVisibility);
+
+        _player.PlayerStatusChanged += OnPlayerStatus;
+    }
+
+    private void OnPlayerStatus(object? sender, SessionStatusEventArgs e)
+    {
+        if (e.NewStatus == SessionStatus.Connected)
+            return;
+
+        _showFloors.Remove(e.Session);
+
+        if (e.Session.AttachedEntity != null)
+            _eye.RefreshVisibilityMask(e.Session.AttachedEntity.Value);
+    }
+
+    private void OnGetVisibility(ref GetVisMaskEvent ev)
+    {
+        if (!TryComp(ev.Entity, out ActorComponent? actor))
+            return;
+
+        if (_showFloors.Contains(actor.PlayerSession))
+        {
+            ev.VisibilityMask |= (int)VisibilityFlags.Subfloor;
+        }
+    }
+
+    private void OnShowSubfloor(ShowSubfloorRequestEvent ev, EntitySessionEventArgs args)
+    {
+        // TODO: Commands are a bit of an eh? for client-only but checking shared perms
+        var ent = args.SenderSession.AttachedEntity;
+
+        if (!TryComp(ent, out EyeComponent? eyeComp))
+            return;
+
+        if (ev.Value)
+        {
+            _showFloors.Add(args.SenderSession);
+        }
+        else
+        {
+            _showFloors.Remove(args.SenderSession);
+        }
+
+        _eye.RefreshVisibilityMask((ent.Value, eyeComp));
+
+        RaiseNetworkEvent(new ShowSubfloorRequestEvent()
+        {
+            Value = ev.Value,
+        }, args.SenderSession);
     }
 
     private void OnAnchorAttempt(EntityUid uid, SubFloorHideComponent component, AnchorAttemptEvent args)
index a4037f2bd7438750f0a0a4acb2de5564a0f7f75e..432e80dd58ab5b83b7768ef582d1df4218a84ca1 100644 (file)
@@ -9,5 +9,6 @@ namespace Content.Shared.Eye
         None   = 0,
         Normal = 1 << 0,
         Ghost  = 1 << 1,
+        Subfloor = 1 << 2,
     }
 }
index 56eee1881c50536f6380f17f495dceb52230e79b..6fbb59a711ce15a358e2110274638d335127bd90 100644 (file)
@@ -5,7 +5,7 @@ using Robust.Shared.Prototypes;
 namespace Content.Shared.Ghost;
 
 [RegisterComponent, NetworkedComponent, Access(typeof(SharedGhostSystem))]
-[AutoGenerateComponentState(true)]
+[AutoGenerateComponentState(true), AutoGenerateComponentPause]
 public sealed partial class GhostComponent : Component
 {
     // Actions
@@ -41,7 +41,7 @@ public sealed partial class GhostComponent : Component
 
     // End actions
 
-    [ViewVariables(VVAccess.ReadWrite), DataField]
+    [ViewVariables(VVAccess.ReadWrite), DataField, AutoPausedField]
     public TimeSpan TimeOfDeath = TimeSpan.Zero;
 
     [DataField("booRadius"), ViewVariables(VVAccess.ReadWrite)]
index c90a28a513268b789b1954b95665da82aa8f7007..d15055875af95663f057caae9708ec26fff26d2f 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Shared.Audio;
 using Content.Shared.Explosion;
+using Content.Shared.Eye;
 using Content.Shared.Interaction.Events;
 using Content.Shared.Maps;
 using JetBrains.Annotations;
@@ -19,11 +20,16 @@ namespace Content.Shared.SubFloor
         [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
         [Dependency] protected readonly SharedMapSystem Map = default!;
         [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
+        [Dependency] private readonly SharedVisibilitySystem _visibility = default!;
+
+        private EntityQuery<SubFloorHideComponent> _hideQuery;
 
         public override void Initialize()
         {
             base.Initialize();
 
+            _hideQuery = GetEntityQuery<SubFloorHideComponent>();
+
             SubscribeLocalEvent<TileChangedEvent>(OnTileChanged);
             SubscribeLocalEvent<SubFloorHideComponent, ComponentStartup>(OnSubFloorStarted);
             SubscribeLocalEvent<SubFloorHideComponent, ComponentShutdown>(OnSubFloorTerminating);
@@ -67,7 +73,7 @@ namespace Content.Shared.SubFloor
                 return;
 
             // Regardless of whether we're on a subfloor or not, unhide.
-            component.IsUnderCover = false;
+            SetUnderCover((uid, component), false);
             UpdateAppearance(uid, component);
         }
 
@@ -80,7 +86,7 @@ namespace Content.Shared.SubFloor
             }
             else if (component.IsUnderCover)
             {
-                component.IsUnderCover = false;
+                SetUnderCover((uid, component), false);
                 UpdateAppearance(uid, component);
             }
         }
@@ -93,7 +99,7 @@ namespace Content.Shared.SubFloor
             if (args.NewTile.Tile.IsEmpty)
                 return; // Anything that was here will be unanchored anyways.
 
-            UpdateTile(args.NewTile.GridUid, Comp<MapGridComponent>(args.NewTile.GridUid), args.NewTile.GridIndices);
+            UpdateTile(args.NewTile.GridUid, args.Entity.Comp, args.NewTile.GridIndices);
         }
 
         /// <summary>
@@ -105,13 +111,24 @@ namespace Content.Shared.SubFloor
                 return;
 
             if (xform.Anchored && TryComp<MapGridComponent>(xform.GridUid, out var grid))
-                component.IsUnderCover = HasFloorCover(xform.GridUid.Value, grid, Map.TileIndicesFor(xform.GridUid.Value, grid, xform.Coordinates));
+                SetUnderCover((uid, component), HasFloorCover(xform.GridUid.Value, grid, Map.TileIndicesFor(xform.GridUid.Value, grid, xform.Coordinates)));
             else
-                component.IsUnderCover = false;
+                SetUnderCover((uid, component), false);
 
             UpdateAppearance(uid, component);
         }
 
+        private void SetUnderCover(Entity<SubFloorHideComponent> entity, bool value)
+        {
+            // If it's not undercover or it always has visible layers then normal visibility.
+            _visibility.SetLayer(entity.Owner, value && entity.Comp.VisibleLayers.Count == 0 ? (ushort) VisibilityFlags.Subfloor : (ushort) VisibilityFlags.Normal);
+
+            if (entity.Comp.IsUnderCover == value)
+                return;
+
+            entity.Comp.IsUnderCover = value;
+        }
+
         public bool HasFloorCover(EntityUid gridUid, MapGridComponent grid, Vector2i position)
         {
             // TODO Redo this function. Currently wires on an asteroid are always "below the floor"
@@ -125,13 +142,13 @@ namespace Content.Shared.SubFloor
 
             foreach (var uid in Map.GetAnchoredEntities(gridUid, grid, position))
             {
-                if (!TryComp(uid, out SubFloorHideComponent? hideComp))
+                if (!_hideQuery.TryComp(uid, out var hideComp))
                     continue;
 
                 if (hideComp.IsUnderCover == covered)
                     continue;
 
-                hideComp.IsUnderCover = covered;
+                SetUnderCover((uid, hideComp), covered);
                 UpdateAppearance(uid, hideComp);
             }
         }
@@ -154,6 +171,12 @@ namespace Content.Shared.SubFloor
                 Appearance.SetData(uid, SubFloorVisuals.Covered, hideComp.IsUnderCover, appearance);
             }
         }
+
+        [Serializable, NetSerializable]
+        protected sealed class ShowSubfloorRequestEvent : EntityEventArgs
+        {
+            public bool Value;
+        }
     }
 
     [Serializable, NetSerializable]
index 8903747e430f2d78cf2b924bf8ad0156214f6051..79bfddeccda1221ef0ae6a6a3c715e15be284ac0 100644 (file)
@@ -1,17 +1,16 @@
+using Content.Shared.Eye;
+using Content.Shared.Hands;
 using Content.Shared.Interaction;
-using Robust.Shared.Containers;
+using Content.Shared.Inventory.Events;
 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!;
+    [Dependency] private readonly SharedEyeSystem _eye = default!;
 
     public const float SubfloorRevealAlpha = 0.8f;
 
@@ -22,6 +21,50 @@ public abstract class SharedTrayScannerSystem : EntitySystem
         SubscribeLocalEvent<TrayScannerComponent, ComponentGetState>(OnTrayScannerGetState);
         SubscribeLocalEvent<TrayScannerComponent, ComponentHandleState>(OnTrayScannerHandleState);
         SubscribeLocalEvent<TrayScannerComponent, ActivateInWorldEvent>(OnTrayScannerActivate);
+
+        SubscribeLocalEvent<TrayScannerComponent, GotEquippedHandEvent>(OnTrayHandEquipped);
+        SubscribeLocalEvent<TrayScannerComponent, GotUnequippedHandEvent>(OnTrayHandUnequipped);
+        SubscribeLocalEvent<TrayScannerComponent, GotEquippedEvent>(OnTrayEquipped);
+        SubscribeLocalEvent<TrayScannerComponent, GotUnequippedEvent>(OnTrayUnequipped);
+
+        SubscribeLocalEvent<TrayScannerUserComponent, GetVisMaskEvent>(OnUserGetVis);
+    }
+
+    private void OnUserGetVis(Entity<TrayScannerUserComponent> ent, ref GetVisMaskEvent args)
+    {
+        args.VisibilityMask |= (int)VisibilityFlags.Subfloor;
+    }
+
+    private void OnEquip(EntityUid user)
+    {
+        EnsureComp<TrayScannerUserComponent>(user);
+        _eye.RefreshVisibilityMask(user);
+    }
+
+    private void OnUnequip(EntityUid user)
+    {
+        RemComp<TrayScannerUserComponent>(user);
+        _eye.RefreshVisibilityMask(user);
+    }
+
+    private void OnTrayHandUnequipped(Entity<TrayScannerComponent> ent, ref GotUnequippedHandEvent args)
+    {
+        OnUnequip(args.User);
+    }
+
+    private void OnTrayHandEquipped(Entity<TrayScannerComponent> ent, ref GotEquippedHandEvent args)
+    {
+        OnEquip(args.User);
+    }
+
+    private void OnTrayUnequipped(Entity<TrayScannerComponent> ent, ref GotUnequippedEvent args)
+    {
+        OnUnequip(args.Equipee);
+    }
+
+    private void OnTrayEquipped(Entity<TrayScannerComponent> ent, ref GotEquippedEvent args)
+    {
+        OnEquip(args.Equipee);
     }
 
     private void OnTrayScannerActivate(EntityUid uid, TrayScannerComponent scanner, ActivateInWorldEvent args)
index 3b29388fa8939173b083ad90bb88f0529e4d04ac..21cf1f4b03640965f48fe4251bb5c493aba52978 100644 (file)
@@ -1,6 +1,4 @@
 using Robust.Shared.GameStates;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
 
 namespace Content.Shared.SubFloor
 {
@@ -27,7 +25,7 @@ namespace Content.Shared.SubFloor
         /// <remarks>
         ///     Useful for entities like vents, which are only partially hidden. Anchor attempts will still be blocked.
         /// </remarks>
-        [DataField("blockInteractions")]
+        [DataField]
         public bool BlockInteractions { get; set; } = true;
 
         /// <summary>
@@ -36,15 +34,15 @@ namespace Content.Shared.SubFloor
         /// <remarks>
         /// Useful for cables and piping, gives maint it's distinct noise.
         /// </remarks>
-        [DataField("blockAmbience")]
+        [DataField]
         public bool BlockAmbience { get; set; } = true;
 
         /// <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 };
+        [DataField]
+        public HashSet<Enum> VisibleLayers = new();
 
         /// <summary>
         /// This is used for storing the original draw depth of a t-ray revealed entity.
index acde11ff5051be1d569123e3cd27f08f535599c5..52c950e108d617fd19826bbb0086fc44fececa27 100644 (file)
@@ -9,12 +9,13 @@ public sealed partial class TrayScannerComponent : Component
     /// <summary>
     ///     Whether the scanner is currently on.
     /// </summary>
-    [ViewVariables, DataField("enabled")] public bool Enabled;
+    [DataField]
+    public bool Enabled;
 
     /// <summary>
     ///     Radius in which the scanner will reveal entities. Centered on the <see cref="LastLocation"/>.
     /// </summary>
-    [ViewVariables(VVAccess.ReadWrite), DataField("range")]
+    [DataField]
     public float Range = 4f;
 }
 
diff --git a/Content.Shared/SubFloor/TrayScannerUserComponent.cs b/Content.Shared/SubFloor/TrayScannerUserComponent.cs
new file mode 100644 (file)
index 0000000..f97046c
--- /dev/null
@@ -0,0 +1,8 @@
+namespace Content.Shared.SubFloor;
+
+// Don't need to network
+/// <summary>
+/// Added to anyone using <see cref="TrayScannerComponent"/> to handle the vismask changes.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TrayScannerUserComponent : Component;
index 4e6650aaaade680fab4515c9e5dbbad371227d71..3d5b78397ef3b259b46a0ac08169d4a802854488 100644 (file)
@@ -34,6 +34,8 @@
         type: NavMapBeaconBoundUserInterface
   - type: Item
     size: Small
+  - type: Visibility
+    layer: 1
   - type: SubFloorHide
   - type: Anchorable
   - type: Construction
index 99fb34bd9ab169e26bb72da2ecbfbd3e3136bc4a..71c0da27369613907ad8b02dee35faa4d652d51d 100644 (file)
@@ -39,6 +39,9 @@
   - type: Rotatable
   - type: Transform
     noRot: false
+  - type: SubFloorHide
+    visibleLayers:
+    - enum.SubfloorLayers.FirstLayer
   - type: Sprite
     sprite: Structures/Piping/Atmospherics/pump.rsi
     layers:
@@ -95,6 +98,9 @@
     - type: Rotatable
     - type: Transform
       noRot: false
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       sprite: Structures/Piping/Atmospherics/pump.rsi
       layers:
   placement:
     mode: SnapgridCenter
   components:
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       sprite: Structures/Piping/Atmospherics/pump.rsi
       layers:
     mode: SnapgridCenter
   components:
     # TODO ATMOS: Give unique sprite.
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       sprite: Structures/Piping/Atmospherics/pump.rsi
       layers:
     mode: SnapgridCenter
   components:
   - type: StationAiWhitelist
+  - type: SubFloorHide
+    visibleLayers:
+    - enum.SubfloorLayers.FirstLayer
   - type: Sprite
     sprite: Structures/Piping/Atmospherics/pump.rsi
     layers:
   placement:
     mode: SnapgridCenter
   components:
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       sprite: Structures/Piping/Atmospherics/gascanisterport.rsi
       layers:
   placement:
     mode: SnapgridCenter
   components:
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       drawdepth: FloorObjects
       sprite: Structures/Piping/Atmospherics/vent.rsi
   id: HeatExchangerBend
   suffix: Bend
   components:
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       layers:
       - sprite: Structures/Piping/Atmospherics/pipe.rsi
index a6c322189b522651ef8bbc3422e835f6f219ffb6..92d0006841f72bdf2491a538d52141fc6e4efd2d 100644 (file)
@@ -7,6 +7,8 @@
   placement:
     mode: SnapgridCenter
   components:
+  - type: Visibility
+    layer: 1
   - type: Item
     size: Normal
   - type: Transform
index 06656d017756ae2ade4d29b13ed98eedff2b50c8..c44f700e7f73b280af02f3a0290f2e2b0624fb13 100644 (file)
@@ -35,6 +35,9 @@
   placement:
     mode: SnapgridCenter
   components:
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       sprite: Structures/Piping/Atmospherics/gasfilter.rsi
       layers:
@@ -84,6 +87,9 @@
   placement:
     mode: SnapgridCenter
   components:
+  - type: SubFloorHide
+    visibleLayers:
+    - enum.SubfloorLayers.FirstLayer
   - type: Sprite
     sprite: Structures/Piping/Atmospherics/gasfilter.rsi
     layers:
index 1b738dedfd247f86a223879457fca675e0bd5733..abb0ead4a08cbc91846c880903b51ed58e8591bb 100644 (file)
@@ -36,6 +36,9 @@
       tags:
         - GasVent
         - Unstackable
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       drawdepth: FloorObjects
       sprite: Structures/Piping/Atmospherics/vent.rsi
@@ -83,6 +86,9 @@
   placement:
     mode: SnapgridCenter
   components:
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       drawdepth: FloorObjects
       sprite: Structures/Piping/Atmospherics/vent.rsi
       tags:
         - GasScrubber
         - Unstackable
+    - type: SubFloorHide
+      visibleLayers:
+      - enum.SubfloorLayers.FirstLayer
     - type: Sprite
       drawdepth: FloorObjects
       sprite: Structures/Piping/Atmospherics/scrubber.rsi
index fca28e99a6ffa2776bd9f9b2ca6d4b3543520d77..d6d5454384a58309a27cf7e4233915020177fb77 100644 (file)
@@ -13,6 +13,8 @@
     sprite: Structures/Piping/disposal.rsi
     visible: false
   - type: Appearance
+  - type: Visibility
+    layer: 1
   - type: SubFloorHide
   - type: Clickable
   - type: InteractionOutline
index cc6abce25ed8ad2629d3dabe696560fd8f25c60f..fc0ec95d4d698b58aac7032c53ddfd061ba5cb66 100644 (file)
@@ -29,6 +29,8 @@
           behaviors:
             - !type:DoActsBehavior
               acts: ["Destruction"]
+    - type: Visibility
+      layer: 1
     - type: SubFloorHide
       blockAmbience: false
       blockInteractions: false
@@ -52,4 +54,4 @@
   suffix: uncuttable
   components:
   - type: Cable
-    cuttingQuality: null
\ No newline at end of file
+    cuttingQuality: null
index f1ae038bc1522ac9b6eda8fbcd52e651b8a8337e..6cb9e3d13841aecfe292644f67d66148d9c8f69f 100644 (file)
@@ -4,6 +4,8 @@
   placement:
     mode: SnapgridCenter
   components:
+  - type: Visibility
+    layer: 1
   - type: Cable
     cuttingDelay: 1
   - type: Clickable