From 26be28efc94d1fd7f8a7e07786b27ecfb41824d8 Mon Sep 17 00:00:00 2001 From: wixoaGit Date: Sat, 4 Jan 2025 19:02:22 -0500 Subject: [PATCH] Code cleanup --- .../Rendering/ClientAppearanceSystem.cs | 2 +- OpenDreamClient/Rendering/DreamIcon.cs | 30 ++++----- OpenDreamRuntime/AtomManager.cs | 17 ++--- OpenDreamRuntime/DreamManager.cs | 2 +- OpenDreamRuntime/DreamMapManager.cs | 8 +-- OpenDreamRuntime/Rendering/DMISpriteSystem.cs | 6 +- .../Rendering/ServerAppearanceSystem.cs | 34 +++++----- OpenDreamRuntime/ServerContentIoC.cs | 1 - OpenDreamShared/Dream/ImmutableAppearance.cs | 66 +++++++++---------- .../Network/Messages/MsgAllAppearances.cs | 2 +- TestGame/map_z1.dmm | 2 +- 11 files changed, 81 insertions(+), 89 deletions(-) diff --git a/OpenDreamClient/Rendering/ClientAppearanceSystem.cs b/OpenDreamClient/Rendering/ClientAppearanceSystem.cs index b47ec0f558..684730c40f 100644 --- a/OpenDreamClient/Rendering/ClientAppearanceSystem.cs +++ b/OpenDreamClient/Rendering/ClientAppearanceSystem.cs @@ -71,7 +71,7 @@ public DreamIcon GetTurfIcon(uint turfId) { } public void OnNewAppearance(MsgNewAppearance e) { - uint appearanceId = e.Appearance.MustGetID(); + uint appearanceId = e.Appearance.MustGetId(); _appearances[appearanceId] = e.Appearance; _appearances[appearanceId].ResolveOverlays(this); diff --git a/OpenDreamClient/Rendering/DreamIcon.cs b/OpenDreamClient/Rendering/DreamIcon.cs index 1b9e44a40d..3834a5c74b 100644 --- a/OpenDreamClient/Rendering/DreamIcon.cs +++ b/OpenDreamClient/Rendering/DreamIcon.cs @@ -256,7 +256,7 @@ private void UpdateAnimation() { float timeFactor = Math.Clamp((float)(DateTime.Now - animation.Start).Ticks / animation.Duration.Ticks, 0.0f, 1.0f); float factor = 0; if((animation.Easing & AnimationEasing.EaseIn) != 0) - timeFactor = timeFactor/2.0f; + timeFactor /= 2.0f; if((animation.Easing & AnimationEasing.EaseOut) != 0) timeFactor = 0.5f+timeFactor/2.0f; @@ -287,6 +287,7 @@ private void UpdateAnimation() { bounce -= 2.625f; factor = MathF.Pow(bounce, 2) + 0.984375f; } + break; case AnimationEasing.Elastic: //http://www.java2s.com/example/csharp/system/easing-equation-function-for-an-elastic-exponentially-decaying-sine-w.html with d=1, s=pi/2, c=2, b = -1 factor = MathF.Pow(2, -10 * timeFactor) * MathF.Sin((timeFactor - MathF.PI/2.0f) * (2.0f*MathF.PI/0.3f)) + 1.0f; @@ -314,27 +315,22 @@ private void UpdateAnimation() { suffix */ - if (endAppearance.Direction != _appearance.Direction) { + if (endAppearance.Direction != _appearance.Direction) _animatedAppearance.Direction = endAppearance.Direction; - } - if (endAppearance.Icon != _appearance.Icon) { + if (endAppearance.Icon != _appearance.Icon) _animatedAppearance.Icon = endAppearance.Icon; - } - if (endAppearance.IconState != _appearance.IconState) { + if (endAppearance.IconState != _appearance.IconState) _animatedAppearance.IconState = endAppearance.IconState; - } - if (endAppearance.Invisibility != _appearance.Invisibility) { + if (endAppearance.Invisibility != _appearance.Invisibility) _animatedAppearance.Invisibility = endAppearance.Invisibility; - } + /* TODO maptext - if (endAppearance.MapText != _appearance.MapText) { + if (endAppearance.MapText != _appearance.MapText) appearance.MapText = endAppearance.MapText; - } */ /* TODO suffix - if (endAppearance.Suffix != _appearance.Suffix) { + if (endAppearance.Suffix != _appearance.Suffix) appearance.Suffix = endAppearance.Suffix; - } */ //smooth animation properties @@ -367,7 +363,7 @@ private void UpdateAnimation() { ColorMatrix.Interpolate(in _appearance.ColorMatrix, in endAppearance.ColorMatrix, factor, out _animatedAppearance.ColorMatrix); } - if (endAppearance.GlideSize != _appearance.GlideSize) { + if (!endAppearance.GlideSize.Equals(_appearance.GlideSize)) { _animatedAppearance.GlideSize = ((1-factor) * _appearance.GlideSize) + (factor * endAppearance.GlideSize); } @@ -377,7 +373,7 @@ private void UpdateAnimation() { } */ - if (endAppearance.Layer != _appearance.Layer) { + if (!endAppearance.Layer.Equals(_appearance.Layer)) { _animatedAppearance.Layer = ((1-factor) * _appearance.Layer) + (factor * endAppearance.Layer); } @@ -481,7 +477,7 @@ private void UpdateIcon() { Overlays.Clear(); foreach (var overlayAppearance in Appearance.Overlays) { - DreamIcon overlay = new DreamIcon(renderTargetPool, gameTiming, clyde, appearanceSystem, overlayAppearance.MustGetID(), _direction); + DreamIcon overlay = new DreamIcon(renderTargetPool, gameTiming, clyde, appearanceSystem, overlayAppearance.MustGetId(), _direction); overlay.SizeChanged += CheckSizeChange; Overlays.Add(overlay); @@ -489,7 +485,7 @@ private void UpdateIcon() { Underlays.Clear(); foreach (var underlayAppearance in Appearance.Underlays) { - DreamIcon underlay = new DreamIcon(renderTargetPool, gameTiming, clyde, appearanceSystem, underlayAppearance.MustGetID(), _direction); + DreamIcon underlay = new DreamIcon(renderTargetPool, gameTiming, clyde, appearanceSystem, underlayAppearance.MustGetId(), _direction); underlay.SizeChanged += CheckSizeChange; Underlays.Add(underlay); diff --git a/OpenDreamRuntime/AtomManager.cs b/OpenDreamRuntime/AtomManager.cs index 476c1d2ff1..6d7b5e94b2 100644 --- a/OpenDreamRuntime/AtomManager.cs +++ b/OpenDreamRuntime/AtomManager.cs @@ -32,13 +32,14 @@ public sealed class AtomManager { private readonly Dictionary _entityToAtom = new(); private readonly Dictionary _definitionAppearanceCache = new(); - private ServerAppearanceSystem? AppearanceSystem{ - get { - if(_appearanceSystem is null) - _entitySystemManager.TryGetEntitySystem(out _appearanceSystem); - return _appearanceSystem; - } - } + private ServerAppearanceSystem? AppearanceSystem { + get { + if(_appearanceSystem is null) + _entitySystemManager.TryGetEntitySystem(out _appearanceSystem); + return _appearanceSystem; + } + } + private ServerVerbSystem VerbSystem => _verbSystem ??= _entitySystemManager.GetEntitySystem(); private ServerAppearanceSystem? _appearanceSystem; private ServerVerbSystem? _verbSystem; @@ -596,7 +597,7 @@ public void AnimateAppearance(DreamObject atom, TimeSpan duration, AnimationEasi } else if (atom is DreamObjectTurf turf) { //TODO: turf appearances are just set to the end appearance, they do not get properly animated _dreamMapManager.SetTurfAppearance(turf, appearance); - turfId = turf.Appearance.MustGetID(); + turfId = turf.Appearance.MustGetId(); } else if (atom is DreamObjectArea area) { //fuck knows, this will trigger a bunch of turf updates to? idek } diff --git a/OpenDreamRuntime/DreamManager.cs b/OpenDreamRuntime/DreamManager.cs index 5c85902e51..4264263a12 100644 --- a/OpenDreamRuntime/DreamManager.cs +++ b/OpenDreamRuntime/DreamManager.cs @@ -240,7 +240,7 @@ public string CreateRef(DreamValue value) { } else if (value.TryGetValueAsAppearance(out var appearance)) { refType = RefType.DreamAppearance; _appearanceSystem ??= _entitySystemManager.GetEntitySystem(); - idx = (int)_appearanceSystem.AddAppearance(appearance).MustGetID(); + idx = (int)_appearanceSystem.AddAppearance(appearance).MustGetId(); } else if (value.TryGetValueAsDreamResource(out var refRsc)) { refType = RefType.DreamResource; idx = refRsc.Id; diff --git a/OpenDreamRuntime/DreamMapManager.cs b/OpenDreamRuntime/DreamMapManager.cs index f0cde6ba3d..2b9959e137 100644 --- a/OpenDreamRuntime/DreamMapManager.cs +++ b/OpenDreamRuntime/DreamMapManager.cs @@ -181,10 +181,10 @@ public void SetTurf(DreamObjectTurf turf, DreamObjectDefinition type, DreamProcA public void SetTurfAppearance(DreamObjectTurf turf, MutableAppearance appearance) { if(turf.Cell.Area.Appearance != _appearanceSystem.DefaultAppearance) if(!appearance.Overlays.Contains(turf.Cell.Area.Appearance)) { - if(!_turfAreaLookup.TryGetValue((appearance, turf.Cell.Area.Appearance.MustGetID()), out var newAppearance)) { + if(!_turfAreaLookup.TryGetValue((appearance, turf.Cell.Area.Appearance.MustGetId()), out var newAppearance)) { newAppearance = MutableAppearance.GetCopy(appearance); newAppearance.Overlays.Add(turf.Cell.Area.Appearance); - _turfAreaLookup.Add((appearance, turf.Cell.Area.Appearance.MustGetID()), newAppearance); + _turfAreaLookup.Add((appearance, turf.Cell.Area.Appearance.MustGetId()), newAppearance); } appearance = newAppearance; @@ -193,7 +193,7 @@ public void SetTurfAppearance(DreamObjectTurf turf, MutableAppearance appearance var immutableAppearance = _appearanceSystem.AddAppearance(appearance); var level = _levels[turf.Z - 1]; - uint turfId = immutableAppearance.MustGetID(); + uint turfId = immutableAppearance.MustGetId(); level.QueuedTileUpdates[(turf.X, turf.Y)] = new Tile((int)turfId); turf.Appearance = immutableAppearance; } @@ -224,7 +224,7 @@ public void SetAreaAppearance(DreamObjectArea area, MutableAppearance appearance } var level = _levels[turf.Z - 1]; - uint turfId = newAppearance.MustGetID(); + uint turfId = newAppearance.MustGetId(); level.QueuedTileUpdates[(turf.X, turf.Y)] = new Tile((int)turfId); } } diff --git a/OpenDreamRuntime/Rendering/DMISpriteSystem.cs b/OpenDreamRuntime/Rendering/DMISpriteSystem.cs index 5bafbabe4f..4b4a39de2e 100644 --- a/OpenDreamRuntime/Rendering/DMISpriteSystem.cs +++ b/OpenDreamRuntime/Rendering/DMISpriteSystem.cs @@ -5,17 +5,15 @@ namespace OpenDreamRuntime.Rendering; public sealed class DMISpriteSystem : EntitySystem { - private ServerAppearanceSystem? _appearance; - [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; + [Dependency] private readonly ServerAppearanceSystem _appearance = default!; public override void Initialize() { SubscribeLocalEvent(GetComponentState); - _entitySystemManager.TryGetEntitySystem(out _appearance); } private void GetComponentState(EntityUid uid, DMISpriteComponent component, ref ComponentGetState args) { uint? appearanceId = (component.Appearance != null) - ? _appearance?.AddAppearance(component.Appearance).MustGetID() + ? _appearance.AddAppearance(component.Appearance).MustGetId() : null; args.State = new SharedDMISpriteComponent.DMISpriteComponentState(appearanceId, component.ScreenLocation); diff --git a/OpenDreamRuntime/Rendering/ServerAppearanceSystem.cs b/OpenDreamRuntime/Rendering/ServerAppearanceSystem.cs index b90ef3cb1b..0091f4f64b 100644 --- a/OpenDreamRuntime/Rendering/ServerAppearanceSystem.cs +++ b/OpenDreamRuntime/Rendering/ServerAppearanceSystem.cs @@ -11,22 +11,24 @@ namespace OpenDreamRuntime.Rendering; public sealed class ServerAppearanceSystem : SharedAppearanceSystem { + public readonly ImmutableAppearance DefaultAppearance; + /// /// Each appearance gets a unique ID when marked as registered. Here we store these as a key -> weakref in a weaktable, which does not count /// as a hard ref but allows quick lookup. Each object which holds an appearance MUST hold that ImmutableAppearance until it is no longer /// needed or it will be GC'd. Overlays & underlays are stored as hard refs on the ImmutableAppearance so you only need to hold the main appearance. /// private readonly HashSet _appearanceLookup = new(); - private readonly Dictionary _idToAppearance = new(); - private uint _counter; - public readonly ImmutableAppearance DefaultAppearance; - [Dependency] private readonly IServerNetManager _networkManager = default!; /// /// This system is used by the PVS thread, we need to be thread-safe /// private readonly object _lock = new(); + private readonly Dictionary _idToAppearance = new(); + private uint _counter; + + [Dependency] private readonly IServerNetManager _networkManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; public ServerAppearanceSystem() { @@ -34,7 +36,7 @@ public ServerAppearanceSystem() { DefaultAppearance.MarkRegistered(_counter++); //first appearance registered gets id 0, this is the blank default appearance ProxyWeakRef proxyWeakRef = new(DefaultAppearance); _appearanceLookup.Add(proxyWeakRef); - _idToAppearance.Add(DefaultAppearance.MustGetID(), proxyWeakRef); + _idToAppearance.Add(DefaultAppearance.MustGetId(), proxyWeakRef); //leaving this in as a sanity check for mutable and immutable appearance hashcodes covering all the same vars //if this debug assert fails, you've probably changed appearance var and not updated its counterpart Debug.Assert(DefaultAppearance.GetHashCode() == MutableAppearance.Default.GetHashCode()); @@ -59,7 +61,7 @@ private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) { foreach(ProxyWeakRef proxyWeakRef in _appearanceLookup){ if(proxyWeakRef.TryGetTarget(out var immutable)) - sendData.Add(immutable.MustGetID(), immutable); + sendData.Add(immutable.MustGetId(), immutable); } Logger.GetSawmill("appearance").Debug($"Sending {sendData.Count} appearances to new player {e.Session.Name}"); @@ -72,7 +74,7 @@ private void RegisterAppearance(ImmutableAppearance immutableAppearance) { immutableAppearance.MarkRegistered(_counter++); //lets this appearance know it needs to do GC finaliser & get an ID ProxyWeakRef proxyWeakRef = new(immutableAppearance); _appearanceLookup.Add(proxyWeakRef); - _idToAppearance.Add(immutableAppearance.MustGetID(), proxyWeakRef); + _idToAppearance.Add(immutableAppearance.MustGetId(), proxyWeakRef); _networkManager.ServerSendToAll(new MsgNewAppearance(immutableAppearance)); } @@ -104,8 +106,8 @@ public override void RemoveAppearance(ImmutableAppearance appearance) { if(weakRef.TryGetTarget(out var target) && !ReferenceEquals(target,appearance)) return; _appearanceLookup.Remove(proxyWeakRef); - _idToAppearance.Remove(appearance.MustGetID()); - RaiseNetworkEvent(new RemoveAppearanceEvent(appearance.MustGetID())); + _idToAppearance.Remove(appearance.MustGetId()); + RaiseNetworkEvent(new RemoveAppearanceEvent(appearance.MustGetId())); } } } @@ -126,7 +128,7 @@ public bool TryGetAppearanceById(uint appearanceId, [NotNullWhen(true)] out Immu } public void Animate(NetEntity entity, MutableAppearance targetAppearance, TimeSpan duration, AnimationEasing easing, int loop, AnimationFlags flags, int delay, bool chainAnim, uint? turfId) { - uint appearanceId = AddAppearance(targetAppearance).MustGetID(); + uint appearanceId = AddAppearance(targetAppearance).MustGetId(); RaiseNetworkEvent(new AnimationEvent(entity, appearanceId, duration, easing, loop, flags, delay, chainAnim, turfId)); } @@ -134,15 +136,15 @@ public void Animate(NetEntity entity, MutableAppearance targetAppearance, TimeSp //this class lets us hold a weakref and also do quick lookups in hash tables internal sealed class ProxyWeakRef: IEquatable{ - public WeakReference WeakRef; private readonly uint? _registeredId; private readonly int _hashCode; - public bool IsAlive => WeakRef.TryGetTarget(out var _); - public bool TryGetTarget([NotNullWhen(true)] out ImmutableAppearance? target) => WeakRef.TryGetTarget(out target); + public bool TryGetTarget([NotNullWhen(true)] out ImmutableAppearance? target) => _weakRef.TryGetTarget(out target); + + private readonly WeakReference _weakRef; public ProxyWeakRef(ImmutableAppearance appearance) { - appearance.TryGetID(out _registeredId); - WeakRef = new(appearance); + appearance.TryGetId(out _registeredId); + _weakRef = new(appearance); _hashCode = appearance.GetHashCode(); } @@ -157,7 +159,7 @@ public bool Equals(ProxyWeakRef? proxy) { return false; if(_registeredId is not null && _registeredId == proxy._registeredId) return true; - if(WeakRef.TryGetTarget(out ImmutableAppearance? thisRef) && proxy.WeakRef.TryGetTarget(out ImmutableAppearance? thatRef)) + if(_weakRef.TryGetTarget(out ImmutableAppearance? thisRef) && proxy._weakRef.TryGetTarget(out ImmutableAppearance? thatRef)) return thisRef.Equals(thatRef); return false; } diff --git a/OpenDreamRuntime/ServerContentIoC.cs b/OpenDreamRuntime/ServerContentIoC.cs index 2673ade59f..a7bde642e9 100644 --- a/OpenDreamRuntime/ServerContentIoC.cs +++ b/OpenDreamRuntime/ServerContentIoC.cs @@ -15,7 +15,6 @@ public static void Register(bool unitTests = false) { IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); - IoCManager.Register(); #if DEBUG IoCManager.Register(); diff --git a/OpenDreamShared/Dream/ImmutableAppearance.cs b/OpenDreamShared/Dream/ImmutableAppearance.cs index 4dac22668d..3190d3ce2d 100644 --- a/OpenDreamShared/Dream/ImmutableAppearance.cs +++ b/OpenDreamShared/Dream/ImmutableAppearance.cs @@ -51,13 +51,6 @@ public sealed class ImmutableAppearance : IEquatable { [ViewVariables] public readonly MouseOpacity MouseOpacity = MutableAppearance.Default.MouseOpacity; [ViewVariables] public readonly ImmutableAppearance[] Overlays; [ViewVariables] public readonly ImmutableAppearance[] Underlays; - - [NonSerialized] - private List? _overlayIDs; - - [NonSerialized] - private List? _underlayIDs; - [ViewVariables] public readonly Robust.Shared.GameObjects.NetEntity[] VisContents; [ViewVariables] public readonly DreamFilter[] Filters; [ViewVariables] public readonly int[] Verbs; @@ -73,24 +66,8 @@ public sealed class ImmutableAppearance : IEquatable { // PixelOffset2 behaves the same as PixelOffset in top-down mode, so this is used public Vector2i TotalPixelOffset => PixelOffset + PixelOffset2; - public void MarkRegistered(uint registeredId){ - _registeredId = registeredId; - _needsFinalizer = true; - } - - //this should only be called client-side, after network transfer - public void ResolveOverlays(SharedAppearanceSystem appearanceSystem) { - if(_overlayIDs is not null) - for (int i = 0; i < _overlayIDs.Count; i++) - Overlays[i] = appearanceSystem.MustGetAppearanceById(_overlayIDs[i]); - - if(_underlayIDs is not null) - for (int i = 0; i < _underlayIDs.Count; i++) - Underlays[i] = appearanceSystem.MustGetAppearanceById(_underlayIDs[i]); - - _overlayIDs = null; - _underlayIDs = null; - } + [NonSerialized] private List? _overlayIDs; + [NonSerialized] private List? _underlayIDs; public ImmutableAppearance(MutableAppearance appearance, SharedAppearanceSystem? serverAppearanceSystem) { _appearanceSystem = serverAppearanceSystem; @@ -129,6 +106,30 @@ public ImmutableAppearance(MutableAppearance appearance, SharedAppearanceSystem? } } + ~ImmutableAppearance() { + if(_needsFinalizer && _registeredId is not null) + _appearanceSystem!.RemoveAppearance(this); + } + + public void MarkRegistered(uint registeredId){ + _registeredId = registeredId; + _needsFinalizer = true; + } + + //this should only be called client-side, after network transfer + public void ResolveOverlays(SharedAppearanceSystem appearanceSystem) { + if(_overlayIDs is not null) + for (int i = 0; i < _overlayIDs.Count; i++) + Overlays[i] = appearanceSystem.MustGetAppearanceById(_overlayIDs[i]); + + if(_underlayIDs is not null) + for (int i = 0; i < _underlayIDs.Count; i++) + Underlays[i] = appearanceSystem.MustGetAppearanceById(_underlayIDs[i]); + + _overlayIDs = null; + _underlayIDs = null; + } + public override bool Equals(object? obj) => obj is ImmutableAppearance immutable && Equals(immutable); public bool Equals(ImmutableAppearance? immutableAppearance) { @@ -188,13 +189,13 @@ public bool Equals(ImmutableAppearance? immutableAppearance) { return true; } - public uint MustGetID() { + public uint MustGetId() { if(_registeredId is null) throw new InvalidDataException("GetID() was called on an appearance without an ID"); return (uint)_registeredId; } - public bool TryGetID([NotNullWhen(true)] out uint? id) { + public bool TryGetId([NotNullWhen(true)] out uint? id) { id = _registeredId; return _registeredId is not null; } @@ -459,7 +460,7 @@ public MutableAppearance ToMutable() { public void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) { buffer.Write((byte)IconAppearanceProperty.Id); - buffer.WriteVariableUInt32(MustGetID()); + buffer.WriteVariableUInt32(MustGetId()); if (Name != MutableAppearance.Default.Name) { buffer.Write((byte)IconAppearanceProperty.Name); @@ -574,7 +575,7 @@ public void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serialize buffer.WriteVariableInt32(Overlays.Length); foreach (var overlay in Overlays) { - buffer.WriteVariableUInt32(overlay.MustGetID()); + buffer.WriteVariableUInt32(overlay.MustGetId()); } } @@ -583,7 +584,7 @@ public void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serialize buffer.WriteVariableInt32(Underlays.Length); foreach (var underlay in Underlays) { - buffer.WriteVariableUInt32(underlay.MustGetID()); + buffer.WriteVariableUInt32(underlay.MustGetId()); } } @@ -633,10 +634,5 @@ public void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serialize public int ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) { throw new NotImplementedException(); } - - ~ImmutableAppearance() { - if(_needsFinalizer && _registeredId is not null) - _appearanceSystem!.RemoveAppearance(this); - } } diff --git a/OpenDreamShared/Network/Messages/MsgAllAppearances.cs b/OpenDreamShared/Network/Messages/MsgAllAppearances.cs index 433b166904..6f7a2bc0f4 100644 --- a/OpenDreamShared/Network/Messages/MsgAllAppearances.cs +++ b/OpenDreamShared/Network/Messages/MsgAllAppearances.cs @@ -20,7 +20,7 @@ public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer for (int i = 0; i < count; i++) { var appearance = new ImmutableAppearance(buffer, serializer); - AllAppearances.Add(appearance.MustGetID(), appearance); + AllAppearances.Add(appearance.MustGetId(), appearance); } } diff --git a/TestGame/map_z1.dmm b/TestGame/map_z1.dmm index 1854213037..54a7a34400 100644 --- a/TestGame/map_z1.dmm +++ b/TestGame/map_z1.dmm @@ -36,8 +36,8 @@ "J" = (/obj/order_test_target,/turf,/area) "K" = (/obj/complex_overlay_test,/turf,/area) "L" = (/obj/float_layer_test,/turf,/area) -"N" = (/obj/plaque/animation_turf_test,/turf,/area) "M" = (/mob,/turf,/area) +"N" = (/obj/plaque/animation_turf_test,/turf,/area) "O" = (/obj/plaque/animation_test,/turf,/area) "R" = (/turf/blue,/area/withicon) "S" = (/obj/button/animation_turf_test,/turf,/area)