From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Fri, 31 Mar 2023 03:40:38 +0000 (+1100)
Subject: Make trays clientside (#14826)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=763089570d988dfa80255595c669b40199278bd6;p=space-station-14.git
Make trays clientside (#14826)
---
diff --git a/Content.Client/SubFloor/SubFloorHideSystem.cs b/Content.Client/SubFloor/SubFloorHideSystem.cs
index 0532f177de..1d47f93a5a 100644
--- a/Content.Client/SubFloor/SubFloorHideSystem.cs
+++ b/Content.Client/SubFloor/SubFloorHideSystem.cs
@@ -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
index 0000000000..e1a8b0caf3
--- /dev/null
+++ b/Content.Client/SubFloor/TrayRevealedComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Client.SubFloor;
+
+///
+/// Added clientside if an entity is revealed for TRay.
+///
+[RegisterComponent]
+public sealed class TrayRevealedComponent : Component
+{
+
+}
diff --git a/Content.Client/SubFloor/TrayScannerSystem.cs b/Content.Client/SubFloor/TrayScannerSystem.cs
new file mode 100644
index 0000000000..2f53226d62
--- /dev/null
+++ b/Content.Client/SubFloor/TrayScannerSystem.cs
@@ -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();
+
+ if (!xformQuery.TryGetComponent(player, out var playerXform))
+ return;
+
+ var playerPos = _transform.GetWorldPosition(playerXform, xformQuery);
+ var playerMap = playerXform.MapID;
+ var range = 0f;
+
+ if (TryComp(player, out var playerHands) &&
+ TryComp(playerHands.ActiveHandEntity, out var scanner) && scanner.Enabled)
+ {
+ range = scanner.Range;
+
+ foreach (var comp in _lookup.GetComponentsInRange(playerMap, playerPos, range))
+ {
+ var uid = comp.Owner;
+ if (!comp.IsUnderCover || !comp.BlockAmbience | !comp.BlockInteractions)
+ continue;
+
+ EnsureComp(uid);
+ }
+ }
+
+ var revealedQuery = AllEntityQuery();
+ var subfloorQuery = GetEntityQuery();
+
+ 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(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
index 0000000000..f93d656d61
--- /dev/null
+++ b/Content.Server/SubFloor/TrayScannerSystem.cs
@@ -0,0 +1,8 @@
+using Content.Shared.SubFloor;
+
+namespace Content.Server.SubFloor;
+
+public sealed class TrayScannerSystem : SharedTrayScannerSystem
+{
+
+}
diff --git a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
index f726827b47..9d2eb3de69 100644
--- a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
+++ b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
@@ -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
}
}
- ///
- /// This function is used by T-Ray scanners or other sub-floor revealing entities to toggle visibility.
- ///
- public void SetEntitiesRevealed(IEnumerable entities, EntityUid revealer, bool visible)
- {
- foreach (var uid in entities)
- {
- SetEntityRevealed(uid, revealer, visible);
- }
- }
-
- ///
- /// This function is used by T-Ray scanners or other sub-floor revealing entities to toggle visibility.
- ///
- 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?
+ ///
+ /// Is there a floor tile over this entity
+ ///
+ Covered,
+
+ ///
+ /// Is this entity revealed by a scanner or some other entity?
+ ///
+ ScannerRevealed,
}
public enum SubfloorLayers : byte
diff --git a/Content.Shared/SubFloor/SharedTrayScannerSystem.cs b/Content.Shared/SubFloor/SharedTrayScannerSystem.cs
new file mode 100644
index 0000000000..1ba88c571c
--- /dev/null
+++ b/Content.Shared/SubFloor/SharedTrayScannerSystem.cs
@@ -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(OnTrayScannerGetState);
+ SubscribeLocalEvent(OnTrayScannerHandleState);
+ SubscribeLocalEvent(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(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
+}
diff --git a/Content.Shared/SubFloor/SubFloorHideComponent.cs b/Content.Shared/SubFloor/SubFloorHideComponent.cs
index e3a170b89d..415b2127e9 100644
--- a/Content.Shared/SubFloor/SubFloorHideComponent.cs
+++ b/Content.Shared/SubFloor/SubFloorHideComponent.cs
@@ -39,24 +39,11 @@ namespace Content.Shared.SubFloor
[DataField("blockAmbience")]
public bool BlockAmbience { get; set; } = true;
- ///
- /// When revealed using some scanning tool, what transparency should be used to draw this item?
- ///
- [DataField("scannerTransparency")]
- public float ScannerTransparency = 0.8f;
-
///
/// 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.
///
[DataField("visibleLayers")]
public HashSet VisibleLayers = new() { SubfloorLayers.FirstLayer };
-
- ///
- /// The entities this subfloor is revealed by.
- ///
- [ViewVariables]
- [Access(typeof(SharedSubFloorHideSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends
- public HashSet RevealedBy { get; set; } = new();
}
}
diff --git a/Content.Shared/SubFloor/TrayScannerComponent.cs b/Content.Shared/SubFloor/TrayScannerComponent.cs
index c6bc3d46f3..811d120a1d 100644
--- a/Content.Shared/SubFloor/TrayScannerComponent.cs
+++ b/Content.Shared/SubFloor/TrayScannerComponent.cs
@@ -3,33 +3,19 @@ using Robust.Shared.Serialization;
namespace Content.Shared.SubFloor;
-[RegisterComponent]
-[NetworkedComponent]
+[RegisterComponent, NetworkedComponent]
public sealed class TrayScannerComponent : Component
{
///
/// Whether the scanner is currently on.
///
- [ViewVariables]
- public bool Enabled { get; set; }
-
- ///
- /// Last position of the scanner. Rounded to integers to avoid excessive entity lookups when moving.
- ///
- [ViewVariables]
- public Vector2i? LastLocation { get; set; }
+ [ViewVariables, DataField("enabled")] public bool Enabled;
///
/// Radius in which the scanner will reveal entities. Centered on the .
///
- [DataField("range")]
- public float Range { get; set; } = 2.5f;
-
- ///
- /// The sub-floor entities that this scanner is currently revealing.
- ///
- [ViewVariables]
- public HashSet 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
index c9eecb3ea2..0000000000
--- a/Content.Shared/SubFloor/TrayScannerSystem.cs
+++ /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 _activeScanners = new();
- private RemQueue _invalidScanners = new();
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent(OnComponentShutdown);
- SubscribeLocalEvent(OnTrayScannerGetState);
- SubscribeLocalEvent(OnTrayScannerHandleState);
- SubscribeLocalEvent(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(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();
- }
-
- ///
- /// When a subfloor entity gets anchored (which includes spawning & coming into PVS range), Check for nearby scanners.
- ///
- 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);
- }
- }
-
- ///
- /// Updates a T-Ray scanner. Should be called on immediate
- /// state change (turned on/off), or during the update
- /// loop.
- ///
- /// true if the update was successful, false otherwise
- 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 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 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
-}