Adds T-ray Scanners (#5420)
This commit is contained in:
45
Content.Client/SubFloor/TrayScannerSubFloorVisualizer.cs
Normal file
45
Content.Client/SubFloor/TrayScannerSubFloorVisualizer.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
|
||||||
|
namespace Content.Client.SubFloor;
|
||||||
|
|
||||||
|
public class TrayScannerSubFloorVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
[Dependency] IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
public override void InitializeEntity(EntityUid uid)
|
||||||
|
{
|
||||||
|
base.InitializeEntity(uid);
|
||||||
|
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
|
||||||
|
if (!_entityManager.TryGetComponent(component.Owner, out SpriteComponent? sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!component.TryGetData(TrayScannerTransparency.Key, out bool transparent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var layer in sprite.AllLayers)
|
||||||
|
{
|
||||||
|
var transparency = transparent == true ? 0.8f : 1f;
|
||||||
|
layer.Color = layer.Color.WithAlpha(transparency);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sprite.LayerMapTryGet(SubFloorShowLayerVisualizer.Layers.FirstLayer, out var firstLayer))
|
||||||
|
{
|
||||||
|
sprite.LayerSetColor(firstLayer, Color.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TrayScannerTransparency
|
||||||
|
{
|
||||||
|
Key,
|
||||||
|
}
|
||||||
176
Content.Client/SubFloor/TrayScannerSystem.cs
Normal file
176
Content.Client/SubFloor/TrayScannerSystem.cs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.SubFloor;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.SubFloor;
|
||||||
|
|
||||||
|
public class TrayScannerSystem : SharedTrayScannerSystem
|
||||||
|
{
|
||||||
|
[Dependency] private IEntityLookup _entityLookup = default!;
|
||||||
|
[Dependency] private SubFloorHideSystem _subfloorSystem = default!;
|
||||||
|
[Dependency] private SharedContainerSystem _containerSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<TrayScannerComponent, ComponentShutdown>(OnComponentShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnComponentShutdown(EntityUid uid, TrayScannerComponent scanner, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
_subfloorSystem.ToggleSubfloorEntities(scanner.RevealedSubfloors, false, uid, _visualizerKeys);
|
||||||
|
_invalidScanners.Add(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToggleTrayScanner(EntityUid uid, bool toggle, TrayScannerComponent? scanner = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref scanner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
scanner.Toggled = toggle;
|
||||||
|
UpdateTrayScanner(uid, scanner);
|
||||||
|
|
||||||
|
if (toggle) _activeScanners.Add(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<EntityUid> _activeScanners = new();
|
||||||
|
private RemQueue<EntityUid> _invalidScanners = new();
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (_invalidScanners.List != null) _invalidScanners.List.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
// whoops?
|
||||||
|
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.Toggled)
|
||||||
|
{
|
||||||
|
_subfloorSystem.ToggleSubfloorEntities(scanner.RevealedSubfloors, false, uid, _visualizerKeys);
|
||||||
|
scanner.LastLocation = Vector2.Zero;
|
||||||
|
scanner.RevealedSubfloors.Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the rounded position so that small movements don't cause this to
|
||||||
|
// update every time
|
||||||
|
Vector2 flooredPos;
|
||||||
|
|
||||||
|
// zero vector implies container
|
||||||
|
//
|
||||||
|
// this means we should get the entity transform's parent
|
||||||
|
if (transform.LocalPosition == Vector2.Zero
|
||||||
|
&& transform.Parent != null
|
||||||
|
&& _containerSystem.ContainsEntity(transform.ParentUid, uid))
|
||||||
|
{
|
||||||
|
flooredPos = transform.Parent.LocalPosition.Rounded();
|
||||||
|
|
||||||
|
// 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 (flooredPos == Vector2.Zero)
|
||||||
|
{
|
||||||
|
var gpTransform = transform.Parent.Parent;
|
||||||
|
if (gpTransform != null
|
||||||
|
&& _containerSystem.ContainsEntity(gpTransform.Owner, transform.ParentUid))
|
||||||
|
{
|
||||||
|
flooredPos = gpTransform.LocalPosition.Rounded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flooredPos = transform.LocalPosition.Rounded();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (flooredPos == Vector2.Zero)
|
||||||
|
{
|
||||||
|
_subfloorSystem.ToggleSubfloorEntities(scanner.RevealedSubfloors, false, uid, _visualizerKeys);
|
||||||
|
scanner.RevealedSubfloors.Clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flooredPos == scanner.LastLocation
|
||||||
|
|| (float.IsNaN(flooredPos.X) && float.IsNaN(flooredPos.Y)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
scanner.LastLocation = flooredPos;
|
||||||
|
|
||||||
|
// get all entities in range by uid
|
||||||
|
// but without using LINQ
|
||||||
|
HashSet<EntityUid> nearby = new();
|
||||||
|
|
||||||
|
foreach (var entityInRange in _entityLookup.GetEntitiesInRange(uid, scanner.Range))
|
||||||
|
if (FilterAnchored(entityInRange)) nearby.Add(entityInRange);
|
||||||
|
|
||||||
|
// get all the old elements that are no longer detected
|
||||||
|
scanner.RevealedSubfloors.ExceptWith(nearby);
|
||||||
|
|
||||||
|
// hide all of them, since they're no longer needed
|
||||||
|
_subfloorSystem.ToggleSubfloorEntities(scanner.RevealedSubfloors, false, uid, _visualizerKeys);
|
||||||
|
scanner.RevealedSubfloors.Clear();
|
||||||
|
|
||||||
|
// set the revealedsubfloor set to the new nearby set
|
||||||
|
scanner.RevealedSubfloors.UnionWith(nearby);
|
||||||
|
|
||||||
|
// show all the new subfloor
|
||||||
|
_subfloorSystem.ToggleSubfloorEntities(scanner.RevealedSubfloors, true, uid, _visualizerKeys);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<object> _visualizerKeys = new List<object>
|
||||||
|
{
|
||||||
|
SubFloorVisuals.SubFloor,
|
||||||
|
TrayScannerTransparency.Key
|
||||||
|
};
|
||||||
|
|
||||||
|
private bool FilterAnchored(EntityUid uid)
|
||||||
|
{
|
||||||
|
return EntityManager.TryGetComponent<TransformComponent>(uid, out var transform)
|
||||||
|
&& transform.Anchored;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Content.Server/SubFloor/TrayScannerSystem.cs
Normal file
11
Content.Server/SubFloor/TrayScannerSystem.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Content.Shared.SubFloor;
|
||||||
|
|
||||||
|
namespace Content.Server.SubFloor;
|
||||||
|
|
||||||
|
public class TrayScannerSystem : SharedTrayScannerSystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
76
Content.Shared/SubFloor/SharedTrayScannerSystem.cs
Normal file
76
Content.Shared/SubFloor/SharedTrayScannerSystem.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.SubFloor;
|
||||||
|
|
||||||
|
public abstract class SharedTrayScannerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<TrayScannerComponent, ComponentGetState>(OnTrayScannerGetState);
|
||||||
|
SubscribeLocalEvent<TrayScannerComponent, ComponentHandleState>(OnTrayScannerHandleState);
|
||||||
|
SubscribeLocalEvent<TrayScannerComponent, UseInHandEvent>(OnTrayScannerUsed);
|
||||||
|
SubscribeLocalEvent<TrayScannerComponent, ActivateInWorldEvent>(OnTrayScannerActivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrayScannerUsed(EntityUid uid, TrayScannerComponent scanner, UseInHandEvent args)
|
||||||
|
{
|
||||||
|
ActivateTray(uid, scanner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrayScannerActivate(EntityUid uid, TrayScannerComponent scanner, ActivateInWorldEvent args)
|
||||||
|
{
|
||||||
|
ActivateTray(uid, scanner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActivateTray(EntityUid uid, TrayScannerComponent? scanner = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref scanner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ToggleTrayScanner(uid, !scanner.Toggled, scanner);
|
||||||
|
if (EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData(TrayScannerVisual.Visual, scanner.Toggled == true ? TrayScannerVisual.On : TrayScannerVisual.Off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ToggleTrayScanner(EntityUid uid, bool state, TrayScannerComponent? scanner = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref scanner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
scanner.Toggled = state;
|
||||||
|
scanner.Dirty();
|
||||||
|
|
||||||
|
// RaiseLocalEvent(uid, new TrayScannerToggleEvent(scanner.Toggled));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrayScannerGetState(EntityUid uid, TrayScannerComponent scanner, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new TrayScannerState(scanner.Toggled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTrayScannerHandleState(EntityUid uid, TrayScannerComponent scanner, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
if (args.Current is not TrayScannerState state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ToggleTrayScanner(uid, state.Toggled, scanner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum TrayScannerVisual : sbyte
|
||||||
|
{
|
||||||
|
Visual,
|
||||||
|
On,
|
||||||
|
Off
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
@@ -39,6 +40,26 @@ namespace Content.Shared.SubFloor
|
|||||||
{
|
{
|
||||||
return new SubFloorHideComponentState(Enabled, RequireAnchored);
|
return new SubFloorHideComponentState(Enabled, RequireAnchored);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not this entity is supposed
|
||||||
|
/// to be visible.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public bool Visible { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The entities this subfloor is revealed by.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public HashSet<EntityUid> RevealedBy { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not this entity was revealed with or without
|
||||||
|
/// an entity.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public bool RevealedWithoutEntity { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
@@ -46,6 +49,7 @@ namespace Content.Shared.SubFloor
|
|||||||
SubscribeLocalEvent<SubFloorHideComponent, ComponentShutdown>(OnSubFloorTerminating);
|
SubscribeLocalEvent<SubFloorHideComponent, ComponentShutdown>(OnSubFloorTerminating);
|
||||||
SubscribeLocalEvent<SubFloorHideComponent, AnchorStateChangedEvent>(HandleAnchorChanged);
|
SubscribeLocalEvent<SubFloorHideComponent, AnchorStateChangedEvent>(HandleAnchorChanged);
|
||||||
SubscribeLocalEvent<SubFloorHideComponent, ComponentHandleState>(HandleComponentState);
|
SubscribeLocalEvent<SubFloorHideComponent, ComponentHandleState>(HandleComponentState);
|
||||||
|
SubscribeLocalEvent<SubFloorHideComponent, InteractUsingEvent>(OnInteractionAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
@@ -70,6 +74,18 @@ namespace Content.Shared.SubFloor
|
|||||||
UpdateEntity(subFloor.Owner);
|
UpdateEntity(subFloor.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnInteractionAttempt(EntityUid uid, SubFloorHideComponent component, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(uid, out TransformComponent? transform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_mapManager.TryGetGrid(transform.GridID, out var grid)
|
||||||
|
&& !IsSubFloor(grid, grid.TileIndicesFor(transform.Coordinates)))
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnSubFloorStarted(EntityUid uid, SubFloorHideComponent component, ComponentStartup _)
|
private void OnSubFloorStarted(EntityUid uid, SubFloorHideComponent component, ComponentStartup _)
|
||||||
{
|
{
|
||||||
UpdateEntity(uid);
|
UpdateEntity(uid);
|
||||||
@@ -153,39 +169,80 @@ namespace Content.Shared.SubFloor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update normally.
|
// Update normally.
|
||||||
UpdateEntity(uid, IsSubFloor(grid, grid.TileIndicesFor(transform.Coordinates)));
|
bool isSubFloor = IsSubFloor(grid, grid.TileIndicesFor(transform.Coordinates));
|
||||||
|
UpdateEntity(uid, isSubFloor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateEntity(EntityUid uid, bool subFloor)
|
// Toggles an enumerable set of entities to display.
|
||||||
|
public void ToggleSubfloorEntities(IEnumerable<EntityUid> entities, bool visible, EntityUid? uid = null, IEnumerable<object>? appearanceKeys = null)
|
||||||
{
|
{
|
||||||
// We raise an event to allow other entity systems to handle this.
|
foreach (var entity in entities)
|
||||||
var subFloorHideEvent = new SubFloorHideEvent(subFloor);
|
|
||||||
RaiseLocalEvent(uid, subFloorHideEvent, false);
|
|
||||||
|
|
||||||
// Check if it has been handled by someone else.
|
|
||||||
if (subFloorHideEvent.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// We only need to query the subfloor component to check if it's enabled or not when we're not on subfloor.
|
|
||||||
// Getting components is expensive, after all.
|
|
||||||
if (!subFloor && EntityManager.TryGetComponent(uid, out SubFloorHideComponent? subFloorHideComponent))
|
|
||||||
{
|
{
|
||||||
// If the component isn't enabled, then subfloor will always be true, and the entity will be shown.
|
if (!EntityManager.HasComponent<SubFloorHideComponent>(entity))
|
||||||
if (!subFloorHideComponent.Enabled)
|
continue;
|
||||||
{
|
|
||||||
subFloor = true;
|
UpdateEntity(entity, visible, uid, appearanceKeys);
|
||||||
}
|
|
||||||
// We only need to query the TransformComp if the SubfloorHide is enabled and requires anchoring.
|
|
||||||
else if (subFloorHideComponent.RequireAnchored && EntityManager.TryGetComponent(uid, out TransformComponent? transformComponent))
|
|
||||||
{
|
|
||||||
// If we require the entity to be anchored but it's not, this will set subfloor to true, unhiding it.
|
|
||||||
subFloor = !transformComponent.Anchored;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEntity(EntityUid uid, bool subFloor, EntityUid? revealedUid = null, IEnumerable<object>? appearanceKeys = null)
|
||||||
|
{
|
||||||
|
bool revealedWithoutEntity = false;
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(uid, out SubFloorHideComponent? subFloorHideComponent))
|
||||||
|
{
|
||||||
|
// We only need to query the subfloor component to check if it's enabled or not when we're not on subfloor.
|
||||||
|
// Getting components is expensive, after all.
|
||||||
|
if (!subFloor)
|
||||||
|
{
|
||||||
|
// If the component isn't enabled, then subfloor will always be true, and the entity will be shown.
|
||||||
|
if (!subFloorHideComponent.Enabled)
|
||||||
|
{
|
||||||
|
subFloor = true;
|
||||||
|
}
|
||||||
|
// We only need to query the TransformComp if the SubfloorHide is enabled and requires anchoring.
|
||||||
|
else if (subFloorHideComponent.RequireAnchored && EntityManager.TryGetComponent(uid, out TransformComponent? transformComponent))
|
||||||
|
{
|
||||||
|
// If we require the entity to be anchored but it's not, this will set subfloor to true, unhiding it.
|
||||||
|
subFloor = !transformComponent.Anchored;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this was revealed by anything, we need to add it into the
|
||||||
|
// component's set of entities that reveal it
|
||||||
|
//
|
||||||
|
if (revealedUid != null)
|
||||||
|
{
|
||||||
|
if (subFloor) subFloorHideComponent.RevealedBy.Add((EntityUid) revealedUid);
|
||||||
|
else subFloorHideComponent.RevealedBy.Remove((EntityUid) revealedUid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subFloorHideComponent.RevealedWithoutEntity = subFloor;
|
||||||
|
}
|
||||||
|
|
||||||
|
subFloor = subFloorHideComponent.RevealedBy.Count != 0 || subFloorHideComponent.RevealedWithoutEntity;
|
||||||
|
revealedWithoutEntity = subFloorHideComponent.RevealedWithoutEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Whether to show this entity as visible, visually.
|
// Whether to show this entity as visible, visually.
|
||||||
var subFloorVisible = ShowAll || subFloor;
|
var subFloorVisible = ShowAll || subFloor;
|
||||||
|
|
||||||
|
// if there are no keys given,
|
||||||
|
// or if the subfloor is already revealed,
|
||||||
|
// set the keys to the default:
|
||||||
|
//
|
||||||
|
// the reason why it's set to default when the subfloor is
|
||||||
|
// revealed without an entity is because the appearance keys
|
||||||
|
// should only apply if the visualizer is underneath a subfloor
|
||||||
|
if (appearanceKeys == null || revealedWithoutEntity) appearanceKeys = _defaultVisualizerKeys;
|
||||||
|
|
||||||
|
ShowSubfloorSprite(uid, subFloorVisible, appearanceKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowSubfloorSprite(EntityUid uid, bool subFloorVisible, IEnumerable<object> appearanceKeys)
|
||||||
|
{
|
||||||
// Show sprite
|
// Show sprite
|
||||||
if (EntityManager.TryGetComponent(uid, out SharedSpriteComponent? spriteComponent))
|
if (EntityManager.TryGetComponent(uid, out SharedSpriteComponent? spriteComponent))
|
||||||
{
|
{
|
||||||
@@ -195,19 +252,22 @@ namespace Content.Shared.SubFloor
|
|||||||
// Set an appearance data value so visualizers can use this as needed.
|
// Set an appearance data value so visualizers can use this as needed.
|
||||||
if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent))
|
if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent))
|
||||||
{
|
{
|
||||||
appearanceComponent.SetData(SubFloorVisuals.SubFloor, subFloorVisible);
|
foreach (var key in appearanceKeys)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case Enum enumKey:
|
||||||
|
appearanceComponent.SetData(enumKey, subFloorVisible);
|
||||||
|
break;
|
||||||
|
case string stringKey:
|
||||||
|
appearanceComponent.SetData(stringKey, subFloorVisible);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class SubFloorHideEvent : HandledEntityEventArgs
|
private static List<object> _defaultVisualizerKeys = new List<object>{ SubFloorVisuals.SubFloor };
|
||||||
{
|
|
||||||
public bool SubFloor { get; }
|
|
||||||
|
|
||||||
public SubFloorHideEvent(bool subFloor)
|
|
||||||
{
|
|
||||||
SubFloor = subFloor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
|||||||
44
Content.Shared/SubFloor/TrayScannerComponent.cs
Normal file
44
Content.Shared/SubFloor/TrayScannerComponent.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Shared.SubFloor;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[NetworkedComponent]
|
||||||
|
public class TrayScannerComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name { get; } = "TrayScanner";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public bool Toggled { get; set; }
|
||||||
|
|
||||||
|
// this should always be rounded
|
||||||
|
[ViewVariables]
|
||||||
|
public Vector2 LastLocation { get; set; }
|
||||||
|
|
||||||
|
// range of the scanner itself
|
||||||
|
[DataField("range")]
|
||||||
|
public float Range { get; set; } = 0.5f;
|
||||||
|
|
||||||
|
// exclude entities that are not the set
|
||||||
|
// of entities in range & entities already revealed
|
||||||
|
[ViewVariables]
|
||||||
|
public HashSet<EntityUid> RevealedSubfloors = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class TrayScannerState : ComponentState
|
||||||
|
{
|
||||||
|
public bool Toggled { get; }
|
||||||
|
|
||||||
|
public TrayScannerState(bool toggle)
|
||||||
|
{
|
||||||
|
Toggled = toggle;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Resources/Prototypes/Entities/Objects/Tools/t-ray.yml
Normal file
20
Resources/Prototypes/Entities/Objects/Tools/t-ray.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
- type: entity
|
||||||
|
name: t-ray scanner
|
||||||
|
parent: BaseItem
|
||||||
|
id: trayScanner
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Tools/t-ray.rsi
|
||||||
|
layers:
|
||||||
|
- state: tray-off
|
||||||
|
- type: TrayScanner
|
||||||
|
- type: Item
|
||||||
|
sprite: Objects/Tools/t-ray.rsi
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: GenericEnumVisualizer
|
||||||
|
key: enum.TrayScannerVisual.Visual
|
||||||
|
layer: 0
|
||||||
|
states:
|
||||||
|
enum.TrayScannerVisual.On: tray-on
|
||||||
|
enum.TrayScannerVisual.Off: tray-off
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: Metallic
|
damageModifierSet: Metallic
|
||||||
|
- type: SubFloorHide
|
||||||
- type: Anchorable
|
- type: Anchorable
|
||||||
- type: Rotatable
|
- type: Rotatable
|
||||||
- type: Pullable
|
- type: Pullable
|
||||||
@@ -58,10 +59,10 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: PipeConnectorVisualizer
|
- type: PipeConnectorVisualizer
|
||||||
- type: PipeColorVisualizer
|
- type: PipeColorVisualizer
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
- type: NodeContainer
|
- type: NodeContainer
|
||||||
- type: AtmosUnsafeUnanchor
|
- type: AtmosUnsafeUnanchor
|
||||||
- type: AtmosPipeColor
|
- type: AtmosPipeColor
|
||||||
- type: SubFloorHide
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Pipe
|
- Pipe
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
- type: DisposalTransit
|
- type: DisposalTransit
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-s
|
state_free: conpipe-s
|
||||||
state_anchored: pipe-s
|
state_anchored: pipe-s
|
||||||
@@ -78,6 +80,8 @@
|
|||||||
- type: DisposalTagger
|
- type: DisposalTagger
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-tagger
|
state_free: conpipe-tagger
|
||||||
state_anchored: pipe-tagger
|
state_anchored: pipe-tagger
|
||||||
@@ -107,6 +111,8 @@
|
|||||||
- type: DisposalEntry
|
- type: DisposalEntry
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-t
|
state_free: conpipe-t
|
||||||
state_anchored: pipe-t
|
state_anchored: pipe-t
|
||||||
@@ -136,6 +142,8 @@
|
|||||||
- 180
|
- 180
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-j1s
|
state_free: conpipe-j1s
|
||||||
state_anchored: pipe-j1s
|
state_anchored: pipe-j1s
|
||||||
@@ -170,6 +178,8 @@
|
|||||||
- 180
|
- 180
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-j2s
|
state_free: conpipe-j2s
|
||||||
state_anchored: pipe-j2s
|
state_anchored: pipe-j2s
|
||||||
@@ -201,6 +211,8 @@
|
|||||||
- 180
|
- 180
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-j1
|
state_free: conpipe-j1
|
||||||
state_anchored: pipe-j1
|
state_anchored: pipe-j1
|
||||||
@@ -231,6 +243,8 @@
|
|||||||
- 180
|
- 180
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-j2
|
state_free: conpipe-j2
|
||||||
state_anchored: pipe-j2
|
state_anchored: pipe-j2
|
||||||
@@ -262,6 +276,8 @@
|
|||||||
- -90
|
- -90
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-y
|
state_free: conpipe-y
|
||||||
state_anchored: pipe-y
|
state_anchored: pipe-y
|
||||||
@@ -287,6 +303,8 @@
|
|||||||
- type: DisposalBend
|
- type: DisposalBend
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
|
- type: SubFloorShowLayerVisualizer
|
||||||
- type: DisposalVisualizer
|
- type: DisposalVisualizer
|
||||||
state_free: conpipe-c
|
state_free: conpipe-c
|
||||||
state_anchored: pipe-c
|
state_anchored: pipe-c
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
- type: CableVisualizer
|
- type: CableVisualizer
|
||||||
base: hvcable_
|
base: hvcable_
|
||||||
|
|
||||||
@@ -117,6 +118,7 @@
|
|||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
- type: CableVisualizer
|
- type: CableVisualizer
|
||||||
base: mvcable_
|
base: mvcable_
|
||||||
|
|
||||||
@@ -160,5 +162,6 @@
|
|||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
|
- type: TrayScannerSubFloorVisualizer
|
||||||
- type: CableVisualizer
|
- type: CableVisualizer
|
||||||
base: lvcable_
|
base: lvcable_
|
||||||
|
|||||||
10
Resources/Textures/Objects/Tools/t-ray.rsi/meta.json
Normal file
10
Resources/Textures/Objects/Tools/t-ray.rsi/meta.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "/tg/station, 'icons/obj/device.dmi', commit 2b8b045d",
|
||||||
|
"size": { "x": 32, "y": 32 },
|
||||||
|
"states": [
|
||||||
|
{ "name": "tray-on" , "delays": [[0.1, 1.0]]},
|
||||||
|
{ "name": "tray-off" }
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Objects/Tools/t-ray.rsi/tray-off.png
Normal file
BIN
Resources/Textures/Objects/Tools/t-ray.rsi/tray-off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 363 B |
BIN
Resources/Textures/Objects/Tools/t-ray.rsi/tray-on.png
Normal file
BIN
Resources/Textures/Objects/Tools/t-ray.rsi/tray-on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 508 B |
Reference in New Issue
Block a user