From a16256451611809a3af093e118ac77299cd8e50c Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 26 Jul 2019 13:52:18 +0200 Subject: [PATCH 01/31] Update submodule. --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 83c738e423..a4f2441153 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 83c738e4231aa4e1bb941d98fed2f761859eaa38 +Subproject commit a4f244115347bc7b667dfad30f213b13a31e79f1 From d906bcda03330860c138e86d64f6f1186f179178 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 26 Jul 2019 13:53:06 +0200 Subject: [PATCH 02/31] Eris low walls & windows. Still needs work blocked by better entity parenting, but oh well. --- Content.Client/EntryPoint.cs | 4 + .../IconSmoothing/IconSmoothComponent.cs | 157 ++++++++++++- .../Components/LowWallComponent.cs | 206 ++++++++++++++++++ .../GameObjects/Components/WindowComponent.cs | 91 ++++++++ .../EntitySystems/IconSmoothSystem.cs | 151 +------------ .../GameObjects/EntitySystems/WindowSystem.cs | 51 +++++ Resources/Prototypes/Entities/walls.yml | 6 +- .../Entities/walls/structures/low_wall.yml | 32 +++ .../Entities/walls/structures/windows.yml | 30 +++ .../Textures/Buildings/low_wall.rsi/meta.json | 1 + .../Textures/Buildings/low_wall.rsi/metal.png | Bin 0 -> 326 bytes .../Buildings/low_wall.rsi/metal_0.png | Bin 0 -> 561 bytes .../Buildings/low_wall.rsi/metal_1.png | Bin 0 -> 432 bytes .../Buildings/low_wall.rsi/metal_2.png | Bin 0 -> 561 bytes .../Buildings/low_wall.rsi/metal_3.png | Bin 0 -> 432 bytes .../Buildings/low_wall.rsi/metal_4.png | Bin 0 -> 435 bytes .../Buildings/low_wall.rsi/metal_5.png | Bin 0 -> 440 bytes .../Buildings/low_wall.rsi/metal_6.png | Bin 0 -> 435 bytes .../Buildings/low_wall.rsi/metal_7.png | Bin 0 -> 243 bytes .../Buildings/low_wall.rsi/metal_over_0.png | Bin 0 -> 96 bytes .../Buildings/low_wall.rsi/metal_over_1.png | Bin 0 -> 400 bytes .../Buildings/low_wall.rsi/metal_over_2.png | Bin 0 -> 96 bytes .../Buildings/low_wall.rsi/metal_over_3.png | Bin 0 -> 235 bytes .../Buildings/low_wall.rsi/metal_over_4.png | Bin 0 -> 396 bytes .../Buildings/low_wall.rsi/metal_over_5.png | Bin 0 -> 521 bytes .../Buildings/low_wall.rsi/metal_over_6.png | Bin 0 -> 232 bytes .../Buildings/low_wall.rsi/metal_over_7.png | Bin 0 -> 288 bytes .../Textures/Buildings/rwindow.rsi/meta.json | 1 + .../Buildings/rwindow.rsi/rwindow0.png | Bin 0 -> 814 bytes .../Buildings/rwindow.rsi/rwindow1.png | Bin 0 -> 460 bytes .../Buildings/rwindow.rsi/rwindow2.png | Bin 0 -> 814 bytes .../Buildings/rwindow.rsi/rwindow3.png | Bin 0 -> 460 bytes .../Buildings/rwindow.rsi/rwindow4.png | Bin 0 -> 489 bytes .../Buildings/rwindow.rsi/rwindow5.png | Bin 0 -> 916 bytes .../Buildings/rwindow.rsi/rwindow6.png | Bin 0 -> 489 bytes .../Buildings/rwindow.rsi/rwindow7.png | Bin 0 -> 324 bytes .../Textures/Buildings/wall.rsi/full.png | Bin 321 -> 269 bytes .../Textures/Buildings/wall.rsi/solid0.png | Bin 264 -> 324 bytes .../Textures/Buildings/wall.rsi/solid1.png | Bin 256 -> 231 bytes .../Textures/Buildings/wall.rsi/solid2.png | Bin 264 -> 324 bytes .../Textures/Buildings/wall.rsi/solid3.png | Bin 256 -> 231 bytes .../Textures/Buildings/wall.rsi/solid4.png | Bin 258 -> 237 bytes .../Textures/Buildings/wall.rsi/solid5.png | Bin 254 -> 283 bytes .../Textures/Buildings/wall.rsi/solid6.png | Bin 258 -> 237 bytes .../Textures/Buildings/wall.rsi/solid7.png | Bin 191 -> 144 bytes .../Textures/Buildings/window.rsi/meta.json | 1 + .../Textures/Buildings/window.rsi/window0.png | Bin 0 -> 524 bytes .../Textures/Buildings/window.rsi/window1.png | Bin 0 -> 348 bytes .../Textures/Buildings/window.rsi/window2.png | Bin 0 -> 524 bytes .../Textures/Buildings/window.rsi/window3.png | Bin 0 -> 348 bytes .../Textures/Buildings/window.rsi/window4.png | Bin 0 -> 352 bytes .../Textures/Buildings/window.rsi/window5.png | Bin 0 -> 516 bytes .../Textures/Buildings/window.rsi/window6.png | Bin 0 -> 352 bytes .../Textures/Buildings/window.rsi/window7.png | Bin 0 -> 246 bytes 54 files changed, 575 insertions(+), 156 deletions(-) create mode 100644 Content.Client/GameObjects/Components/LowWallComponent.cs create mode 100644 Content.Client/GameObjects/Components/WindowComponent.cs create mode 100644 Content.Client/GameObjects/EntitySystems/WindowSystem.cs create mode 100644 Resources/Prototypes/Entities/walls/structures/low_wall.yml create mode 100644 Resources/Prototypes/Entities/walls/structures/windows.yml create mode 100644 Resources/Textures/Buildings/low_wall.rsi/meta.json create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_0.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_1.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_2.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_3.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_4.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_5.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_6.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_7.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_0.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_1.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_2.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_3.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_4.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_5.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_6.png create mode 100644 Resources/Textures/Buildings/low_wall.rsi/metal_over_7.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/meta.json create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow0.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow1.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow2.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow3.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow4.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow5.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow6.png create mode 100644 Resources/Textures/Buildings/rwindow.rsi/rwindow7.png create mode 100644 Resources/Textures/Buildings/window.rsi/meta.json create mode 100644 Resources/Textures/Buildings/window.rsi/window0.png create mode 100644 Resources/Textures/Buildings/window.rsi/window1.png create mode 100644 Resources/Textures/Buildings/window.rsi/window2.png create mode 100644 Resources/Textures/Buildings/window.rsi/window3.png create mode 100644 Resources/Textures/Buildings/window.rsi/window4.png create mode 100644 Resources/Textures/Buildings/window.rsi/window5.png create mode 100644 Resources/Textures/Buildings/window.rsi/window6.png create mode 100644 Resources/Textures/Buildings/window.rsi/window7.png diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 0a04e76ce2..a9a4663f29 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -109,6 +109,8 @@ namespace Content.Client factory.Register(); factory.Register(); factory.Register(); + factory.Register(); + factory.RegisterReference(); factory.Register(); factory.Register(); factory.Register(); @@ -159,6 +161,8 @@ namespace Content.Client factory.Register(); factory.Register(); + factory.Register(); + IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); diff --git a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs index 6b510ff8bd..74352642b8 100644 --- a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs +++ b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs @@ -1,10 +1,14 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Content.Client.GameObjects.EntitySystems; using JetBrains.Annotations; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; +using Robust.Shared.Maths; using Robust.Shared.Serialization; using static Robust.Client.GameObjects.SpriteComponent; @@ -21,7 +25,7 @@ namespace Content.Client.GameObjects.Components.IconSmoothing /// To use, set base equal to the prefix of the corner states in the sprite base RSI. /// Any objects with the same key will connect. /// - public sealed class IconSmoothComponent : Component + public class IconSmoothComponent : Component { private string _smoothKey; private string _stateBase; @@ -76,9 +80,9 @@ namespace Content.Client.GameObjects.Components.IconSmoothing SnapGrid.OnPositionChanged += SnapGridOnPositionChanged; Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode)); - var state0 = $"{StateBase}0"; if (Mode == IconSmoothingMode.Corners) { + var state0 = $"{StateBase}0"; Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0)); Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None); Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0)); @@ -90,6 +94,107 @@ namespace Content.Client.GameObjects.Components.IconSmoothing } } + internal virtual void CalculateNewSprite() + { + switch (Mode) + { + case IconSmoothingMode.Corners: + CalculateNewSpriteCorers(); + break; + + case IconSmoothingMode.CardinalFlags: + CalculateNewSpriteCardinal(); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void CalculateNewSpriteCardinal() + { + var dirs = CardinalConnectDirs.None; + + if (MatchingEntity(SnapGrid.GetInDir(Direction.North))) + dirs |= CardinalConnectDirs.North; + if (MatchingEntity(SnapGrid.GetInDir(Direction.South))) + dirs |= CardinalConnectDirs.South; + if (MatchingEntity(SnapGrid.GetInDir(Direction.East))) + dirs |= CardinalConnectDirs.East; + if (MatchingEntity(SnapGrid.GetInDir(Direction.West))) + dirs |= CardinalConnectDirs.West; + + Sprite.LayerSetState(0, $"{StateBase}{(int) dirs}"); + } + + private void CalculateNewSpriteCorers() + { + var n = MatchingEntity(SnapGrid.GetInDir(Direction.North)); + var ne = MatchingEntity(SnapGrid.GetInDir(Direction.NorthEast)); + var e = MatchingEntity(SnapGrid.GetInDir(Direction.East)); + var se = MatchingEntity(SnapGrid.GetInDir(Direction.SouthEast)); + var s = MatchingEntity(SnapGrid.GetInDir(Direction.South)); + var sw = MatchingEntity(SnapGrid.GetInDir(Direction.SouthWest)); + var w = MatchingEntity(SnapGrid.GetInDir(Direction.West)); + var nw = MatchingEntity(SnapGrid.GetInDir(Direction.NorthWest)); + + // ReSharper disable InconsistentNaming + var cornerNE = CornerFill.None; + var cornerSE = CornerFill.None; + var cornerSW = CornerFill.None; + var cornerNW = CornerFill.None; + // ReSharper restore InconsistentNaming + + if (n) + { + cornerNE |= CornerFill.CounterClockwise; + cornerNW |= CornerFill.Clockwise; + } + + if (ne) + { + cornerNE |= CornerFill.Diagonal; + } + + if (e) + { + cornerNE |= CornerFill.Clockwise; + cornerSE |= CornerFill.CounterClockwise; + } + + if (se) + { + cornerSE |= CornerFill.Diagonal; + } + + if (s) + { + cornerSE |= CornerFill.Clockwise; + cornerSW |= CornerFill.CounterClockwise; + } + + if (sw) + { + cornerSW |= CornerFill.Diagonal; + } + + if (w) + { + cornerSW |= CornerFill.Clockwise; + cornerNW |= CornerFill.CounterClockwise; + } + + if (nw) + { + cornerNW |= CornerFill.Diagonal; + } + + Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int) cornerNE}"); + Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int) cornerSE}"); + Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}"); + Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}"); + } + public override void Shutdown() { SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged; @@ -104,6 +209,52 @@ namespace Content.Client.GameObjects.Components.IconSmoothing _lastPosition = (Owner.Transform.GridID, SnapGrid.Position); } + [System.Diagnostics.Contracts.Pure] + protected bool MatchingEntity(IEnumerable candidates) + { + foreach (var entity in candidates) + { + if (!entity.TryGetComponent(out IconSmoothComponent other)) + { + continue; + } + + if (other.SmoothKey == SmoothKey) + { + return true; + } + } + + return false; + } + + [Flags] + private enum CardinalConnectDirs : byte + { + None = 0, + North = 1, + South = 2, + East = 4, + West = 8 + } + + [Flags] + public enum CornerFill : byte + { + // These values are pulled from Baystation12. + // I'm too lazy to convert the state names. + None = 0, + + // The cardinal tile counter-clockwise of this corner is filled. + CounterClockwise = 1, + + // The diagonal tile in the direction of this corner. + Diagonal = 2, + + // The cardinal tile clockwise of this corner is filled. + Clockwise = 4, + } + [SuppressMessage("ReSharper", "InconsistentNaming")] public enum CornerLayers { diff --git a/Content.Client/GameObjects/Components/LowWallComponent.cs b/Content.Client/GameObjects/Components/LowWallComponent.cs new file mode 100644 index 0000000000..2f1b6e3868 --- /dev/null +++ b/Content.Client/GameObjects/Components/LowWallComponent.cs @@ -0,0 +1,206 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Content.Client.GameObjects.Components.IconSmoothing; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Maths; +using static Robust.Client.GameObjects.SpriteComponent; + +namespace Content.Client.GameObjects.Components +{ + // TODO: Over layers should be placed ABOVE the window itself too. + // This is gonna require a client entity & parenting, + // so IsMapTransform being naive is gonna be a problem. + + /// + /// Override of icon smoothing to handle the specific complexities of low walls. + /// + public class LowWallComponent : IconSmoothComponent + { + public override string Name => "LowWall"; + + public CornerFill LastCornerNE { get; private set; } + public CornerFill LastCornerSE { get; private set; } + public CornerFill LastCornerSW { get; private set; } + public CornerFill LastCornerNW { get; private set; } + + public override void Startup() + { + base.Startup(); + + var overState0 = $"{StateBase}over_0"; + Sprite.LayerMapSet(OverCornerLayers.SE, Sprite.AddLayerState(overState0)); + Sprite.LayerSetDirOffset(OverCornerLayers.SE, DirectionOffset.None); + Sprite.LayerMapSet(OverCornerLayers.NE, Sprite.AddLayerState(overState0)); + Sprite.LayerSetDirOffset(OverCornerLayers.NE, DirectionOffset.CounterClockwise); + Sprite.LayerMapSet(OverCornerLayers.NW, Sprite.AddLayerState(overState0)); + Sprite.LayerSetDirOffset(OverCornerLayers.NW, DirectionOffset.Flip); + Sprite.LayerMapSet(OverCornerLayers.SW, Sprite.AddLayerState(overState0)); + Sprite.LayerSetDirOffset(OverCornerLayers.SW, DirectionOffset.Clockwise); + } + + internal override void CalculateNewSprite() + { + base.CalculateNewSprite(); + + var (n, nl) = MatchingWall(SnapGrid.GetInDir(Direction.North)); + var (ne, nel) = MatchingWall(SnapGrid.GetInDir(Direction.NorthEast)); + var (e, el) = MatchingWall(SnapGrid.GetInDir(Direction.East)); + var (se, sel) = MatchingWall(SnapGrid.GetInDir(Direction.SouthEast)); + var (s, sl) = MatchingWall(SnapGrid.GetInDir(Direction.South)); + var (sw, swl) = MatchingWall(SnapGrid.GetInDir(Direction.SouthWest)); + var (w, wl) = MatchingWall(SnapGrid.GetInDir(Direction.West)); + var (nw, nwl) = MatchingWall(SnapGrid.GetInDir(Direction.NorthWest)); + + // ReSharper disable InconsistentNaming + var cornerNE = CornerFill.None; + var cornerSE = CornerFill.None; + var cornerSW = CornerFill.None; + var cornerNW = CornerFill.None; + + var lowCornerNE = CornerFill.None; + var lowCornerSE = CornerFill.None; + var lowCornerSW = CornerFill.None; + var lowCornerNW = CornerFill.None; + // ReSharper restore InconsistentNaming + + if (n) + { + cornerNE |= CornerFill.CounterClockwise; + cornerNW |= CornerFill.Clockwise; + + if (!nl) + { + lowCornerNE |= CornerFill.CounterClockwise; + lowCornerNW |= CornerFill.Clockwise; + } + } + + if (ne) + { + cornerNE |= CornerFill.Diagonal; + + if (!nel && (nl || el || n && e)) + { + lowCornerNE |= CornerFill.Diagonal; + } + } + + if (e) + { + cornerNE |= CornerFill.Clockwise; + cornerSE |= CornerFill.CounterClockwise; + + if (!el) + { + lowCornerNE |= CornerFill.Clockwise; + lowCornerSE |= CornerFill.CounterClockwise; + } + } + + if (se) + { + cornerSE |= CornerFill.Diagonal; + + if (!sel && (sl || el || s && e)) + { + lowCornerSE |= CornerFill.Diagonal; + } + } + + if (s) + { + cornerSE |= CornerFill.Clockwise; + cornerSW |= CornerFill.CounterClockwise; + + if (!sl) + { + lowCornerSE |= CornerFill.Clockwise; + lowCornerSW |= CornerFill.CounterClockwise; + } + } + + if (sw) + { + cornerSW |= CornerFill.Diagonal; + + if (!swl && (sl || wl || s && w)) + { + lowCornerSW |= CornerFill.Diagonal; + } + } + + if (w) + { + cornerSW |= CornerFill.Clockwise; + cornerNW |= CornerFill.CounterClockwise; + + if (!wl) + { + lowCornerSW |= CornerFill.Clockwise; + lowCornerNW |= CornerFill.CounterClockwise; + } + } + + if (nw) + { + cornerNW |= CornerFill.Diagonal; + + if (!nwl && (nl || wl || n && w)) + { + lowCornerNW |= CornerFill.Diagonal; + } + } + + Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int) cornerNE}"); + Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int) cornerSE}"); + Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}"); + Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}"); + + Sprite.LayerSetState(OverCornerLayers.NE, $"{StateBase}over_{(int) lowCornerNE}"); + Sprite.LayerSetState(OverCornerLayers.SE, $"{StateBase}over_{(int) lowCornerSE}"); + Sprite.LayerSetState(OverCornerLayers.SW, $"{StateBase}over_{(int) lowCornerSW}"); + Sprite.LayerSetState(OverCornerLayers.NW, $"{StateBase}over_{(int) lowCornerNW}"); + + LastCornerNE = cornerNE; + LastCornerSE = cornerSE; + LastCornerSW = cornerSW; + LastCornerNW = cornerNW; + + foreach (var entity in SnapGrid.GetLocal()) + { + if (entity.TryGetComponent(out WindowComponent window)) + { + window.UpdateSprite(); + } + } + } + + [System.Diagnostics.Contracts.Pure] + private (bool connected, bool lowWall) MatchingWall(IEnumerable candidates) + { + foreach (var entity in candidates) + { + if (!entity.TryGetComponent(out IconSmoothComponent other)) + { + continue; + } + + if (other.SmoothKey == SmoothKey) + { + return (true, other is LowWallComponent); + } + } + + return (false, false); + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum OverCornerLayers + { + SE, + NE, + NW, + SW, + } + } +} diff --git a/Content.Client/GameObjects/Components/WindowComponent.cs b/Content.Client/GameObjects/Components/WindowComponent.cs new file mode 100644 index 0000000000..f92c7b4f20 --- /dev/null +++ b/Content.Client/GameObjects/Components/WindowComponent.cs @@ -0,0 +1,91 @@ +using Content.Client.GameObjects.EntitySystems; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.Serialization; +using static Content.Client.GameObjects.Components.IconSmoothing.IconSmoothComponent; + +namespace Content.Client.GameObjects.Components +{ + public sealed class WindowComponent : Component + { + public override string Name => "Window"; + + private string _stateBase; + private ISpriteComponent _sprite; + private SnapGridComponent _snapGrid; + + public override void Initialize() + { + base.Initialize(); + + _sprite = Owner.GetComponent(); + _snapGrid = Owner.GetComponent(); + } + + public override void Startup() + { + base.Startup(); + + _snapGrid.OnPositionChanged += SnapGridOnPositionChanged; + Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent()); + + var state0 = $"{_stateBase}0"; + _sprite.LayerMapSet(CornerLayers.SE, _sprite.AddLayerState(state0)); + _sprite.LayerSetDirOffset(CornerLayers.SE, SpriteComponent.DirectionOffset.None); + _sprite.LayerMapSet(CornerLayers.NE, _sprite.AddLayerState(state0)); + _sprite.LayerSetDirOffset(CornerLayers.NE, SpriteComponent.DirectionOffset.CounterClockwise); + _sprite.LayerMapSet(CornerLayers.NW, _sprite.AddLayerState(state0)); + _sprite.LayerSetDirOffset(CornerLayers.NW, SpriteComponent.DirectionOffset.Flip); + _sprite.LayerMapSet(CornerLayers.SW, _sprite.AddLayerState(state0)); + _sprite.LayerSetDirOffset(CornerLayers.SW, SpriteComponent.DirectionOffset.Clockwise); + } + + public override void Shutdown() + { + _snapGrid.OnPositionChanged -= SnapGridOnPositionChanged; + + base.Shutdown(); + } + + private void SnapGridOnPositionChanged() + { + Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent()); + } + + public void UpdateSprite() + { + var lowWall = FindLowWall(); + if (lowWall == null) + { + return; + } + + _sprite.LayerSetState(CornerLayers.NE, $"{_stateBase}{(int) lowWall.LastCornerNE}"); + _sprite.LayerSetState(CornerLayers.SE, $"{_stateBase}{(int) lowWall.LastCornerSE}"); + _sprite.LayerSetState(CornerLayers.SW, $"{_stateBase}{(int) lowWall.LastCornerSW}"); + _sprite.LayerSetState(CornerLayers.NW, $"{_stateBase}{(int) lowWall.LastCornerNW}"); + } + + private LowWallComponent FindLowWall() + { + foreach (var entity in _snapGrid.GetLocal()) + { + if (entity.TryGetComponent(out LowWallComponent lowWall)) + { + return lowWall; + } + } + + return null; + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _stateBase, "base", null); + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs index b210804f00..9b7851360a 100644 --- a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs @@ -1,9 +1,7 @@ -using System; using System.Collections.Generic; using System.Linq; using Content.Client.GameObjects.Components.IconSmoothing; using JetBrains.Annotations; -using Robust.Client.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.GameObjects.Systems; @@ -132,157 +130,10 @@ namespace Content.Client.GameObjects.EntitySystems return; } - var sprite = smoothing.Sprite; - var snapGrid = smoothing.SnapGrid; - - switch (smoothing.Mode) - { - case IconSmoothingMode.Corners: - _calculateNewSpriteCorers(smoothing, snapGrid, sprite); - break; - - case IconSmoothingMode.CardinalFlags: - _calculateNewSpriteCardinal(smoothing, snapGrid, sprite); - break; - - default: - throw new ArgumentOutOfRangeException(); - } + smoothing.CalculateNewSprite(); smoothing.UpdateGeneration = _generation; } - - private static void _calculateNewSpriteCardinal(IconSmoothComponent smoothing, SnapGridComponent snapGrid, - ISpriteComponent sprite) - { - var dirs = CardinalConnectDirs.None; - - if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.North))) - dirs |= CardinalConnectDirs.North; - if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.South))) - dirs |= CardinalConnectDirs.South; - if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.East))) - dirs |= CardinalConnectDirs.East; - if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.West))) - dirs |= CardinalConnectDirs.West; - - sprite.LayerSetState(0, $"{smoothing.StateBase}{(int) dirs}"); - } - - private static void _calculateNewSpriteCorers(IconSmoothComponent smoothing, SnapGridComponent snapGrid, - ISpriteComponent sprite) - { - var n = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.North)); - var ne = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.NorthEast)); - var e = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.East)); - var se = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.SouthEast)); - var s = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.South)); - var sw = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.SouthWest)); - var w = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.West)); - var nw = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.NorthWest)); - - // ReSharper disable InconsistentNaming - var cornerNE = CornerFill.None; - var cornerSE = CornerFill.None; - var cornerSW = CornerFill.None; - var cornerNW = CornerFill.None; - // ReSharper restore InconsistentNaming - - if (n) - { - cornerNE |= CornerFill.CounterClockwise; - cornerNW |= CornerFill.Clockwise; - } - - if (ne) - { - cornerNE |= CornerFill.Diagonal; - } - - if (e) - { - cornerNE |= CornerFill.Clockwise; - cornerSE |= CornerFill.CounterClockwise; - } - - if (se) - { - cornerSE |= CornerFill.Diagonal; - } - - if (s) - { - cornerSE |= CornerFill.Clockwise; - cornerSW |= CornerFill.CounterClockwise; - } - - if (sw) - { - cornerSW |= CornerFill.Diagonal; - } - - if (w) - { - cornerSW |= CornerFill.Clockwise; - cornerNW |= CornerFill.CounterClockwise; - } - - if (nw) - { - cornerNW |= CornerFill.Diagonal; - } - - sprite.LayerSetState(IconSmoothComponent.CornerLayers.NE, $"{smoothing.StateBase}{(int) cornerNE}"); - sprite.LayerSetState(IconSmoothComponent.CornerLayers.SE, $"{smoothing.StateBase}{(int) cornerSE}"); - sprite.LayerSetState(IconSmoothComponent.CornerLayers.SW, $"{smoothing.StateBase}{(int) cornerSW}"); - sprite.LayerSetState(IconSmoothComponent.CornerLayers.NW, $"{smoothing.StateBase}{(int) cornerNW}"); - } - - [System.Diagnostics.Contracts.Pure] - private static bool MatchingEntity(IconSmoothComponent source, IEnumerable candidates) - { - foreach (var entity in candidates) - { - if (!entity.TryGetComponent(out IconSmoothComponent other)) - { - return false; - } - - if (other.SmoothKey == source.SmoothKey) - { - return true; - } - } - - return false; - } - - [Flags] - private enum CardinalConnectDirs : byte - { - None = 0, - North = 1, - South = 2, - East = 4, - West = 8 - } - - [Flags] - private enum CornerFill : byte - { - // These values are pulled from Baystation12. - // I'm too lazy to convert the state names. - None = 0, - - // The cardinal tile counter-clockwise of this corner is filled. - CounterClockwise = 1, - - // The diagonal tile in the direction of this corner. - Diagonal = 2, - - // The cardinal tile clockwise of this corner is filled. - Clockwise = 4, - } } /// diff --git a/Content.Client/GameObjects/EntitySystems/WindowSystem.cs b/Content.Client/GameObjects/EntitySystems/WindowSystem.cs new file mode 100644 index 0000000000..73b33afb10 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/WindowSystem.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using Content.Client.GameObjects.Components; +using Content.Client.GameObjects.Components.IconSmoothing; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Client.GameObjects.EntitySystems +{ + [UsedImplicitly] + public sealed class WindowSystem : EntitySystem + { + private readonly Queue _dirtyEntities = new Queue(); + + public override void Initialize() + { + base.Initialize(); + + SubscribeEvent(HandleDirtyEvent); + } + + private void HandleDirtyEvent(object sender, WindowSmoothDirtyEvent ev) + { + if (sender is IEntity senderEnt && senderEnt.HasComponent()) + { + _dirtyEntities.Enqueue(senderEnt); + } + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + // Performance: This could be spread over multiple updates, or made parallel. + while (_dirtyEntities.Count > 0) + { + _dirtyEntities.Dequeue().GetComponent().UpdateSprite(); + } + } + } + + /// + /// Event raised by a when it needs to be recalculated. + /// + public sealed class WindowSmoothDirtyEvent : EntitySystemMessage + { + } +} diff --git a/Resources/Prototypes/Entities/walls.yml b/Resources/Prototypes/Entities/walls.yml index 3f571b595c..1d76d42830 100644 --- a/Resources/Prototypes/Entities/walls.yml +++ b/Resources/Prototypes/Entities/walls.yml @@ -5,7 +5,7 @@ - type: Clickable - type: Sprite netsync: false - color: "#636769" + color: "#71797a" drawdepth: Walls sprite: Buildings/wall.rsi @@ -23,10 +23,10 @@ sizeX: 32 sizeY: 32 - type: SnapGrid - offset: Edge + offset: Center - type: IconSmooth - key: walls. Seriously, just a wall. Nothing extraordinary here. + key: walls base: solid placement: diff --git a/Resources/Prototypes/Entities/walls/structures/low_wall.yml b/Resources/Prototypes/Entities/walls/structures/low_wall.yml new file mode 100644 index 0000000000..7394d08de8 --- /dev/null +++ b/Resources/Prototypes/Entities/walls/structures/low_wall.yml @@ -0,0 +1,32 @@ +- type: entity + id: low_wall + name: Low Wall + description: Goes up to about your waist. + components: + - type: Clickable + - type: Sprite + netsync: false + color: "#71797a" + drawdepth: Walls + sprite: Buildings/low_wall.rsi + + - type: Icon + sprite: Buildings/low_wall.rsi + state: metal + + - type: BoundingBox + - type: Collidable + - type: Damageable + - type: Destructible + thresholdvalue: 100 + + - type: SnapGrid + offset: Center + + - type: LowWall + key: walls + base: metal_ + + placement: + snap: + - Wall diff --git a/Resources/Prototypes/Entities/walls/structures/windows.yml b/Resources/Prototypes/Entities/walls/structures/windows.yml new file mode 100644 index 0000000000..550b606c84 --- /dev/null +++ b/Resources/Prototypes/Entities/walls/structures/windows.yml @@ -0,0 +1,30 @@ +- type: entity + id: window + name: Window + description: Don't smudge up the glass down there. + components: + - type: Clickable + - type: Sprite + netsync: false + drawdepth: WallTops + sprite: Buildings/window.rsi + + - type: Icon + sprite: Buildings/window.rsi + state: window0 + + - type: BoundingBox + - type: Collidable + - type: Damageable + - type: Destructible + thresholdvalue: 100 + + - type: SnapGrid + offset: Center + + - type: Window + base: window + + placement: + snap: + - Wall diff --git a/Resources/Textures/Buildings/low_wall.rsi/meta.json b/Resources/Textures/Buildings/low_wall.rsi/meta.json new file mode 100644 index 0000000000..13c05547ff --- /dev/null +++ b/Resources/Textures/Buildings/low_wall.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/b503939d31b23c025ddb936b75e0a265d85154c5/icons/obj/structures/low_wall.dmi", "states": [{"name": "metal", "directions": 1, "delays": [[1.0]]}, {"name": "metal_0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal.png b/Resources/Textures/Buildings/low_wall.rsi/metal.png new file mode 100644 index 0000000000000000000000000000000000000000..21a1e3e05911b41088404cdc48654fb59c30199a GIT binary patch literal 326 zcmV-M0lEH(P)e;T1&4WAVN*(vQOJyE=cvw3jUMT z0JL2L)A%HV!C2GygtlwK0DEP^093LK@W&Z2SAT}E3Z^uG?~t4!GnWQPU45v3Na-!? zD(v0^G5HSWk>;j6`r)_2oCS8rHDl2Cm*|JFZA$rVhvA`b*}`nkQ*OUaDet_{J9{4L Y4a}{43&cCLYXATM07*qoM6N<$f&_Vr>Hq)$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_0.png b/Resources/Textures/Buildings/low_wall.rsi/metal_0.png new file mode 100644 index 0000000000000000000000000000000000000000..e1498c75363ac3b63f106c31dd6445aea8f4e793 GIT binary patch literal 561 zcmV-10?z%3P)s~f#U)*(d55u8IfM+hh(>s%t)sC%Jd4wEdTCxaNRp?ms&V!w@` zHdFPx?5?hA2O#sZD8EC-zphtYN?(5wEWmR4 zeDU+I&wcYcn~(pW0Nz0>%mU~+l5T@O3Y4Ja0ZI#EQ~@lZtri8rYe3r>rQfy{S}Lp} zR@7afz29G=sy5~fvTuR~XwPKroM~oNoCkV13n)2fAxSFSJ`J9>!Pz9aATcZo)Xp_d z`#eBF1j;V3-5q3-pm*B(MyE`ofx z`3T4Yunl071z;P%CJVqefQ_60e*aHZERp%kOq?@aHwe%RDb zKhYTY*W7{0Yu}sKe}X@iPJZx@&Bo4_Xa94J1-~>O#5MWJKVO|%5F=>LI^(yIh2C$y z=Qn+u7X?4qziz|npIP@eM6P#wqrB=r8;Z>n8LSw5zcO9u?YMbA^yb|<>o(%fEmJ5s-Dh+%N%8VrpvtF@2sGn(QTwPsz{1~5N!uI=o`%;FMof3=WB z0A_5m+3TxMlG`HKPTDDiunL5~JH)ZzophUk!8?}a&%|GLJ8ooNyXPb@CKxs~f#U)*(d55u8IfM+hh(>s%t)sC%Jd4wEdTCxaNRp?ms&V!w@` zHdFPx?5?hA2O#sZD8EC-zphtYN?(5wEWmR4 zeDU+I&wcYcn~(pW0Nz0>%mU~+l5T@O3Y4Ja0ZI#EQ~@lZtri8rYe3r>rQfy{S}Lp} zR@7afz29G=sy5~fvTuR~XwPKroM~oNoCkV13n)2fAxSFSJ`J9>!Pz9aATcZo)Xp_d z`#eBF1j;V3-5q3-pm*B(MyE`ofx z`3T4Yunl071z;P%CJVqefQ_60e*aHZERp%kOq?@aHwe%RDb zKhYTY*W7{0Yu}sKe}X@iPJZx@&Bo4_Xa94J1-~>O#5MWJKVO|%5F=>LI^(yIh2C$y z=Qn+u7X?4qziz|npIP@eM6P#wqrB=r8;Z>n8LSw5zcO9u?YMbA^yb|<>o(%fEmJ5s-Dh+%N%8VrpvtF@2sGn(QTwPsz{1~5N!uI=o`%;FMof3=WB z0A_5m+3TxMlG`HKPTDDiunL5~JH)ZzophUk!8?}a&%|GLJ8ooNyXPb@CKx$i!CoR&|o^q`d|Y60KHqCV9-5nfGe;jjy@Kj`n=5xfT-s zpXH#<+SNN^bie#7oT4&!mfNHf^O+@8`&M03RQ>0B>hSdjX$S5Fh0Ga@CV33H4aayF zuwD?!cLUC! zuy|AF4#q7EQgEkqnIEW$e;`zqd%+m!I{j6TiW?=8FU2UdO!y-Gfv2MSughcccxIr3 z9pa1RHyz48ARs6Aesk^h{ihr5JdiYaa{r8F(F3*|GyT2q>`i^IJ$uQWxy1R%<=64cfMqDX;`jzfK5?9wt@4*CDs=jH8b`mh60OnM0kH`KR? zJ$NPS@J4)>z=nu(8*81!nN;$&ONcwz)t+o*=(N>t;9hW^;{nsQ*|Jr6AGpLV0;(5u SRXha72!p4qpUXO@geCxq*0!(! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_6.png b/Resources/Textures/Buildings/low_wall.rsi/metal_6.png new file mode 100644 index 0000000000000000000000000000000000000000..bb544bf0cbf1c6e58addc89f30ecc1f8abf02ac1 GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV65_VaSW-L^LCbR7L%huYkYf* zs=|)`yh+|W#2inEJ`;E>$i!CoR&|o^q`d|Y60KHqCV9-5nfGe;jjy@Kj`n=5xfT-s zpXH#<+SNN^bie#7oT4&!mfNHf^O+@8`&M03RQ>0B>hSdjX$S5Fh0Ga@CV33H4aayF zuwD?!cLUC! zuy|AF4#q7EQgEkqnIEW$e;`zqd%+m!I{j6TiW?=8FU2UdO!y-Gfv2MSughcccxIr3 z9pa1RHyz48ARs6Aesk^h{ihr5JdiYaa{r8F(F3*|GyT2q>`i^IJ$uQWxy1R%*b2*^%dfL%f%- zVE7TyiD8qK{z#ngs&5vklPFt%(B}N}-81*U|Gsr*eQw+TMy3o#U&bvB%NU{@f*Eud zSlS(U)idYg@;B2Sn=gQhX*P&m5OLtn;99_H!g_&e7Md0;(!8~^=YRaq-FLr%u-da9 a8S6|B@zfP=@VE)|1%s!npUXO@geCxhMO1+R literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_0.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_0.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_1.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6390841edd4bbbd3722ee80744bbcd2deaf3bb32 GIT binary patch literal 400 zcmV;B0dM|^P)=#J-cX``8&*T063ji)O@-CHWI*Iz@WLly`#PW0d;@`Pz8LX zPi8y-b$|p&05g0)>@nj3=q0E}KmyncU?TzS1+b9-_5#>Q05kk+wPMEenLR$yCqhC9 zA%qw%quc`X=f&E`%I+<*|sHTqXCJElqX2`1W{lm>@ znUYoc&QJ$f7B8U-)B)B3-n(G%9nc$19bHa;)B!>WA%qY^#odhVKbktWmsjU&$Nn10 zZAYgr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_3.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b487006f41453d651ca1753a3fcfc9feafc8ad6b GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=n><|{Ln`LHz3Is3V8Fn7G3?IC zzRjyer?1lX*q1V^U1%1x*XzSFO3 z#VohryBzC^t#0Wv{%ziYrqd(lZRdKy|8o9+3pnIBpFd?Sm$@EXZuZ5|T6rrArw6@8 zTVv3e2ws5Z>Wf4mK%1ZiXs^CV-~xOQtNtg#JKhlg-vDOgv7&4S2WThYKP$;!~1r+ z;5|Ox3^U9F$fQZ8**Q=tJ`Pj?kIdjMAOhG4Od9t12c!Z-09C-};fom_fK-485CP2K zQ5Z181CU8jhJXlQC%{GouoGZ2c>zzR7x=xU-EH^S?s}zg>8@--5A# zF482^eN~`Tt^wd!*EYi6gcSjOD3$9d41OwSldG{)Xkl#rZ30Jz@-=mJch{t*2I^p)UlyT@|1xVj34ZmReO`COvmFNEBa00000 LNkvXXu0mjfMgr** literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_6.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_6.png new file mode 100644 index 0000000000000000000000000000000000000000..ff8e3ed9fffb95b7ae3b4e484ab8b84d70be2102 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>pfi@Ln`LHy>XDU!9ajDF#OHQ z+1K)HGJ`jE#7a0nyL zc~x1#(&?+(D}3$F{7&chQPW)*@a({xTh7Vz%&aR{>J#@zuB+(igFI`^)u{Qff_Q9aLA31 ik#(p4HE>nsALO@tqowz1OK}d+%M6~belF{r5}E+mJ86&r literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/rwindow.rsi/meta.json b/Resources/Textures/Buildings/rwindow.rsi/meta.json new file mode 100644 index 0000000000..e45955bc22 --- /dev/null +++ b/Resources/Textures/Buildings/rwindow.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/icons/obj/structures/windows.dmi", "states": [{"name": "rwindow0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow0.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow0.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c71ee3941da9126d1425710b522f7faf814d93 GIT binary patch literal 814 zcmV+}1JV46P)|6u@YHhZj*Wr zc=Ne$lF!kg4~6%K_;%<*VAYLYV>J8SdFwlBM|2Yw512(jH0VRI(q?6DVNg$kWHy%3 zd4Pcc#Y!99W(@$JG0Ge2Az&Q0pc!6hh8NvtO*#>%Bf!*$mitoY0{-+EFla3=25JE+ zjlShRaJ!CtGJ%8LAGD?y0<{2-9^A5RH}xUV5HiuUKpz3Ekxg3}`D6m`K2>SWbBAjt z=ueM%nr8wx0rpGNC=ea)YXQ-tfLZ{}@H$>)hyrQ>OnnH=@Y-GpB1Zw&2#_HPxX%GZ z5D}Nc0EblAj_s^2r1J`eLZMJ76pH^D>J;_f^MVNg=O3q=qjvTDYW1bCsWA16?VXq= z0Mt7J936k1)dc~}YJ;BNC-|`YOh^%^SA+G=0QJrQ(V!36)CS@)kEJLI0B6f#WHxt9 z2NTx{v*j=m!D)5qRP(=XnC}P3RvHs>T&`sc=2GbH?4F!8h~*~OdYZGG5P5OmPvwJD zCq#g0HJX&#fl(=5Dgjm^Yv?v>vyE26Xi?jgMgV_$ zj8f+UcW||h*sCIq0QqDB`=v4}KTnz3l|lg0%{&H@%dXex;rrl?_igSEnTQqw!zH#t@Fk63_Ccltxj#1ut{KCYx4bs zBePgQOq!f!#sMa$rOziev*{?jEwL@S(7>9r?!4pI?HLRLHEb#JKm{)UWfU0SFytgK zdImQ20jY(THZRfOtxZ`hd4TVL+AsG+#TEf44nge?o31>(S^Q%CJD@$;OLxwlza_UU z^HiL*{ruDWHo5QKf8g4u|I9y9J9ch)>-Z(VSqP{*?a8c3GjD!!Gxj;7&v))OZ)x`W zL~Cu+>WWI~80Y``9d&FT4Au=N9$3>Zrcp00i_>zopr0Dn!vVE_OC literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow2.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow2.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c71ee3941da9126d1425710b522f7faf814d93 GIT binary patch literal 814 zcmV+}1JV46P)|6u@YHhZj*Wr zc=Ne$lF!kg4~6%K_;%<*VAYLYV>J8SdFwlBM|2Yw512(jH0VRI(q?6DVNg$kWHy%3 zd4Pcc#Y!99W(@$JG0Ge2Az&Q0pc!6hh8NvtO*#>%Bf!*$mitoY0{-+EFla3=25JE+ zjlShRaJ!CtGJ%8LAGD?y0<{2-9^A5RH}xUV5HiuUKpz3Ekxg3}`D6m`K2>SWbBAjt z=ueM%nr8wx0rpGNC=ea)YXQ-tfLZ{}@H$>)hyrQ>OnnH=@Y-GpB1Zw&2#_HPxX%GZ z5D}Nc0EblAj_s^2r1J`eLZMJ76pH^D>J;_f^MVNg=O3q=qjvTDYW1bCsWA16?VXq= z0Mt7J936k1)dc~}YJ;BNC-|`YOh^%^SA+G=0QJrQ(V!36)CS@)kEJLI0B6f#WHxt9 z2NTx{v*j=m!D)5qRP(=XnC}P3RvHs>T&`sc=2GbH?4F!8h~*~OdYZGG5P5OmPvwJD zCq#g0HJX&#fl(=5Dgjm^Yv?v>vyE26Xi?jgMgV_$ zj8f+UcW||h*sCIq0QqDB`=v4}KTnz3l|lg0%{&H@%dXex;rrl?_igSEnTQqw!zH#t@Fk63_Ccltxj#1ut{KCYx4bs zBePgQOq!f!#sMa$rOziev*{?jEwL@S(7>9r?!4pI?HLRLHEb#JKm{)UWfU0SFytgK zdImQ20jY(THZRfOtxZ`hd4TVL+AsG+#TEf44nge?o31>(S^Q%CJD@$;OLxwlza_UU z^HiL*{ruDWHo5QKf8g4u|I9y9J9ch)>-Z(VSqP{*?a8c3GjD!!Gxj;7&v))OZ)x`W zL~Cu+>WWI~80Y``9d&FT4Au=N9$3>Zrcp00i_>zopr0Dn!vVE_OC literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow4.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow4.png new file mode 100644 index 0000000000000000000000000000000000000000..5545fa5d9ea741186914f80084ed37d019cb1f39 GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVBFy8;uumf=k2V$Ud)ant>?Q0 zc%^((3S)&`rX);s%gxPkso@gT)|Nkd%1h;Zf}&DK?^=yXPGZd+AN9LEMW%SPY`j&X z^n`C-%ij3SksQT*^0RMp8uRU%uyg4m&mWiH{yyU)wDptvH1kgp+7&x0GZ`3~HgwLt z%IQAos(O}}+Izl^<1aE9%>o$TFy*)ib1=M_cis0(Wm%0#`_l9|@7UjVYCn4YQS5s9 z>qj=XkNo2Vs|#V+%^)p$K<|JX>jv%(fgr8;g*@0f4lV1IGx?RvBjhRJbxY!HyRO}$L|$)xFmCNG{`y1tRXH#U89ZJ6T-G@y GGywp2CeT0t literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow5.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow5.png new file mode 100644 index 0000000000000000000000000000000000000000..155e2d2a9464cbd6168cfcb4126c4215fa928ed9 GIT binary patch literal 916 zcmV;F18e+=P)+$V=|PD}B33dYUwROU=&8RTsHdKK_qoTQ7kf&H{)0jy!l0Li zh?R`NU@0Q4H640wRwydBhjHz?U8i!-x#u_C2gb(s+wc5--+OlM`Tc%p8icv}@TFP# zUR$)yv2D-Ie%$HNF}t`50LT{C@$B{m&5eCmU#8$y#x(WjgSWRPZ}I4Q$kiPDZoW*x zmxTf@hfj;yKOtt>Mz**vW?KmXByk-Bo_{u~g4khj`x|!4vG)MBAlMZNa&=7#ivV4b zAl{}699@$`E`T-pbaEOIUzECga!3WRPd?b)hsDec+Vv(%6Xfv3fP4t(F279A87wBK zU<-n)nHk&~x`9G&wr0B&*8mO(n*iIJIshP@|I1~91eQFYSlR{vOiZOPnCRs&K?Z9g zWK4>$wf2QQ6I9&`*afhAfmUpBe3rzMwSeUXX1D~c*s|+c8czhMj0H!^1G2^Sokw8} z$QfIX?Np5guEVr_J4*LaHa0tGEDfW^#yy_8*45 zK9CY|0aiaO;8aJTW}C(BJb-={5yS;R)PNb@-1Fn5!fyn-`;bmfgF^&y0ha!3VyQ+A zLHpU0J?)bA;20u@@C4;sTf*%T+Z4UR`}a0RbvK zz{0EgBJtZ`CI7E}_0V$077A;$8!6%fm>tV7!@G+r_PYA9kRN(8NdICZE z2Twkk<6}txLC@@q#{fH{!vk6*;KN3K-ZPs@2>>|P5IEHuP@$XvUQ-tWaMl{sg#es1 q1dtwpG<7WiMMfx|2ptycRQMnBD+w^A+9=Eb0000?Q0 zc%^((3S)&`rX);s%gxPkso@gT)|Nkd%1h;Zf}&DK?^=yXPGZd+AN9LEMW%SPY`j&X z^n`C-%ij3SksQT*^0RMp8uRU%uyg4m&mWiH{yyU)wDptvH1kgp+7&x0GZ`3~HgwLt z%IQAos(O}}+Izl^<1aE9%>o$TFy*)ib1=M_cis0(Wm%0#`_l9|@7UjVYCn4YQS5s9 z>qj=XkNo2Vs|#V+%^)p$K<|JX>jv%(fgr8;g*@0f4lV1IGx?RvBjhRJbxY!HyRO}$L|$)xFmCNG{`y1tRXH#U89ZJ6T-G@y GGywp2CeT0t literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow7.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow7.png new file mode 100644 index 0000000000000000000000000000000000000000..ce4a98b3b561868c0da72731ec40e782d6f312b6 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVC436aSW-L^LExk!9xxL4Ej7w z-3}KRcrUPQU7*40s+-xwc8NiWNm^XTs@!#>%|_h`E|a=QdVrO>@m%G z+l!~)te+m~v)Sa1{cOH~gIY{Hk6YgE?P5?_$*rRF=0(yF=a+csI1|Ui?$I;oLLjB70BQC;#;`{;^;;1-CU0ZCw|mPFC1(TPpuyd}X4r V+qhNtD=>5zJYD@<);T3K0Ra0=bMycJ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/wall.rsi/full.png b/Resources/Textures/Buildings/wall.rsi/full.png index 21a102bb3a9ddc4ca5e1e090ee56a44f4c0de0fc..ff0bdc22d76b59ebc39e05f2874a0096b919b50d 100644 GIT binary patch delta 233 zcmVg z&jC>8&wcrF*B*22vYxGc*M+gEjsXZjFm(inGeSA-8lf^0{`exy-j{2_`1Vr?i;q>$ zBcaV-3t@HIU5Elrl!@L%g;5N!7b8@$fTL(o#0oA_fHvIRgNIaL%)r#y2e%vK0GwU* jzTNh|FJ)tTDt`X~3mGbgjq8f~00000NkvXXu0mjfp4?=h delta 286 zcmV+(0pb3Q0>J{17zqdl0001UdV2JcAsB!2NkllE4B!3T3OjJbx003oTc8ZFg!okV^|NjBW!CL?T00DGTPE!Ct=GbNc z0084jL_t(Y$DP%|ZA2jq1km3CY#R7u8d#4T2zLK9<&fP=Bs@ucLwblo$mY6!)Ogi( zs$l?bt0R~WV8$6d0NAX5fU4U8JdZmo6`%m*Qvp}N(1K4y4}ZL(Kf=f@uE`W384|bv z+zO-uA%P3Ptw1Ue61V`|3SXHnhWI0oXaD z?rsJCIAP?Bq5u!F2PObqfy76DM3%K+k=}x!xMs2sX$mX~5DKIKrof^Ap+E{?3VcUs vKq!zTX$q|7Ya&))tg5Oe!w{=bQFZ(Q2>r(dANr1r#@E7w~6=?mt37?WGW(R6G>=j`A53 z&5J@jL`{Oz*~9|5i3QXKjlE4B!3T3OjJbx003oTc8ZFg!okV^|NjBW!CL?T00DGTPE!Ct=GbNc z0084jL_t(Y$DP%|ZA2jq1km3CY#R7u8d#4T2zLK9<&fP=Bs@ucLwblo$mY6!)Ogi( zs$l?bt0R~WV8$6d0NAX5fU4U8JdZmo6`%m*Qvp}N(1K4y4}ZL(Kf=f@uE`W384|bv z+zO-uA%P3Ptw1Ue61V`|3SXHnhWI0oXaD z?rsJCIAP?Bq5u!F2PObqfy76DM3%K+k=}x!xMs2sX$mX~5DKIKrof^Ap+E{?3VcUs vKq!zTX$q|7Ya&))tg5Oe!w{=bQFZ(Q2>r(dANr1r#@E7w~6=?mt37?WGW(R6G>=j`A53 z&5J@jL`{Oz*~9|5i3QXKjsrMaBi1CMC^5R zr7WOPeFCV)G|%_=l6>nGp&Om3n zU^@e5P-@>EFnE2NOaXw%FM_s*BKn)mvI0;(4zA28>nF@NfB+x~e7qc3|LfU7Bml+% gbQD$)miT@Q>`!-qk>W;(O8@`>07*qoM6N<$f^^Vb4*&oF diff --git a/Resources/Textures/Buildings/wall.rsi/solid5.png b/Resources/Textures/Buildings/wall.rsi/solid5.png index 5c69be5b4175df96870a75a5e4a6f9e25406b942..bb0d903bab91dd8670f73108a59bb4d9c7b0948d 100644 GIT binary patch delta 255 zcmV8b delta 226 zcmV<803H9E0{#JzB!3l9OjJbx003lUWO{mfiHV7zprEO#slvj-MFkIQ00001bW%=J z06^y0W&i*Hmq|oHR7l6&mf;P+5Ds3pkf0SDAx_T{|XKLCpk}=km&mN8$;LL}LCv}>XqXPmEe`zSmFs@YVH`||Bp8b@SYb57 caIe1y52#3mH|(9w0000007*qoM6N<$f)kirkN^Mx diff --git a/Resources/Textures/Buildings/wall.rsi/solid6.png b/Resources/Textures/Buildings/wall.rsi/solid6.png index 940e57145661bd0722888e88ad9c70cb20a2f342..6fc90a41545cf476416d35924a3e8f0d2f87f636 100644 GIT binary patch delta 209 zcmV;?051Q60__2iB!3T3OjJbx003oTc8ZFg!okV^|NjBW!CL?T00DGTPE!Ct=GbNc z004|hL_t(Y$L-SF4S*mF1yEK%T!7XEq;6pMpGjjSCMI|jiLb=_M>srMaBi1CMC^5R zr7WOPeFCV)G|%_=l6>nGp&Om3n zU^@e5P-@>EFnE2NOaXw%FM_s*BKn)mvI0;(4zA28>nF@NfB+x~e7qc3|LfU7Bml+% gbQD$)miT@Q>`!-qk>W;(O8@`>07*qoM6N<$f^^Vb4*&oF diff --git a/Resources/Textures/Buildings/wall.rsi/solid7.png b/Resources/Textures/Buildings/wall.rsi/solid7.png index 5ee21983bcb56f8c050271d4a5baa12656d1de03..5ad40cae4c9edfaf5cb6640cdeb622c416cdd44a 100644 GIT binary patch delta 115 zcmdnbIDv73N)Bg$Plzi61H++%C;$Kd&u~_t3&>$C3GxeOaCmkj4ahO|ba4!^IGvo( z(6lCWb(o<7^C70d3f8cNr~9~g{1|&Gcv+dWZfp|T&oHwyFC?LXB`nETnZfGwe6#i5 SC!K)?FnGH9xvX<)|Ns9VMPO@aX(*}yx{B@SW>7<5KP?Q!F92lULy@JGz(3mC z0*s?L6oJs#&^UAz817hwUjRc3HbdivOAulR&?gnrFY#|Bm>ktH3IkY@006J{w1ZO= Ry9fXP002ovPDHLkV1j>>KWzX2 diff --git a/Resources/Textures/Buildings/window.rsi/meta.json b/Resources/Textures/Buildings/window.rsi/meta.json new file mode 100644 index 0000000000..bb6a983f12 --- /dev/null +++ b/Resources/Textures/Buildings/window.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/icons/obj/structures/windows.dmi", "states": [{"name": "window0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Buildings/window.rsi/window0.png b/Resources/Textures/Buildings/window.rsi/window0.png new file mode 100644 index 0000000000000000000000000000000000000000..bc0a3c27313769e7db8a52db9d5c04d25bedf29d GIT binary patch literal 524 zcmV+n0`vWeP)nI zzkkTN;P!mNZ`lO7roTG94;vHt9Q+HlpD`SLDs!0m@L!$)hNuQN#tcR&)&;B?A`M~- z0)Ya@Y8ez;1e`b?PF*qo*sn;bPmBKiT=l1HSNqwbp8CH3NB(YZV7kC$@{ak>-2g7d zmX}H4TdU5le;m2|x7-%}HUGtT+-Kx+;J%>2pzE-hVGBbqNHJl7cg!}70W&n#maN&m Q0T^lwp00i_>zopr0A1daApigX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/window.rsi/window2.png b/Resources/Textures/Buildings/window.rsi/window2.png new file mode 100644 index 0000000000000000000000000000000000000000..bc0a3c27313769e7db8a52db9d5c04d25bedf29d GIT binary patch literal 524 zcmV+n0`vWeP)nI zzkkTN;P!mNZ`lO7roTG94;vHt9Q+HlpD`SLDs!0m@L!$)hNuQN#tcR&)&;B?A`M~- z0)Ya@Y8ez;1e`b?PF*qo*sn;bPmBKiT=l1HSNqwbp8CH3NB(YZV7kC$@{ak>-2g7d zmX}H4TdU5le;m2|x7-%}HUGtT+-Kx+;J%>2pzE-hVGBbqNHJl7cg!}70W&n#maN&m Q0T^lwp00i_>zopr0A1daApigX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/window.rsi/window4.png b/Resources/Textures/Buildings/window.rsi/window4.png new file mode 100644 index 0000000000000000000000000000000000000000..f7bdfb316fb7f2ad0474947318c8f9db839f21c6 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU{v>XaSW-L^LExku0sJ5Ztst% zB}L40WLX`#;Rn;chPx?SXXb=WzAOHLRj28uR>#5A=8no`Clk6J=*xYrQ}5ka$>07_ z`W^2b@k{c$le`ws*)4zd)jG-6JYo6#?`&(c5+YY8RQ{9?V2Els_M2fD literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/window.rsi/window5.png b/Resources/Textures/Buildings/window.rsi/window5.png new file mode 100644 index 0000000000000000000000000000000000000000..cb440e5fc2f8bd0d825a03d16b858869b598e51c GIT binary patch literal 516 zcmV+f0{i`mP)YU6vn?;Hwg}%uR{p9b`t~<+@&wz?&Rv`)XmkYyD#7iI68MNgbW6gyguBiejAXV4fZ_|x(R2h0LUFMmJ^|aqOSqb15p1t(e5vZ-T~@OQeEE~ zT*Xx#K-a{$dJfb9^ywqufG~<05V9OqSzuLd$Xjnl0f1BH0UTDJOXdM^%QOJ))d!3N zkdRpb5~~jw1|TJq0HjtQFbY6Y<^V{pK41`lwA6ow+PlJ!FCTkAw#nL*1D1<br;1hnMXaSW-L^LExku0sJ5Ztst% zB}L40WLX`#;Rn;chPx?SXXb=WzAOHLRj28uR>#5A=8no`Clk6J=*xYrQ}5ka$>07_ z`W^2b@k{c$le`ws*)4zd)jG-6JYo6#?`&(c5+YY8RQ{9?V2Els_M2fD literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/window.rsi/window7.png b/Resources/Textures/Buildings/window.rsi/window7.png new file mode 100644 index 0000000000000000000000000000000000000000..58a2d6a215bb231072067db3bdb64d49356c088b GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=dp%toLn`LHz2(U3*9Q)nI?PR#5Gs$wZDJ%&*#GZW}mm8{a_!!pu51*?!c>tGe4BK zJ^jI}(I9p~#DP15YXPeX>jkD+Oc{*6j9VI(F+@281C?sxmUh1XEd9^_rpM+B2&+Xl ds*nEz^Ic)I$ztaD0e0syYDQ+EIW literal 0 HcmV?d00001 From ff90bb4802eeed03f16b345b818cc618188339ab Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 26 Jul 2019 17:55:50 +0200 Subject: [PATCH 03/31] Update submodule. --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index a4f2441153..e0512a1052 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit a4f244115347bc7b667dfad30f213b13a31e79f1 +Subproject commit e0512a1052bcde98b0b8bb54bbb35dfcf12edd57 From c635aeba7941fab25b97724bf16dd1a9938a398b Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 26 Jul 2019 17:56:07 +0200 Subject: [PATCH 04/31] Fix crash related to game HUD upon joining. --- Content.Client/GameTicking/ClientGameTicker.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Client/GameTicking/ClientGameTicker.cs b/Content.Client/GameTicking/ClientGameTicker.cs index 2092c78424..bab225f1e9 100644 --- a/Content.Client/GameTicking/ClientGameTicker.cs +++ b/Content.Client/GameTicking/ClientGameTicker.cs @@ -91,6 +91,7 @@ namespace Content.Client.GameTicking _lobby = null; _gameChat?.Dispose(); _gameChat = null; + _gameHud.RootControl.Orphan(); } public void FrameUpdate(RenderFrameEventArgs renderFrameEventArgs) @@ -171,7 +172,7 @@ namespace Content.Client.GameTicking _gameChat = null; } - _gameHud.RootControl.Parent?.RemoveChild(_gameHud.RootControl); + _gameHud.RootControl.Orphan(); _tickerState = TickerState.InLobby; From 448ee88357e53e3130758df075fe739f09d9826b Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 26 Jul 2019 19:43:20 +0200 Subject: [PATCH 05/31] Re-organize entity prototypes. --- Resources/Prototypes/Entities/Items.yml | 156 ------------------ .../Prototypes/Entities/PoweredLighting.yml | 0 Resources/Prototypes/Entities/Projectiles.yml | 0 .../{Door.yml => buildings/airlock_base.yml} | 28 ---- .../Entities/buildings/airlock_types.yml | 27 +++ .../Entities/{ => buildings}/catwalk.yml | 0 .../fuel_tank.yml} | 31 +--- .../Entities/{ => buildings}/girder.yml | 0 .../{Lathe.yml => buildings/lathe.yml} | 0 .../{Lights.yml => buildings/lighting.yml} | 57 +------ .../structures => buildings}/low_wall.yml | 0 .../{Power.yml => buildings/power.yml} | 0 .../buildings/storage/closet_base.yml | 39 +++++ .../buildings/storage/closet_types.yml | 90 ++++++++++ .../Entities/buildings/storage/crate_base.yml | 28 ++++ .../Entities/{ => buildings}/table.yml | 0 .../{Turret.yml => buildings/turret.yml} | 0 .../Entities/{ => buildings}/walls.yml | 0 .../structures => buildings}/windows.yml | 0 Resources/Prototypes/Entities/closet.yml | 130 --------------- .../Prototypes/Entities/items/bike_horn.yml | 21 +++ .../{Clothing => items/clothing}/IDs.yml | 0 .../clothing}/backpacks.yml | 0 .../{Clothing => items/clothing}/belts.yml | 0 .../clothing/clothing_base.yml} | 0 .../{Clothing => items/clothing}/ears.yml | 0 .../{Clothing => items/clothing}/eyes.yml | 0 .../{Clothing => items/clothing}/gloves.yml | 0 .../{Clothing => items/clothing}/helmets.yml | 0 .../{Clothing => items/clothing}/masks.yml | 0 .../{Clothing => items/clothing}/shoes.yml | 0 .../{Clothing => items/clothing}/suits.yml | 0 .../{Clothing => items/clothing}/uniforms.yml | 0 .../Entities/{Dice.yml => items/dice.yml} | 0 .../{Explosives.yml => items/explosives.yml} | 0 .../Entities/items/fire_extinguisher.yml | 12 ++ .../Prototypes/Entities/items/flashlight.yml | 19 +++ .../Prototypes/Entities/items/item_base.yml | 17 ++ .../Prototypes/Entities/items/light_bulb.yml | 56 +++++++ .../{Materials.yml => items/materials.yml} | 0 .../{Medical.yml => items/medical.yml} | 0 Resources/Prototypes/Entities/items/mop.yml | 12 ++ .../Entities/{ => items}/powercells.yml | 0 .../Prototypes/Entities/items/table_parts.yml | 17 ++ .../teleporters.yml} | 0 .../Prototypes/Entities/items/toolbox.yml | 51 ++++++ .../Entities/{Tools.yml => items/tools.yml} | 0 .../{ => items}/weapons/ammunition.yml | 0 .../Entities/{ => items}/weapons/guns.yml | 0 .../{ => items}/weapons/laserguns.yml | 0 .../{ => items}/weapons/projectiles.yml | 0 .../{Weapons.yml => items/weapons/spear.yml} | 0 .../construction_ghost.yml} | 0 .../Prototypes/Entities/mobs/adminghost.yml | 4 + .../Entities/{Mobs.yml => mobs/human.yml} | 23 --- .../Prototypes/Entities/mobs/observer.yml | 16 ++ 56 files changed, 411 insertions(+), 423 deletions(-) delete mode 100644 Resources/Prototypes/Entities/Items.yml delete mode 100644 Resources/Prototypes/Entities/PoweredLighting.yml delete mode 100644 Resources/Prototypes/Entities/Projectiles.yml rename Resources/Prototypes/Entities/{Door.yml => buildings/airlock_base.yml} (61%) create mode 100644 Resources/Prototypes/Entities/buildings/airlock_types.yml rename Resources/Prototypes/Entities/{ => buildings}/catwalk.yml (100%) rename Resources/Prototypes/Entities/{Container.yml => buildings/fuel_tank.yml} (56%) rename Resources/Prototypes/Entities/{ => buildings}/girder.yml (100%) rename Resources/Prototypes/Entities/{Lathe.yml => buildings/lathe.yml} (100%) rename Resources/Prototypes/Entities/{Lights.yml => buildings/lighting.yml} (54%) rename Resources/Prototypes/Entities/{walls/structures => buildings}/low_wall.yml (100%) rename Resources/Prototypes/Entities/{Power.yml => buildings/power.yml} (100%) create mode 100644 Resources/Prototypes/Entities/buildings/storage/closet_base.yml create mode 100644 Resources/Prototypes/Entities/buildings/storage/closet_types.yml create mode 100644 Resources/Prototypes/Entities/buildings/storage/crate_base.yml rename Resources/Prototypes/Entities/{ => buildings}/table.yml (100%) rename Resources/Prototypes/Entities/{Turret.yml => buildings/turret.yml} (100%) rename Resources/Prototypes/Entities/{ => buildings}/walls.yml (100%) rename Resources/Prototypes/Entities/{walls/structures => buildings}/windows.yml (100%) delete mode 100644 Resources/Prototypes/Entities/closet.yml create mode 100644 Resources/Prototypes/Entities/items/bike_horn.yml rename Resources/Prototypes/Entities/{Clothing => items/clothing}/IDs.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/backpacks.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/belts.yml (100%) rename Resources/Prototypes/Entities/{Clothing.yml => items/clothing/clothing_base.yml} (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/ears.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/eyes.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/gloves.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/helmets.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/masks.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/shoes.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/suits.yml (100%) rename Resources/Prototypes/Entities/{Clothing => items/clothing}/uniforms.yml (100%) rename Resources/Prototypes/Entities/{Dice.yml => items/dice.yml} (100%) rename Resources/Prototypes/Entities/{Explosives.yml => items/explosives.yml} (100%) create mode 100644 Resources/Prototypes/Entities/items/fire_extinguisher.yml create mode 100644 Resources/Prototypes/Entities/items/flashlight.yml create mode 100644 Resources/Prototypes/Entities/items/item_base.yml create mode 100644 Resources/Prototypes/Entities/items/light_bulb.yml rename Resources/Prototypes/Entities/{Materials.yml => items/materials.yml} (100%) rename Resources/Prototypes/Entities/{Medical.yml => items/medical.yml} (100%) create mode 100644 Resources/Prototypes/Entities/items/mop.yml rename Resources/Prototypes/Entities/{ => items}/powercells.yml (100%) create mode 100644 Resources/Prototypes/Entities/items/table_parts.yml rename Resources/Prototypes/Entities/{Teleporters.yml => items/teleporters.yml} (100%) create mode 100644 Resources/Prototypes/Entities/items/toolbox.yml rename Resources/Prototypes/Entities/{Tools.yml => items/tools.yml} (100%) rename Resources/Prototypes/Entities/{ => items}/weapons/ammunition.yml (100%) rename Resources/Prototypes/Entities/{ => items}/weapons/guns.yml (100%) rename Resources/Prototypes/Entities/{ => items}/weapons/laserguns.yml (100%) rename Resources/Prototypes/Entities/{ => items}/weapons/projectiles.yml (100%) rename Resources/Prototypes/Entities/{Weapons.yml => items/weapons/spear.yml} (100%) rename Resources/Prototypes/Entities/{Construction.yml => markers/construction_ghost.yml} (100%) create mode 100644 Resources/Prototypes/Entities/mobs/adminghost.yml rename Resources/Prototypes/Entities/{Mobs.yml => mobs/human.yml} (78%) create mode 100644 Resources/Prototypes/Entities/mobs/observer.yml diff --git a/Resources/Prototypes/Entities/Items.yml b/Resources/Prototypes/Entities/Items.yml deleted file mode 100644 index 137b2ad6d1..0000000000 --- a/Resources/Prototypes/Entities/Items.yml +++ /dev/null @@ -1,156 +0,0 @@ -- type: entity - name: "Item" - id: BaseItem - components: - - type: Item - Size: 5 - - type: Clickable - - type: BoundingBox - aabb: "-0.25,-0.25,0.25,0.25" - - type: Collidable - mask: 5 - layer: 8 - IsScrapingFloor: true - - type: Physics - mass: 5 - - type: Sprite - drawdepth: Items - -- type: entity - name: "Emergency Toolbox With Handle" - parent: BaseItem - id: RedToolboxItem - description: A shiny red and robust container - components: - - type: Sprite - texture: Objects/toolbox_r.png - - type: Icon - texture: Objects/toolbox_r.png - - type: Storage - Capacity: 60 - - type: Item - Size: 9999 - -- type: entity - name: "Mechanical Toolbox With Handle" - parent: BaseItem - id: BlueToolboxItem - description: A blue box, not the kind you're thinking of - components: - - type: Sprite - texture: Objects/Toolbox_b.png - - type: Icon - texture: Objects/Toolbox_b.png - - type: Storage - Capacity: 60 - - type: Item - Size: 9999 - -- type: entity - name: Electrical Toolbox - parent: BaseItem - id: YellowToolboxItem - description: A toolbox typically stocked with electrical gear - components: - - type: Sprite - texture: Objects/Toolbox_y.png - - type: Icon - texture: Objects/Toolbox_y.png - - type: Storage - Capacity: 60 - - type: Item - Size: 9999 - -- type: entity - id: YellowToolboxItemFilled - name: Electrical Toolbox (Filled) - parent: YellowToolboxItem - components: - - type: ToolboxElectricalFill - -- type: entity - name: "Extra-Grip™ Mop" - parent: BaseItem - id: MopItem - description: A mop that cant be stopped, viscera cleanup detail awaits - components: - - type: Sprite - texture: Objects/mop.png - - type: Icon - texture: Objects/mop.png - - type: Item - Size: 10 - -- type: entity - name: "Fire Extinguisher" - parent: BaseItem - id: fire_extinguisher - description: Extinguishes fires. - components: - - type: Sprite - texture: Objects/fire_extinguisher.png - - type: Icon - texture: Objects/fire_extinguisher.png - - type: Item - Size: 10 - -#handheld lights -- type: entity - name: "Flashlight" - parent: BaseItem - id: FlashlightLantern - description: They light the way to freedom - components: - - type: HandheldLight - - type: Sprite - sprite: Objects/lantern.rsi - layers: - - state: lantern_off - - state: HandheldLightOnOverlay - shader: unshaded - visible: false - - type: Icon - sprite: Objects/lantern.rsi - state: lantern_off - - type: PointLight - state: Off - -- type: entity - name: Bike Horn - parent: BaseItem - id: BikeHorn - description: A horn off of a bicycle. - components: - - type: Sprite - sprite: Objects/bikehorn.rsi - state: icon - - - type: Icon - sprite: Objects/bikehorn.rsi - state: icon - - - type: Item - Size: 5 - sprite: Objects/bikehorn.rsi - - - type: Sound - - type: EmitSoundOnUse - sound: /Audio/items/bikehorn.ogg - -- type: entity - name: Table Parts - parent: BaseItem - id: TableParts - description: Parts of a table. - components: - - type: Sprite - sprite: Objects/table_parts.rsi - state: icon - - - type: Icon - sprite: Objects/table_parts.rsi - state: icon - - - type: Item - Size: 25 - sprite: Objects/table_parts.rsi diff --git a/Resources/Prototypes/Entities/PoweredLighting.yml b/Resources/Prototypes/Entities/PoweredLighting.yml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Resources/Prototypes/Entities/Projectiles.yml b/Resources/Prototypes/Entities/Projectiles.yml deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Resources/Prototypes/Entities/Door.yml b/Resources/Prototypes/Entities/buildings/airlock_base.yml similarity index 61% rename from Resources/Prototypes/Entities/Door.yml rename to Resources/Prototypes/Entities/buildings/airlock_base.yml index 69914433bc..7ee129c9d5 100644 --- a/Resources/Prototypes/Entities/Door.yml +++ b/Resources/Prototypes/Entities/buildings/airlock_base.yml @@ -36,31 +36,3 @@ placement: mode: SnapgridBorder - -- type: entity - parent: airlock - id: airlock_external - name: External Airlock - components: - - type: Sprite - sprite: Buildings/airlock_external.rsi - - - type: Icon - sprite: Buildings/airlock_external.rsi - - - type: Appearance - visuals: - - type: AirlockVisualizer2D - open_sound: /Audio/machines/airlock_ext_open.ogg - close_sound: /Audio/machines/airlock_ext_close.ogg - -- type: entity - parent: airlock - id: airlock_engineering - name: Engineering Airlock - components: - - type: Sprite - sprite: Buildings/airlock_engineering.rsi - - - type: Icon - sprite: Buildings/airlock_engineering.rsi diff --git a/Resources/Prototypes/Entities/buildings/airlock_types.yml b/Resources/Prototypes/Entities/buildings/airlock_types.yml new file mode 100644 index 0000000000..c2e7548bfa --- /dev/null +++ b/Resources/Prototypes/Entities/buildings/airlock_types.yml @@ -0,0 +1,27 @@ +- type: entity + parent: airlock + id: airlock_external + name: External Airlock + components: + - type: Sprite + sprite: Buildings/airlock_external.rsi + + - type: Icon + sprite: Buildings/airlock_external.rsi + + - type: Appearance + visuals: + - type: AirlockVisualizer2D + open_sound: /Audio/machines/airlock_ext_open.ogg + close_sound: /Audio/machines/airlock_ext_close.ogg + +- type: entity + parent: airlock + id: airlock_engineering + name: Engineering Airlock + components: + - type: Sprite + sprite: Buildings/airlock_engineering.rsi + + - type: Icon + sprite: Buildings/airlock_engineering.rsi diff --git a/Resources/Prototypes/Entities/catwalk.yml b/Resources/Prototypes/Entities/buildings/catwalk.yml similarity index 100% rename from Resources/Prototypes/Entities/catwalk.yml rename to Resources/Prototypes/Entities/buildings/catwalk.yml diff --git a/Resources/Prototypes/Entities/Container.yml b/Resources/Prototypes/Entities/buildings/fuel_tank.yml similarity index 56% rename from Resources/Prototypes/Entities/Container.yml rename to Resources/Prototypes/Entities/buildings/fuel_tank.yml index 483b6f568a..d4a6605fef 100644 --- a/Resources/Prototypes/Entities/Container.yml +++ b/Resources/Prototypes/Entities/buildings/fuel_tank.yml @@ -1,32 +1,3 @@ -- type: entity - id: crate_generic - name: Crate - description: A large container for items. - components: - - type: Sprite - sprite: Buildings/crate.rsi - layers: - - state: crate - - state: crate_door - - - type: Icon - sprite: Buildings/crate.rsi - state: crate - - - type: Clickable - - type: BoundingBox - - type: Collidable - - type: Storage - Capacity: 60 - - - type: Damageable - - type: Destructible - thresholdvalue: 100 - - placement: - snap: - - Wall - - type: entity id: weldtank name: Fueltank @@ -58,4 +29,4 @@ placement: snap: - - Wall \ No newline at end of file + - Wall diff --git a/Resources/Prototypes/Entities/girder.yml b/Resources/Prototypes/Entities/buildings/girder.yml similarity index 100% rename from Resources/Prototypes/Entities/girder.yml rename to Resources/Prototypes/Entities/buildings/girder.yml diff --git a/Resources/Prototypes/Entities/Lathe.yml b/Resources/Prototypes/Entities/buildings/lathe.yml similarity index 100% rename from Resources/Prototypes/Entities/Lathe.yml rename to Resources/Prototypes/Entities/buildings/lathe.yml diff --git a/Resources/Prototypes/Entities/Lights.yml b/Resources/Prototypes/Entities/buildings/lighting.yml similarity index 54% rename from Resources/Prototypes/Entities/Lights.yml rename to Resources/Prototypes/Entities/buildings/lighting.yml index ce44c3087d..ac44f005fa 100644 --- a/Resources/Prototypes/Entities/Lights.yml +++ b/Resources/Prototypes/Entities/buildings/lighting.yml @@ -46,7 +46,7 @@ - type: PoweredLight bulb: Tube - + - type: entity name: Small Light id: poweredsmalllight @@ -72,58 +72,3 @@ - type: PoweredLight bulb: Bulb -- type: entity - parent: BaseItem - name: BaseLightbulb - id: BaseLightbulb - components: - - type: LightBulb - -- type: entity - parent: BaseLightbulb - name: Light Tube - id: LightTube - components: - - type: LightBulb - bulb: Tube - - - type: Sprite - sprite: Objects/light_tube.rsi - state: normal - - - type: Icon - sprite: Objects/light_tube.rsi - state: normal - -- type: entity - parent: BaseLightbulb - name: LED Light Tube - id: LedLightTube - components: - - type: LightBulb - bulb: Tube - color: "#EEEEFF" - BurningTemperature: 350 - PowerUse: 9 - - type: Sprite - sprite: Objects/light_tube.rsi - state: normal - - type: Icon - sprite: Objects/light_tube.rsi - state: normal - -- type: entity - parent: BaseLightbulb - name: Light Bulb - id: LightBulb - components: - - type: LightBulb - bulb: Bulb - - - type: Sprite - sprite: Objects/light_bulb.rsi - state: normal - - - type: Icon - sprite: Objects/light_bulb.rsi - state: normal \ No newline at end of file diff --git a/Resources/Prototypes/Entities/walls/structures/low_wall.yml b/Resources/Prototypes/Entities/buildings/low_wall.yml similarity index 100% rename from Resources/Prototypes/Entities/walls/structures/low_wall.yml rename to Resources/Prototypes/Entities/buildings/low_wall.yml diff --git a/Resources/Prototypes/Entities/Power.yml b/Resources/Prototypes/Entities/buildings/power.yml similarity index 100% rename from Resources/Prototypes/Entities/Power.yml rename to Resources/Prototypes/Entities/buildings/power.yml diff --git a/Resources/Prototypes/Entities/buildings/storage/closet_base.yml b/Resources/Prototypes/Entities/buildings/storage/closet_base.yml new file mode 100644 index 0000000000..685e1628b8 --- /dev/null +++ b/Resources/Prototypes/Entities/buildings/storage/closet_base.yml @@ -0,0 +1,39 @@ +- type: entity + id: locker_generic + name: Locker + description: A standard-issue Nanotrasen storage unit. + components: + - type: Sprite + sprite: Buildings/closet.rsi + layers: + - state: generic + - state: generic_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Icon + sprite: Buildings/closet.rsi + state: generic_door + + - type: Clickable + - type: BoundingBox + aabb: "-0.5,-0.25,0.5,0.25" + - type: Collidable + mask: 3 + IsScrapingFloor: true + - type: Physics + mass: 25 + Anchored: false + - type: EntityStorage + - type: PlaceableSurface + - type: Damageable + - type: Destructible + thresholdvalue: 100 + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: generic_open + state_closed: generic_door + + placement: + snap: + - Wall diff --git a/Resources/Prototypes/Entities/buildings/storage/closet_types.yml b/Resources/Prototypes/Entities/buildings/storage/closet_types.yml new file mode 100644 index 0000000000..744ac26b17 --- /dev/null +++ b/Resources/Prototypes/Entities/buildings/storage/closet_types.yml @@ -0,0 +1,90 @@ +- type: entity + id: locker_tool + name: Tool Locker + parent: locker_generic + components: + - type: Sprite + sprite: Buildings/closet.rsi + layers: + - state: eng + - state: eng_tool_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: eng_open + state_closed: eng_tool_door + + - type: Icon + state: eng_tool_door + +- type: entity + id: locker_tool_filled + name: Tool Locker (Filled) + parent: locker_tool + components: + - type: ToolLockerFill + +- type: entity + id: locker_electrical_supplies + name: Electrical Supplies Locker + parent: locker_generic + components: + - type: Sprite + sprite: Buildings/closet.rsi + layers: + - state: eng + - state: eng_elec_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: eng_open + state_closed: eng_elec_door + + - type: Icon + state: eng_elec_door + +- type: entity + id: locker_welding_supplies + name: Welding Supplies Locker + parent: locker_generic + components: + - type: Sprite + sprite: Buildings/closet.rsi + layers: + - state: eng + - state: eng_weld_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: eng_open + state_closed: eng_weld_door + + - type: Icon + state: eng_weld_door + +- type: entity + id: locker_radiation_suit + name: Radiation Suit Locker + parent: locker_generic + components: + - type: Sprite + sprite: Buildings/closet.rsi + layers: + - state: eng + - state: eng_rad_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: eng_open + state_closed: eng_rad_door + + - type: Icon + state: eng_rad_door diff --git a/Resources/Prototypes/Entities/buildings/storage/crate_base.yml b/Resources/Prototypes/Entities/buildings/storage/crate_base.yml new file mode 100644 index 0000000000..de4c846a38 --- /dev/null +++ b/Resources/Prototypes/Entities/buildings/storage/crate_base.yml @@ -0,0 +1,28 @@ +- type: entity + id: crate_generic + name: Crate + description: A large container for items. + components: + - type: Sprite + sprite: Buildings/crate.rsi + layers: + - state: crate + - state: crate_door + + - type: Icon + sprite: Buildings/crate.rsi + state: crate + + - type: Clickable + - type: BoundingBox + - type: Collidable + - type: Storage + Capacity: 60 + + - type: Damageable + - type: Destructible + thresholdvalue: 100 + + placement: + snap: + - Wall diff --git a/Resources/Prototypes/Entities/table.yml b/Resources/Prototypes/Entities/buildings/table.yml similarity index 100% rename from Resources/Prototypes/Entities/table.yml rename to Resources/Prototypes/Entities/buildings/table.yml diff --git a/Resources/Prototypes/Entities/Turret.yml b/Resources/Prototypes/Entities/buildings/turret.yml similarity index 100% rename from Resources/Prototypes/Entities/Turret.yml rename to Resources/Prototypes/Entities/buildings/turret.yml diff --git a/Resources/Prototypes/Entities/walls.yml b/Resources/Prototypes/Entities/buildings/walls.yml similarity index 100% rename from Resources/Prototypes/Entities/walls.yml rename to Resources/Prototypes/Entities/buildings/walls.yml diff --git a/Resources/Prototypes/Entities/walls/structures/windows.yml b/Resources/Prototypes/Entities/buildings/windows.yml similarity index 100% rename from Resources/Prototypes/Entities/walls/structures/windows.yml rename to Resources/Prototypes/Entities/buildings/windows.yml diff --git a/Resources/Prototypes/Entities/closet.yml b/Resources/Prototypes/Entities/closet.yml deleted file mode 100644 index dd68a6f66a..0000000000 --- a/Resources/Prototypes/Entities/closet.yml +++ /dev/null @@ -1,130 +0,0 @@ -- type: entity - id: locker_generic - name: Locker - description: A standard-issue Nanotrasen storage unit. - components: - - type: Sprite - sprite: Buildings/closet.rsi - layers: - - state: generic - - state: generic_door - map: ["enum.StorageVisualLayers.Door"] - - - type: Icon - sprite: Buildings/closet.rsi - state: generic_door - - - type: Clickable - - type: BoundingBox - aabb: "-0.5,-0.25,0.5,0.25" - - type: Collidable - mask: 3 - IsScrapingFloor: true - - type: Physics - mass: 25 - Anchored: false - - type: EntityStorage - - type: PlaceableSurface - - type: Damageable - - type: Destructible - thresholdvalue: 100 - - type: Appearance - visuals: - - type: StorageVisualizer2D - state_open: generic_open - state_closed: generic_door - - placement: - snap: - - Wall - -- type: entity - id: locker_tool - name: Tool Locker - parent: locker_generic - components: - - type: Sprite - sprite: Buildings/closet.rsi - layers: - - state: eng - - state: eng_tool_door - map: ["enum.StorageVisualLayers.Door"] - - - type: Appearance - visuals: - - type: StorageVisualizer2D - state_open: eng_open - state_closed: eng_tool_door - - - type: Icon - state: eng_tool_door - -- type: entity - id: locker_tool_filled - name: Tool Locker (Filled) - parent: locker_tool - components: - - type: ToolLockerFill - -- type: entity - id: locker_electrical_supplies - name: Electrical Supplies Locker - parent: locker_generic - components: - - type: Sprite - sprite: Buildings/closet.rsi - layers: - - state: eng - - state: eng_elec_door - map: ["enum.StorageVisualLayers.Door"] - - - type: Appearance - visuals: - - type: StorageVisualizer2D - state_open: eng_open - state_closed: eng_elec_door - - - type: Icon - state: eng_elec_door - -- type: entity - id: locker_welding_supplies - name: Welding Supplies Locker - parent: locker_generic - components: - - type: Sprite - sprite: Buildings/closet.rsi - layers: - - state: eng - - state: eng_weld_door - map: ["enum.StorageVisualLayers.Door"] - - - type: Appearance - visuals: - - type: StorageVisualizer2D - state_open: eng_open - state_closed: eng_weld_door - - - type: Icon - state: eng_weld_door - -- type: entity - id: locker_radiation_suit - name: Radiation Suit Locker - parent: locker_generic - components: - - type: Sprite - sprite: Buildings/closet.rsi - layers: - - state: eng - - state: eng_rad_door - map: ["enum.StorageVisualLayers.Door"] - - - type: Appearance - visuals: - - type: StorageVisualizer2D - state_open: eng_open - state_closed: eng_rad_door - - - type: Icon - state: eng_rad_door diff --git a/Resources/Prototypes/Entities/items/bike_horn.yml b/Resources/Prototypes/Entities/items/bike_horn.yml new file mode 100644 index 0000000000..f5f8c1fa34 --- /dev/null +++ b/Resources/Prototypes/Entities/items/bike_horn.yml @@ -0,0 +1,21 @@ +- type: entity + name: Bike Horn + parent: BaseItem + id: BikeHorn + description: A horn off of a bicycle. + components: + - type: Sprite + sprite: Objects/bikehorn.rsi + state: icon + + - type: Icon + sprite: Objects/bikehorn.rsi + state: icon + + - type: Item + Size: 5 + sprite: Objects/bikehorn.rsi + + - type: Sound + - type: EmitSoundOnUse + sound: /Audio/items/bikehorn.ogg diff --git a/Resources/Prototypes/Entities/Clothing/IDs.yml b/Resources/Prototypes/Entities/items/clothing/IDs.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/IDs.yml rename to Resources/Prototypes/Entities/items/clothing/IDs.yml diff --git a/Resources/Prototypes/Entities/Clothing/backpacks.yml b/Resources/Prototypes/Entities/items/clothing/backpacks.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/backpacks.yml rename to Resources/Prototypes/Entities/items/clothing/backpacks.yml diff --git a/Resources/Prototypes/Entities/Clothing/belts.yml b/Resources/Prototypes/Entities/items/clothing/belts.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/belts.yml rename to Resources/Prototypes/Entities/items/clothing/belts.yml diff --git a/Resources/Prototypes/Entities/Clothing.yml b/Resources/Prototypes/Entities/items/clothing/clothing_base.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing.yml rename to Resources/Prototypes/Entities/items/clothing/clothing_base.yml diff --git a/Resources/Prototypes/Entities/Clothing/ears.yml b/Resources/Prototypes/Entities/items/clothing/ears.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/ears.yml rename to Resources/Prototypes/Entities/items/clothing/ears.yml diff --git a/Resources/Prototypes/Entities/Clothing/eyes.yml b/Resources/Prototypes/Entities/items/clothing/eyes.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/eyes.yml rename to Resources/Prototypes/Entities/items/clothing/eyes.yml diff --git a/Resources/Prototypes/Entities/Clothing/gloves.yml b/Resources/Prototypes/Entities/items/clothing/gloves.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/gloves.yml rename to Resources/Prototypes/Entities/items/clothing/gloves.yml diff --git a/Resources/Prototypes/Entities/Clothing/helmets.yml b/Resources/Prototypes/Entities/items/clothing/helmets.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/helmets.yml rename to Resources/Prototypes/Entities/items/clothing/helmets.yml diff --git a/Resources/Prototypes/Entities/Clothing/masks.yml b/Resources/Prototypes/Entities/items/clothing/masks.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/masks.yml rename to Resources/Prototypes/Entities/items/clothing/masks.yml diff --git a/Resources/Prototypes/Entities/Clothing/shoes.yml b/Resources/Prototypes/Entities/items/clothing/shoes.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/shoes.yml rename to Resources/Prototypes/Entities/items/clothing/shoes.yml diff --git a/Resources/Prototypes/Entities/Clothing/suits.yml b/Resources/Prototypes/Entities/items/clothing/suits.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/suits.yml rename to Resources/Prototypes/Entities/items/clothing/suits.yml diff --git a/Resources/Prototypes/Entities/Clothing/uniforms.yml b/Resources/Prototypes/Entities/items/clothing/uniforms.yml similarity index 100% rename from Resources/Prototypes/Entities/Clothing/uniforms.yml rename to Resources/Prototypes/Entities/items/clothing/uniforms.yml diff --git a/Resources/Prototypes/Entities/Dice.yml b/Resources/Prototypes/Entities/items/dice.yml similarity index 100% rename from Resources/Prototypes/Entities/Dice.yml rename to Resources/Prototypes/Entities/items/dice.yml diff --git a/Resources/Prototypes/Entities/Explosives.yml b/Resources/Prototypes/Entities/items/explosives.yml similarity index 100% rename from Resources/Prototypes/Entities/Explosives.yml rename to Resources/Prototypes/Entities/items/explosives.yml diff --git a/Resources/Prototypes/Entities/items/fire_extinguisher.yml b/Resources/Prototypes/Entities/items/fire_extinguisher.yml new file mode 100644 index 0000000000..4a8a847631 --- /dev/null +++ b/Resources/Prototypes/Entities/items/fire_extinguisher.yml @@ -0,0 +1,12 @@ +- type: entity + name: Fire Extinguisher + parent: BaseItem + id: fire_extinguisher + description: Extinguishes fires. + components: + - type: Sprite + texture: Objects/fire_extinguisher.png + - type: Icon + texture: Objects/fire_extinguisher.png + - type: Item + Size: 10 diff --git a/Resources/Prototypes/Entities/items/flashlight.yml b/Resources/Prototypes/Entities/items/flashlight.yml new file mode 100644 index 0000000000..7d3bbee634 --- /dev/null +++ b/Resources/Prototypes/Entities/items/flashlight.yml @@ -0,0 +1,19 @@ +- type: entity + name: Flashlight + parent: BaseItem + id: FlashlightLantern + description: They light the way to freedom + components: + - type: HandheldLight + - type: Sprite + sprite: Objects/lantern.rsi + layers: + - state: lantern_off + - state: HandheldLightOnOverlay + shader: unshaded + visible: false + - type: Icon + sprite: Objects/lantern.rsi + state: lantern_off + - type: PointLight + state: Off diff --git a/Resources/Prototypes/Entities/items/item_base.yml b/Resources/Prototypes/Entities/items/item_base.yml new file mode 100644 index 0000000000..b5be445067 --- /dev/null +++ b/Resources/Prototypes/Entities/items/item_base.yml @@ -0,0 +1,17 @@ +- type: entity + name: "Item" + id: BaseItem + components: + - type: Item + Size: 5 + - type: Clickable + - type: BoundingBox + aabb: "-0.25,-0.25,0.25,0.25" + - type: Collidable + mask: 5 + layer: 8 + IsScrapingFloor: true + - type: Physics + mass: 5 + - type: Sprite + drawdepth: Items diff --git a/Resources/Prototypes/Entities/items/light_bulb.yml b/Resources/Prototypes/Entities/items/light_bulb.yml new file mode 100644 index 0000000000..fb6dadc64a --- /dev/null +++ b/Resources/Prototypes/Entities/items/light_bulb.yml @@ -0,0 +1,56 @@ +- type: entity + parent: BaseLightbulb + name: Light Bulb + id: LightBulb + components: + - type: LightBulb + bulb: Bulb + + - type: Sprite + sprite: Objects/light_bulb.rsi + state: normal + + - type: Icon + sprite: Objects/light_bulb.rsi + state: normal + +- type: entity + parent: BaseItem + name: BaseLightbulb + id: BaseLightbulb + components: + - type: LightBulb + +- type: entity + parent: BaseLightbulb + name: Light Tube + id: LightTube + components: + - type: LightBulb + bulb: Tube + + - type: Sprite + sprite: Objects/light_tube.rsi + state: normal + + - type: Icon + sprite: Objects/light_tube.rsi + state: normal + +- type: entity + parent: BaseLightbulb + name: LED Light Tube + id: LedLightTube + components: + - type: LightBulb + bulb: Tube + color: "#EEEEFF" + BurningTemperature: 350 + PowerUse: 9 + - type: Sprite + sprite: Objects/light_tube.rsi + state: normal + - type: Icon + sprite: Objects/light_tube.rsi + state: normal + diff --git a/Resources/Prototypes/Entities/Materials.yml b/Resources/Prototypes/Entities/items/materials.yml similarity index 100% rename from Resources/Prototypes/Entities/Materials.yml rename to Resources/Prototypes/Entities/items/materials.yml diff --git a/Resources/Prototypes/Entities/Medical.yml b/Resources/Prototypes/Entities/items/medical.yml similarity index 100% rename from Resources/Prototypes/Entities/Medical.yml rename to Resources/Prototypes/Entities/items/medical.yml diff --git a/Resources/Prototypes/Entities/items/mop.yml b/Resources/Prototypes/Entities/items/mop.yml new file mode 100644 index 0000000000..66e0856a06 --- /dev/null +++ b/Resources/Prototypes/Entities/items/mop.yml @@ -0,0 +1,12 @@ +- type: entity + name: Extra-Grip Mop + parent: BaseItem + id: MopItem + description: A mop that cant be stopped, viscera cleanup detail awaits + components: + - type: Sprite + texture: Objects/mop.png + - type: Icon + texture: Objects/mop.png + - type: Item + Size: 10 diff --git a/Resources/Prototypes/Entities/powercells.yml b/Resources/Prototypes/Entities/items/powercells.yml similarity index 100% rename from Resources/Prototypes/Entities/powercells.yml rename to Resources/Prototypes/Entities/items/powercells.yml diff --git a/Resources/Prototypes/Entities/items/table_parts.yml b/Resources/Prototypes/Entities/items/table_parts.yml new file mode 100644 index 0000000000..88a59b2705 --- /dev/null +++ b/Resources/Prototypes/Entities/items/table_parts.yml @@ -0,0 +1,17 @@ +- type: entity + name: Table Parts + parent: BaseItem + id: TableParts + description: Parts of a table. + components: + - type: Sprite + sprite: Objects/table_parts.rsi + state: icon + + - type: Icon + sprite: Objects/table_parts.rsi + state: icon + + - type: Item + Size: 25 + sprite: Objects/table_parts.rsi diff --git a/Resources/Prototypes/Entities/Teleporters.yml b/Resources/Prototypes/Entities/items/teleporters.yml similarity index 100% rename from Resources/Prototypes/Entities/Teleporters.yml rename to Resources/Prototypes/Entities/items/teleporters.yml diff --git a/Resources/Prototypes/Entities/items/toolbox.yml b/Resources/Prototypes/Entities/items/toolbox.yml new file mode 100644 index 0000000000..8516602a9c --- /dev/null +++ b/Resources/Prototypes/Entities/items/toolbox.yml @@ -0,0 +1,51 @@ +- type: entity + name: Emergency Toolbox + parent: BaseItem + id: RedToolboxItem + description: A shiny red and robust container + components: + - type: Sprite + texture: Objects/toolbox_r.png + - type: Icon + texture: Objects/toolbox_r.png + - type: Storage + Capacity: 60 + - type: Item + Size: 9999 + +- type: entity + name: Mechanical Toolbox + parent: BaseItem + id: BlueToolboxItem + description: A blue box, not the kind you're thinking of + components: + - type: Sprite + texture: Objects/Toolbox_b.png + - type: Icon + texture: Objects/Toolbox_b.png + - type: Storage + Capacity: 60 + - type: Item + Size: 9999 + +- type: entity + name: Electrical Toolbox + parent: BaseItem + id: YellowToolboxItem + description: A toolbox typically stocked with electrical gear + components: + - type: Sprite + texture: Objects/Toolbox_y.png + - type: Icon + texture: Objects/Toolbox_y.png + - type: Storage + Capacity: 60 + - type: Item + Size: 9999 + +- type: entity + id: YellowToolboxItemFilled + name: Electrical Toolbox (Filled) + parent: YellowToolboxItem + components: + - type: ToolboxElectricalFill diff --git a/Resources/Prototypes/Entities/Tools.yml b/Resources/Prototypes/Entities/items/tools.yml similarity index 100% rename from Resources/Prototypes/Entities/Tools.yml rename to Resources/Prototypes/Entities/items/tools.yml diff --git a/Resources/Prototypes/Entities/weapons/ammunition.yml b/Resources/Prototypes/Entities/items/weapons/ammunition.yml similarity index 100% rename from Resources/Prototypes/Entities/weapons/ammunition.yml rename to Resources/Prototypes/Entities/items/weapons/ammunition.yml diff --git a/Resources/Prototypes/Entities/weapons/guns.yml b/Resources/Prototypes/Entities/items/weapons/guns.yml similarity index 100% rename from Resources/Prototypes/Entities/weapons/guns.yml rename to Resources/Prototypes/Entities/items/weapons/guns.yml diff --git a/Resources/Prototypes/Entities/weapons/laserguns.yml b/Resources/Prototypes/Entities/items/weapons/laserguns.yml similarity index 100% rename from Resources/Prototypes/Entities/weapons/laserguns.yml rename to Resources/Prototypes/Entities/items/weapons/laserguns.yml diff --git a/Resources/Prototypes/Entities/weapons/projectiles.yml b/Resources/Prototypes/Entities/items/weapons/projectiles.yml similarity index 100% rename from Resources/Prototypes/Entities/weapons/projectiles.yml rename to Resources/Prototypes/Entities/items/weapons/projectiles.yml diff --git a/Resources/Prototypes/Entities/Weapons.yml b/Resources/Prototypes/Entities/items/weapons/spear.yml similarity index 100% rename from Resources/Prototypes/Entities/Weapons.yml rename to Resources/Prototypes/Entities/items/weapons/spear.yml diff --git a/Resources/Prototypes/Entities/Construction.yml b/Resources/Prototypes/Entities/markers/construction_ghost.yml similarity index 100% rename from Resources/Prototypes/Entities/Construction.yml rename to Resources/Prototypes/Entities/markers/construction_ghost.yml diff --git a/Resources/Prototypes/Entities/mobs/adminghost.yml b/Resources/Prototypes/Entities/mobs/adminghost.yml new file mode 100644 index 0000000000..736f388b67 --- /dev/null +++ b/Resources/Prototypes/Entities/mobs/adminghost.yml @@ -0,0 +1,4 @@ +- type: entity + parent: MobObserver + save: false + id: AdminObserver diff --git a/Resources/Prototypes/Entities/Mobs.yml b/Resources/Prototypes/Entities/mobs/human.yml similarity index 78% rename from Resources/Prototypes/Entities/Mobs.yml rename to Resources/Prototypes/Entities/mobs/human.yml index 5d5d58865f..fc390c9609 100644 --- a/Resources/Prototypes/Entities/Mobs.yml +++ b/Resources/Prototypes/Entities/mobs/human.yml @@ -69,26 +69,3 @@ - type: Examiner - type: CharacterInfo -- type: entity - id: MobObserver - name: Observer - save: false - description: Boo! - components: - - type: Physics - mass: 5 - - type: Eye - zoom: 0.5, 0.5 - - type: BoundingBox - aabb: "-0.5,-0.25,-0.05,0.25" - - type: Input - context: "ghost" - - type: Examiner - DoRangeCheck: false - - -- type: entity - parent: MobObserver - save: false - id: AdminObserver - diff --git a/Resources/Prototypes/Entities/mobs/observer.yml b/Resources/Prototypes/Entities/mobs/observer.yml new file mode 100644 index 0000000000..28cbf23009 --- /dev/null +++ b/Resources/Prototypes/Entities/mobs/observer.yml @@ -0,0 +1,16 @@ +- type: entity + id: MobObserver + name: Observer + save: false + description: Boo! + components: + - type: Physics + mass: 5 + - type: Eye + zoom: 0.5, 0.5 + - type: BoundingBox + aabb: "-0.5,-0.25,-0.05,0.25" + - type: Input + context: "ghost" + - type: Examiner + DoRangeCheck: false From aea7d01eaa1bfd3b90d46bed309f17f7d2c10056 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 26 Jul 2019 21:43:01 +0200 Subject: [PATCH 06/31] More crate types. --- .../buildings/storage/closet_base.yml | 1 + .../Entities/buildings/storage/crate_base.yml | 20 +- .../buildings/storage/crate_types.yml | 120 ++++++++++ .../Textures/Buildings/crate.rsi/crate.png | Bin 278 -> 197 bytes .../Buildings/crate.rsi/crate_door.png | Bin 183 -> 202 bytes .../Buildings/crate.rsi/crate_open.png | Bin 166 -> 205 bytes .../Textures/Buildings/crate.rsi/freezer.png | Bin 0 -> 197 bytes .../Buildings/crate.rsi/freezer_door.png | Bin 0 -> 208 bytes .../Buildings/crate.rsi/freezer_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/hydrocrate.png | Bin 0 -> 248 bytes .../Buildings/crate.rsi/hydrocrate_door.png | Bin 0 -> 244 bytes .../Buildings/crate.rsi/hydrocrate_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/hydrosecurecrate.png | Bin 0 -> 269 bytes .../crate.rsi/hydrosecurecrate_door.png | Bin 0 -> 244 bytes .../crate.rsi/hydrosecurecrate_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/lock_locked.png | Bin 0 -> 116 bytes .../Textures/Buildings/crate.rsi/lock_off.png | Bin 0 -> 119 bytes .../Buildings/crate.rsi/lock_unlocked.png | Bin 0 -> 116 bytes .../Buildings/crate.rsi/medicalcrate.png | Bin 0 -> 234 bytes .../Buildings/crate.rsi/medicalcrate_door.png | Bin 0 -> 244 bytes .../Buildings/crate.rsi/medicalcrate_open.png | Bin 0 -> 205 bytes .../Textures/Buildings/crate.rsi/meta.json | 225 +++++++++++++++++- .../Textures/Buildings/crate.rsi/o2crate.png | Bin 0 -> 226 bytes .../Buildings/crate.rsi/o2crate_door.png | Bin 0 -> 244 bytes .../Buildings/crate.rsi/o2crate_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/plasmacrate.png | Bin 0 -> 277 bytes .../Buildings/crate.rsi/plasmacrate_door.png | Bin 0 -> 244 bytes .../Buildings/crate.rsi/plasmacrate_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/plasticcrate.png | Bin 0 -> 197 bytes .../Buildings/crate.rsi/plasticcrate_door.png | Bin 0 -> 208 bytes .../Buildings/crate.rsi/plasticcrate_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/radiationcrate.png | Bin 0 -> 249 bytes .../crate.rsi/radiationcrate_door.png | Bin 0 -> 271 bytes .../crate.rsi/radiationcrate_open.png | Bin 0 -> 205 bytes .../Buildings/crate.rsi/secgearcrate.png | Bin 0 -> 272 bytes .../Buildings/crate.rsi/secgearcrate_door.png | Bin 0 -> 244 bytes .../Buildings/crate.rsi/secgearcrate_open.png | Bin 0 -> 206 bytes .../Buildings/crate.rsi/securecrate.png | Bin 0 -> 225 bytes .../Buildings/crate.rsi/securecrate_door.png | Bin 0 -> 202 bytes .../Buildings/crate.rsi/securecrate_open.png | Bin 0 -> 205 bytes .../Textures/Buildings/crate.rsi/sparking.png | Bin 0 -> 206 bytes .../Buildings/crate.rsi/weaponcrate.png | Bin 0 -> 255 bytes .../Buildings/crate.rsi/weaponcrate_door.png | Bin 0 -> 230 bytes .../Buildings/crate.rsi/weaponcrate_open.png | Bin 0 -> 198 bytes 44 files changed, 361 insertions(+), 5 deletions(-) create mode 100644 Resources/Prototypes/Entities/buildings/storage/crate_types.yml create mode 100644 Resources/Textures/Buildings/crate.rsi/freezer.png create mode 100644 Resources/Textures/Buildings/crate.rsi/freezer_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/freezer_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/hydrocrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/hydrocrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/hydrocrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/hydrosecurecrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/lock_locked.png create mode 100644 Resources/Textures/Buildings/crate.rsi/lock_off.png create mode 100644 Resources/Textures/Buildings/crate.rsi/lock_unlocked.png create mode 100644 Resources/Textures/Buildings/crate.rsi/medicalcrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/medicalcrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/medicalcrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/o2crate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/o2crate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/o2crate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/plasmacrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/plasmacrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/plasmacrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/plasticcrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/plasticcrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/plasticcrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/radiationcrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/radiationcrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/radiationcrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/secgearcrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/secgearcrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/secgearcrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/securecrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/securecrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/securecrate_open.png create mode 100644 Resources/Textures/Buildings/crate.rsi/sparking.png create mode 100644 Resources/Textures/Buildings/crate.rsi/weaponcrate.png create mode 100644 Resources/Textures/Buildings/crate.rsi/weaponcrate_door.png create mode 100644 Resources/Textures/Buildings/crate.rsi/weaponcrate_open.png diff --git a/Resources/Prototypes/Entities/buildings/storage/closet_base.yml b/Resources/Prototypes/Entities/buildings/storage/closet_base.yml index 685e1628b8..b9f5f20b8c 100644 --- a/Resources/Prototypes/Entities/buildings/storage/closet_base.yml +++ b/Resources/Prototypes/Entities/buildings/storage/closet_base.yml @@ -4,6 +4,7 @@ description: A standard-issue Nanotrasen storage unit. components: - type: Sprite + netsync: false sprite: Buildings/closet.rsi layers: - state: generic diff --git a/Resources/Prototypes/Entities/buildings/storage/crate_base.yml b/Resources/Prototypes/Entities/buildings/storage/crate_base.yml index de4c846a38..161b954fdf 100644 --- a/Resources/Prototypes/Entities/buildings/storage/crate_base.yml +++ b/Resources/Prototypes/Entities/buildings/storage/crate_base.yml @@ -4,10 +4,12 @@ description: A large container for items. components: - type: Sprite + netsync: false sprite: Buildings/crate.rsi layers: - state: crate - state: crate_door + map: ["enum.StorageVisualLayers.Door"] - type: Icon sprite: Buildings/crate.rsi @@ -15,14 +17,24 @@ - type: Clickable - type: BoundingBox + aabb: -0.4, -0.4, 0.4, 0.4 + + - type: Physics + mass: 25 + Anchored: false + - type: Collidable - - type: Storage + - type: EntityStorage Capacity: 60 + - type: PlaceableSurface - type: Damageable - type: Destructible thresholdvalue: 100 - placement: - snap: - - Wall + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: crate_open + state_closed: crate_door + diff --git a/Resources/Prototypes/Entities/buildings/storage/crate_types.yml b/Resources/Prototypes/Entities/buildings/storage/crate_types.yml new file mode 100644 index 0000000000..6f4238d1fa --- /dev/null +++ b/Resources/Prototypes/Entities/buildings/storage/crate_types.yml @@ -0,0 +1,120 @@ +- type: entity + id: crate_plastic + name: Plastic Crate + parent: crate_generic + components: + - type: Sprite + layers: + - state: plasticcrate + - state: plasticcrate_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: plasticcrate_open + state_closed: plasticcrate_door + + - type: Icon + state: plasticcrate + +- type: entity + id: crate_freezer + name: Freezer + parent: crate_generic + components: + - type: Sprite + layers: + - state: freezer + - state: freezer_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: freezer_open + state_closed: freezer_door + + - type: Icon + state: freezer + +- type: entity + id: crate_hydroponics + name: Hydroponics Crate + parent: crate_generic + components: + - type: Sprite + layers: + - state: hydrocrate + - state: hydrocrate_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: hydrocrate_open + state_closed: hydrocrate_door + + - type: Icon + state: hydrocrate + +- type: entity + id: crate_medical + name: Medical Crate + parent: crate_generic + components: + - type: Sprite + layers: + - state: medicalcrate + - state: medicalcrate_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: medicalcrate_open + state_closed: medicalcrate_door + + - type: Icon + state: medicalcrate + +- type: entity + id: crate_radiation + name: Radiation Gear Crate + description: Is not actually lead lined. Do not store your plutonium in this. + parent: crate_generic + components: + - type: Sprite + layers: + - state: radiationcrate + - state: radiationcrate_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: radiationcrate_open + state_closed: radiationcrate_door + + - type: Icon + state: radiationcrate + +- type: entity + id: crate_internals + name: Internals Crate + parent: crate_generic + components: + - type: Sprite + layers: + - state: o2crate + - state: o2crate_door + map: ["enum.StorageVisualLayers.Door"] + + - type: Appearance + visuals: + - type: StorageVisualizer2D + state_open: o2crate_open + state_closed: o2crate_door + + - type: Icon + state: o2crate diff --git a/Resources/Textures/Buildings/crate.rsi/crate.png b/Resources/Textures/Buildings/crate.rsi/crate.png index c6a11f9f6ad36e83ca1a818d9f749ac7c7a3cee8..09ceade5d23bf66129e6914cd82ebcccfcaa07a8 100644 GIT binary patch delta 181 zcmbQnbd+&|L_G^L0|P^2NcwRgr5NB7;(GMxQGIg{_n@+h=9wGz91jaiYwet3Vqq&U zubxrd8=lm3JD;^0sF<-N$S;_|;n|HeAScMv#W6%OU^WXrdj=~ZaJ@zi9h`Ww$4bOZmX0V7|h+<{$ gX4z0Vzleb$Y?GyIR_@|OK;s!aUHx3vIVCg!0Lm6UN&o-= delta 262 zcmV+h0r~#L0hR)g7=H)@0000)q>9D>002KwOjJe1#l>f5XQQH`Mn*=qva+hGs#H`| zVq#)%Z*M_CK{hrvFfuLG)zvRCE6~u;g@uJ%TU%ymU`I(qWMpJ7FE5TxF6saP00DGT zPE!Ct=GbNc004zaL_t(IjqTFW4#FS|g<(cJCUkYc_WsYRGk+So9TT_2c;$E1gde!6 zbALb8y=BflF(BWHj`{$4GJy}nWoHQX1^yUB{35aqQUu8aBx3@jPzzYEK-mNnE8xin zS@TLuDfKz#O+Y$7Xsxe_w!sX(9%OJbsDw-)cz-2rrQ~i|WXBzH1MPzoRa^-X@&Et; M07*qoM6N<$g0mcHZ2$lO diff --git a/Resources/Textures/Buildings/crate.rsi/crate_door.png b/Resources/Textures/Buildings/crate.rsi/crate_door.png index a191869066f929bcd2c8ea1312ab2dfd45c7188d..c0546d988e2590caa9858817872ff879c017d1df 100644 GIT binary patch delta 174 zcmV;f08#(90m=c8B!3c6OjJe1#l!3w*-v9sr0d!JMQvg8b z*k%9#0A@)69Dvvku7Jdd$_PU2qVh5<^^m>hq^$kIZ|n<&(%AG#jwj;8MQNlN5NE(X5kf5XGTUwwz9ISsi~u)qA)To(9qB?F)O=)56u7o z00DGTPE!Ct=GbNc002r!L_t(2kz-&O(tuGA3Iw16%EnM&1mQE8xIlrk0$4!Q1r7qi z0>XF%3?TvtGav$N#V}jU6Cl>KmqS4X)EyihP|!fz0H8Gh02Ddq9Z2cQb147-002ov JPDHLkV1gO3H_!k8 diff --git a/Resources/Textures/Buildings/crate.rsi/crate_open.png b/Resources/Textures/Buildings/crate.rsi/crate_open.png index abafc0975125c37afce1b1887014d6f255562e0b..05c811e36f3aaf29915e0a7b644616fc08699d03 100644 GIT binary patch delta 177 zcmV;i08am=0nGuBB!3=IOjJe1#l&vLD zasU7T0d!JMQvg8b*k%9#09{E$K~yNuV_+Z$2nsMT3c@J{21X@CK_MkUK`7cdYMaRCbmiYiPI1Orb;K>@H+Sxg{K fc6MMG1*8K2vX3MGPK%O;00000NkvXXu0mjfITJTt delta 138 zcmX@hxQuavO1)5kPl)T$qetD`+*Ykz+1lC~9UYyXo}QL6e<=e417k^$UoeBivm0qZ zj+3X0V~EDY)SC p5_MnU9qGJKp&?P^0uuwnQfCo(AK+_mJUHx3vF*_wR0RSoKEvEng diff --git a/Resources/Textures/Buildings/crate.rsi/freezer.png b/Resources/Textures/Buildings/crate.rsi/freezer.png new file mode 100644 index 0000000000000000000000000000000000000000..90c0d5715e0ddd365fdc7dc84e33117acc66ff60 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv#Q>iW*P};|Mnq(E^i1D>^z74@ zufxL9T05thSlG(TtFPU(d)EAw?5=#OK*fwDL4Lsu4$p3+0XadQE{-7@6O$7p!W;xR z8-DbhI#!UN!XQ-O+uSU$p`ltsW=ewi2aWb-u?`1z83&e-mgTe~DWM4ffMq}n literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/freezer_door.png b/Resources/Textures/Buildings/crate.rsi/freezer_door.png new file mode 100644 index 0000000000000000000000000000000000000000..a03690e11527ddb3c9706b29b10cecaa3d3e5b85 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv(Ey(i*P};|Mnq&heffI-(X$;r z(_g-MuW#-V#(OdfsDQB~$S;_|;n|HeASct)#W6(V{MGXZc^edXS|3i5I4=^>kmqoU zL8yRv=kEU^PO7hNPTqHV`X5bp20P;`3qCM8Ok{ViDqu5d(daqQmLm|?wlZ(eHJR3> z@jG1BNyJNe&U(`9PJ7B|(0{3=Yq3qyagxo-U3d8t0P}6xcbq3=Fsq zX|l1osk%BUsyaFvs4@r{urZ2@8?cHQ_%=5uY-otIlu;4ZOt{C$el&qm+}%;!KtQCB yk(;B-N05ct-`$aMLvW;zf?ru#f&}XlW`<4u%K!bkC$#}BV(@hJb6Mw<&;$V1Iy&V5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/hydrocrate.png b/Resources/Textures/Buildings/crate.rsi/hydrocrate.png new file mode 100644 index 0000000000000000000000000000000000000000..8f717bb2f926a24e9a8c2b628bdc88048262ba5b GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv-2k5u*P};|>YIDG2bEPc&)l%* zcvx6kYv&Xb3tM@4b=EjzlcnMr#l0%M3gJmjqGeikk{MTk8W~H1{DK)Ap4~_TawB-4qqV5~S!mSYJ*d$)Hx6uf_X r+nXujy|7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/hydrocrate_door.png b/Resources/Textures/Buildings/crate.rsi/hydrocrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d9ca8cf8ac6fcfcad09df31a6f1f4ba5233e69 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*P};|>YICP*mImU&ba4B zTt)LtlcnPBL1j;0zUK9~Ckj-?SQ6wH%;50sMjDXQ?&;zfqH#VsLBhl#prJ8Pz|YXY zKugnzLzB}%v!h|bgh>k&W-xIY?6zp1wPOZbvnF$g!>rEkNTV4>4H=%oK|4~lp+>|JcTWzk|286VMxkPdOJ>Bm)0kH}ZJ2iHK)}U-iw6P}MEe8;L|iyH nnjA7TW-xIp{Pu20YICP*mJz1d8T_% znY_GuSXf$X=ak(CPda20b6%8{u8Z1nficewJ%_#0w=~W0%Y7#Bel3)|r3^akUB*-tA z!Qt7BG$5zd)5S5wqWA4YM?Pjn4p;UgRwX)*{_5Y(kSRQ9l4<^Sk-lEtqi(i;+y4I4 ze9%v9J(##2qoU7b#Og_AiOHWN$bQ2*>rhln>QF P2QhfM`njxgN@xNAko#e2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_door.png b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea9cf39e11128334113ff6af4936438178f8179 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*P};|>YICP*mImU&ba4B zTt)LtlcnPBL1j;0zUK9~Ckj-?SQ6wH%;50sMjDXQ?&;zfqH#VsLBhl#prJ8Pz|YXY zKugnzLzB}%v!h|bgh>k&W-xIY?6zp1wPOZbvnF$g!>rEkNTV4>4H=%oK|4~lp+>|JcTWzk|286VMxkPdOJ>Bm)0kH}ZJ2iHK)}U-iw6P}MEe8;L|iyH oniwv;RA3Nu_%@y4umBswvx9Qky2%r>fKFoYboFyt=akR{0FGWyN&o-= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_open.png b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..05c811e36f3aaf29915e0a7b644616fc08699d03 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*P};|>YICP*mJz1d8T_% znY_GuSXf$X=ak(CPdN zN`m}?87wuYxf%d@5}q!OArhC96C{EfE;61zopr0POA^%K!iX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/lock_off.png b/Resources/Textures/Buildings/crate.rsi/lock_off.png new file mode 100644 index 0000000000000000000000000000000000000000..783088854b04e9ae3ecc6438a15136e4dc200e02 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*P};|vP&|Uhw2(LFr+as zXxLXR0ZK8J1o;IsI6S)n6k-tbba4!kkW7|f{le^|#XK51tED O!QkoY=d#Wzp$P!G(;Tk= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/lock_unlocked.png b/Resources/Textures/Buildings/crate.rsi/lock_unlocked.png new file mode 100644 index 0000000000000000000000000000000000000000..83175cbb8e19326dc0af5ba081c4f63f1a1aec17 GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$ef*P};|8vi#2qT0D7SAl{| zB|(0{436a;2kK+z_4r~<9cTEKm(u}22WQ% Jmvv4FO#m%J9_Ii6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/medicalcrate.png b/Resources/Textures/Buildings/crate.rsi/medicalcrate.png new file mode 100644 index 0000000000000000000000000000000000000000..cfc42cc577fbea0321e442e43659d17f956beb30 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvtpJ}8*P};|Mnq(E^i1D>^z74@ zufxL9T05thSlG(TtMe?Kzjo7Zp1ujQ=C9RvP5>yz33VfTJ1vWHPYsgGV5dWaj-YnMPz%Jv!5)$*^0H=<^ z5*GHZ1jbbF1>8F7%$+CQcChNCpPSPY?U4O-Rp{!l_e?^&#Tr>l&dswde)dLIq44VS)*P};|Mnq&hefgRvv5^1a zf&E9%@+_U-(KG$!oAw6!0@N zFwoL8;?U%D(ClbfFk#XHg&9no2D>fVXYH85)~w0g;V`SSJJM)|QA38OaFCEUOK^a( zQ|lBL=7S<04SN^cZdtV0M8-$7A*4fGt8+TH<}~J&P8+6OIuLL%;NpP*1<^hM0TCAt ojwXi;jTubb3ctM@5;>R|ir>nMdK~)N0(26Cr>mdKI;Vst0P;~%JOBUy literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/medicalcrate_open.png b/Resources/Textures/Buildings/crate.rsi/medicalcrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..0ab9fd39965642835512494c373db0fde4f2f8c4 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*P};|Mnq&heffI-(X$;r z)8*yW!@|;9JE!bEc=F|&_j(>(`9PJ7B|(0{3=Yq3qyagxo-U3d8t0P}6xcbq3=Fsq zX|l1osk%BUsyaFvs4@r{urZ2@8?cHQ_%=5uY-otIlu;4ZOt{C$el&qm+}%;!KtQCB yk(;B-N05ct-`$aMLvW;zf?ru#f&}XlW`<4u%K!bkC$#}BV(@hJb6Mw<&;$V1Iy&V5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/meta.json b/Resources/Textures/Buildings/crate.rsi/meta.json index e8fa1c03c2..4afb51c966 100644 --- a/Resources/Textures/Buildings/crate.rsi/meta.json +++ b/Resources/Textures/Buildings/crate.rsi/meta.json @@ -7,6 +7,31 @@ "y": 32 }, "states": [ + { + "name": "lock_locked", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "lock_off", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "lock_unlocked", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "sparking", + "select": [], + "flags": {}, + "directions": 1, + "delays": [[0.1,0.1,0.1,0.1,0.1,0.1]] + }, { "name": "crate", "select": [], @@ -24,6 +49,204 @@ "select": [], "flags": {}, "directions": 1 + }, + { + "name": "freezer", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "freezer_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "freezer_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "hydrocrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "hydrocrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "hydrocrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "hydrosecurecrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "hydrosecurecrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "hydrosecurecrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "medicalcrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "medicalcrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "medicalcrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "o2crate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "o2crate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "o2crate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "plasmacrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "plasmacrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "plasmacrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "plasticcrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "plasticcrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "plasticcrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "radiationcrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "radiationcrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "radiationcrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "secgearcrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "secgearcrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "secgearcrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "securecrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "securecrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "securecrate_open", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "weaponcrate", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "weaponcrate_door", + "select": [], + "flags": {}, + "directions": 1 + }, + { + "name": "weaponcrate_open", + "select": [], + "flags": {}, + "directions": 1 } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Buildings/crate.rsi/o2crate.png b/Resources/Textures/Buildings/crate.rsi/o2crate.png new file mode 100644 index 0000000000000000000000000000000000000000..29b9eb3733386b6a8a5f0a56b718fbf6f60068ec GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvl>na**P};|8V3~k=Ff=h-Pp6^ zaadSdYv&Xb3tM@4^|B|-dyMtieZhXcEe14~HEg9Ds83QJ6aJ%c%U zL=G~Yns#h*qrgMHrzek1n|AC4(+jPDIqS9-U0o9@uz^Eo!QSd;c^WrV8qWTn!pyL_ W$JS|DR^DZxy$qhNelF{r5}E+z%Tj^> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/o2crate_door.png b/Resources/Textures/Buildings/crate.rsi/o2crate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..4de2c8a77f5ff086a814005e9afe1cf022087acd GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*P};|8V3{u4ifTa2@WuJ zYMtW3d{D%rVeewwEsGYL$oPmhgmj2&bx!BjoW{J;X~VQj2LdhzTs#neXK2CQNRzRk@E8yX@lWmJSU6YepxA5CBscXt#w5D+P3 y=usEva;2u;qgP#=ZEr!1k9l&%*kTaT-sJ9hZ15_gX7bP0l+XkK>}6<0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/plasmacrate_door.png b/Resources/Textures/Buildings/crate.rsi/plasmacrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..0f0727d4b3770c432c650404286327bb6d137c3c GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*P};|7P@HN+h&`hY5E~2 zaa*JQQ7wmVAH7$%o11pmcLJ3$mIV0)GdMiEkp|?nd%8G=Xq-<@kT7uwXlM)+@G~?p z(9$&G(ByQ`>}XgpVbTJH8BCl8yDi#h?U=#VtjXNrFsrjW(rAWJLx!htkdQY^aDcH> z>l7E}gCZUcdl%boS+v+h#z(Xvq(fY*b2_)?H0G5~8>U@45O6Wz;(-7K(LMnI5f=`Q oCWZ?y6&S=EzD;L1EWpO_?4Vq>Zt}z|ppzIpUHx3vIVCg!0PU+!(*OVf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/plasmacrate_open.png b/Resources/Textures/Buildings/crate.rsi/plasmacrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..1a194dad10e805f9166d2e82419536a1746b916f GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*P};|7P@HN+h)71QNPEaloaXvXgft`cPz<}$J zCL5cZs;i@-s-vTUDua*#8>6_m0jrpSZ*z0PhK5K>85Lp8gnNwaM-v#u-5tdZ1VjoM xxjDLg1X-B<-5nV>1V{QP_?49iW*P};|Mnq(E^i1D>^z74@ zufxL9T05thSlG(TtFPU(d)EAw?5=#OK*fwDL4Lsu4$p3+0XadQE{-7@6O$7p!W;xR z8-DbhI#!UN!XQ-O+uSU$p`ltsW=ewi2aWb-u?`1z83&e-mgTe~DWM4ffMq}n literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/plasticcrate_door.png b/Resources/Textures/Buildings/crate.rsi/plasticcrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..a03690e11527ddb3c9706b29b10cecaa3d3e5b85 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv(Ey(i*P};|Mnq&heffI-(X$;r z(_g-MuW#-V#(OdfsDQB~$S;_|;n|HeASct)#W6(V{MGXZc^edXS|3i5I4=^>kmqoU zL8yRv=kEU^PO7hNPTqHV`X5bp20P;`3qCM8Ok{ViDqu5d(daqQmLm|?wlZ(eHJR3> z@jG1BNyJNe&U(`9PJ7B|(0{3=Yq3qyagxo-U3d8t0P}6xcbq3=Fsq zX|l1osk%BUsyaFvs4@r{urZ2@8?cHQ_%=5uY-otIlu;4ZOt{C$el&qm+}%;!KtQCB yk(;B-N05ct-`$aMLvW;zf?ru#f&}XlW`<4u%K!bkC$#}BV(@hJb6Mw<&;$V1Iy&V5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/radiationcrate.png b/Resources/Textures/Buildings/crate.rsi/radiationcrate.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed466469cd085acbe580e0ea67a9d089b916837 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv-2k5u*P};|Mnq(E^i1D>^z74@ zufxL9T05thSlG(TtFH(UxVO!A?WWylrs&O@zj9ZR`~~(e&OnWfB|(0{3=Yq3qyafq zo-U3d8WWQfB*Gj7I2(TSoH|yJpu!+j;M?3Ru%V$^LuN{X_y>*lX0Z+jb{PkjkeCMt zICT`3tYl%GEOLFu_VYZn8D%MjWi%4oyx6&5niz6DBQCn8CzpuzSa{nLApR?y^|kx=mC7_NEclJ&$`}S_5j6o^G5~pVi zCY_N~JZkLlN+II(#v>*hO@M^L)Mfzz5f=`QCWk1g8BE*?zr7n0IhYwHe$dWevu^iJ Qpz|0!UHx3vIVCg!0JHdI2LJ#7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/radiationcrate_open.png b/Resources/Textures/Buildings/crate.rsi/radiationcrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..0ab9fd39965642835512494c373db0fde4f2f8c4 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*P};|Mnq&heffI-(X$;r z)8*yW!@|;9JE!bEc=F|&_j(>(`9PJ7B|(0{3=Yq3qyagxo-U3d8t0P}6xcbq3=Fsq zX|l1osk%BUsyaFvs4@r{urZ2@8?cHQ_%=5uY-otIlu;4ZOt{C$el&qm+}%;!KtQCB yk(;B-N05ct-`$aMLvW;zf?ru#f&}XlW`<4u%K!bkC$#}BV(@hJb6Mw<&;$V1Iy&V5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/secgearcrate.png b/Resources/Textures/Buildings/crate.rsi/secgearcrate.png new file mode 100644 index 0000000000000000000000000000000000000000..66b98656e5d089f97f426395fb64d8a339436a06 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyW&u7Su1Aj^)i?KW4=Sr@p1EPq z@vyM8*3Ky=7Pj*8>M5G06%8{u8Z3@#IZR>K%_#1jq-hbJ)Ksc&ddJsS8)yP!NswPK zgTu2MX+Tbgr;B5V#p$;bH}V};;BiSlK4r!(wtxTAr30F5FL<53#8;bS(YgIcUgW<& zA|IMQ_P-Xf;ayNLTi`^CgxV4R7G1v^dkl`UESbD@Kl5%T0ZD0}mwxUpECse6xA^^? zekigTe~DWM4f_`+!T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/secgearcrate_door.png b/Resources/Textures/Buildings/crate.rsi/secgearcrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..1949650bbc4fb1dc5ca965e3ac6e17ef6f0e98fe GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*P};|>YICP*mFEZ)AU15 zVnxG@qgoE`L1j;0zP`=fcMhnGu_VYZn8D%MjWi&q-P6S}MB{vNf`o}fKtp4ofS;j( zftIEbhbE_kW=F$<36mBm%wXa)*lp21YsU<>W=-Y}hgqH7kw!C&8ZtbEgM_?Uf&+}5 zTBo=$9~ALu*t^(v%c8|5GCraWAsymcozuBBr!lW|+A!_Xfq;tv7Y_s|i1rBxh`4ZY oG%;LwslXuS@NGK7VF5OVX9wl7b(1G%0iDF)>FVdQ&MBb@0D<^WrT_o{ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/secgearcrate_open.png b/Resources/Textures/Buildings/crate.rsi/secgearcrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..b284819fc30ec16bfee2938560b594aceaa52bd8 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*P};|>YICP*mJz1d8T_% znY_GuSXf$X=ak(CPdgTe~DWM4fCdN6D literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/securecrate.png b/Resources/Textures/Buildings/crate.rsi/securecrate.png new file mode 100644 index 0000000000000000000000000000000000000000..d30acc782ce90e4d014ef77630b2d6626fd116bd GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvtpJ}8*P};|>YIDG2bEPc&)l%* zcvx6kYv&Xb3tM@4^@@fW91Rvz*mX0Cd&85O4t@5R2Gqq^666=m;PC858jzFf>Ealo zF)=woBFsU6v*Ab2sbd8RDhxsezRk@78yc!LWTqsDf6!=e7VB_emvLYTiD@`+MAF5o zk+o$?!+~PXju4TC-G?)|56LDl3a6Verc6)bcrmB3**Ssn?(TvDPlnmwHQ5=y_So$( T&E2O5w2;Bm)z4*}Q$iB}Y^h4m literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/securecrate_door.png b/Resources/Textures/Buildings/crate.rsi/securecrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..90b4c7ebe666bb5cc13bbe567e9ab17f875e7c77 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvp#Yx{*P};|>YICP*mJz1d8T_% z+0&P=7q}MR2g)**1o;IsI6S+N2IQo9x;TbtoWI(CkhejBhr#<1!bP0l+XkKtX)kX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/securecrate_open.png b/Resources/Textures/Buildings/crate.rsi/securecrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..05c811e36f3aaf29915e0a7b644616fc08699d03 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*P};|>YICP*mJz1d8T_% znY_GuSXf$X=ak(CPdQXSZ^$5X5FCBsLJs@fG2hgpXAxzo?UdK185n8r>mdKI;Vst0DN#gB>(^b literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/weaponcrate.png b/Resources/Textures/Buildings/crate.rsi/weaponcrate.png new file mode 100644 index 0000000000000000000000000000000000000000..94e4da9d281cc9efcb68180cbcf47899e2152d74 GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyHUT~%u1Aj^l~>d-wX}fQgu^nTi1$)85|83N3|T>gUY6`>rT?NaB~Yv(KKD$a{mp` z9LAC$zhDN3XE)M-oI+0*#}JFtZ!c{WIv~K)kjUw^M_1E=!C6YEs{_>sk|ISl` zXWK<2GM;CIo?x}uueoQkLWS!L&ZK}Nb^)FZeUVDH&5T%={B=I=xyMhzJVkEqy4e+T z137iJes;Vtlk3!Cjo1szUZ_razUEePc*IldeMiJNIs2EbV*y&u;OXk;vd$@?2>@`} BT+#pl literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/weaponcrate_door.png b/Resources/Textures/Buildings/crate.rsi/weaponcrate_door.png new file mode 100644 index 0000000000000000000000000000000000000000..2141125b11eeaf3f5420b1dc69e6d9b2faf9fe6f GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvi2$Dv*P};|$}4Jg^h`IkwA+95 zY>K97RAkmsEeGy}Yv%*iFqQ=Q1v5B2yO9Ru)Ofl$hG?9>d+s1-g8>igg$`~L!B;nZ z7HH@t+;#X8bL5U~$Lrh67HN0<|McK6KjROd3l44k43gmvIe9^iM>@Q8ip)@pa*CC&-=m`NchXKddne`bT-sR|S`uUuvn6C}qnr9(aqVl~3ANluwjY@Bp{l3R b{wb5Ej?4n@q`##=cQAOm`njxgN@xNADtuQ~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/crate.rsi/weaponcrate_open.png b/Resources/Textures/Buildings/crate.rsi/weaponcrate_open.png new file mode 100644 index 0000000000000000000000000000000000000000..fc2255b59a3c99a55b316fb2ca35ebcda14c0bbf GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvi2$Dv*P};|$}4Jg^h}S6%rdpK z6A%zkP*5;1F!(7Jw;ia4u_VYZn8D%MjWi%9#?!?yMB{vNf&x1Smw^G-Ax$ Date: Sat, 27 Jul 2019 09:23:00 +0200 Subject: [PATCH 07/31] Opening lockers or crates makes sound now. --- .../Items/Storage/EntityStorageComponent.cs | 12 +++++++++++- Resources/Audio/machines/closetclose.ogg | Bin 0 -> 16110 bytes Resources/Audio/machines/closetopen.ogg | Bin 0 -> 5623 bytes .../Entities/buildings/storage/closet_base.yml | 1 + .../Entities/buildings/storage/crate_base.yml | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Resources/Audio/machines/closetclose.ogg create mode 100644 Resources/Audio/machines/closetopen.ogg diff --git a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs index 327c8a089d..fdf6029fbc 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs @@ -9,6 +9,7 @@ using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; using System.Linq; using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.Components.Sound; using Content.Shared.GameObjects.Components.Storage; using Robust.Server.GameObjects; @@ -70,7 +71,12 @@ namespace Content.Server.GameObjects.Components break; } } + ModifyComponents(); + if (Owner.TryGetComponent(out SoundComponent soundComponent)) + { + soundComponent.Play("/Audio/machines/closetclose.ogg"); + } } private void OpenStorage() @@ -78,10 +84,14 @@ namespace Content.Server.GameObjects.Components Open = true; EmptyContents(); ModifyComponents(); + if (Owner.TryGetComponent(out SoundComponent soundComponent)) + { + soundComponent.Play("/Audio/machines/closetopen.ogg"); + } } private void ModifyComponents() - { + { if (Owner.TryGetComponent(out var collidableComponent)) { collidableComponent.CollisionEnabled = IsCollidableWhenOpen || !Open; diff --git a/Resources/Audio/machines/closetclose.ogg b/Resources/Audio/machines/closetclose.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b1e3c232946ceefb3f4921663fccca23f5422948 GIT binary patch literal 16110 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 c1BqWhymbYheR#2ppVoH5Ckb%7 literal 0 HcmV?d00001 diff --git a/Resources/Audio/machines/closetopen.ogg b/Resources/Audio/machines/closetopen.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1ee1b0de5cc492dc30c9083e77cff1f9e4976ce2 GIT binary patch literal 5623 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 Date: Sat, 27 Jul 2019 11:56:36 +0200 Subject: [PATCH 08/31] Flashlight improvements: 1. Sound effects 2. fixed sprite having a hole --- .../Interactable/HandheldLightComponent.cs | 88 +++++++++++++++--- Resources/Audio/items/flashlight_toggle.ogg | Bin 0 -> 10091 bytes Resources/Audio/items/weapons/pistol_cock.ogg | Bin 0 -> 9550 bytes .../Audio/items/weapons/pistol_magin.ogg | Bin 0 -> 6331 bytes .../Audio/items/weapons/pistol_magout.ogg | Bin 0 -> 6456 bytes Resources/Audio/items/weapons/sources.txt | 3 + Resources/Audio/machines/button.ogg | Bin 0 -> 7048 bytes .../Prototypes/Entities/items/flashlight.yml | 1 + .../lantern.rsi/HandheldLightOnOverlay.png | Bin 1321 -> 164 bytes 9 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 Resources/Audio/items/flashlight_toggle.ogg create mode 100644 Resources/Audio/items/weapons/pistol_cock.ogg create mode 100644 Resources/Audio/items/weapons/pistol_magin.ogg create mode 100644 Resources/Audio/items/weapons/pistol_magout.ogg create mode 100644 Resources/Audio/machines/button.ogg diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index e827658d2b..57aad41b94 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -1,4 +1,5 @@ using Content.Server.GameObjects.Components.Power; +using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; @@ -50,9 +51,20 @@ namespace Content.Server.GameObjects.Components.Interactable if (Cell != null) return false; - eventArgs.User.GetComponent().Drop(eventArgs.AttackWith, _cellContainer); + var handsComponent = eventArgs.User.GetComponent(); + + if (!handsComponent.Drop(eventArgs.AttackWith, _cellContainer)) + { + return false; + } + + if (Owner.TryGetComponent(out SoundComponent soundComponent)) + { + soundComponent.Play("/Audio/items/weapons/pistol_magin.ogg"); + } + + return true; - return _cellContainer.Insert(eventArgs.AttackWith); } void IExamine.Examine(FormattedMessage message) @@ -85,17 +97,14 @@ namespace Content.Server.GameObjects.Components.Interactable /// True if the light's status was toggled, false otherwise. public bool ToggleStatus() { - // Update the activation state. - Activated = !Activated; - // Update sprite and light states to match the activation. if (Activated) { - SetState(LightState.On); + TurnOff(); } else { - SetState(LightState.Off); + TurnOn(); } // Toggle always succeeds. @@ -104,25 +113,57 @@ namespace Content.Server.GameObjects.Components.Interactable public void TurnOff() { - if (!Activated) return; + if (!Activated) + { + return; + } SetState(LightState.Off); Activated = false; + + if (Owner.TryGetComponent(out SoundComponent soundComponent)) + { + soundComponent.Play("/Audio/items/flashlight_toggle.ogg"); + } } public void TurnOn() { - if (Activated) return; + if (Activated) + { + return; + } var cell = Cell; - if (cell == null) return; + SoundComponent soundComponent; + if (cell == null) + { + if (Owner.TryGetComponent(out soundComponent)) + { + soundComponent.Play("/Audio/machines/button.ogg"); + } + return; + } // To prevent having to worry about frame time in here. // Let's just say you need a whole second of charge before you can turn it on. // Simple enough. - if (cell.AvailableCharge(1) < Wattage) return; + if (cell.AvailableCharge(1) < Wattage) + { + if (Owner.TryGetComponent(out soundComponent)) + { + soundComponent.Play("/Audio/machines/button.ogg"); + } + return; + } + Activated = true; SetState(LightState.On); + + if (Owner.TryGetComponent(out soundComponent)) + { + soundComponent.Play("/Audio/items/flashlight_toggle.ogg"); + } } private void SetState(LightState newState) @@ -145,15 +186,32 @@ namespace Content.Server.GameObjects.Components.Interactable private void EjectCell(IEntity user) { - if (Cell == null) return; + if (Cell == null) + { + return; + } var cell = Cell; - if (!_cellContainer.Remove(cell.Owner)) return; + if (!_cellContainer.Remove(cell.Owner)) + { + return; + } - if (!user.TryGetComponent(out HandsComponent hands) - || !hands.PutInHand(cell.Owner.GetComponent())) + if (!user.TryGetComponent(out HandsComponent hands)) + { + return; + } + + if (!hands.PutInHand(cell.Owner.GetComponent())) + { cell.Owner.Transform.GridPosition = user.Transform.GridPosition; + } + + if (Owner.TryGetComponent(out SoundComponent soundComponent)) + { + soundComponent.Play("/Audio/items/weapons/pistol_magout.ogg"); + } } [Verb] diff --git a/Resources/Audio/items/flashlight_toggle.ogg b/Resources/Audio/items/flashlight_toggle.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7839e1f0351f407fdbd964e3625ec3657244dabb GIT binary patch literal 10091 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 C=IAp3 literal 0 HcmV?d00001 diff --git a/Resources/Audio/items/weapons/pistol_cock.ogg b/Resources/Audio/items/weapons/pistol_cock.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ff2512af27a595ed9a04300da7745696ab3b27fe GIT binary patch literal 9550 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/items/weapons/pistol_magout.ogg b/Resources/Audio/items/weapons/pistol_magout.ogg new file mode 100644 index 0000000000000000000000000000000000000000..334d1a12f299212d8afa17cd478ba5e997c8401e GIT binary patch literal 6456 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 IFk#?-094*m82|tP literal 0 HcmV?d00001 diff --git a/Resources/Audio/items/weapons/sources.txt b/Resources/Audio/items/weapons/sources.txt index 5e7f1a1173..03628c6ca9 100644 --- a/Resources/Audio/items/weapons/sources.txt +++ b/Resources/Audio/items/weapons/sources.txt @@ -5,3 +5,6 @@ smg_empty_alarm.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a864 casingfall1.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a8647a82587d363da999a94cf02c2e128c/sound/weapons/guns/misc/casingfall1.ogg casingfall2.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a8647a82587d363da999a94cf02c2e128c/sound/weapons/guns/misc/casingfall2.ogg casingfall3.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a8647a82587d363da999a94cf02c2e128c/sound/weapons/guns/misc/casingfall3.ogg +pistol_cock.ogg: https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/sound/weapons/guns/interact/pistol_cock.ogg +pistol_magin.ogg: https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/sound/weapons/guns/interact/pistol_magin.ogg +pistol_magout.ogg: https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/sound/weapons/guns/interact/pistol_magout.ogg diff --git a/Resources/Audio/machines/button.ogg b/Resources/Audio/machines/button.ogg new file mode 100644 index 0000000000000000000000000000000000000000..79b458317acff08550309eb150771fd618534096 GIT binary patch literal 7048 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 literal 0 HcmV?d00001 diff --git a/Resources/Prototypes/Entities/items/flashlight.yml b/Resources/Prototypes/Entities/items/flashlight.yml index 7d3bbee634..f1b539af7a 100644 --- a/Resources/Prototypes/Entities/items/flashlight.yml +++ b/Resources/Prototypes/Entities/items/flashlight.yml @@ -17,3 +17,4 @@ state: lantern_off - type: PointLight state: Off + - type: Sound diff --git a/Resources/Textures/Objects/lantern.rsi/HandheldLightOnOverlay.png b/Resources/Textures/Objects/lantern.rsi/HandheldLightOnOverlay.png index b08e42294fdad6883c0f2659380c929e105dd144..dc69a9359b8a101d1abe5997730164e9947d958c 100644 GIT binary patch delta 148 zcmZ3fX24pjMy85}Sb4q9e00h-8w*UYD delta 1314 zcmV+-1>O3j0jUa*7=H)`0001UdV2H#00a_xR9JLUVRs;Ka&Km7Y-J#Hd2nSQWq4_3 z004N}?U!4Y<0uS<-&w^h0SScAa>VVN*}*J-euyhcrK@YsRCm9XNeq@{f%M6M!~Ey( z75>7(#4%*iTC9|aBU?6hG-|vZx0+%;=X3CN3)k=D;eLZ5N`I)+?Xt{E-yxUB1DY>+ zdoK^#FFW-zblrF}n0C**w@a^Hh7#Z8bX^C#p7Z?V&h>BOlF6-lz0QhY41vAGfoGx= zajv_Ugb^f5jyj)n;Vogb_u-J1k7F0^&6nWaTQ9MTe#z7OP=r`6h4K=kOHT4}>`sK9 zM?{aF-`zlvHGe)IPqABT)V1c#JI@7?D&cbK&6U%FVnZm?d90u){(`oiVki|Zb`Tq& z*-&~QBSy3rWg6tPXr8)L#}G45R@BU$(~;GrY}^l&ybCQ>;29xRFzKL{Am;m6==5u+ zzfKiB4}vBWjBScPl<<-8E9Guzt)03=vEE~aaq-S+41Z&j+h=G22(2roa^ibRc*>jj z1U7-7oG@27=&{{QG@(asrNcQvPht-7_G*xh%K$=zz6FD!1Ol;85-LarW+g%#EBH7@ z&M9*P0TSUsVS!D;o1k2I_l;+ijxGz|#F$zDLQ+WzGMSn^uTJ{{}nl!6uQPrxZUQ^9gYN=Xlwd%%}FolT~(_q!i+|jASwBu=qhI`|d zT5i%x(^i``??|7XyY$kv*KXYhk2LW5k1{ljI&Ao)iBy_-$}Cf7oi=?T*H&72$tp`% zUAFvA?V|dg8oiMFoElx!HnDv4^g#_`)i)Egr+*XK%s`AYfw*o0NNC>7Vx^pUliSRq zFm?yC;y0d$b`;=Rd{J*&I&&Y+1?st$28{I|jM{XZb8-7-lbO7zQ zaK|*Jg^3MH&J{n*$6v3*uNwF^^lj+d(6^!gQtaw`3zYjv6ZglqrjBSm@)4j)E ztHUP>a0=s-*|N9EtEwC3@Ro-*ovxViwZ-9V10IBd4UK5;y;&`2c@wcFSOtnngMK%c ziFuuekJ(0Vm1l`QPW1M9RlycFKneS=(SO?VI^pas&}}xv=8xe|1UK2clr*$sRmCnC zOBoh4Tfx>8U>s}oX&K8F)^sesCp@z?Jd>jPIwGud)aqD;dYf~=;ptc_6NWy*3G6CZ zRJ*U8C=0&sL}|WP*kyR60RMW+liA2_O>93Nb$AtgwZ0jmor9(Cyky0=+5wOTHh)Ei z>u7`KSXk^2r|p8gcL5(YU-06?I{XH&z773pL-y{D4^000SaNLh0L01m_e01m_fl`9S#00007bV*G`2jc_=3L!4hF{f$( z005XtL_t(o!(;sa|3AY(0w#t527jXt7VQ!Pj5=V{0W1Vn{If(fnV60< z(l-QEX$btY{Qvz&I|C=@U%1e(UoRNgSS|lkGbHdv0UMjn>c4-H_^dUdbWH=y z%okBC{Pin`fsJ(vozei)aYly!H4NXsGb0866sjjgMuPnU8s`GW(T>Te0~ Date: Mon, 29 Jul 2019 23:12:14 +0200 Subject: [PATCH 09/31] Robust Lite, also known as "Qt was too hard to distribute". --- RobustToolbox | 2 +- SS14.Launcher/Helpers.cs | 82 ++++++ SS14.Launcher/JenkinsData.cs | 19 ++ SS14.Launcher/Program.cs | 392 +++++++++++++++++++++++++++++ SS14.Launcher/SS14.Launcher.csproj | 24 ++ SpaceStation14.sln | 21 ++ 6 files changed, 539 insertions(+), 1 deletion(-) create mode 100644 SS14.Launcher/Helpers.cs create mode 100644 SS14.Launcher/JenkinsData.cs create mode 100644 SS14.Launcher/Program.cs create mode 100644 SS14.Launcher/SS14.Launcher.csproj diff --git a/RobustToolbox b/RobustToolbox index e0512a1052..6d377ee1e3 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit e0512a1052bcde98b0b8bb54bbb35dfcf12edd57 +Subproject commit 6d377ee1e3c7dd63b4813643cad519937763bd68 diff --git a/SS14.Launcher/Helpers.cs b/SS14.Launcher/Helpers.cs new file mode 100644 index 0000000000..e9b74dd5dd --- /dev/null +++ b/SS14.Launcher/Helpers.cs @@ -0,0 +1,82 @@ +using System; +using System.Buffers; +using System.IO; +using System.IO.Compression; +using System.Net.Http; +using System.Threading.Tasks; + +namespace SS14.Launcher +{ + internal static class Helpers + { + public static void ExtractZipToDirectory(string directory, Stream zipStream) + { + using (var zipArchive = new ZipArchive(zipStream)) + { + zipArchive.ExtractToDirectory(directory); + } + } + + public static void ClearDirectory(string directory) + { + var dirInfo = new DirectoryInfo(directory); + foreach (var fileInfo in dirInfo.EnumerateFiles()) + { + fileInfo.Delete(); + } + + foreach (var childDirInfo in dirInfo.EnumerateDirectories()) + { + childDirInfo.Delete(true); + } + } + + public static async Task DownloadToFile(this HttpClient client, Uri uri, string filePath, + Action progress = null) + { + await Task.Run(async () => + { + using (var response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead)) + { + response.EnsureSuccessStatusCode(); + + using (var contentStream = await response.Content.ReadAsStreamAsync()) + using (var fileStream = File.OpenWrite(filePath)) + { + var totalLength = response.Content.Headers.ContentLength; + if (totalLength.HasValue) + { + progress?.Invoke(0); + } + + var totalRead = 0L; + var reads = 0L; + const int bufferLength = 8192; + var buffer = ArrayPool.Shared.Rent(bufferLength); + var isMoreToRead = true; + + do + { + var read = await contentStream.ReadAsync(buffer, 0, bufferLength); + if (read == 0) + { + isMoreToRead = false; + } + else + { + await fileStream.WriteAsync(buffer, 0, read); + + reads += 1; + totalRead += read; + if (totalLength.HasValue && reads % 20 == 0) + { + progress?.Invoke(totalRead / (float) totalLength.Value); + } + } + } while (isMoreToRead); + } + } + }); + } + } +} diff --git a/SS14.Launcher/JenkinsData.cs b/SS14.Launcher/JenkinsData.cs new file mode 100644 index 0000000000..3b133ab9a7 --- /dev/null +++ b/SS14.Launcher/JenkinsData.cs @@ -0,0 +1,19 @@ +using System; + +namespace SS14.Launcher +{ +#pragma warning disable 649 + [Serializable] + internal class JenkinsJobInfo + { + public JenkinsBuildRef LastSuccessfulBuild; + } + + [Serializable] + internal class JenkinsBuildRef + { + public int Number; + public string Url; + } +#pragma warning restore 649 +} diff --git a/SS14.Launcher/Program.cs b/SS14.Launcher/Program.cs new file mode 100644 index 0000000000..80ece2907b --- /dev/null +++ b/SS14.Launcher/Program.cs @@ -0,0 +1,392 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Net.Http; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Content.Client.UserInterface; +using Content.Client.Utility; +using JetBrains.Annotations; +using Newtonsoft.Json; +using Robust.Client.Graphics.Drawing; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.Interfaces.UserInterface; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.Utility; +using Robust.Lite; +using Robust.Shared.Asynchronous; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Log; +using Robust.Shared.Maths; +using Robust.Shared.Utility; +using static Robust.Client.UserInterface.Control; + +namespace SS14.Launcher +{ + internal class Program + { + private const string JenkinsBaseUrl = "https://builds.spacestation14.io/jenkins"; + private const string JenkinsJobName = "SS14 Content"; + private const string CurrentLauncherVersion = "1"; + + private readonly HttpClient _httpClient; + private string _dataDir; + + private LauncherInterface _interface; + private string ClientBin => Path.Combine(_dataDir, "client_bin"); + +#pragma warning disable 649 + [Dependency] private readonly ILocalizationManager _loc; + [Dependency] private readonly ITaskManager _taskManager; + [Dependency] private readonly IUriOpener _uriOpener; + [Dependency] private readonly IUserInterfaceManager _userInterfaceManager; +#pragma warning restore 649 + + public static void Main(string[] args) + { + LiteLoader.Run(() => new Program().Run(), new InitialWindowParameters + { + Size = (500, 250), + WindowTitle = "SS14 Launcher" + }); + } + + private Program() + { + IoCManager.InjectDependencies(this); + + _httpClient = new HttpClient(); + _httpClient.DefaultRequestHeaders.Add("User-Agent", $"SS14.Launcher v{CurrentLauncherVersion}"); + } + + private async void Run() + { + _dataDir = Path.Combine(UserDataDir.GetUserDataDir(), "launcher"); + + _userInterfaceManager.Stylesheet = new NanoStyle().Stylesheet; + + _interface = new LauncherInterface + { + ProgressBarVisible = false + }; + + _interface.StatusLabel.Text = _loc.GetString("Checking for launcher update.."); + _userInterfaceManager.StateRoot.AddChild(_interface.RootControl); + + try + { + var needsUpdate = await NeedLauncherUpdate(); + if (needsUpdate) + { + _interface.StatusLabel.Text = _loc.GetString("This launcher is out of date."); + _interface.LaunchButton.Text = _loc.GetString("Download update."); + _interface.LaunchButton.OnPressed += + _ => _uriOpener.OpenUri("https://spacestation14.io/about/nightlies/"); + _interface.LaunchButton.Disabled = false; + return; + } + + await RunUpdate(); + + _interface.StatusLabel.Text = _loc.GetString("Ready!"); + _interface.LaunchButton.Disabled = false; + _interface.LaunchButton.OnPressed += _ => LaunchClient(); + } + catch (Exception e) + { + Logger.ErrorS("launcher", "Exception while trying to run updates:\n{0}", e); + _interface.ProgressBarVisible = false; + _interface.StatusLabel.Text = + _loc.GetString("An error occured.\nMake sure you can access builds.spacestation14.io"); + } + } + + private async Task NeedLauncherUpdate() + { + var launcherVersionUri = + new Uri($"{JenkinsBaseUrl}/userContent/current_launcher_version.txt"); + var versionRequest = await _httpClient.GetAsync(launcherVersionUri); + versionRequest.EnsureSuccessStatusCode(); + return CurrentLauncherVersion != (await versionRequest.Content.ReadAsStringAsync()).Trim(); + } + + private async Task RunUpdate() + { + _interface.StatusLabel.Text = _loc.GetString("Checking for client update.."); + + Logger.InfoS("launcher", "Checking for update..."); + + var jobUri = new Uri($"{JenkinsBaseUrl}/job/{Uri.EscapeUriString(JenkinsJobName)}/api/json"); + var jobDataResponse = await _httpClient.GetAsync(jobUri); + if (!jobDataResponse.IsSuccessStatusCode) + { + throw new Exception($"Got bad status code {jobDataResponse.StatusCode} from Jenkins."); + } + + var jobInfo = JsonConvert.DeserializeObject( + await jobDataResponse.Content.ReadAsStringAsync()); + var latestBuildNumber = jobInfo.LastSuccessfulBuild.Number; + + var versionFile = Path.Combine(_dataDir, "current_build"); + bool needUpdate; + if (File.Exists(versionFile)) + { + var buildNumber = int.Parse(File.ReadAllText(versionFile, EncodingHelpers.UTF8), + CultureInfo.InvariantCulture); + needUpdate = buildNumber != latestBuildNumber; + if (needUpdate) + { + Logger.InfoS("launcher", "Current version ({0}) is out of date, updating to {1}.", buildNumber, + latestBuildNumber); + } + } + else + { + Logger.InfoS("launcher", "As it turns out, we don't have any version yet. Time to update."); + // Version file doesn't exist, assume first run or whatever. + needUpdate = true; + } + + if (!needUpdate) + { + Logger.InfoS("launcher", "No update needed!"); + return; + } + + _interface.StatusLabel.Text = _loc.GetString("Downloading client update.."); + _interface.ProgressBarVisible = true; + var binPath = Path.Combine(_dataDir, "client_bin"); + + await Task.Run(() => + { + if (!Directory.Exists(binPath)) + { + Directory.CreateDirectory(binPath); + } + else + { + Helpers.ClearDirectory(binPath); + } + }); + + // We download the artifact to a temporary file on disk. + // This is to avoid having to load the entire thing into memory. + // (.NET's zip code loads it into a memory stream if the stream you give it doesn't support seeking.) + // (this makes a lot of sense due to how the zip file format works.) + var tmpFile = await _downloadArtifactToTempFile(latestBuildNumber, GetBuildFilename()); + _interface.StatusLabel.Text = _loc.GetString("Extracting update.."); + _interface.ProgressBarVisible = false; + + await Task.Run(() => + { + using (var file = File.OpenRead(tmpFile)) + { + Helpers.ExtractZipToDirectory(binPath, file); + } + + File.Delete(tmpFile); + }); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + // .NET's zip extraction system doesn't seem to preserve +x. + // Technically can't blame it because there's no "official" way to store that, + // since zip files are DOS-centric. + + // Manually chmod +x the App bundle then. + var process = Process.Start(new ProcessStartInfo + { + FileName = "chmod", + Arguments = $"+x '{Path.Combine("Space Station 14.app", "Contents", "MacOS", "SS14")}'", + WorkingDirectory = binPath, + }); + process?.WaitForExit(); + } + + // Write version to disk. + File.WriteAllText(versionFile, latestBuildNumber.ToString(CultureInfo.InvariantCulture), + EncodingHelpers.UTF8); + + Logger.InfoS("launcher", "Update done!"); + } + + private async Task _downloadArtifactToTempFile(int buildNumber, string fileName) + { + var artifactUri + = new Uri( + $"{JenkinsBaseUrl}/job/{Uri.EscapeUriString(JenkinsJobName)}/{buildNumber}/artifact/release/{Uri.EscapeUriString(fileName)}"); + + var tmpFile = Path.GetTempFileName(); + Logger.InfoS("launcher", tmpFile); + await _httpClient.DownloadToFile(artifactUri, tmpFile, f => _taskManager.RunOnMainThread(() => + { + _interface.ProgressBarVisible = true; + _interface.ProgressBar.Value = f; + })); + + return tmpFile; + } + + private void LaunchClient() + { + var binPath = ClientBin; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "mono", + Arguments = "Robust.Client.exe", + WorkingDirectory = binPath, + UseShellExecute = false, + }, + }; + process.Start(); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Process.Start(new ProcessStartInfo + { + FileName = Path.Combine(binPath, "Robust.Client.exe"), + }); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + // TODO: does this cause macOS to make a security warning? + // If it does we'll have to manually launch the contents, which is simple enough. + Process.Start(new ProcessStartInfo + { + FileName = "open", + Arguments = "'Space Station 14.app'", + WorkingDirectory = binPath, + }); + } + else + { + throw new NotSupportedException("Unsupported platform."); + } + } + + + [Pure] + private static string GetBuildFilename() + { + string platform; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + platform = "Windows"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + platform = "Linux"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + platform = "macOS"; + } + else + { + throw new NotSupportedException("Unsupported platform."); + } + + return $"SS14.Client_{platform}_x64.zip"; + } + + + private class LauncherInterface + { +#pragma warning disable 649 + [Dependency] private readonly IResourceCache _resourceCache; + [Dependency] private readonly ILocalizationManager _loc; + [Dependency] private readonly IUriOpener _uriOpener; + private bool _progressBarVisible; +#pragma warning restore 649 + + public Control RootControl { get; } + public Label StatusLabel { get; } + public ProgressBar ProgressBar { get; } + public Button LaunchButton { get; } + + public bool ProgressBarVisible + { + get => _progressBarVisible; + set + { + _progressBarVisible = value; + ProgressBar.Visible = value; + StatusLabel.SizeFlagsHorizontal = value ? SizeFlags.Fill : SizeFlags.FillExpand; + } + } + + public LauncherInterface() + { + IoCManager.InjectDependencies(this); + + Button visitWebsiteButton; + + RootControl = new PanelContainer + { + PanelOverride = new StyleBoxFlat + { + BackgroundColor = Color.FromHex("#20202a"), + ContentMarginLeftOverride = 4, + ContentMarginRightOverride = 4, + ContentMarginBottomOverride = 4, + ContentMarginTopOverride = 4 + }, + Children = + { + new VBoxContainer + { + Children = + { + new Label + { + Text = _loc.GetString("Space Station 14"), + FontOverride = _resourceCache.GetFont("/Fonts/Animal Silence.otf", 40), + SizeFlagsHorizontal = SizeFlags.ShrinkCenter + }, + + (visitWebsiteButton = new Button + { + SizeFlagsHorizontal = SizeFlags.ShrinkCenter, + SizeFlagsVertical = SizeFlags.Expand | SizeFlags.ShrinkCenter, + Text = _loc.GetString("Visit website") + }), + + new HBoxContainer + { + SizeFlagsVertical = SizeFlags.ShrinkEnd, + SeparationOverride = 5, + Children = + { + (StatusLabel = new Label()), + (ProgressBar = new ProgressBar + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + MinValue = 0, + MaxValue = 1 + }), + (LaunchButton = new Button + { + Disabled = true, + Text = _loc.GetString("Launch!") + }) + } + } + } + } + } + }; + + visitWebsiteButton.OnPressed += _ => _uriOpener.OpenUri("https://spacestation14.io"); + + RootControl.SetAnchorPreset(LayoutPreset.Wide); + } + } + } +} diff --git a/SS14.Launcher/SS14.Launcher.csproj b/SS14.Launcher/SS14.Launcher.csproj new file mode 100644 index 0000000000..6198b6196b --- /dev/null +++ b/SS14.Launcher/SS14.Launcher.csproj @@ -0,0 +1,24 @@ + + + + net472 + 7.3 + false + x64;x86 + false + ..\bin\SS14.Launcher\ + Exe + + + + + + + + + + + + + + diff --git a/SpaceStation14.sln b/SpaceStation14.sln index 878f0c3e6d..734804dfef 100644 --- a/SpaceStation14.sln +++ b/SpaceStation14.sln @@ -40,6 +40,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Content.IntegrationTests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Benchmarks", "Content.Benchmarks\Content.Benchmarks.csproj", "{7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.Lite", "RobustToolbox\Robust.Lite\Robust.Lite.csproj", "{0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SS14.Launcher", "SS14.Launcher\SS14.Launcher.csproj", "{47B4D2F3-6767-4ACB-A803-972FEF7215E9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -151,6 +155,22 @@ Global {7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}.Release|x64.Build.0 = Release|x64 {7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}.Release|x86.ActiveCfg = Release|x86 {7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}.Release|x86.Build.0 = Release|x86 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x64.ActiveCfg = Debug|x64 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x64.Build.0 = Debug|x64 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x86.ActiveCfg = Debug|x86 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x86.Build.0 = Debug|x86 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x64.ActiveCfg = Release|x64 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x64.Build.0 = Release|x64 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x86.ActiveCfg = Release|x86 + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x86.Build.0 = Release|x86 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x64.ActiveCfg = Debug|x64 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x64.Build.0 = Debug|x64 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x86.ActiveCfg = Debug|x86 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x86.Build.0 = Debug|x86 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x64.ActiveCfg = Release|x64 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x64.Build.0 = Release|x64 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x86.ActiveCfg = Release|x86 + {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -163,6 +183,7 @@ Global {93F23A82-00C5-4572-964E-E7C9457726D4} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {F0ADA779-40B8-4F7E-BA6C-CDB19F3065D9} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} {0529F740-0000-0000-0000-000000000000} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} + {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AA37ED9F-F8D6-468E-A101-658AD605B09A} From dc6e65559be92094f3bd41467e7745f553c9bc03 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 00:55:54 +0200 Subject: [PATCH 10/31] Launching the client closes the launcher now. --- SS14.Launcher/Program.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SS14.Launcher/Program.cs b/SS14.Launcher/Program.cs index 80ece2907b..deb6056020 100644 --- a/SS14.Launcher/Program.cs +++ b/SS14.Launcher/Program.cs @@ -10,6 +10,7 @@ using Content.Client.Utility; using JetBrains.Annotations; using Newtonsoft.Json; using Robust.Client.Graphics.Drawing; +using Robust.Client.Interfaces; using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.Interfaces.UserInterface; using Robust.Client.UserInterface; @@ -43,6 +44,7 @@ namespace SS14.Launcher [Dependency] private readonly ITaskManager _taskManager; [Dependency] private readonly IUriOpener _uriOpener; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager; + [Dependency] private readonly IGameController _gameController; #pragma warning restore 649 public static void Main(string[] args) @@ -93,7 +95,11 @@ namespace SS14.Launcher _interface.StatusLabel.Text = _loc.GetString("Ready!"); _interface.LaunchButton.Disabled = false; - _interface.LaunchButton.OnPressed += _ => LaunchClient(); + _interface.LaunchButton.OnPressed += _ => + { + LaunchClient(); + _gameController.Shutdown(); + }; } catch (Exception e) { From e00a737285029c7362c06ae9cc5dbdb3f0b84387 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 01:08:22 +0200 Subject: [PATCH 11/31] Animal Silence has been moved to content. --- Resources/Fonts/Animal Silence.otf | Bin 0 -> 7184 bytes RobustToolbox | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Resources/Fonts/Animal Silence.otf diff --git a/Resources/Fonts/Animal Silence.otf b/Resources/Fonts/Animal Silence.otf new file mode 100644 index 0000000000000000000000000000000000000000..a923bd099d7c3265471b788e67c305c04ebec09c GIT binary patch literal 7184 zcmd5>YitzP6+U+!yBi>c#UVHl!)zQ%NR8tM=9NcH;$TAEKrs-frI4+6ZLj3V#x{utqMPU|WK*)K_2FjRVPs(j=TLLgL+kkt_ix~5R`cdf zt#m8R!u@&N&uwnq_CWVH21jxK0q(s`t#{Ww*!6=qAz~Q!kGJ1XvN%?DVPN)=0OYF`xWA*T zXK?sbm$ex8zrm5}?rV>}ap$>XMD9sE|9MYzI7xB38PD2q@AXD|;%kS$xsYi75!g_Z z>>C(7_QU3Ph!(tt=i}lV{Oh@K(Nnu_y7%uiGlXHH*K4ac%K5`iJe^)03e7&Z|(zP<7!f2Tur|_{m1DG(|?$5pZ;?8J9Bor zJB@r{DftPgSLOcqAE8i4GX3$-C5%Nkl3TD7>4nh%1t~-~&@Uwyz(PH=zfq#|oWC?wWmeQTHjP9aOQxz?zYPy?hsFv!eo>ou; zt)x}7n%2--x`*zi`{;i9474`VI(mQ}q$YZZ)>AWWpoeKAeU@72bMy#pqRsSq+Cr_g zmA27#dX(DeG5P|1k#+#pokhOXUG%sNEdZ+gt%3hZO4E<%ES;yzYOcCV ztyLS;cGaOq)B$x&omOwEOIFBQWUaNfTisU5I&8gQy<(lWKD5j2wf1Ja!`^2fv43oz zvoF|xb>=#EI1e~GoIxk;Jmd)*!GuzSdT&VA8+&3)T_KM)Aq9#|P@ z33LSZ2F3y}1kMEB2wVzegSP~$gH6Gm!J*)x;Pb&(f^P*cg=U4SLmNVmhlWC_&=`Mp z7P{x%VPp{1s)!0l!VzVww5r09&LwkeGVbuy39D^lzjb=5iQSg`RB7{JHAbIDkY`S_RZnO^PgLA@yh^{V<{q%0DQ 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 O_M-1{c-;KAf&K*{C`1_m literal 0 HcmV?d00001 diff --git a/RobustToolbox b/RobustToolbox index 6d377ee1e3..be379b2e20 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 6d377ee1e3c7dd63b4813643cad519937763bd68 +Subproject commit be379b2e205fd35dcd06f0921aaec9c19ac28910 From 29b00fc6333d476c7f80facfaa471cb5f948f859 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 01:08:36 +0200 Subject: [PATCH 12/31] Launcher packaged. --- BuildFiles/Linux/SS14.Launcher | 5 ++ .../Contents/Info.plist | 20 ++++++ .../Contents/MacOS/SS14 | 8 +++ .../Contents/Resources/ss14.icns | Bin 0 -> 48304 bytes BuildFiles/Windows/launch.bat | 1 - BuildFiles/Windows/run_me.bat | 1 + Tools/package_release_build.py | 62 ++++++++++++++---- 7 files changed, 85 insertions(+), 12 deletions(-) create mode 100755 BuildFiles/Linux/SS14.Launcher create mode 100644 BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist create mode 100755 BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14 create mode 100644 BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Resources/ss14.icns delete mode 100644 BuildFiles/Windows/launch.bat create mode 100644 BuildFiles/Windows/run_me.bat diff --git a/BuildFiles/Linux/SS14.Launcher b/BuildFiles/Linux/SS14.Launcher new file mode 100755 index 0000000000..96d0722021 --- /dev/null +++ b/BuildFiles/Linux/SS14.Launcher @@ -0,0 +1,5 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +exec mono bin/SS14.Launcher.exe diff --git a/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist new file mode 100644 index 0000000000..d5e34b0787 --- /dev/null +++ b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleName + SS14L + CFBundleDisplayName + Space Station 14 Launcher + CFBundleExecutable + SS14 + + CFBundleIconFile + ss14 + + diff --git a/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14 b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14 new file mode 100755 index 0000000000..57abef5dc5 --- /dev/null +++ b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14 @@ -0,0 +1,8 @@ +#!/bin/sh + +# cd to file containing script or something? +BASEDIR=$(dirname "$0") +echo "$BASEDIR" +cd "$BASEDIR" + +exec /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono ../Resources/SS14.Launcher.exe diff --git a/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Resources/ss14.icns b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Resources/ss14.icns new file mode 100644 index 0000000000000000000000000000000000000000..ea22dc64c71b4e2fd53c0566362c251cb0b08718 GIT binary patch literal 48304 zcmeFYbyOVP(=OUG3@})551s_qUu6mx@b{0-<0MJouXTc=^0K{w&>Z)=$m=u@* z0N^OdOKT#}uzx;KH00m!qGrR$6Ua?dP7haSh?W$jCA2?)4&K^T63dWq;NyM3 zm6jPt-wjIdX`yFPB%(KbMp4M)npP$j+ADoyRyf!z_TqJ>;K@L54^5$lTyINHt$goF zXj%AOEConT248z6;zyxZS52qKm)CDQuR4#qu6Cd09L}r0@!LAznKxusqXxyn5Ml8D7RQ3{=4y)DR8jJ}o}ZjLOwiS0ji-K&qM)i^Lp3$)086hM)x__Zb~HfG zjAaOPCx5~Hyf8irN9{xJ8GQ+aWXMTOU+O)n`|YC}gm;a3(?B{{5sym7?=Y8b-09Ou z#0*n2ga&?(_ff@v62d0l?f)=yG~Za!sriM7IY`YAI}k@+l%6wc$(xX8(YgDfNviZ{ zvAx-6HH5U-tMD#Si9=&K0MWTS`8m#@&OBt^x%0TC%5e>CS{GPBlHu88l{Y8Xv*?uWIAx$9~;`Ah3EcEhG0 z`SIA6!EG&JPpDoyBOb1nF*ZLw1lg~^15_wgl3>%rJL--lb_FD=u7Jj-f@g>yrT*wfprrvD=K+!-ZC@9OV5u zUTNWQ?t!O8rXFvfx_NzfV+OjyluoK>98-gr_gBA%Wf?!VK7pol=Je#&|KOuduE1~c z*qf1H3QtKTfrY%JbmsMSI4>>;kDN|y`%u>t?qtiZIv?h9_C7_*A3Wy!UPkG>C`Du~ zoFQ3WO&?oP*+@263Rk3o_@nW6VqV*Gzwe>1RWN-$B2JQ3Qjr8VKtG&&!7IjZ;ZN18v!1PP+sDe7wZ2z}t+wtlNu@r2njGK#h`;@X9z!Lh(|NVz+qMvLXp`sXY1e^C z{LIEYwpkia48_e=B?5};ZSzi&Vck*l`svch-HTAgNh#qmc{c6I$A`NLw^0#+$bqIZ zAT8h>7R>d6TODRL@$s$KqQ|?N(+vsIv6R4b%9qy4yP*Zjf8H)+8|t<3>NaWW?Mb?KdQ98B_Ho{q@(MfGew!WBLS+?kZ+X#CvaFUu*(RPhgzrf{NF z$)70fqM2(l3XsUSD9g7CR{hX21U@2iN;ke?acWmp?X>3&P38yUHloWlB^1y#H|K)CCHP!A*N zu}-XyDA6DBF9l>xR6F3clLgW(SW9IY%-Bl;p|`e&mPV^em86hRKb z3h!^YV>b(qc-|T`>ocCca`e&dKzSla>m&^0QOb6aKf{;?WR}?%|z|?w$M; zScWLP^4s5Ku06_5v88|8VN{BI2^qhZqGO|o)m4r4hl)S<>+9;a)*nx}{w|9yFyBKR zzs-TV!mFlZN=#i=Ege<74<5fi75eo?T3;bczuK8gVK&0wd$-U1MO@i!-Tv*%k<<2h zh8HxaeBnIBY+tJyWI{^w#g#2HKJccpROnP;>KxQMXI=W-pA4Xgo^6e)<;b4Rutxnt zI=&IR!SyK4F6gP~dh|=4&tb=`+w^D^(eB>oIThi&qP8(Mn<}E5UDxI@10`w3yMF`i zjt!nR$Yi@3`|Ok$Jbhcbo5Pd+X;>klhHy!T2V2F^3@)AHF{7_)?V4*~@BO*dhK@>1 z&0w==a(Ii^YRoy8wW^x%`w){M0d6dBcrtn!+KSxrLWac zm(`#75{Hd>+4Qmc{&M=S+Z{A8xkxB3;wx2reSIxKmPR`>%T9i2tFDK_c1HK+O9Z;- z@EUSi=*buLBH0+sd36m`k%#li^`UdjbHO@xOu4L%$;*2+-A*rqu_%Rdgh#~?_v#BL>jPnH{>YiA z)4|z&&qEZp(epx+HP`d0$CO6FwUGs_-S2v<#t&zkKa+ZTsKxc2$#;;>xca1Jzkb-# zWukB_UR%2IbjMkFh?()XksQH46EM&27K@6N1a1$qgC3vJn-wT}3b zXdO_{^Hciqh)uGy$32O<{k41C;5Ep|(*4XoPW0ARGnqEq4JA9*f3K?9=!AK4)xOZaR=eJlu9l~E$y8UJPRy}f<;4d_Wt%wfO`lMtrD>_; zP`tV(&Fo6SgwL#ry$v^e)iNy9X!7lfnU97X-vR}bF-3350pH7OZ7mULl7iYlgZsDw zWIhF~mt$zLh_l20MjutKO-H*=stE8|)a~lLFc9$fB;_#L)&{UWzfd~0NGu}Vbv4gD zN-mbm^j`;06kG|oREuP91}ks0CLgOda5$DL?EU`7@^NjOaw+Oc zap2i{&+`%9M!W5mAY2_={Lc})>wm>z)_E~To}G56hwVpQc%&R;F$Dwo{c1fV{oKUx z32d}?YmZ$GzW0JIYs4#Re=Xa;M0?_G(tN^rwuv`gAy1Z;0V{5lP1FG{adi{FJgdHM zU4K%|p(y8V{b$1U(5EhyO<$8z-F#=#Q?2OTka04zk!O{6ORBI-rrnf0~7>%=&H zMqQEg7ZJ+T8XK!**z7q`>A9&AsWGfg8<;N={23OcTJ&INy#;E(U6u?byLBieg*ch$ z0xb)^&0Ecr@R=w*%ErKdWVkQsF|kIU(Y)`}>UmOFh5z3zmi7!a?brR|R`j?LgrDx@ zSYR1}0f(7Tb!KLFV{K!WAobu!35Iz5x6U@Rl}(&{_*@}s%}w+M_)N~mowc-upK#*y zcoG$+NE}6#0}u<1`1$m;od9aV2S z1&-rPd7w%~24n9&##l>bJz)tV^`F%y@;@sI9;J}zuUVb>X5$FD7KZB3xthQ~_&WNFH_QIH5xQ9f zGpk|Zpw#aghDH5bZoghJ&gp@w%7x6v28Xh4EK-yf&pfQ)O$oh)*aCZV&^2qaA=OlJ zrDG-w)dwLvLEdM{+o!{v&e9pI*F+(wqC3S&6p76vkk5IcL*QP_ySmsI+9BoCW)?&H z?yy$cV2V1N1gF&?1tUdAj?etx@7>Pm@SfL{JJ`PrWNX!iJxLEo)YI7##4&A66@9J_ z1gxG1EJ0=pAKqVOVDHkNM4xHK#_?=Oe|7MIO5|^0D=O0RgMG4ddGqo zSoP&DT>!C~9`LSY_$}De2&|4h9dk!$s-q=`2+Jk#6zwy87bHp~g2i;9)`A0)lv`AB z)_+d?X{U?^tXAfm6*4qD75Wsk0Up?k197GIVV3=boUJWztu0#d{R@l=YYZmVp^@__ zAJr0ItT@E9R+?wEVG~#Ep0=~IT>^@C7yf1A`J0UAsn1ft@mL1Qd-?ieO0mKh-wi<# ziVusu3m$8jR?_;@C6II#1MM8mhEj@gD6>`Qq#F9?u!MA}A2Tw))n)aA^X9?v%(uzT z>m&}W{4ZBuNb|l{=0q6DLBc(H`$yT|kWX`ZxpU@v=?9*-QBqAB!fYKZq0gTB+%acW zCXQNyemwott-I2sZ~b=^5+6P_N)>pqS?;i#R<{`)Ju~$klQ#)<3_&fOQzcMUM)|^^ zYb0Z_9y=M;s&FG|V@XKKl8Ur+(>hv247id%2%GubcDq|K{T)}Vva{_x=YnZn8W#h6 zyEVa@lto5p??yyI(NN8jq}+iiBP%1Cq?2FfDUgKvT>mez^(H^; z7u4@(h58o4PT*qaPr=7mV&Gn#%O)n2A$rc)1x(mrm_R|yofL|_x0}n_bBD5H zZ5l{;)vImUeP*PJb8IVde&(vBZ9X5y&!qOxYI(WM!lG{>;9l+ANaH^L_tJ^lOCdyn z+t0jJvW%rt;+1a@YK)^VMv(9?t$1PSguX-h@~R<3F!J>~H(}oKOa}P)rbZHx%+S2W z6y|a5uH0}TdlR=m4Qexal)!sX8xZ)1b6&?GpHq)w>i50F1+OCfRUp&dycfP ztQK4g2qs1kcoZuX1Z64X8KA7{>DC?Yviz1dzt)1?N$-QhOaTQ-jQ< zE1%(OnX^7*O)rLOuqXv-jA0^TspL4YxO~pHTb?a)M3dpOBCqjV2iI)N054G+4_c2> zq}^th5+{|IOmmH>G46EDz&fIQRmfbR`{eyc)~L#IC~H} z?xD*Ar+B|3g#e2W+em83Ad^ww#hv~GMLQcX>HZlD!8U8tfNN?{mbJ_jyf}Q1!+&}a4Xr_1; zB$!Tig8tV=5>d1DV3Bb!9*Q~L37vIs^%A(I0@ZX?z-i%{HMVe>sR}?yzvFN%_mas< z5#x>zuzIf38$HKo-}*JR0+;ue;#oa!XJcdIr%<(@nCHA$@HRq}2qoeQ(c>DS=|!-% zeJ#4*Z^tnQdw;?pnV!R}+!ps}kIi2U=B5PP^g74(U8pqH5^kbyC{pt4+;_x!fw`6- zJsVPzHvWPmiY|`=Do$^f$u|=&UbuT~5p#G9JIhrI*Ihro z*r}wvKJ&P5kCinS{<(IW<=(?AFd*fo1(Q%exkxnVZ8yK@91-kH!#Zz8q z^FWNes$SW(3HHUZeaSRpajUB4LZP;T`-0a5SmqPt-<(=dO`jL+9GOM`F_2v%PjPn7 z#cOz}WGz+& zT2CjFVqFK9g7gAseE{Gw)Zh|SQWHYMd8Mw%1_09ch@=Jtq8$Lz5RWo20IL)c zUyDFA0ze|76nQ(bhXka!Q(wP)E%pfj*JU;aA%M~#0IVD@_(=m)D;ETSu!WF+1hDgg z{~7%MS8v`;(9s?VqC@{NssDaBeEzS)8QJq>6Y*ci<`V!={4WXlMG*k9|1D<&`0M|c z*PiJ7TSOpKwg0=Ug+B7{h7ok&zx_Z50MP!WF!B%n|1Sk(_rDeX)BP`n|8yf268_f% zCH(X2|M!8U90UP?x%mI296(4_5bz($!RURN^*_?TCFxH_dBU zWH!A?Y*Mt1=aqNJ981WH*}Ou-@f7E&D13n?otPnF$AfojkLRySU1P1FL_sAyu8-II zyN0>$ljL>6klSA-t6cMFcg@G0*py<;qq|pM-nM#lZteRWiXe^*YIhgfY?dFk+OLdl z4jN~T86%^yK~iu$F3A6-Q~naPvRvbW{|kplxmrwqU3mj`piJYI1l7ED8b-5(X$R+$ z4!U~flTh&<=*Q~&xNsU`qga8v&z;Oe3bh7(9rV=9p9NX_@XCk+4O#p?U*}#|lf~o{ z_>?DVR;f#ww&2fIZ<-LPMGEL($V^iJO7T@|?B)#sgOn*5o@wO~UI0tAJGpTqAbv}S zdKH-vDH{r-Q>O>N!2*hDLdA*;66j2!$Aft^_=@wTO5=rjgEtV@cz6?laPaV_^8r%4hA zB()+3VIc&>bb1hWmX^;bXlUYQs^9LZ35!SG+}vy^R$Q*ZKj*&wMknC;bW~S)y|Kc> zbd1&jLhIHDBc&R2f4?OrmY+&}jZ7outWe|~8(wo$P*O&D9?ZY_t;Ny!$#W9#2YR4} z)mcEVmQtnCEA2Kw{p*wPW&KVckH3UKQBl!&9^!sW@8U&g0^OJ6^Rc1J0!~TX@0P`d5{K@^1K`aOv&#M{(_OQD2kL**7s7osgEXDc83Bku>5ho zDm^=>Fose<7O=B~^5TG~^_1^(guHaD1)ua)x`XgE>#7W!`w5a8yDO}jHZnrPB;Kr0?z(QfB5rk-*>-} z{a%SJl^+P@5)j2t;?WyiU zkJJoXU$j0eQbyy_h(>1`)o63IJMr8cEwoNvI1>3GQQ~p?noga}F%M$-^0;=BjYe$H zab?r#<;RDM*`m(k_crUun03b%c}4EC-*UFVBD&YdZsv7S3RsQthgbA2L-a%M-glnD z2kijwzi(Wqi-rQaKgf2R7N>OmNWyFe*-|y!A+gl9d<>Dzik6AKSi zU5;=s(nWuSg(sW>??5gog9?_Ptw$JE9pxRl`&VDRi!NeJz1pNZx8f~bv5}J26R@zJ z=g|_?yM)myO?E%lt#{CA`r|y9I#Sagn%!4Oec`o^SWJdF;^(s$u^2`|(wHxI!4R zZP>4y%AG2A;D0l0A{%f!nP=XvUL*e8J9*rhx)BdhHfNjKy#3=WFn_cg4eKynKZ!BB zM&hDn(*$3+K=}$H^btZFl<;aZx5rl>uU*`c1m_fY!~^)}XEr31G*eM|DbSGpz5L4f z!Ef!pspfkHR5Y1X}WC`kYVe=(D09%li+lvXxJN?CQwae)^h-Q9r&hmq|+(T z(h^DrCdXrP_(}z$y%0Nc)2bS{y1~g=ZSQ9%{s>`XH?A& z_rLqI-0y#~M570m%I|@?T%ue#M+eHqK8?T~c(a&I4}r7rMNX0|eK2+yzTegDj?8&^ zOv?1l2ClGJ9@unRAqRVIcO`^9R6UKvY{^8&A6WiwNDHXdp*#MKW$p>q#Q4%}HJqwWEPxuk06*gGfFrHa=G%mb3QNX)7^7I*zmP z6jt3e?r+u7D>KjBb`!5lulZa#Y@*JHfC}Clfu8d0v~2Wz0W%arE`1cC#;KW*DSLGZ zt#?5b24n`f22eLz2JU9lnoz1t=Ugyc(m$-wX$LznlU99BAC}oLT5g6kGiGQyAP*XF zA_qIl(Z)T8f3=^f^hR0FQ+@RAL_m`zXh)m$AODD|SNh#Bz@L7&J7_MV6mXL6Sf`Iq zw;1RpLs5%D$E3^+1LoL@(1+-^P1N5IZK*SHe?A_AP92j$= z^#oxHXjaqpVhr%y17)MboZU~|JNUjhE*_W#yguI`|9dkoMG_5z+fU7 z*ij}w?>QiZZrEqoYj$U@_=5zSQ-LkhGAaB!dz}m_{>Q+x*{3~hnVXxNsm%zcnr#;w z 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
)k=eUo{3 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 literal 0 HcmV?d00001 diff --git a/BuildFiles/Windows/launch.bat b/BuildFiles/Windows/launch.bat deleted file mode 100644 index 12fea13879..0000000000 --- a/BuildFiles/Windows/launch.bat +++ /dev/null @@ -1 +0,0 @@ -call Godot\godot.windows.tools.64.mono.exe --path SS14.Client.Godot diff --git a/BuildFiles/Windows/run_me.bat b/BuildFiles/Windows/run_me.bat new file mode 100644 index 0000000000..83d3eb16b1 --- /dev/null +++ b/BuildFiles/Windows/run_me.bat @@ -0,0 +1 @@ +call bin/SS14.Launcher.exe diff --git a/Tools/package_release_build.py b/Tools/package_release_build.py index 560d8980c0..e73c9e7cbc 100755 --- a/Tools/package_release_build.py +++ b/Tools/package_release_build.py @@ -44,8 +44,12 @@ SERVER_IGNORED_RESOURCES = { "Shaders", } +LAUNCHER_RESOURCES = { + "Nano", + "Fonts", +} + def main(): - global GODOT parser = argparse.ArgumentParser( description="Packages the SS14 content repo for release on all platforms.") parser.add_argument("--platform", @@ -72,7 +76,7 @@ def main(): build_windows() if "linux" in platforms: - wipe_bin() + #wipe_bin() build_linux() if "mac" in platforms: @@ -125,6 +129,15 @@ def build_windows(): copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True) server_zip.close() + print(Fore.GREEN + "Packaging Windows x64 launcher..." + Style.RESET_ALL) + launcher_zip = zipfile.ZipFile(p("release", "SS14.Launcher_Windows_x64.zip"), "w", + compression=zipfile.ZIP_DEFLATED) + + copy_dir_into_zip(p("bin", "SS14.Launcher"), "bin", launcher_zip) + copy_launcher_resources(p("bin", "Resources"), launcher_zip) + launcher_zip.write(p("BuildFiles", "Windows", "run_me.bat"), "run_me.bat") + launcher_zip.close() + def build_macos(): print(Fore.GREEN + "Building project for macOS x64..." + Style.RESET_ALL) @@ -161,6 +174,17 @@ def build_macos(): copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True) server_zip.close() + print(Fore.GREEN + "Packaging macOS x64 launcher..." + Style.RESET_ALL) + launcher_zip = zipfile.ZipFile(p("release", "SS14.Launcher_macOS_x64.zip"), "w", + compression=zipfile.ZIP_DEFLATED) + + contents = p("Space Station 14 Launcher.app", "Contents", "Resources") + copy_dir_into_zip(p("BuildFiles", "Mac", "Space Station 14 Launcher.app"), "Space Station 14 Launcher.app", launcher_zip) + copy_dir_into_zip(p("bin", "SS14.Launcher"), contents, launcher_zip) + + copy_launcher_resources(p(contents, "Resources"), launcher_zip) + launcher_zip.close() + def build_linux(): # Run a full build. @@ -197,21 +221,37 @@ def build_linux(): copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True) server_zip.close() + print(Fore.GREEN + "Packaging Linux x64 launcher..." + Style.RESET_ALL) + launcher_zip = zipfile.ZipFile(p("release", "SS14.Launcher_Linux_x64.zip"), "w", + compression=zipfile.ZIP_DEFLATED) + + copy_dir_into_zip(p("bin", "SS14.Launcher"), "bin", launcher_zip) + copy_launcher_resources(p("bin", "Resources"), launcher_zip) + launcher_zip.write(p("BuildFiles", "Linux", "SS14.Launcher"), "SS14.Launcher") + launcher_zip.close() def copy_resources(target, zipf, server): # Content repo goes FIRST so that it won't override engine files as that's forbidden. - do_resource_copy(target, "Resources", zipf, server) - do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, server) + ignore_set = SHARED_IGNORED_RESOURCES + if server: + ignore_set = ignore_set.union(SERVER_IGNORED_RESOURCES) + else: + ignore_set = ignore_set.union(CLIENT_IGNORED_RESOURCES) + + do_resource_copy(target, "Resources", zipf, ignore_set) + do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, ignore_set) -def do_resource_copy(target, source, zipf, server): +def copy_launcher_resources(target, zipf): + # Copy all engine resources, since those are stripped down enough now. + do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, SHARED_IGNORED_RESOURCES) + for folder in LAUNCHER_RESOURCES: + copy_dir_into_zip(p("Resources", folder), p(target, folder), zipf) + + +def do_resource_copy(target, source, zipf, ignore_set): for filename in os.listdir(source): - if filename in SHARED_IGNORED_RESOURCES \ - or filename in (SERVER_IGNORED_RESOURCES if server else CLIENT_IGNORED_RESOURCES): - continue - - # Get rid of Godot .import files, thanks. - if filename.endswith(".import"): + if filename in ignore_set: continue path = p(source, filename) From 15d81c187642c56a0a5118776fa117eb6701e178 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 12:57:08 +0200 Subject: [PATCH 13/31] Fix build scripts. --- BuildFiles/Windows/run_me.bat | 2 +- Content.IntegrationTests/Content.IntegrationTests.csproj | 2 +- SS14.Launcher/SS14.Launcher.csproj | 5 +++++ Tools/package_release_build.py | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/BuildFiles/Windows/run_me.bat b/BuildFiles/Windows/run_me.bat index 83d3eb16b1..9b35a18cbe 100644 --- a/BuildFiles/Windows/run_me.bat +++ b/BuildFiles/Windows/run_me.bat @@ -1 +1 @@ -call bin/SS14.Launcher.exe +call bin\SS14.Launcher.exe diff --git a/Content.IntegrationTests/Content.IntegrationTests.csproj b/Content.IntegrationTests/Content.IntegrationTests.csproj index 368600ff66..77e30e5314 100644 --- a/Content.IntegrationTests/Content.IntegrationTests.csproj +++ b/Content.IntegrationTests/Content.IntegrationTests.csproj @@ -28,5 +28,5 @@ ..\RobustToolbox\Tools\ - + diff --git a/SS14.Launcher/SS14.Launcher.csproj b/SS14.Launcher/SS14.Launcher.csproj index 6198b6196b..408c7bcc82 100644 --- a/SS14.Launcher/SS14.Launcher.csproj +++ b/SS14.Launcher/SS14.Launcher.csproj @@ -21,4 +21,9 @@ + + + ..\RobustToolbox\Tools\ + + diff --git a/Tools/package_release_build.py b/Tools/package_release_build.py index e73c9e7cbc..d0b3d3e6c3 100755 --- a/Tools/package_release_build.py +++ b/Tools/package_release_build.py @@ -76,7 +76,7 @@ def main(): build_windows() if "linux" in platforms: - #wipe_bin() + wipe_bin() build_linux() if "mac" in platforms: From 1132e5b6a77887c631c2de009d8e0c22113b89af Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 13:31:46 +0200 Subject: [PATCH 14/31] Update submodule: light cleanup. --- .../Interactable/HandheldLightComponent.cs | 13 ++++++------- .../Components/Power/PoweredLightComponent.cs | 17 ++++++++--------- .../Prototypes/Entities/buildings/lighting.yml | 6 +++--- .../Entities/items/clothing/helmets.yml | 4 ++-- .../Prototypes/Entities/items/flashlight.yml | 2 +- RobustToolbox | 2 +- 6 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index 57aad41b94..b662990f1a 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -6,7 +6,6 @@ using Content.Shared.GameObjects; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.Interfaces.GameObjects; -using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Utility; @@ -118,7 +117,7 @@ namespace Content.Server.GameObjects.Components.Interactable return; } - SetState(LightState.Off); + SetState(false); Activated = false; if (Owner.TryGetComponent(out SoundComponent soundComponent)) @@ -158,7 +157,7 @@ namespace Content.Server.GameObjects.Components.Interactable } Activated = true; - SetState(LightState.On); + SetState(true); if (Owner.TryGetComponent(out soundComponent)) { @@ -166,13 +165,13 @@ namespace Content.Server.GameObjects.Components.Interactable } } - private void SetState(LightState newState) + private void SetState(bool on) { - _spriteComponent.LayerSetVisible(1, newState == LightState.On); - _pointLight.State = newState; + _spriteComponent.LayerSetVisible(1, on); + _pointLight.Enabled = on; if (_clothingComponent != null) { - _clothingComponent.ClothingEquippedPrefix = newState.ToString(); + _clothingComponent.ClothingEquippedPrefix = on ? "On" : "Off"; } } diff --git a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs index c78e7067ad..651c129bf1 100644 --- a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs @@ -5,7 +5,6 @@ using Content.Shared.GameObjects; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Shared.Audio; -using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Timing; @@ -68,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Power bool CanBurn(int heatResistance) { - return _lightState == LightState.On && heatResistance < LightBulb.BurningTemperature; + return _lightState && heatResistance < LightBulb.BurningTemperature; } void Burn() @@ -135,8 +134,8 @@ namespace Content.Server.GameObjects.Components.Power UpdateLight(); } - private LightState _lightState => Owner.GetComponent().State; - + private bool _lightState => Owner.GetComponent().Enabled; + /// /// Updates the light's power drain, sprite and actual light state. /// @@ -149,7 +148,7 @@ namespace Content.Server.GameObjects.Components.Power { device.Load = 0; sprite.LayerSetState(0, "empty"); - light.State = LightState.Off; + light.Enabled = false; return; } @@ -160,7 +159,7 @@ namespace Content.Server.GameObjects.Components.Power if (device.Powered) { sprite.LayerSetState(0, "on"); - light.State = LightState.On; + light.Enabled = true; light.Color = LightBulb.Color; var time = IoCManager.Resolve().CurTime; if (time > _lastThunk + _thunkDelay) @@ -172,18 +171,18 @@ namespace Content.Server.GameObjects.Components.Power else { sprite.LayerSetState(0, "off"); - light.State = LightState.Off; + light.Enabled = false; } break; case LightBulbState.Broken: device.Load = 0; sprite.LayerSetState(0, "broken"); - light.State = LightState.Off; + light.Enabled = false; break; case LightBulbState.Burned: device.Load = 0; sprite.LayerSetState(0, "burned"); - light.State = LightState.Off; + light.Enabled = false; break; } } diff --git a/Resources/Prototypes/Entities/buildings/lighting.yml b/Resources/Prototypes/Entities/buildings/lighting.yml index ac44f005fa..f9679aa2b3 100644 --- a/Resources/Prototypes/Entities/buildings/lighting.yml +++ b/Resources/Prototypes/Entities/buildings/lighting.yml @@ -16,7 +16,7 @@ - type: PointLight radius: 8 energy: 1.2 - offset: "0, -16" + #offset: "0, -16" color: "#DCDCC6" placement: @@ -39,7 +39,7 @@ state: off - type: PointLight - state: Off + enabled: false - type: PowerDevice priority: Low @@ -64,7 +64,7 @@ - type: PointLight energy: 1.0 - state: Off + enabled: false - type: PowerDevice priority: Low diff --git a/Resources/Prototypes/Entities/items/clothing/helmets.yml b/Resources/Prototypes/Entities/items/clothing/helmets.yml index 056bb679f2..092e487d4a 100644 --- a/Resources/Prototypes/Entities/items/clothing/helmets.yml +++ b/Resources/Prototypes/Entities/items/clothing/helmets.yml @@ -38,7 +38,7 @@ components: - type: HandheldLight - type: PointLight - state: Off + enabled: false - type: Sprite sprite: Clothing/helmet_engineering.rsi layers: @@ -52,4 +52,4 @@ - type: Clothing Slots: - head - sprite: Clothing/helmet_engineering.rsi \ No newline at end of file + sprite: Clothing/helmet_engineering.rsi diff --git a/Resources/Prototypes/Entities/items/flashlight.yml b/Resources/Prototypes/Entities/items/flashlight.yml index f1b539af7a..886dd4cf51 100644 --- a/Resources/Prototypes/Entities/items/flashlight.yml +++ b/Resources/Prototypes/Entities/items/flashlight.yml @@ -16,5 +16,5 @@ sprite: Objects/lantern.rsi state: lantern_off - type: PointLight - state: Off + enabled: false - type: Sound diff --git a/RobustToolbox b/RobustToolbox index be379b2e20..fdfbf92223 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit be379b2e205fd35dcd06f0921aaec9c19ac28910 +Subproject commit fdfbf92223b5539ac2a97143b090aed540e8a498 From ffee6bbd35437db3087b43235d5cea5f80724f43 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 14:00:33 +0200 Subject: [PATCH 15/31] Make light_tube_on.ogg mono. --- Resources/Audio/machines/light_tube_on.ogg | Bin 24548 -> 10444 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Audio/machines/light_tube_on.ogg b/Resources/Audio/machines/light_tube_on.ogg index 195e1f957255a9b0194483db3a135d560dfc19d4..deeffa7339897db4942c2bd3e758078d0ef86360 100644 GIT binary patch literal 10444 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 literal 24548 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 Date: Tue, 30 Jul 2019 21:50:13 +0200 Subject: [PATCH 16/31] Lerp is a word. --- SpaceStation14.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 555541861c..d4086e1cd7 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -13,6 +13,7 @@ <data /> <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data> True + True True True True \ No newline at end of file From 211dd56f945a0fd8a5ef90a590cc8ef2c51bd524 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 23:11:27 +0200 Subject: [PATCH 17/31] Correctly send saying entity UID to clients. --- Content.Server/Chat/ChatManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Content.Server/Chat/ChatManager.cs b/Content.Server/Chat/ChatManager.cs index e07d2a401e..cc67d3a26c 100644 --- a/Content.Server/Chat/ChatManager.cs +++ b/Content.Server/Chat/ChatManager.cs @@ -1,13 +1,10 @@ using System.Linq; -using System.Net.Http; using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; using Content.Shared.Chat; using Robust.Server.Interfaces.Player; -using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; -using Robust.Shared.Interfaces.Resources; using Robust.Shared.IoC; namespace Content.Server.Chat @@ -57,6 +54,7 @@ namespace Content.Server.Chat msg.Channel = ChatChannel.Local; msg.Message = message; msg.MessageWrap = $"{source.Name} says, \"{{0}}\""; + msg.SenderEntity = source.Uid; _netManager.ServerSendToMany(msg, clients.ToList()); } From 388cc8fddebdade45e9e11ae294bf4ea39b18132 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 23:11:54 +0200 Subject: [PATCH 18/31] Update submodule. --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index fdfbf92223..0e31193e7f 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit fdfbf92223b5539ac2a97143b090aed540e8a498 +Subproject commit 0e31193e7f48e853b56af2e837135a7305b58f9c From 0086e60b6ad574e879ed6d449430c3fbeb087760 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 30 Jul 2019 23:13:05 +0200 Subject: [PATCH 19/31] Speech bubbles yo. --- Content.Client/Chat/ChatManager.cs | 212 +++++++++++++++++- Content.Client/Chat/SpeechBubble.cs | 132 +++++++++++ Content.Client/EntryPoint.cs | 35 ++- .../Interfaces/Chat/IChatManager.cs | 6 + Content.Client/UserInterface/NanoStyle.cs | 5 + 5 files changed, 366 insertions(+), 24 deletions(-) create mode 100644 Content.Client/Chat/SpeechBubble.cs diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs index a596184cd7..e88ed4d1eb 100644 --- a/Content.Client/Chat/ChatManager.cs +++ b/Content.Client/Chat/ChatManager.cs @@ -1,23 +1,48 @@ using System.Collections.Generic; using Content.Client.Interfaces.Chat; using Content.Shared.Chat; +using Robust.Client; using Robust.Client.Console; +using Robust.Client.Interfaces.Graphics.ClientEye; +using Robust.Client.Interfaces.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Maths; using Robust.Shared.Utility; -using Robust.Client.UserInterface.Controls; namespace Content.Client.Chat { internal sealed class ChatManager : IChatManager { + /// + /// The max amount of chars allowed to fit in a single speech bubble. + /// + private const int SingleBubbleCharLimit = 100; + + /// + /// Base queue delay each speech bubble has. + /// + private const float BubbleDelayBase = 0.2f; + + /// + /// Factor multiplied by speech bubble char length to add to delay. + /// + private const float BubbleDelayFactor = 0.8f / SingleBubbleCharLimit; + + /// + /// The max amount of speech bubbles over a single entity at once. + /// + private const int SpeechBubbleCap = 4; + private const char ConCmdSlash = '/'; private const char OOCAlias = '['; private const char MeAlias = '@'; - public List filteredHistory = new List(); + private readonly List filteredHistory = new List(); // Filter Button States private bool _allState; @@ -30,15 +55,69 @@ namespace Content.Client.Chat #pragma warning disable 649 [Dependency] private readonly IClientNetManager _netManager; [Dependency] private readonly IClientConsole _console; + [Dependency] private readonly IEntityManager _entityManager; + [Dependency] private readonly IEyeManager _eyeManager; + [Dependency] private readonly IUserInterfaceManager _userInterfaceManager; #pragma warning restore 649 private ChatBox _currentChatBox; + /// + /// Speech bubbles that are currently visible on screen. + /// We track them to push them up when new ones get added. + /// + private readonly Dictionary> _activeSpeechBubbles = + new Dictionary>(); + + /// + /// Speech bubbles that are to-be-sent because of the "rate limit" they have. + /// + private readonly Dictionary _queuedSpeechBubbles + = new Dictionary(); + public void Initialize() { _netManager.RegisterNetMessage(MsgChatMessage.NAME, _onChatMessage); } + public void FrameUpdate(RenderFrameEventArgs delta) + { + // Update queued speech bubbles. + if (_queuedSpeechBubbles.Count == 0) + { + return; + } + + foreach (var (entityUid, queueData) in _queuedSpeechBubbles.ShallowClone()) + { + if (!_entityManager.TryGetEntity(entityUid, out var entity)) + { + _queuedSpeechBubbles.Remove(entityUid); + continue; + } + + queueData.TimeLeft -= delta.Elapsed; + if (queueData.TimeLeft > 0) + { + continue; + } + + if (queueData.MessageQueue.Count == 0) + { + _queuedSpeechBubbles.Remove(entityUid); + continue; + } + + var msg = queueData.MessageQueue.Dequeue(); + + queueData.TimeLeft += BubbleDelayBase + msg.Length * BubbleDelayFactor; + + // We keep the queue around while it has 0 items. This allows us to keep the timer. + // When the timer hits 0 and there's no messages left, THEN we can clear it up. + CreateSpeechBubble(entity, msg); + } + } + public void SetChatBox(ChatBox chatBox) { if (_currentChatBox != null) @@ -60,6 +139,19 @@ namespace Content.Client.Chat _currentChatBox.OOCButton.Pressed = !_oocState; } + public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble) + { + bubble.Dispose(); + + var list = _activeSpeechBubbles[entityUid]; + list.Remove(bubble); + + if (list.Count == 0) + { + _activeSpeechBubbles.Remove(entityUid); + } + } + private void WriteChatMessage(StoredChatMessage message) { Logger.Debug($"{message.Channel}: {message.Message}"); @@ -88,7 +180,6 @@ namespace Content.Client.Chat } _currentChatBox?.AddLine(messageText, message.Channel, color); - } private void _onChatBoxTextSubmitted(ChatBox chatBox, string text) @@ -185,15 +276,126 @@ namespace Content.Client.Chat Logger.Debug($"{msg.Channel}: {msg.Message}"); // Log all incoming chat to repopulate when filter is un-toggled - StoredChatMessage storedMessage = new StoredChatMessage(msg); + var storedMessage = new StoredChatMessage(msg); filteredHistory.Add(storedMessage); WriteChatMessage(storedMessage); + + // Local messages that have an entity attached get a speech bubble. + if (msg.Channel == ChatChannel.Local && msg.SenderEntity != default) + { + AddSpeechBubble(msg); + } + } + + private void AddSpeechBubble(MsgChatMessage msg) + { + if (!_entityManager.TryGetEntity(msg.SenderEntity, out var entity)) + { + Logger.WarningS("chat", "Got local chat message with invalid sender entity: {0}", msg.SenderEntity); + return; + } + + // Split message into words separated by spaces. + var words = msg.Message.Split(' '); + var messages = new List(); + var currentBuffer = new List(); + + // Really shoddy way to approximate word length. + // Yes, I am aware of all the crimes here. + // TODO: Improve this to use actual glyph width etc.. + var currentWordLength = 0; + foreach (var word in words) + { + // +1 for the space. + currentWordLength += word.Length + 1; + + if (currentWordLength > SingleBubbleCharLimit) + { + // Too long for the current speech bubble, flush it. + messages.Add(string.Join(" ", currentBuffer)); + currentBuffer.Clear(); + + currentWordLength = word.Length; + + if (currentWordLength > SingleBubbleCharLimit) + { + // Word is STILL too long. + // Truncate it with an ellipse. + messages.Add($"{word.Substring(0, SingleBubbleCharLimit-3)}..."); + currentWordLength = 0; + continue; + } + } + + currentBuffer.Add(word); + } + + if (currentBuffer.Count != 0) + { + // Don't forget the last bubble. + messages.Add(string.Join(" ", currentBuffer)); + } + + foreach (var message in messages) + { + EnqueueSpeechBubble(entity, message); + } + } + + private void EnqueueSpeechBubble(IEntity entity, string contents) + { + if (!_queuedSpeechBubbles.TryGetValue(entity.Uid, out var queueData)) + { + queueData = new SpeechBubbleQueueData(); + _queuedSpeechBubbles.Add(entity.Uid, queueData); + } + + queueData.MessageQueue.Enqueue(contents); + } + + private void CreateSpeechBubble(IEntity entity, string contents) + { + var bubble = new SpeechBubble(contents, entity, _eyeManager, this); + + if (_activeSpeechBubbles.TryGetValue(entity.Uid, out var existing)) + { + // Push up existing bubbles above the mob's head. + foreach (var existingBubble in existing) + { + existingBubble.VerticalOffset += bubble.ContentHeight; + } + } + else + { + existing = new List(); + _activeSpeechBubbles.Add(entity.Uid, existing); + } + + existing.Add(bubble); + _userInterfaceManager.StateRoot.AddChild(bubble); + + if (existing.Count > SpeechBubbleCap) + { + // Get the oldest to start fading fast. + var last = existing[0]; + last.FadeNow(); + } } private bool IsFiltered(ChatChannel channel) { - // _ALLstate works as inverter. + // _allState works as inverter. return _allState ^ _filteredChannels.HasFlag(channel); } + + private sealed class SpeechBubbleQueueData + { + /// + /// Time left until the next speech bubble can appear. + /// + public float TimeLeft { get; set; } + + public Queue MessageQueue { get; } = new Queue(); + } } } diff --git a/Content.Client/Chat/SpeechBubble.cs b/Content.Client/Chat/SpeechBubble.cs new file mode 100644 index 0000000000..33eca6c622 --- /dev/null +++ b/Content.Client/Chat/SpeechBubble.cs @@ -0,0 +1,132 @@ +using Content.Client.Interfaces.Chat; +using Robust.Client; +using Robust.Client.Interfaces.Graphics.ClientEye; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Maths; +using Robust.Shared.Timers; + +namespace Content.Client.Chat +{ + public class SpeechBubble : Control + { + /// + /// The total time a speech bubble stays on screen. + /// + private const float TotalTime = 4; + + /// + /// The amount of time at the end of the bubble's life at which it starts fading. + /// + private const float FadeTime = 0.25f; + + /// + /// The distance in world space to offset the speech bubble from the center of the entity. + /// i.e. greater -> higher above the mob's head. + /// + private const float EntityVerticalOffset = 0.5f; + + private readonly IEyeManager _eyeManager; + private readonly IEntity _senderEntity; + private readonly IChatManager _chatManager; + + private Control _panel; + + private float _timeLeft = TotalTime; + + public float VerticalOffset { get; set; } + private float _verticalOffsetAchieved; + + public float ContentHeight { get; } + + public SpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager) + { + _chatManager = chatManager; + _senderEntity = senderEntity; + _eyeManager = eyeManager; + + MouseFilter = MouseFilterMode.Ignore; + // Use text clipping so new messages don't overlap old ones being pushed up. + RectClipContent = true; + + var label = new RichTextLabel + { + MaxWidth = 256, + MouseFilter = MouseFilterMode.Ignore + }; + label.SetMessage(text); + + _panel = new PanelContainer + { + StyleClasses = { "tooltipBox" }, + Children = { label }, + MouseFilter = MouseFilterMode.Ignore, + ModulateSelfOverride = Color.White.WithAlpha(0.75f) + }; + + AddChild(_panel); + + _panel.Size = _panel.CombinedMinimumSize; + ContentHeight = _panel.Height; + Size = (_panel.Width, 0); + _verticalOffsetAchieved = -ContentHeight; + } + + protected override void FrameUpdate(RenderFrameEventArgs args) + { + base.FrameUpdate(args); + + _timeLeft -= args.Elapsed; + + if (_timeLeft <= FadeTime) + { + // Update alpha if we're fading. + Modulate = Color.White.WithAlpha(_timeLeft / FadeTime); + } + + if (_senderEntity.Deleted || _timeLeft <= 0) + { + // Timer spawn to prevent concurrent modification exception. + Timer.Spawn(0, Die); + return; + } + + // Lerp to our new vertical offset if it's been modified. + if (FloatMath.CloseTo(_verticalOffsetAchieved - VerticalOffset, 0, 0.1)) + { + _verticalOffsetAchieved = VerticalOffset; + } + else + { + _verticalOffsetAchieved = FloatMath.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.Elapsed); + } + + var worldPos = _senderEntity.Transform.WorldPosition; + worldPos += (0, EntityVerticalOffset); + + var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale; + var screenPos = lowerCenter - (Width / 2, ContentHeight + _verticalOffsetAchieved); + Position = screenPos; + + var height = (lowerCenter.Y - screenPos.Y).Clamp(0, ContentHeight); + Size = (Size.X, height); + } + + private void Die() + { + _chatManager.RemoveSpeechBubble(_senderEntity.Uid, this); + } + + /// + /// Causes the speech bubble to start fading IMMEDIATELY. + /// + public void FadeNow() + { + if (_timeLeft > FadeTime) + { + _timeLeft = FadeTime; + } + } + } +} diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index a9a4663f29..2b8984fc11 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -1,44 +1,40 @@ -using Content.Client.GameObjects; +using System; +using Content.Client.Chat; +using Content.Client.GameObjects; +using Content.Client.GameObjects.Components; using Content.Client.GameObjects.Components.Actor; using Content.Client.GameObjects.Components.Clothing; using Content.Client.GameObjects.Components.Construction; -using Content.Client.GameObjects.Components.Power; using Content.Client.GameObjects.Components.IconSmoothing; +using Content.Client.GameObjects.Components.Mobs; +using Content.Client.GameObjects.Components.Power; +using Content.Client.GameObjects.Components.Research; +using Content.Client.GameObjects.Components.Sound; using Content.Client.GameObjects.Components.Storage; using Content.Client.GameObjects.Components.Weapons.Ranged; using Content.Client.GameTicking; using Content.Client.Input; using Content.Client.Interfaces; +using Content.Client.Interfaces.Chat; using Content.Client.Interfaces.GameObjects; using Content.Client.Interfaces.Parallax; using Content.Client.Parallax; +using Content.Client.UserInterface; +using Content.Shared.GameObjects.Components.Markers; +using Content.Shared.GameObjects.Components.Materials; +using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Research; using Content.Shared.Interfaces; using Robust.Client; using Robust.Client.Interfaces; using Robust.Client.Interfaces.Graphics.Overlays; using Robust.Client.Interfaces.Input; +using Robust.Client.Interfaces.UserInterface; using Robust.Client.Player; using Robust.Shared.ContentPack; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Prototypes; -using System; -using Content.Client.Chat; -using Content.Client.GameObjects.Components; -using Content.Client.GameObjects.Components.Mobs; -using Content.Client.GameObjects.Components.Movement; -using Content.Client.GameObjects.Components.Research; -using Content.Client.GameObjects.Components.Sound; -using Content.Client.Interfaces.Chat; -using Content.Client.UserInterface; -using Content.Shared.GameObjects.Components.Markers; -using Content.Shared.GameObjects.Components.Materials; -using Content.Shared.GameObjects.Components.Mobs; -using Content.Shared.GameObjects.Components.Movement; -using Content.Shared.GameObjects.Components.Research; -using Robust.Client.Interfaces.State; -using Robust.Client.Interfaces.UserInterface; -using Robust.Client.State.States; namespace Content.Client { @@ -242,6 +238,7 @@ namespace Content.Client var renderFrameEventArgs = new RenderFrameEventArgs(frameTime); IoCManager.Resolve().FrameUpdate(renderFrameEventArgs); IoCManager.Resolve().FrameUpdate(renderFrameEventArgs); + IoCManager.Resolve().FrameUpdate(renderFrameEventArgs); break; } } diff --git a/Content.Client/Interfaces/Chat/IChatManager.cs b/Content.Client/Interfaces/Chat/IChatManager.cs index 41123d318a..989d044136 100644 --- a/Content.Client/Interfaces/Chat/IChatManager.cs +++ b/Content.Client/Interfaces/Chat/IChatManager.cs @@ -1,4 +1,6 @@ using Content.Client.Chat; +using Robust.Client; +using Robust.Shared.GameObjects; namespace Content.Client.Interfaces.Chat { @@ -6,6 +8,10 @@ namespace Content.Client.Interfaces.Chat { void Initialize(); + void FrameUpdate(RenderFrameEventArgs delta); + void SetChatBox(ChatBox chatBox); + + void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble); } } diff --git a/Content.Client/UserInterface/NanoStyle.cs b/Content.Client/UserInterface/NanoStyle.cs index 8ccab3bb5a..d9c7cba7b6 100644 --- a/Content.Client/UserInterface/NanoStyle.cs +++ b/Content.Client/UserInterface/NanoStyle.cs @@ -371,6 +371,11 @@ namespace Content.Client.UserInterface new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox) }), + new StyleRule(new SelectorElement(typeof(PanelContainer), new []{"tooltipBox"}, null, null), new[] + { + new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox) + }), + // Entity tooltip new StyleRule( new SelectorElement(typeof(PanelContainer), new[] {ExamineSystem.StyleClassEntityTooltip}, null, From ad9d7573d6852c67c702eca9b201e1c88702527c Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 13:17:06 +0200 Subject: [PATCH 20/31] Fix crash with speech bubbles maybe. --- Content.Client/Chat/SpeechBubble.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Content.Client/Chat/SpeechBubble.cs b/Content.Client/Chat/SpeechBubble.cs index 33eca6c622..0815e283b7 100644 --- a/Content.Client/Chat/SpeechBubble.cs +++ b/Content.Client/Chat/SpeechBubble.cs @@ -115,6 +115,11 @@ namespace Content.Client.Chat private void Die() { + if (Disposed) + { + return; + } + _chatManager.RemoveSpeechBubble(_senderEntity.Uid, this); } From ec771abfaab7c8f3b000c8f167ad55c0c9638e5a Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 13:43:19 +0200 Subject: [PATCH 21/31] Update submodule. --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 0e31193e7f..effb731340 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 0e31193e7f48e853b56af2e837135a7305b58f9c +Subproject commit effb73134027e58cb09bb4450327d2b9be1fd6c4 From b6ab0298f4928a2892776b890bf3413756e32964 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 13:43:59 +0200 Subject: [PATCH 22/31] Make sure speech bubbles stay below the HUD. --- Content.Client/Chat/ChatManager.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs index e88ed4d1eb..0f923df1eb 100644 --- a/Content.Client/Chat/ChatManager.cs +++ b/Content.Client/Chat/ChatManager.cs @@ -5,6 +5,7 @@ using Robust.Client; using Robust.Client.Console; using Robust.Client.Interfaces.Graphics.ClientEye; using Robust.Client.Interfaces.UserInterface; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; @@ -61,6 +62,7 @@ namespace Content.Client.Chat #pragma warning restore 649 private ChatBox _currentChatBox; + private Control _speechBubbleRoot; /// /// Speech bubbles that are currently visible on screen. @@ -78,6 +80,11 @@ namespace Content.Client.Chat public void Initialize() { _netManager.RegisterNetMessage(MsgChatMessage.NAME, _onChatMessage); + + _speechBubbleRoot = new Control(); + _speechBubbleRoot.SetAnchorPreset(Control.LayoutPreset.Wide); + _userInterfaceManager.StateRoot.AddChild(_speechBubbleRoot); + _speechBubbleRoot.SetPositionFirst(); } public void FrameUpdate(RenderFrameEventArgs delta) @@ -372,7 +379,7 @@ namespace Content.Client.Chat } existing.Add(bubble); - _userInterfaceManager.StateRoot.AddChild(bubble); + _speechBubbleRoot.AddChild(bubble); if (existing.Count > SpeechBubbleCap) { From 41b72d5aa2745aa37fa741f28689c1593bb333bc Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 13:48:50 +0200 Subject: [PATCH 23/31] Remove visibility set from StorageWindow. --- .../Components/Storage/ClientStorageComponent.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs index 1227ab5c63..d757397753 100644 --- a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs +++ b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs @@ -1,4 +1,6 @@ -using Content.Shared.GameObjects.Components.Storage; +using System; +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Storage; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; @@ -7,13 +9,8 @@ using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; -using Robust.Shared.Utility; -using System; -using System.Collections.Generic; -using Robust.Client.Interfaces.Graphics; using Robust.Shared.Maths; using Robust.Shared.Serialization; -using Robust.Shared.ViewVariables; namespace Content.Client.GameObjects.Components.Storage { @@ -118,7 +115,6 @@ namespace Content.Client.GameObjects.Components.Storage base.Initialize(); Title = "Storage Item"; - Visible = false; RectClipContent = true; VSplitContainer = new VBoxContainer("VSplitContainer"); From 2ea8bbf4eb286e409fe1f600e94df93660f649a9 Mon Sep 17 00:00:00 2001 From: Acruid Date: Wed, 31 Jul 2019 05:10:06 -0700 Subject: [PATCH 24/31] Reagents & Solutions (#280) * Added the ReagentPrototype class. * Added the new Solution class. * Added new shared SolutionComponent to the ECS system. * Added some basic element and chemical reagent prototypes. * Added a new Beaker item utilizing the SolutionComponent. This is a testing/debug entity, and should be removed or changed soon. * Added filters for code coverage. * Nightly work. * Added the server SolutionComponent class. * Added a bucket. Verbs set up for solution interaction. * Adds water tank entity to the game. * Added a full water tank entity. Solutions are properly serialized. Solution can be poured between two containers. * Solution class can now be enumerated. SolutionComponent now calculates the color of the solution. * Minor Cleanup. --- Content.Client/EntryPoint.cs | 2 + Content.Server/EntryPoint.cs | 4 + .../Components/Chemistry/SolutionComponent.cs | 140 +++++++++ Content.Shared/Chemistry/ReagentPrototype.cs | 25 ++ Content.Shared/Chemistry/Solution.cs | 273 ++++++++++++++++++ Content.Shared/Chemistry/SolutionCaps.cs | 21 ++ .../Components/Chemistry/SolutionComponent.cs | 166 +++++++++++ Content.Shared/GameObjects/ContentNetIDs.cs | 1 + Content.Shared/GameObjects/Verb.cs | 3 +- .../Chemistry/ReagentPrototype_Tests.cs | 42 +++ .../Shared/Chemistry/Solution_Tests.cs | 251 ++++++++++++++++ Resources/Prototypes/Entities/Chemistry.yml | 8 + Resources/Prototypes/Entities/Janitor.yml | 46 +++ Resources/Prototypes/Entities/water_tank.yml | 46 +++ Resources/Prototypes/Reagents/chemicals.yml | 9 + Resources/Prototypes/Reagents/elements.yml | 16 + Resources/Textures/Buildings/watertank.png | Bin 0 -> 447 bytes Resources/Textures/Objects/bucket.png | Bin 0 -> 228 bytes Resources/Textures/Objects/bucket_water.png | Bin 0 -> 142 bytes Resources/Textures/Objects/mopbucket.png | Bin 0 -> 525 bytes .../Textures/Objects/mopbucket_water.png | Bin 0 -> 140 bytes SpaceStation14.sln.DotSettings | 4 +- 22 files changed, 1055 insertions(+), 2 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs create mode 100644 Content.Shared/Chemistry/ReagentPrototype.cs create mode 100644 Content.Shared/Chemistry/Solution.cs create mode 100644 Content.Shared/Chemistry/SolutionCaps.cs create mode 100644 Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs create mode 100644 Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs create mode 100644 Content.Tests/Shared/Chemistry/Solution_Tests.cs create mode 100644 Resources/Prototypes/Entities/Chemistry.yml create mode 100644 Resources/Prototypes/Entities/Janitor.yml create mode 100644 Resources/Prototypes/Entities/water_tank.yml create mode 100644 Resources/Prototypes/Reagents/chemicals.yml create mode 100644 Resources/Prototypes/Reagents/elements.yml create mode 100644 Resources/Textures/Buildings/watertank.png create mode 100644 Resources/Textures/Objects/bucket.png create mode 100644 Resources/Textures/Objects/bucket_water.png create mode 100644 Resources/Textures/Objects/mopbucket.png create mode 100644 Resources/Textures/Objects/mopbucket_water.png diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 2b8984fc11..01be9dbffd 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -20,6 +20,7 @@ using Content.Client.Interfaces.GameObjects; using Content.Client.Interfaces.Parallax; using Content.Client.Parallax; using Content.Client.UserInterface; +using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.Components.Markers; using Content.Shared.GameObjects.Components.Materials; using Content.Shared.GameObjects.Components.Mobs; @@ -111,6 +112,7 @@ namespace Content.Client factory.Register(); factory.Register(); factory.Register(); + factory.Register(); factory.Register(); factory.Register(); factory.RegisterReference(); diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 612d1633a4..df458d5127 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -39,6 +39,7 @@ using Content.Server.GameObjects.Components.Weapon.Ranged; using Content.Server.GameTicking; using Content.Server.Interfaces; using Content.Server.Interfaces.GameTicking; +using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.Components.Materials; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Markers; @@ -59,6 +60,7 @@ using Content.Server.GameObjects.Components.Explosive; using Content.Server.GameObjects.Components.Items; using Content.Server.GameObjects.Components.Triggers; using Content.Shared.GameObjects.Components.Movement; +using SolutionComponent = Content.Server.GameObjects.Components.Chemistry.SolutionComponent; namespace Content.Server { @@ -94,6 +96,8 @@ namespace Content.Server factory.Register(); factory.RegisterReference(); + factory.Register(); + //Power Components factory.Register(); factory.Register(); diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs new file mode 100644 index 0000000000..a052eea348 --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs @@ -0,0 +1,140 @@ +using System; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + /// + /// Shared ECS component that manages a liquid solution of reagents. + /// + internal class SolutionComponent : Shared.GameObjects.Components.Chemistry.SolutionComponent + { + /// + /// Transfers solution from the held container to the target container. + /// + [Verb] + private sealed class FillTargetVerb : Verb + { + protected override string GetText(IEntity user, SolutionComponent component) + { + if(!user.TryGetComponent(out var hands)) + return ""; + + if(hands.GetActiveHand == null) + return ""; + + var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; + var myName = component.Owner.Prototype?.Name ?? ""; + + return $"Transfer liquid from [{heldEntityName}] to [{myName}]."; + } + + protected override VerbVisibility GetVisibility(IEntity user, SolutionComponent component) + { + if (user.TryGetComponent(out var hands)) + { + if (hands.GetActiveHand != null) + { + if (hands.GetActiveHand.Owner.TryGetComponent(out var solution)) + { + if ((solution.Capabilities & SolutionCaps.PourOut) != 0 && (component.Capabilities & SolutionCaps.PourIn) != 0) + return VerbVisibility.Visible; + } + } + } + + return VerbVisibility.Invisible; + } + + protected override void Activate(IEntity user, SolutionComponent component) + { + if (!user.TryGetComponent(out var hands)) + return; + + if (hands.GetActiveHand == null) + return; + + if (!hands.GetActiveHand.Owner.TryGetComponent(out var handSolutionComp)) + return; + + if ((handSolutionComp.Capabilities & SolutionCaps.PourOut) == 0 || (component.Capabilities & SolutionCaps.PourIn) == 0) + return; + + var transferQuantity = Math.Min(component.MaxVolume - component.CurrentVolume, handSolutionComp.CurrentVolume); + transferQuantity = Math.Min(transferQuantity, 10); + + // nothing to transfer + if (transferQuantity <= 0) + return; + + var transferSolution = handSolutionComp.SplitSolution(transferQuantity); + component.TryAddSolution(transferSolution); + + } + } + + /// + /// Transfers solution from a target container to the held container. + /// + [Verb] + private sealed class EmptyTargetVerb : Verb + { + protected override string GetText(IEntity user, SolutionComponent component) + { + if (!user.TryGetComponent(out var hands)) + return ""; + + if (hands.GetActiveHand == null) + return ""; + + var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; + var myName = component.Owner.Prototype?.Name ?? ""; + + return $"Transfer liquid from [{myName}] to [{heldEntityName}]."; + } + + protected override VerbVisibility GetVisibility(IEntity user, SolutionComponent component) + { + if (user.TryGetComponent(out var hands)) + { + if (hands.GetActiveHand != null) + { + if (hands.GetActiveHand.Owner.TryGetComponent(out var solution)) + { + if ((solution.Capabilities & SolutionCaps.PourIn) != 0 && (component.Capabilities & SolutionCaps.PourOut) != 0) + return VerbVisibility.Visible; + } + } + } + + return VerbVisibility.Invisible; + } + + protected override void Activate(IEntity user, SolutionComponent component) + { + if (!user.TryGetComponent(out var hands)) + return; + + if (hands.GetActiveHand == null) + return; + + if(!hands.GetActiveHand.Owner.TryGetComponent(out var handSolutionComp)) + return; + + if ((handSolutionComp.Capabilities & SolutionCaps.PourIn) == 0 || (component.Capabilities & SolutionCaps.PourOut) == 0) + return; + + var transferQuantity = Math.Min(handSolutionComp.MaxVolume - handSolutionComp.CurrentVolume, component.CurrentVolume); + transferQuantity = Math.Min(transferQuantity, 10); + + // pulling from an empty container, pointless to continue + if (transferQuantity <= 0) + return; + + var transferSolution = component.SplitSolution(transferQuantity); + handSolutionComp.TryAddSolution(transferSolution); + } + } + } +} diff --git a/Content.Shared/Chemistry/ReagentPrototype.cs b/Content.Shared/Chemistry/ReagentPrototype.cs new file mode 100644 index 0000000000..b123489a2b --- /dev/null +++ b/Content.Shared/Chemistry/ReagentPrototype.cs @@ -0,0 +1,25 @@ +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Chemistry +{ + [Prototype("reagent")] + public class ReagentPrototype : IPrototype, IIndexedPrototype + { + public string ID { get; private set; } + public string Name { get; private set; } + public string Description { get; private set; } + public Color SubstanceColor { get; private set; } + + public void LoadFrom(YamlMappingNode mapping) + { + ID = mapping.GetNode("id").AsString(); + Name = mapping.GetNode("name").ToString(); + Description = mapping.GetNode("desc").ToString(); + + SubstanceColor = mapping.TryGetNode("color", out var colorNode) ? colorNode.AsHexColor(Color.White) : Color.White; + } + } +} diff --git a/Content.Shared/Chemistry/Solution.cs b/Content.Shared/Chemistry/Solution.cs new file mode 100644 index 0000000000..ef305605fe --- /dev/null +++ b/Content.Shared/Chemistry/Solution.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Robust.Shared.Interfaces.Serialization; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.Chemistry +{ + /// + /// A solution of reagents. + /// + public class Solution : IExposeData, IEnumerable + { + // Most objects on the station hold only 1 or 2 reagents + [ViewVariables] + private List _contents = new List(2); + + /// + /// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker). + /// + [ViewVariables] + public int TotalVolume { get; private set; } + + /// + /// Constructs an empty solution (ex. an empty beaker). + /// + public Solution() { } + + /// + /// Constructs a solution containing 100% of a reagent (ex. A beaker of pure water). + /// + /// The prototype ID of the reagent to add. + /// The quantity in milli-units. + public Solution(string reagentId, int quantity) + { + AddReagent(reagentId, quantity); + } + + /// + public void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(ref _contents, "reagents", new List()); + + if (serializer.Reading) + { + TotalVolume = 0; + foreach (var reagent in _contents) + { + TotalVolume += reagent.Quantity; + } + } + } + + /// + /// Adds a given quantity of a reagent directly into the solution. + /// + /// The prototype ID of the reagent to add. + /// The quantity in milli-units. + public void AddReagent(string reagentId, int quantity) + { + if(quantity <= 0) + return; + + for (var i = 0; i < _contents.Count; i++) + { + var reagent = _contents[i]; + if (reagent.ReagentId != reagentId) + continue; + + _contents[i] = new ReagentQuantity(reagentId, reagent.Quantity + quantity); + TotalVolume += quantity; + return; + } + + _contents.Add(new ReagentQuantity(reagentId, quantity)); + TotalVolume += quantity; + } + + /// + /// Returns the amount of a single reagent inside the solution. + /// + /// The prototype ID of the reagent to add. + /// The quantity in milli-units. + public int GetReagentQuantity(string reagentId) + { + for (var i = 0; i < _contents.Count; i++) + { + if (_contents[i].ReagentId == reagentId) + return _contents[i].Quantity; + } + + return 0; + } + + public void RemoveReagent(string reagentId, int quantity) + { + if(quantity <= 0) + return; + + for (var i = 0; i < _contents.Count; i++) + { + var reagent = _contents[i]; + if(reagent.ReagentId != reagentId) + continue; + + var curQuantity = reagent.Quantity; + + var newQuantity = curQuantity - quantity; + if (newQuantity <= 0) + { + _contents.RemoveSwap(i); + TotalVolume -= curQuantity; + } + else + { + _contents[i] = new ReagentQuantity(reagentId, newQuantity); + TotalVolume -= quantity; + } + + return; + } + } + + public void RemoveSolution(int quantity) + { + if(quantity <=0) + return; + + var ratio = (float)(TotalVolume - quantity) / TotalVolume; + + if (ratio <= 0) + { + RemoveAllSolution(); + return; + } + + for (var i = 0; i < _contents.Count; i++) + { + var reagent = _contents[i]; + var oldQuantity = reagent.Quantity; + + // quantity taken is always a little greedy, so fractional quantities get rounded up to the nearest + // whole unit. This should prevent little bits of chemical remaining because of float rounding errors. + var newQuantity = (int)Math.Floor(oldQuantity * ratio); + + _contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity); + } + + TotalVolume = (int)Math.Floor(TotalVolume * ratio); + } + + public void RemoveAllSolution() + { + _contents.Clear(); + TotalVolume = 0; + } + + public Solution SplitSolution(int quantity) + { + if (quantity <= 0) + return new Solution(); + + Solution newSolution; + + if (quantity >= TotalVolume) + { + newSolution = Clone(); + RemoveAllSolution(); + return newSolution; + } + + newSolution = new Solution(); + var newTotalVolume = 0; + var ratio = (float)(TotalVolume - quantity) / TotalVolume; + + for (var i = 0; i < _contents.Count; i++) + { + var reagent = _contents[i]; + + var newQuantity = (int)Math.Floor(reagent.Quantity * ratio); + var splitQuantity = reagent.Quantity - newQuantity; + + _contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity); + newSolution._contents.Add(new ReagentQuantity(reagent.ReagentId, splitQuantity)); + newTotalVolume += splitQuantity; + } + + TotalVolume = (int)Math.Floor(TotalVolume * ratio); + newSolution.TotalVolume = newTotalVolume; + + return newSolution; + } + + public void AddSolution(Solution otherSolution) + { + for (var i = 0; i < otherSolution._contents.Count; i++) + { + var otherReagent = otherSolution._contents[i]; + + var found = false; + for (var j = 0; j < _contents.Count; j++) + { + var reagent = _contents[j]; + if (reagent.ReagentId == otherReagent.ReagentId) + { + found = true; + _contents[j] = new ReagentQuantity(reagent.ReagentId, reagent.Quantity + otherReagent.Quantity); + break; + } + } + + if (!found) + { + _contents.Add(new ReagentQuantity(otherReagent.ReagentId, otherReagent.Quantity)); + } + } + + TotalVolume += otherSolution.TotalVolume; + } + + public Solution Clone() + { + var volume = 0; + var newSolution = new Solution(); + + for (var i = 0; i < _contents.Count; i++) + { + var reagent = _contents[i]; + newSolution._contents.Add(reagent); + volume += reagent.Quantity; + } + + newSolution.TotalVolume = volume; + return newSolution; + } + + [Serializable, NetSerializable] + public readonly struct ReagentQuantity + { + public readonly string ReagentId; + public readonly int Quantity; + + public ReagentQuantity(string reagentId, int quantity) + { + ReagentId = reagentId; + Quantity = quantity; + } + + [ExcludeFromCodeCoverage] + public override string ToString() + { + return $"{ReagentId}:{Quantity}"; + } + } + + #region Enumeration + + public IEnumerator GetEnumerator() + { + return _contents.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + } +} diff --git a/Content.Shared/Chemistry/SolutionCaps.cs b/Content.Shared/Chemistry/SolutionCaps.cs new file mode 100644 index 0000000000..c5e4edf193 --- /dev/null +++ b/Content.Shared/Chemistry/SolutionCaps.cs @@ -0,0 +1,21 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chemistry +{ + /// + /// These are the defined capabilities of a container of a solution. + /// + [Flags] + [Serializable, NetSerializable] + public enum SolutionCaps + { + None = 0, + + PourIn = 1, + PourOut = 2, + + Injector = 4, + Injectable = 8, + } +} diff --git a/Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs new file mode 100644 index 0000000000..5ec42b038f --- /dev/null +++ b/Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs @@ -0,0 +1,166 @@ +using System; +using Content.Shared.Chemistry; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.GameObjects.Components.Chemistry +{ + public class SolutionComponent : Component + { +#pragma warning disable 649 + [Dependency] private readonly IPrototypeManager _prototypeManager; +#pragma warning restore 649 + + [ViewVariables] + private Solution _containedSolution; + private int _maxVolume; + private SolutionCaps _capabilities; + + /// + /// The maximum volume of the container. + /// + [ViewVariables(VVAccess.ReadWrite)] + public int MaxVolume + { + get => _maxVolume; + set => _maxVolume = value; // Note that the contents won't spill out if the capacity is reduced. + } + + /// + /// The total volume of all the of the reagents in the container. + /// + [ViewVariables] + public int CurrentVolume => _containedSolution.TotalVolume; + + /// + /// The current blended color of all the reagents in the container. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Color SubstanceColor { get; private set; } + + /// + /// The current capabilities of this container (is the top open to pour? can I inject it into another object?). + /// + [ViewVariables(VVAccess.ReadWrite)] + public SolutionCaps Capabilities + { + get => _capabilities; + set => _capabilities = value; + } + + /// + public override string Name => "Solution"; + + /// + public sealed override uint? NetID => ContentNetIDs.SOLUTION; + + /// + public sealed override Type StateType => typeof(SolutionComponentState); + + /// + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _maxVolume, "maxVol", 0); + serializer.DataField(ref _containedSolution, "contents", new Solution()); + serializer.DataField(ref _capabilities, "caps", SolutionCaps.None); + } + + public override void Startup() + { + base.Startup(); + + RecalculateColor(); + } + + public override void Shutdown() + { + base.Shutdown(); + + _containedSolution.RemoveAllSolution(); + _containedSolution = new Solution(); + } + + public bool TryAddReagent(string reagentId, int quantity, out int acceptedQuantity) + { + throw new NotImplementedException(); + } + + public bool TryAddSolution(Solution solution) + { + if (solution.TotalVolume > (_maxVolume - _containedSolution.TotalVolume)) + return false; + + _containedSolution.AddSolution(solution); + RecalculateColor(); + return true; + } + + public Solution SplitSolution(int quantity) + { + return _containedSolution.SplitSolution(quantity); + } + + private void RecalculateColor() + { + if(_containedSolution.TotalVolume == 0) + SubstanceColor = Color.White; + + Color mixColor = default; + float runningTotalQuantity = 0; + + foreach (var reagent in _containedSolution) + { + runningTotalQuantity += reagent.Quantity; + + if(!_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto)) + continue; + + if (mixColor == default) + mixColor = proto.SubstanceColor; + + mixColor = BlendRGB(mixColor, proto.SubstanceColor, reagent.Quantity / runningTotalQuantity); + } + } + + private Color BlendRGB(Color rgb1, Color rgb2, float amount) + { + var r = (float)Math.Round(rgb1.R + (rgb2.R - rgb1.R) * amount, 1); + var g = (float)Math.Round(rgb1.G + (rgb2.G - rgb1.G) * amount, 1); + var b = (float)Math.Round(rgb1.B + (rgb2.B - rgb1.B) * amount, 1); + var alpha = (float)Math.Round(rgb1.A + (rgb2.A - rgb1.A) * amount, 1); + + return new Color(r, g, b, alpha); + } + + /// + public override ComponentState GetComponentState() + { + return new SolutionComponentState(); + } + + /// + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + base.HandleComponentState(curState, nextState); + + if(curState == null) + return; + + var compState = (SolutionComponentState)curState; + + //TODO: Make me work! + } + + [Serializable, NetSerializable] + public class SolutionComponentState : ComponentState + { + public SolutionComponentState() : base(ContentNetIDs.SOLUTION) { } + } + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index a2b54f0dff..166a0cdb0e 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -7,6 +7,7 @@ public const uint DESTRUCTIBLE = 1001; public const uint TEMPERATURE = 1002; public const uint HANDS = 1003; + public const uint SOLUTION = 1004; public const uint STORAGE = 1005; public const uint INVENTORY = 1006; public const uint POWER_DEBUG_TOOL = 1007; diff --git a/Content.Shared/GameObjects/Verb.cs b/Content.Shared/GameObjects/Verb.cs index 7bc38b4dc3..4fd3fe288b 100644 --- a/Content.Shared/GameObjects/Verb.cs +++ b/Content.Shared/GameObjects/Verb.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using JetBrains.Annotations; using Robust.Shared.Interfaces.GameObjects; @@ -116,7 +117,7 @@ namespace Content.Shared.GameObjects foreach (var component in entity.GetComponentInstances()) { var type = component.GetType(); - foreach (var nestedType in type.GetNestedTypes()) + foreach (var nestedType in type.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if (!typeof(Verb).IsAssignableFrom(nestedType) || nestedType.IsAbstract) { diff --git a/Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs b/Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs new file mode 100644 index 0000000000..d78a67178c --- /dev/null +++ b/Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs @@ -0,0 +1,42 @@ +using System.IO; +using Content.Shared.Chemistry; +using NUnit.Framework; +using Robust.Shared.Maths; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Tests.Shared.Chemistry +{ + [TestFixture, Parallelizable, TestOf(typeof(ReagentPrototype))] + public class ReagentPrototype_Tests + { + [Test] + public void DeserializeReagentPrototype() + { + using (TextReader stream = new StringReader(YamlReagentPrototype)) + { + var yamlStream = new YamlStream(); + yamlStream.Load(stream); + var document = yamlStream.Documents[0]; + var rootNode = (YamlSequenceNode)document.RootNode; + var proto = (YamlMappingNode)rootNode[0]; + + var defType = proto.GetNode("type").AsString(); + var newReagent = new ReagentPrototype(); + newReagent.LoadFrom(proto); + + Assert.That(defType, Is.EqualTo("reagent")); + Assert.That(newReagent.ID, Is.EqualTo("chem.H2")); + Assert.That(newReagent.Name, Is.EqualTo("Hydrogen")); + Assert.That(newReagent.Description, Is.EqualTo("A light, flammable gas.")); + Assert.That(newReagent.SubstanceColor, Is.EqualTo(Color.Teal)); + } + } + + private const string YamlReagentPrototype = @"- type: reagent + id: chem.H2 + name: Hydrogen + desc: A light, flammable gas. + color: " + "\"#008080\""; + } +} diff --git a/Content.Tests/Shared/Chemistry/Solution_Tests.cs b/Content.Tests/Shared/Chemistry/Solution_Tests.cs new file mode 100644 index 0000000000..d78dc39a2f --- /dev/null +++ b/Content.Tests/Shared/Chemistry/Solution_Tests.cs @@ -0,0 +1,251 @@ +using Content.Shared.Chemistry; +using NUnit.Framework; + +namespace Content.Tests.Shared.Chemistry +{ + [TestFixture, Parallelizable, TestOf(typeof(Solution))] + public class Solution_Tests + { + [Test] + public void AddReagentAndGetSolution() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity, Is.EqualTo(1000)); + } + + [Test] + public void ConstructorAddReagent() + { + var solution = new Solution("water", 1000); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity, Is.EqualTo(1000)); + } + + [Test] + public void NonExistingReagentReturnsZero() + { + var solution = new Solution(); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity, Is.EqualTo(0)); + } + + [Test] + public void AddLessThanZeroReagentReturnsZero() + { + var solution = new Solution("water", -1000); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity, Is.EqualTo(0)); + } + + [Test] + public void AddingReagentsSumsProperly() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("water", 2000); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity, Is.EqualTo(3000)); + } + + [Test] + public void ReagentQuantitiesStayUnique() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("fire", 2000); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(1000)); + Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(2000)); + } + + [Test] + public void TotalVolumeIsCorrect() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("fire", 2000); + + Assert.That(solution.TotalVolume, Is.EqualTo(3000)); + } + + [Test] + public void CloningSolutionIsCorrect() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("fire", 2000); + + var newSolution = solution.Clone(); + + Assert.That(newSolution.GetReagentQuantity("water"), Is.EqualTo(1000)); + Assert.That(newSolution.GetReagentQuantity("fire"), Is.EqualTo(2000)); + Assert.That(newSolution.TotalVolume, Is.EqualTo(3000)); + } + + [Test] + public void RemoveSolutionRecalculatesProperly() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("fire", 2000); + + solution.RemoveReagent("water", 500); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(500)); + Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(2000)); + Assert.That(solution.TotalVolume, Is.EqualTo(2500)); + } + + [Test] + public void RemoveLessThanOneQuantityDoesNothing() + { + var solution = new Solution("water", 100); + + solution.RemoveReagent("water", -100); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(100)); + Assert.That(solution.TotalVolume, Is.EqualTo(100)); + } + + [Test] + public void RemoveMoreThanTotalRemovesAllReagent() + { + var solution = new Solution("water", 100); + + solution.RemoveReagent("water", 1000); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(0)); + Assert.That(solution.TotalVolume, Is.EqualTo(0)); + } + + [Test] + public void RemoveNonExistReagentDoesNothing() + { + var solution = new Solution("water", 100); + + solution.RemoveReagent("fire", 1000); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(100)); + Assert.That(solution.TotalVolume, Is.EqualTo(100)); + } + + [Test] + public void RemoveSolution() + { + var solution = new Solution("water", 700); + + solution.RemoveSolution(500); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(200)); + Assert.That(solution.TotalVolume, Is.EqualTo(200)); + } + + [Test] + public void RemoveSolutionMoreThanTotalRemovesAll() + { + var solution = new Solution("water", 800); + + solution.RemoveSolution(1000); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(0)); + Assert.That(solution.TotalVolume, Is.EqualTo(0)); + } + + [Test] + public void RemoveSolutionRatioPreserved() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("fire", 2000); + + solution.RemoveSolution(1500); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(500)); + Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(1000)); + Assert.That(solution.TotalVolume, Is.EqualTo(1500)); + } + + [Test] + public void RemoveSolutionLessThanOneDoesNothing() + { + var solution = new Solution("water", 800); + + solution.RemoveSolution(-200); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(800)); + Assert.That(solution.TotalVolume, Is.EqualTo(800)); + } + + [Test] + public void SplitSolution() + { + var solution = new Solution(); + solution.AddReagent("water", 1000); + solution.AddReagent("fire", 2000); + + var splitSolution = solution.SplitSolution(750); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(750)); + Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(1500)); + Assert.That(solution.TotalVolume, Is.EqualTo(2250)); + + Assert.That(splitSolution.GetReagentQuantity("water"), Is.EqualTo(250)); + Assert.That(splitSolution.GetReagentQuantity("fire"), Is.EqualTo(500)); + Assert.That(splitSolution.TotalVolume, Is.EqualTo(750)); + } + + [Test] + public void SplitSolutionMoreThanTotalRemovesAll() + { + var solution = new Solution("water", 800); + + var splitSolution = solution.SplitSolution(1000); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(0)); + Assert.That(solution.TotalVolume, Is.EqualTo(0)); + + Assert.That(splitSolution.GetReagentQuantity("water"), Is.EqualTo(800)); + Assert.That(splitSolution.TotalVolume, Is.EqualTo(800)); + } + + [Test] + public void SplitSolutionLessThanOneDoesNothing() + { + var solution = new Solution("water", 800); + + var splitSolution = solution.SplitSolution(-200); + + Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(800)); + Assert.That(solution.TotalVolume, Is.EqualTo(800)); + + Assert.That(splitSolution.GetReagentQuantity("water"), Is.EqualTo(0)); + Assert.That(splitSolution.TotalVolume, Is.EqualTo(0)); + } + + [Test] + public void AddSolution() + { + var solutionOne = new Solution(); + solutionOne.AddReagent("water", 1000); + solutionOne.AddReagent("fire", 2000); + + var solutionTwo = new Solution(); + solutionTwo.AddReagent("water", 500); + solutionTwo.AddReagent("earth", 1000); + + solutionOne.AddSolution(solutionTwo); + + Assert.That(solutionOne.GetReagentQuantity("water"), Is.EqualTo(1500)); + Assert.That(solutionOne.GetReagentQuantity("fire"), Is.EqualTo(2000)); + Assert.That(solutionOne.GetReagentQuantity("earth"), Is.EqualTo(1000)); + Assert.That(solutionOne.TotalVolume, Is.EqualTo(4500)); + } + } +} diff --git a/Resources/Prototypes/Entities/Chemistry.yml b/Resources/Prototypes/Entities/Chemistry.yml new file mode 100644 index 0000000000..bd7048b73f --- /dev/null +++ b/Resources/Prototypes/Entities/Chemistry.yml @@ -0,0 +1,8 @@ +- type: entity + parent: BaseItem + id: ReagentItem + name: "Reagent Item" + abstract: true + components: + - type: Solution + maxVol: 5 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Janitor.yml b/Resources/Prototypes/Entities/Janitor.yml new file mode 100644 index 0000000000..b5f799b554 --- /dev/null +++ b/Resources/Prototypes/Entities/Janitor.yml @@ -0,0 +1,46 @@ +- type: entity + parent: ReagentItem + name: "Extra-Grip™ Mop" + id: MopItem + description: A mop that cant be stopped, viscera cleanup detail awaits. + components: + - type: Sprite + texture: Objects/mop.png + - type: Icon + texture: Objects/mop.png + - type: Item + Size: 10 + - type: Solution + maxVol: 10 + caps: 1 + +- type: entity + parent: ReagentItem + name: Mop Bucket + id: MopBucket + description: Holds water and the tears of the janitor. + components: + - type: Sprite + texture: Objects/mopbucket.png + - type: Icon + texture: Objects/mopbucket.png + - type: Clickable + - type: BoundingBox + - type: Solution + maxVol: 500 + caps: 3 + +- type: entity + parent: ReagentItem + name: Bucket + id: Bucket + description: "It's a bucket." + components: + - type: Sprite + texture: Objects/bucket.png + - type: Icon + texture: Objects/bucket.png + - type: Solution + maxVol: 500 + caps: 3 + \ No newline at end of file diff --git a/Resources/Prototypes/Entities/water_tank.yml b/Resources/Prototypes/Entities/water_tank.yml new file mode 100644 index 0000000000..27b1620c11 --- /dev/null +++ b/Resources/Prototypes/Entities/water_tank.yml @@ -0,0 +1,46 @@ +- type: entity + parent: ReagentItem + id: watertank + name: Water Tank + description: "A water tank. It is used to store high amounts of water." + components: + - type: Sprite + texture: Buildings/watertank.png + + - type: Icon + texture: Buildings/watertank.png + + - type: Clickable + - type: BoundingBox + aabb: "-0.5,-0.25,0.5,0.25" + - type: Collidable + mask: 3 + layer: 1 + IsScrapingFloor: true + - type: Physics + mass: 15 + Anchored: false + + - type: Damageable + - type: Destructible + thresholdvalue: 10 + + - type: Solution + maxVol: 1500 + caps: 3 + + + placement: + snap: + - Wall + +- type: entity + parent: watertank + id: watertank_full + components: + - type: Solution + contents: + reagents: + - ReagentId: chem.H2O + Quantity: 1500 + \ No newline at end of file diff --git a/Resources/Prototypes/Reagents/chemicals.yml b/Resources/Prototypes/Reagents/chemicals.yml new file mode 100644 index 0000000000..f698560651 --- /dev/null +++ b/Resources/Prototypes/Reagents/chemicals.yml @@ -0,0 +1,9 @@ +- type: reagent + id: chem.H2SO4 + name: Sulfuric Acid + desc: A highly corrosive, oily, colorless liquid. + +- type: reagent + id: chem.H2O + name: Water + desc: A tasty colorless liquid. \ No newline at end of file diff --git a/Resources/Prototypes/Reagents/elements.yml b/Resources/Prototypes/Reagents/elements.yml new file mode 100644 index 0000000000..461a9c4d0a --- /dev/null +++ b/Resources/Prototypes/Reagents/elements.yml @@ -0,0 +1,16 @@ +- type: reagent + id: chem.H2 + name: Hydrogen + desc: A light, flammable gas. + +- type: reagent + id: chem.O2 + name: Oxygen + desc: An oxidizing, colorless gas. + +- type: reagent + id: chem.S8 + name: Sulfur + desc: A yellow, crystalline solid. + color: "#FFFACD" + \ No newline at end of file diff --git a/Resources/Textures/Buildings/watertank.png b/Resources/Textures/Buildings/watertank.png new file mode 100644 index 0000000000000000000000000000000000000000..56ee09de2444756ee1684c7f3989347bfea6ae44 GIT binary patch literal 447 zcmV;w0YLtVP)CndA_M>c00DGTPE!Ct z=GbNc00BcuL_t(2k*$$2OT$1E$78l`NfXf0r9DDOI2}p_KR_z2w42hw4-jzFYAfgz zL@&+K772HapP*YaMQ$oiLOy`_X}ou-wcY)5%l)|DdyjjH@;}jaT~kz~l~HluJ8oVy z6x+WU`ZWm*Z*=Erwm3>B;z|F-fv9 z;RUdCIyGxJqDdr`(qS*pdoGU7x{(VYu78XMt2)lUzqlZ}P^q}K-|zd507@d2DdyJ?97Erv=;CmrniW7Q4qoPs^$V#`ynI|0fWCo39j;e1 z2S6MO<&$83zb+aR#uz0bLSirg%;%6aB|&-xqf=HS6ona**8>L**aTITEj%>;$V0zG z_oRv_vw|Go_6;WP-Zy)tUY%ob&F#7L>h39^dd89YmS~d!+RWhT>gTe~DWM4f+ksAG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/bucket_water.png b/Resources/Textures/Objects/bucket_water.png new file mode 100644 index 0000000000000000000000000000000000000000..5f97bfaa5ec52b7ed32c8892a52ec730e0ae8353 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv(Ey(i*8>L**aTJiCA#a^wsNdI z%dq{b|CJB28NV(76)=_r`2{mLJiCzwJqvXT*M*LfZ$Nb;vgLa9bBY1cai)F{V`;dE?L?R{R70sxr2*?g$(LY z2cd%?Sac8_Lc0VPEu@3SCWa(;8tdYN440SWeeT`&y}K}qqTrBra?t2UfFr;W06@Ua z`Cd!wPQGMbVfGFH0L5z{9GBK(wJ)Pm^&>PPKsYX;TYmxoj3z-8LYZiEp1+X9tu>(LduP}{TTEBmg@LGPc z`24C2;#SN>$Y)IRERhD(z6>EJ5wEN9jxPY33N%|RE-AZTv&BMFXS)MrM1^@Pr*$r3 zSG^(5Y|8HIc4nSU2-smeZnWnpUN1MR%_^ZWVgR%1jo`qtOtUF#snS#k5kN*%m~O|u zo=(k(H2uJqosj2PRH`!obIZMLniCbkXc7b$S*)(j*)P`5n8ADln0^7%x_4R81P1_y z=HKw{M$&oy93QL*2+lgfu>Gq4l@A;% z&(_@F+60thED7=pW^j0RBMr#W_H=O!(U_Q=Ai?UOuw+R})0y-Vqo5#{N8GD4G&PmE jEx3Rd?YeNhkeQR=jvdoWDP{F3Ky3`3u6{1-oD!M<data /> <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data> True + <data /> + <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data> True True True - True \ No newline at end of file + True From a90d7a645c2e8dbbbe57dabf5fa35372e93ad165 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 15:01:00 +0200 Subject: [PATCH 25/31] Update submodule. --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index effb731340..fa10e1c330 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit effb73134027e58cb09bb4450327d2b9be1fd6c4 +Subproject commit fa10e1c330da9613d4598154a71cfeb7bdb6dd00 From ceb8cc8421a3f54680af416f6382728d91cb53fc Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 15:02:36 +0200 Subject: [PATCH 26/31] Use automatic component registration. --- Content.Client/EntryPoint.cs | 182 ++++++---------- .../Actor/CharacterInfoComponent.cs | 1 + .../Components/Actor/CharacterInterface.cs | 1 + .../Components/Clothing/ClothingComponent.cs | 6 +- .../ConstructionGhostComponent.cs | 1 + .../Construction/ConstructorComponent.cs | 1 + .../Components/DamageableComponent.cs | 5 +- .../HUD/Inventory/ClientInventoryComponent.cs | 1 + .../IconSmoothing/IconSmoothComponent.cs | 1 + .../Components/Items/ClientHandsComponent.cs | 2 + .../Components/Items/ItemComponent.cs | 5 +- .../Components/LowWallComponent.cs | 3 + .../Components/Mobs/CameraRecoilComponent.cs | 2 + .../GameObjects/Components/Mobs/SpeciesUI.cs | 20 +- .../Components/Power/PowerDebugTool.cs | 3 +- .../Research/LatheDatabaseComponent.cs | 4 +- .../Research/MaterialStorageComponent.cs | 4 +- .../Components/Sound/SoundComponent.cs | 3 +- .../Storage/ClientStorageComponent.cs | 1 + .../Components/SubFloorHideComponent.cs | 1 + .../Ranged/ClientRangedWeaponComponent.cs | 3 +- .../GameObjects/Components/WindowComponent.cs | 1 + Content.Server/EntryPoint.cs | 201 ++---------------- .../Components/CatwalkComponent.cs | 1 + .../Components/Chemistry/SolutionComponent.cs | 4 +- .../Construction/ConstructionComponent.cs | 1 + .../Construction/ConstructorComponent.cs | 5 +- .../Components/Damage/DamageableComponent.cs | 10 +- .../Damage/DestructibleComponent.cs | 14 +- .../Components/Doors/ServerDoorComponent.cs | 2 + .../Explosion/ExplosiveComponent.cs | 21 +- .../Components/GUI/InventoryComponent.cs | 3 +- .../Components/GUI/ServerHandsComponent.cs | 6 +- .../Components/Healing/HealingComponent.cs | 17 +- .../Interactable/HandheldLightComponent.cs | 1 + .../Interactable/Tools/CrowbarComponent.cs | 2 + .../Interactable/Tools/MultitoolComponent.cs | 7 +- .../Tools/ScrewdriverComponent.cs | 7 +- .../Interactable/Tools/WelderComponent.cs | 9 +- .../Interactable/Tools/WirecutterComponent.cs | 7 +- .../Interactable/Tools/WrenchComponent.cs | 7 +- .../Items/Clothing/ClothingComponent.cs | 9 +- .../Components/Items/DiceComponent.cs | 2 +- .../Items/Storage/EntityStorageComponent.cs | 15 +- .../Storage/Fill/ToolLockerFillComponent.cs | 1 + .../Fill/ToolboxElectricalFillComponent.cs | 1 + .../Components/Items/Storage/ItemComponent.cs | 15 +- .../Items/Storage/ServerStorageComponent.cs | 21 +- .../Items/Storage/StoreableComponent.cs | 1 + .../Components/Markers/SpawnPointComponent.cs | 3 +- .../Components/Mobs/CameraRecoilComponent.cs | 3 + .../Components/Mobs/CombatModeComponent.cs | 1 + .../Mobs/HeatResistanceComponent.cs | 3 +- .../Components/Mobs/MindComponent.cs | 11 +- .../Components/Mobs/SpeciesComponent.cs | 1 + .../Movement/AiControllerComponent.cs | 1 + .../Movement/PlayerInputMoverComponent.cs | 2 + .../Movement/ServerPortalComponent.cs | 2 + .../Movement/ServerTeleporterComponent.cs | 2 +- .../Movement/TeleportableComponent.cs | 2 +- .../Components/PlaceableSurfaceComponent.cs | 1 + .../Components/Power/ApcComponent.cs | 6 +- .../Components/Power/LightBulbComponent.cs | 3 +- .../Components/Power/PowerCellComponent.cs | 3 + .../Components/Power/PowerDebugTool.cs | 3 +- .../Components/Power/PowerDevice.cs | 17 +- .../Power/PowerGeneratorComponent.cs | 7 +- .../Components/Power/PowerNodeComponent.cs | 6 +- .../Power/PowerProviderComponent.cs | 12 +- .../Power/PowerStorageNetComponent.cs | 3 + .../Power/PowerTransferComponent.cs | 12 +- .../Components/Power/PoweredLightComponent.cs | 1 + .../Components/Power/SmesComponent.cs | 4 +- .../Projectiles/ProjectileComponent.cs | 7 +- .../Projectiles/ThrownItemComponent.cs | 1 + .../Components/Research/LatheComponent.cs | 5 +- .../Research/LatheDatabaseComponent.cs | 3 +- .../Research/MaterialStorageComponent.cs | 3 +- .../Sound/EmitSoundOnUseComponent].cs | 21 +- .../Sound/FootstepModifierComponent.cs | 20 +- .../Components/Sound/SoundComponent.cs | 7 +- .../Components/Stack/StackComponent.cs | 1 + .../Temperature/TemperatureComponent.cs | 11 +- .../OnUseTimerTriggerComponent.cs | 11 +- .../Weapon/Melee/MeleeWeaponComponent.cs | 11 +- .../HitscanWeaponCapacitorComponent.cs | 6 +- .../Ranged/Hitscan/HitscanWeaponComponent.cs | 17 +- .../Projectile/BallisticBulletComponent.cs | 1 + .../Projectile/BallisticMagazineComponent.cs | 1 + .../BallisticMagazineWeaponComponent.cs | 2 + .../Components/Weapon/Ranged/RangedWeapon.cs | 5 +- Content.Shared/Chemistry/Solution.cs | 8 +- .../Components/Materials/MaterialComponent.cs | 1 + .../Components/Mobs/ExaminerComponent.cs | 1 + 94 files changed, 353 insertions(+), 540 deletions(-) diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 01be9dbffd..bf830edbae 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -1,29 +1,15 @@ using System; using Content.Client.Chat; -using Content.Client.GameObjects; -using Content.Client.GameObjects.Components; using Content.Client.GameObjects.Components.Actor; -using Content.Client.GameObjects.Components.Clothing; -using Content.Client.GameObjects.Components.Construction; -using Content.Client.GameObjects.Components.IconSmoothing; -using Content.Client.GameObjects.Components.Mobs; -using Content.Client.GameObjects.Components.Power; -using Content.Client.GameObjects.Components.Research; -using Content.Client.GameObjects.Components.Sound; -using Content.Client.GameObjects.Components.Storage; -using Content.Client.GameObjects.Components.Weapons.Ranged; using Content.Client.GameTicking; using Content.Client.Input; using Content.Client.Interfaces; using Content.Client.Interfaces.Chat; -using Content.Client.Interfaces.GameObjects; using Content.Client.Interfaces.Parallax; using Content.Client.Parallax; using Content.Client.UserInterface; using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.Components.Markers; -using Content.Shared.GameObjects.Components.Materials; -using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Research; using Content.Shared.Interfaces; using Robust.Client; @@ -51,115 +37,74 @@ namespace Content.Client var factory = IoCManager.Resolve(); var prototypes = IoCManager.Resolve(); - factory.RegisterIgnore("Interactable"); - factory.RegisterIgnore("Destructible"); - factory.RegisterIgnore("Temperature"); - factory.RegisterIgnore("PowerTransfer"); - factory.RegisterIgnore("PowerNode"); - factory.RegisterIgnore("PowerProvider"); - factory.RegisterIgnore("PowerDevice"); - factory.RegisterIgnore("PowerStorage"); - factory.RegisterIgnore("PowerGenerator"); + factory.DoAutoRegistrations(); - factory.RegisterIgnore("Explosive"); - factory.RegisterIgnore("OnUseTimerTrigger"); + var registerIgnore = new[] + { + "Interactable", + "Destructible", + "Temperature", + "PowerTransfer", + "PowerNode", + "PowerProvider", + "PowerDevice", + "PowerStorage", + "PowerGenerator", + "Explosive", + "OnUseTimerTrigger", + "ToolboxElectricalFill", + "ToolLockerFill", + "EmitSoundOnUse", + "FootstepModifier", + "HeatResistance", + "CombatMode", + "Teleportable", + "ItemTeleporter", + "Portal", + "EntityStorage", + "PlaceableSurface", + "Wirecutter", + "Screwdriver", + "Multitool", + "Welder", + "Wrench", + "Crowbar", + "HitscanWeapon", + "ProjectileWeapon", + "Projectile", + "MeleeWeapon", + "Storeable", + "Stack", + "Dice", + "Construction", + "Apc", + "Door", + "PoweredLight", + "Smes", + "Powercell", + "HandheldLight", + "LightBulb", + "Healing", + "Catwalk", + "BallisticMagazine", + "BallisticMagazineWeapon", + "BallisticBullet", + "HitscanWeaponCapacitor", + "PowerCell", + "AiController", + "PlayerInputMover", + }; - factory.RegisterIgnore("ToolboxElectricalFill"); - factory.RegisterIgnore("ToolLockerFill"); - - factory.RegisterIgnore("EmitSoundOnUse"); - factory.RegisterIgnore("FootstepModifier"); - - factory.RegisterIgnore("HeatResistance"); - factory.RegisterIgnore("CombatMode"); - - factory.RegisterIgnore("Teleportable"); - factory.RegisterIgnore("ItemTeleporter"); - factory.RegisterIgnore("Portal"); - - factory.RegisterIgnore("EntityStorage"); - factory.RegisterIgnore("PlaceableSurface"); - - factory.RegisterIgnore("Wirecutter"); - factory.RegisterIgnore("Screwdriver"); - factory.RegisterIgnore("Multitool"); - factory.RegisterIgnore("Welder"); - factory.RegisterIgnore("Wrench"); - factory.RegisterIgnore("Crowbar"); - factory.Register(); - factory.RegisterIgnore("HitscanWeapon"); - factory.RegisterIgnore("ProjectileWeapon"); - factory.RegisterIgnore("Projectile"); - factory.RegisterIgnore("MeleeWeapon"); - - factory.RegisterIgnore("Storeable"); - - factory.RegisterIgnore("Stack"); - - factory.RegisterIgnore("Dice"); - - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.RegisterReference(); - - factory.RegisterReference(); - - factory.Register(); - factory.Register(); - - factory.RegisterIgnore("Construction"); - factory.RegisterIgnore("Apc"); - factory.RegisterIgnore("Door"); - factory.RegisterIgnore("PoweredLight"); - factory.RegisterIgnore("Smes"); - factory.RegisterIgnore("Powercell"); - factory.RegisterIgnore("HandheldLight"); - factory.RegisterIgnore("LightBulb"); - factory.RegisterIgnore("Healing"); - factory.RegisterIgnore("Catwalk"); - factory.RegisterIgnore("BallisticMagazine"); - factory.RegisterIgnore("BallisticMagazineWeapon"); - factory.RegisterIgnore("BallisticBullet"); - factory.RegisterIgnore("HitscanWeaponCapacitor"); - - prototypes.RegisterIgnore("material"); - - factory.RegisterIgnore("PowerCell"); - - factory.Register(); + foreach (var ignoreName in registerIgnore) + { + factory.RegisterIgnore(ignoreName); + } factory.Register(); - factory.Register(); + factory.Register(); + factory.Register(); - factory.RegisterReference(); - - factory.Register(); - factory.RegisterReference(); - - factory.Register(); - - factory.RegisterIgnore("AiController"); - factory.RegisterIgnore("PlayerInputMover"); - - factory.Register(); - factory.Register(); - - factory.Register(); + prototypes.RegisterIgnore("material"); IoCManager.Register(); IoCManager.Register(); @@ -188,6 +133,7 @@ namespace Content.Client _escapeMenuOwner.Initialize(); } + /// /// Subscribe events to the player manager after the player manager is set up /// diff --git a/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs b/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs index aa8faec6c3..18b939d90b 100644 --- a/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs +++ b/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs @@ -10,6 +10,7 @@ using Robust.Shared.Localization; namespace Content.Client.GameObjects.Components.Actor { + [RegisterComponent] public sealed class CharacterInfoComponent : Component, ICharacterUI { private CharacterInfoControl _control; diff --git a/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs b/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs index fe2d2a5063..b468e9ffdc 100644 --- a/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs +++ b/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs @@ -18,6 +18,7 @@ namespace Content.Client.GameObjects.Components.Actor /// A semi-abstract component which gets added to entities upon attachment and collects all character /// user interfaces into a single window and keybind for the user /// + [RegisterComponent] public class CharacterInterface : Component { public override string Name => "Character Interface Component"; diff --git a/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs b/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs index 8a9eb99b9d..57ffb68a17 100644 --- a/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs +++ b/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs @@ -1,13 +1,15 @@ -using Content.Shared.GameObjects; +using System; +using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Items; using Robust.Client.Graphics; using Robust.Shared.GameObjects; using Robust.Shared.ViewVariables; -using System; namespace Content.Client.GameObjects.Components.Clothing { + [RegisterComponent] + [ComponentReference(typeof(ItemComponent))] public class ClothingComponent : ItemComponent { public override string Name => "Clothing"; diff --git a/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs b/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs index 1f9a0f1531..6abd5846a5 100644 --- a/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs +++ b/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs @@ -6,6 +6,7 @@ using Robust.Shared.ViewVariables; namespace Content.Client.GameObjects.Components.Construction { + [RegisterComponent] public class ConstructionGhostComponent : Component { public override string Name => "ConstructionGhost"; diff --git a/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs index 9d948a8498..f5b5edaf34 100644 --- a/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs +++ b/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs @@ -15,6 +15,7 @@ using Robust.Shared.Maths; namespace Content.Client.GameObjects.Components.Construction { + [RegisterComponent] public class ConstructorComponent : SharedConstructorComponent { #pragma warning disable 649 diff --git a/Content.Client/GameObjects/Components/DamageableComponent.cs b/Content.Client/GameObjects/Components/DamageableComponent.cs index 311f89e80c..bde34e4d96 100644 --- a/Content.Client/GameObjects/Components/DamageableComponent.cs +++ b/Content.Client/GameObjects/Components/DamageableComponent.cs @@ -1,6 +1,6 @@ -using Content.Shared.GameObjects; +using System.Collections.Generic; +using Content.Shared.GameObjects; using Robust.Shared.GameObjects; -using System.Collections.Generic; namespace Content.Client.GameObjects { @@ -8,6 +8,7 @@ namespace Content.Client.GameObjects /// Fuck I really hate doing this /// TODO: make sure the client only gets damageable component on the clientside entity for its player mob ///
+ [RegisterComponent] public class DamageableComponent : SharedDamageableComponent { /// diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs index 0d672b28d2..bdaeedcc82 100644 --- a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs +++ b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs @@ -18,6 +18,7 @@ namespace Content.Client.GameObjects /// /// A character UI which shows items the user has equipped within his inventory /// + [RegisterComponent] public class ClientInventoryComponent : SharedInventoryComponent { private readonly Dictionary _slots = new Dictionary(); diff --git a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs index 74352642b8..6abe1145a7 100644 --- a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs +++ b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs @@ -25,6 +25,7 @@ namespace Content.Client.GameObjects.Components.IconSmoothing /// To use, set base equal to the prefix of the corner states in the sprite base RSI. /// Any objects with the same key will connect. /// + [RegisterComponent] public class IconSmoothComponent : Component { private string _smoothKey; diff --git a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs index 62158c0e0d..4e0899724c 100644 --- a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs @@ -15,6 +15,8 @@ using Robust.Shared.ViewVariables; namespace Content.Client.GameObjects { + [RegisterComponent] + [ComponentReference(typeof(IHandsComponent))] public class HandsComponent : SharedHandsComponent, IHandsComponent { private HandsGui _gui; diff --git a/Content.Client/GameObjects/Components/Items/ItemComponent.cs b/Content.Client/GameObjects/Components/Items/ItemComponent.cs index 574f25b50d..80eed4d948 100644 --- a/Content.Client/GameObjects/Components/Items/ItemComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ItemComponent.cs @@ -1,4 +1,5 @@ -using Content.Shared.GameObjects; +using System; +using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; using Robust.Client.Graphics; using Robust.Client.Interfaces.ResourceManagement; @@ -9,10 +10,10 @@ using Robust.Shared.IoC; using Robust.Shared.Serialization; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; -using System; namespace Content.Client.GameObjects { + [RegisterComponent] public class ItemComponent : Component { public override string Name => "Item"; diff --git a/Content.Client/GameObjects/Components/LowWallComponent.cs b/Content.Client/GameObjects/Components/LowWallComponent.cs index 2f1b6e3868..c183beb568 100644 --- a/Content.Client/GameObjects/Components/LowWallComponent.cs +++ b/Content.Client/GameObjects/Components/LowWallComponent.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Content.Client.GameObjects.Components.IconSmoothing; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; using static Robust.Client.GameObjects.SpriteComponent; @@ -14,6 +15,8 @@ namespace Content.Client.GameObjects.Components /// /// Override of icon smoothing to handle the specific complexities of low walls. /// + [RegisterComponent] + [ComponentReference(typeof(IconSmoothComponent))] public class LowWallComponent : IconSmoothComponent { public override string Name => "LowWall"; diff --git a/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs b/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs index 6745d2a271..92a8b6f87e 100644 --- a/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs @@ -8,6 +8,8 @@ using Robust.Shared.Maths; namespace Content.Client.GameObjects.Components.Mobs { + [RegisterComponent] + [ComponentReference(typeof(SharedCameraRecoilComponent))] public sealed class CameraRecoilComponent : SharedCameraRecoilComponent { // Maximum rate of magnitude restore towards 0 kick. diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs index c590245f90..2999ede1bf 100644 --- a/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs +++ b/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs @@ -1,31 +1,31 @@ -using Content.Client.GameObjects.Components.Actor; -using Content.Client.GameObjects.Components.Mobs; +using System.Collections.Generic; +using Content.Client.GameObjects.Components.Actor; using Content.Client.Graphics.Overlays; +using Content.Client.UserInterface; +using Content.Client.Utility; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Mobs; using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Graphics.Overlays; using Robust.Client.Interfaces.Graphics.Overlays; using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.Interfaces.UserInterface; using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.Renderable; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; -using System.Collections.Generic; -using Content.Client.UserInterface; -using Content.Client.Utility; -using Content.Shared.GameObjects.Components.Mobs; -using Robust.Client.Graphics; -using Robust.Client.Graphics.Overlays; -using Robust.Client.Interfaces.UserInterface; -using Robust.Shared.GameObjects.Components.Renderable; namespace Content.Client.GameObjects { /// /// A character UI component which shows the current damage state of the mob (living/dead) /// + [RegisterComponent] public class SpeciesUI : SharedSpeciesComponent//, ICharacterUI { private StatusEffectsUI _ui; diff --git a/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs index d36d3be317..21e7452068 100644 --- a/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs +++ b/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs @@ -1,14 +1,13 @@ using Content.Shared.GameObjects.Components.Power; -using Robust.Client.Interfaces.Graphics; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; -using Robust.Shared.IoC; namespace Content.Client.GameObjects.Components.Power { + [RegisterComponent] public class PowerDebugTool : SharedPowerDebugTool { SS14Window LastWindow; diff --git a/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs b/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs index b40d96319d..962948e7e8 100644 --- a/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs +++ b/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs @@ -1,13 +1,13 @@ using Content.Shared.GameObjects.Components.Research; using Content.Shared.Research; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Prototypes; namespace Content.Client.GameObjects.Components.Research { + [RegisterComponent] + [ComponentReference(typeof(SharedLatheDatabaseComponent))] public class LatheDatabaseComponent : SharedLatheDatabaseComponent { #pragma warning disable CS0649 diff --git a/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs b/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs index de32c6f55c..62dfd8c18d 100644 --- a/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs +++ b/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using Content.Shared.GameObjects.Components.Research; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Network; namespace Content.Client.GameObjects.Components.Research { + [RegisterComponent] + [ComponentReference(typeof(SharedMaterialStorageComponent))] public class MaterialStorageComponent : SharedMaterialStorageComponent { protected override Dictionary Storage { get; set; } = new Dictionary(); diff --git a/Content.Client/GameObjects/Components/Sound/SoundComponent.cs b/Content.Client/GameObjects/Components/Sound/SoundComponent.cs index e8a47f1643..cfed2998ee 100644 --- a/Content.Client/GameObjects/Components/Sound/SoundComponent.cs +++ b/Content.Client/GameObjects/Components/Sound/SoundComponent.cs @@ -5,14 +5,13 @@ using Robust.Client.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; -using Robust.Shared.Interfaces.Timers; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Serialization; using Robust.Shared.Timers; namespace Content.Client.GameObjects.Components.Sound { + [RegisterComponent] public class SoundComponent : SharedSoundComponent { private readonly List _schedules = new List(); diff --git a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs index d757397753..ad8501cc64 100644 --- a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs +++ b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs @@ -17,6 +17,7 @@ namespace Content.Client.GameObjects.Components.Storage /// /// Client version of item storage containers, contains a UI which displays stored entities and their size /// + [RegisterComponent] public class ClientStorageComponent : SharedStorageComponent { private Dictionary StoredEntities { get; set; } = new Dictionary(); diff --git a/Content.Client/GameObjects/Components/SubFloorHideComponent.cs b/Content.Client/GameObjects/Components/SubFloorHideComponent.cs index 45d6c366d0..b5cabd00dd 100644 --- a/Content.Client/GameObjects/Components/SubFloorHideComponent.cs +++ b/Content.Client/GameObjects/Components/SubFloorHideComponent.cs @@ -10,6 +10,7 @@ namespace Content.Client.GameObjects.Components /// is not a sub floor (plating). /// /// + [RegisterComponent] public sealed class SubFloorHideComponent : Component { private SnapGridComponent _snapGridComponent; diff --git a/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs b/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs index 3c7c76c5e4..291e05e4c1 100644 --- a/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs +++ b/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs @@ -1,12 +1,13 @@ using System; using Content.Shared.GameObjects.Components.Weapons.Ranged; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Map; namespace Content.Client.GameObjects.Components.Weapons.Ranged { + [RegisterComponent] public sealed class ClientRangedWeaponComponent : SharedRangedWeaponComponent { private TimeSpan _lastFireTime; diff --git a/Content.Client/GameObjects/Components/WindowComponent.cs b/Content.Client/GameObjects/Components/WindowComponent.cs index f92c7b4f20..f4ae19448f 100644 --- a/Content.Client/GameObjects/Components/WindowComponent.cs +++ b/Content.Client/GameObjects/Components/WindowComponent.cs @@ -8,6 +8,7 @@ using static Content.Client.GameObjects.Components.IconSmoothing.IconSmoothCompo namespace Content.Client.GameObjects.Components { + [RegisterComponent] public sealed class WindowComponent : Component { public override string Name => "Window"; diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index df458d5127..7d3a279492 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -1,73 +1,22 @@ using Content.Server.Chat; -using Content.Server.GameObjects; -using Content.Server.GameObjects.Components; -using Content.Server.GameObjects.Components.Power; -using Content.Server.GameObjects.Components.Interactable.Tools; -using Content.Server.Interfaces.GameObjects; -using Content.Server.Placement; -using Robust.Server; -using Robust.Server.Interfaces; -using Robust.Server.Interfaces.Maps; -using Robust.Server.Interfaces.Player; -using Robust.Server.Player; -using Robust.Shared.Console; -using Robust.Shared.ContentPack; -using Robust.Shared.Enums; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Map; -using Robust.Shared.Interfaces.Timers; -using Robust.Shared.IoC; -using Robust.Shared.Log; -using Robust.Shared.Map; -using Robust.Shared.Timers; -using Robust.Shared.Interfaces.Timing; -using Robust.Shared.Maths; -using Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan; -using Content.Server.GameObjects.Components.Weapon.Ranged.Projectile; -using Content.Server.GameObjects.Components.Projectiles; -using Content.Server.GameObjects.Components.Weapon.Melee; -using Content.Server.GameObjects.Components.Stack; -using Content.Server.GameObjects.Components.Construction; -using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; -using Content.Server.Mobs; -using Content.Server.Players; -using Content.Server.GameObjects.Components.Interactable; -using Content.Server.GameObjects.Components.Markers; -using Content.Server.GameObjects.Components.Sound; -using Content.Server.GameObjects.Components.Weapon.Ranged; using Content.Server.GameTicking; using Content.Server.Interfaces; -using Content.Server.Interfaces.GameTicking; -using Content.Shared.GameObjects.Components.Chemistry; -using Content.Shared.GameObjects.Components.Materials; -using Content.Shared.GameObjects.Components.Inventory; -using Content.Shared.GameObjects.Components.Markers; -using Content.Shared.GameObjects.Components.Mobs; -using Content.Shared.Interfaces; -using Robust.Server.Interfaces.ServerStatus; -using Robust.Shared.Timing; -using Content.Server.GameObjects.Components.Destructible; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.Components.Items.Storage.Fill; -using Content.Server.GameObjects.Components.Movement; using Content.Server.Interfaces.Chat; -using Content.Server.Interfaces.GameObjects.Components.Movement; -using Content.Server.GameObjects.Components.Research; -using Content.Shared.GameObjects.Components.Research; +using Content.Server.Interfaces.GameTicking; +using Content.Shared.Interfaces; +using Robust.Server.Interfaces.Player; +using Robust.Shared.ContentPack; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Log; -using Content.Server.GameObjects.Components.Explosive; -using Content.Server.GameObjects.Components.Items; -using Content.Server.GameObjects.Components.Triggers; -using Content.Shared.GameObjects.Components.Movement; -using SolutionComponent = Content.Server.GameObjects.Components.Chemistry.SolutionComponent; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Timing; namespace Content.Server { public class EntryPoint : GameServer { private IGameTicker _gameTicker; - private IMoMMILink _mommiLink; private StatusShell _statusShell; /// @@ -77,129 +26,19 @@ namespace Content.Server var factory = IoCManager.Resolve(); - factory.Register(); - factory.RegisterReference(); + factory.DoAutoRegistrations(); - factory.Register(); + var registerIgnore = new[] + { + "ConstructionGhost", + "IconSmooth", + "SubFloorHide" + }; - factory.Register(); - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.RegisterReference(); - factory.RegisterReference(); - factory.Register(); - - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.RegisterReference(); - - factory.Register(); - - //Power Components - factory.Register(); - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.Register(); - factory.Register(); - - //Tools - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - - factory.Register(); - factory.Register(); - - factory.Register(); - - factory.Register(); - factory.RegisterReference(); - factory.RegisterReference(); - factory.Register(); - factory.RegisterReference(); - factory.RegisterReference(); - - factory.Register(); - factory.Register(); - - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.RegisterReference(); - factory.Register(); - factory.Register(); - factory.Register(); - factory.RegisterReference(); - - factory.Register(); - factory.Register(); - factory.RegisterIgnore("ConstructionGhost"); - - factory.Register(); - factory.Register(); - factory.Register(); - - factory.Register(); - factory.RegisterReference(); - - factory.Register(); - factory.RegisterReference(); - factory.Register(); - - factory.RegisterReference(); - - factory.Register(); - factory.Register(); - - factory.Register(); - - factory.Register(); - factory.RegisterReference(); - - factory.RegisterIgnore("IconSmooth"); - factory.RegisterIgnore("SubFloorHide"); - - factory.Register(); - factory.RegisterReference(); - - factory.Register(); - factory.Register(); - factory.Register(); - factory.Register(); - - factory.Register(); - - factory.Register(); - - factory.Register(); - factory.Register(); - - factory.Register(); - factory.Register(); - - factory.Register(); - - factory.Register(); + foreach (var ignoreName in registerIgnore) + { + factory.RegisterIgnore(ignoreName); + } IoCManager.Register(); IoCManager.Register(); @@ -218,8 +57,6 @@ namespace Content.Server IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); - _mommiLink = IoCManager.Resolve(); - var playerManager = IoCManager.Resolve(); _statusShell = new StatusShell(); diff --git a/Content.Server/GameObjects/Components/CatwalkComponent.cs b/Content.Server/GameObjects/Components/CatwalkComponent.cs index 4e1769b210..4027c5045d 100644 --- a/Content.Server/GameObjects/Components/CatwalkComponent.cs +++ b/Content.Server/GameObjects/Components/CatwalkComponent.cs @@ -5,6 +5,7 @@ namespace Content.Server.GameObjects.Components /// /// Literally just a marker component for footsteps for now. /// + [RegisterComponent] public sealed class CatwalkComponent : Component { public override string Name => "Catwalk"; diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs index a052eea348..7398bd83c6 100644 --- a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs @@ -1,6 +1,7 @@ using System; using Content.Shared.Chemistry; using Content.Shared.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; namespace Content.Server.GameObjects.Components.Chemistry @@ -8,6 +9,7 @@ namespace Content.Server.GameObjects.Components.Chemistry /// /// Shared ECS component that manages a liquid solution of reagents. /// + [RegisterComponent] internal class SolutionComponent : Shared.GameObjects.Components.Chemistry.SolutionComponent { /// @@ -131,7 +133,7 @@ namespace Content.Server.GameObjects.Components.Chemistry // pulling from an empty container, pointless to continue if (transferQuantity <= 0) return; - + var transferSolution = component.SplitSolution(transferQuantity); handSolutionComp.TryAddSolution(transferSolution); } diff --git a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs index 4e35820fd6..86e64d2b5c 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs +++ b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs @@ -17,6 +17,7 @@ using static Content.Shared.Construction.ConstructionStepTool; namespace Content.Server.GameObjects.Components.Construction { + [RegisterComponent] public class ConstructionComponent : Component, IAttackBy { public override string Name => "Construction"; diff --git a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs index 2c58b26c14..8f13d8cf23 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs +++ b/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs @@ -3,13 +3,11 @@ using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Construction; using Content.Shared.GameObjects.Components.Construction; -using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -18,6 +16,7 @@ using Robust.Shared.Prototypes; namespace Content.Server.GameObjects.Components.Construction { + [RegisterComponent] public class ConstructorComponent : SharedConstructorComponent { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs b/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs index 52b3c663c2..46909bf75f 100644 --- a/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs +++ b/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs @@ -1,12 +1,9 @@ -using Content.Server.Interfaces.GameObjects; -using System; +using System; using System.Collections.Generic; -using Robust.Shared.Maths; -using Robust.Shared.GameObjects; -using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; using Content.Server.Interfaces; +using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -18,6 +15,7 @@ namespace Content.Server.GameObjects /// A component that handles receiving damage and healing, /// as well as informing other components of it. /// + [RegisterComponent] public class DamageableComponent : SharedDamageableComponent, IDamageableComponent { /// diff --git a/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs b/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs index daa1355754..d5efd91802 100644 --- a/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs +++ b/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs @@ -1,21 +1,21 @@ using System; using System.Collections.Generic; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces; +using Content.Shared.GameObjects; using Robust.Shared.GameObjects; -using Robust.Shared.Serialization; -using Robust.Shared.ViewVariables; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Maths; -using Content.Server.Interfaces; -using Content.Server.GameObjects.EntitySystems; -using Content.Shared.GameObjects; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Destructible { /// /// Deletes the entity once a certain damage threshold has been reached. /// + [RegisterComponent] public class DestructibleComponent : Component, IOnDamageBehavior, IDestroyAct, IExAct { #pragma warning disable 649 @@ -63,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Destructible /// void IOnDamageBehavior.OnDamageThresholdPassed(object obj, DamageThresholdPassedEventArgs e) - { + { if (e.Passed && e.DamageThreshold == Threshold && destroyed == false) { destroyed = true; diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs index 6f9957d617..3ddee7f3bf 100644 --- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs @@ -10,6 +10,8 @@ using Robust.Shared.Timers; namespace Content.Server.GameObjects { + [RegisterComponent] + [ComponentReference(typeof(IActivate))] public class ServerDoorComponent : Component, IActivate { public override string Name => "Door"; diff --git a/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs b/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs index a5e401efd6..656ccd4c5a 100644 --- a/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs +++ b/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs @@ -1,28 +1,27 @@ using System; using System.Linq; -using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; -using Robust.Server.Interfaces.GameObjects; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Maps; using Robust.Server.GameObjects.EntitySystems; -using Robust.Shared.GameObjects.EntitySystemMessages; +using Robust.Server.Interfaces.GameObjects; +using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.Timing; -using Robust.Shared.Interfaces.Map; +using Robust.Shared.GameObjects.EntitySystemMessages; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Serialization; -using Content.Server.GameObjects.EntitySystems; -using Content.Shared.GameObjects; -using Content.Shared.Maps; -using Robust.Server.Interfaces.Player; namespace Content.Server.GameObjects.Components.Explosive { + [RegisterComponent] public class ExplosiveComponent : Component, ITimerTrigger, IDestroyAct { -#pragma warning disable 649 +#pragma warning disable 649 [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager; [Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IServerEntityManager _serverEntityManager; @@ -66,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Explosive if (distanceFromEntity < DevastationRange) { severity = ExplosionSeverity.Destruction; - } + } else if (distanceFromEntity < HeavyImpactRange) { severity = ExplosionSeverity.Heavy; diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 69c14bcb5d..54b01700b3 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -5,8 +5,8 @@ using Content.Shared.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Utility; @@ -16,6 +16,7 @@ using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventory namespace Content.Server.GameObjects { + [RegisterComponent] public class InventoryComponent : SharedInventoryComponent { [ViewVariables] diff --git a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs index a2477d2d2a..7b42e79451 100644 --- a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs @@ -3,16 +3,12 @@ using System.Collections.Generic; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; -using Content.Shared.Input; -using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.EntitySystemMessages; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; -using Robust.Shared.Input; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -24,6 +20,8 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects { + [RegisterComponent] + [ComponentReference(typeof(IHandsComponent))] public class HandsComponent : SharedHandsComponent, IHandsComponent { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Healing/HealingComponent.cs b/Content.Server/GameObjects/Components/Healing/HealingComponent.cs index 82b5420fe6..5fb3bdc7cc 100644 --- a/Content.Server/GameObjects/Components/Healing/HealingComponent.cs +++ b/Content.Server/GameObjects/Components/Healing/HealingComponent.cs @@ -1,21 +1,12 @@ -using System; -using Content.Server.GameObjects.Components.Stack; -using Robust.Shared.GameObjects; +using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Map; -using Robust.Shared.IoC; -using Robust.Server.GameObjects; -using Robust.Shared.Maths; -using Robust.Server.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Timing; -using Robust.Shared.GameObjects.EntitySystemMessages; -using Robust.Shared.Serialization; -using Robust.Shared.Interfaces.GameObjects.Components; using Content.Shared.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Weapon.Melee { + [RegisterComponent] public class HealingComponent : Component, IAfterAttack, IUse { public override string Name => "Healing"; diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index b662990f1a..8f7817f775 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -16,6 +16,7 @@ namespace Content.Server.GameObjects.Components.Interactable /// /// Component that represents a handheld lightsource which can be toggled on and off. /// + [RegisterComponent] internal class HandheldLightComponent : Component, IUse, IExamine, IAttackBy, IMapInit { public const float Wattage = 10; diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs index 3b7c0af218..2f61ad57ed 100644 --- a/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs @@ -1,6 +1,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Shared.Maps; using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -8,6 +9,7 @@ using Robust.Shared.Map; namespace Content.Server.GameObjects.Components.Interactable.Tools { + [RegisterComponent] public class CrowbarComponent : ToolComponent, IAfterAttack { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs index 92f1972962..7493374f57 100644 --- a/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs @@ -1,10 +1,13 @@ -namespace Content.Server.GameObjects.Components.Interactable.Tools +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Interactable.Tools { /// /// Tool used for interfacing/hacking into configurable computers /// + [RegisterComponent] public class MultitoolComponent : ToolComponent { public override string Name => "Multitool"; } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs index 9095a3b2c8..8f69c1b2c7 100644 --- a/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs @@ -1,5 +1,8 @@ -namespace Content.Server.GameObjects.Components.Interactable.Tools +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Interactable.Tools { + [RegisterComponent] public class ScrewdriverComponent : ToolComponent { /// @@ -7,4 +10,4 @@ /// public override string Name => "Screwdriver"; } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs index cb1e6597b7..a7de418d8f 100644 --- a/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs @@ -1,12 +1,10 @@ using System; -using System.Text; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; -using Robust.Server.GameObjects; using Content.Server.GameObjects.EntitySystems; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Serialization; +using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Interactable.Tools @@ -14,6 +12,7 @@ namespace Content.Server.GameObjects.Components.Interactable.Tools /// /// Tool used to weld metal together, light things on fire, or melt into constituent parts /// + [RegisterComponent] class WelderComponent : ToolComponent, EntitySystems.IUse, EntitySystems.IExamine { SpriteComponent spriteComponent; diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs index 8f7edaa0d3..bc7568c381 100644 --- a/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs @@ -1,10 +1,13 @@ -namespace Content.Server.GameObjects.Components.Interactable.Tools +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Interactable.Tools { /// /// Tool that can be used for some cutting interactions such as wires or hacking /// + [RegisterComponent] public class WirecutterComponent : ToolComponent { public override string Name => "Wirecutter"; } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs index 1b69b39ee9..8bb24680d9 100644 --- a/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs @@ -1,10 +1,13 @@ -namespace Content.Server.GameObjects.Components.Interactable.Tools +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Interactable.Tools { /// /// Wrenches bolts, and interacts with things that have been bolted /// + [RegisterComponent] public class WrenchComponent : ToolComponent { public override string Name => "Wrench"; } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs b/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs index 6235e24ee0..4a216d5b12 100644 --- a/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs @@ -1,15 +1,18 @@ +using System; +using System.Collections.Generic; +using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; -using System; -using System.Collections.Generic; -using Content.Server.GameObjects.EntitySystems; using Robust.Shared.Utility; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; namespace Content.Server.GameObjects { + [RegisterComponent] + [ComponentReference(typeof(ItemComponent))] + [ComponentReference(typeof(StoreableComponent))] public class ClothingComponent : ItemComponent, IUse { public override string Name => "Clothing"; diff --git a/Content.Server/GameObjects/Components/Items/DiceComponent.cs b/Content.Server/GameObjects/Components/Items/DiceComponent.cs index 78915e44de..ef9b10afb2 100644 --- a/Content.Server/GameObjects/Components/Items/DiceComponent.cs +++ b/Content.Server/GameObjects/Components/Items/DiceComponent.cs @@ -6,7 +6,6 @@ using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Maths; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; @@ -15,6 +14,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Items { + [RegisterComponent] public class DiceComponent : Component, IActivate, IUse, ILand, IExamine { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs index fdf6029fbc..7ea736315b 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs @@ -1,4 +1,9 @@ -using Content.Server.GameObjects.EntitySystems; +using System.Linq; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.Components.Sound; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Storage; +using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; @@ -7,14 +12,12 @@ using Robust.Shared.Interfaces.Network; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; -using System.Linq; -using Content.Server.GameObjects.Components.Items.Storage; -using Content.Server.GameObjects.Components.Sound; -using Content.Shared.GameObjects.Components.Storage; -using Robust.Server.GameObjects; namespace Content.Server.GameObjects.Components { + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + [ComponentReference(typeof(IStorageComponent))] public class EntityStorageComponent : Component, IActivate, IStorageComponent { public override string Name => "EntityStorage"; diff --git a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs index 7071481fa1..d84e55d2f8 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs @@ -7,6 +7,7 @@ using Robust.Shared.Maths; namespace Content.Server.GameObjects.Components.Items.Storage.Fill { + [RegisterComponent] internal sealed class ToolLockerFillComponent : Component, IMapInit { public override string Name => "ToolLockerFill"; diff --git a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs index 40161e7c88..95227b7141 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs @@ -7,6 +7,7 @@ using Robust.Shared.Maths; namespace Content.Server.GameObjects.Components.Items.Storage.Fill { + [RegisterComponent] internal sealed class ToolboxElectricalFillComponent : Component, IMapInit { public override string Name => "ToolboxElectricalFill"; diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index 85f1668b5f..a5d61d955d 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -1,17 +1,18 @@ -using Content.Server.Interfaces.GameObjects; -using Robust.Server.Interfaces.GameObjects; -using Content.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; +using System; using Content.Server.GameObjects.EntitySystems; -using Robust.Shared.GameObjects; -using System; +using Content.Server.Interfaces.GameObjects; +using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; -using Content.Server.GameObjects.Components; using Robust.Server.GameObjects; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; namespace Content.Server.GameObjects { + [RegisterComponent] + [ComponentReference(typeof(StoreableComponent))] public class ItemComponent : StoreableComponent, IAttackHand { public override string Name => "Item"; diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index f9a4b57b2c..f03d04cf91 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -1,32 +1,33 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; +using Content.Server.GameObjects.Components; +using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Storage; +using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; +using Robust.Server.GameObjects.EntitySystemMessages; using Robust.Server.Interfaces.Player; using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Serialization; -using System.Collections.Generic; -using Content.Shared.Interfaces; -using Robust.Shared.GameObjects.EntitySystemMessages; -using Robust.Shared.Interfaces.Map; -using Robust.Shared.ViewVariables; -using Content.Server.GameObjects.Components; -using Content.Server.GameObjects.Components.Items.Storage; -using Robust.Server.GameObjects.EntitySystemMessages; namespace Content.Server.GameObjects { /// /// Storage component for containing entities within this one, matches a UI on the client which shows stored entities /// + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + [ComponentReference(typeof(IStorageComponent))] public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent, IDestroyAct { #pragma warning disable 649 @@ -149,7 +150,7 @@ namespace Content.Server.GameObjects { return false; } - + //Check that we can drop the item from our hands first otherwise we obviously cant put it inside if (CanInsert(hands.GetActiveHand.Owner) && hands.Drop(hands.ActiveIndex)) { diff --git a/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs index b800fc58fa..7f25245112 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs @@ -3,6 +3,7 @@ using Robust.Shared.Serialization; namespace Content.Server.GameObjects { + [RegisterComponent] public class StoreableComponent : Component { public override string Name => "Storeable"; diff --git a/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs b/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs index 318931dbd8..7c8ea4f4e4 100644 --- a/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs +++ b/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs @@ -1,4 +1,3 @@ -using System; using Content.Shared.GameObjects.Components.Markers; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; @@ -6,6 +5,8 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Markers { + [RegisterComponent] + [ComponentReference(typeof(SharedSpawnPointComponent))] public sealed class SpawnPointComponent : SharedSpawnPointComponent { private SpawnPointType _spawnType; diff --git a/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs b/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs index ce2c3e76ed..42fc2fba63 100644 --- a/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs @@ -1,8 +1,11 @@ using Content.Shared.GameObjects.Components.Mobs; +using Robust.Shared.GameObjects; using Robust.Shared.Maths; namespace Content.Server.GameObjects.Components.Mobs { + [RegisterComponent] + [ComponentReference(typeof(SharedCameraRecoilComponent))] public sealed class CameraRecoilComponent : SharedCameraRecoilComponent { public override void Kick(Vector2 recoil) diff --git a/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs b/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs index 3b962f03d7..d5078ec107 100644 --- a/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs @@ -8,6 +8,7 @@ namespace Content.Server.GameObjects.Components.Mobs /// This is used to differentiate between regular item interactions or /// using *everything* as a weapon. /// + [RegisterComponent] public sealed class CombatModeComponent : Component { public override string Name => "CombatMode"; diff --git a/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs b/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs index 193d215d9a..8d3283fe25 100644 --- a/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs @@ -1,9 +1,10 @@ using System; -using Robust.Shared.GameObjects; using Content.Shared.GameObjects.Components.Inventory; +using Robust.Shared.GameObjects; namespace Content.Server.GameObjects { + [RegisterComponent] public class HeatResistanceComponent : Component { public override string Name => "HeatResistance"; diff --git a/Content.Server/GameObjects/Components/Mobs/MindComponent.cs b/Content.Server/GameObjects/Components/Mobs/MindComponent.cs index 061d2d5315..882d827969 100644 --- a/Content.Server/GameObjects/Components/Mobs/MindComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/MindComponent.cs @@ -1,14 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Content.Server.Mobs; -using Robust.Server.GameObjects; +using Content.Server.Mobs; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Network; -using Robust.Shared.Log; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Mobs @@ -16,6 +8,7 @@ namespace Content.Server.GameObjects.Components.Mobs /// /// Stores a on a mob. /// + [RegisterComponent] public class MindComponent : Component { /// diff --git a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs index 86029362a9..f703d53cea 100644 --- a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs @@ -12,6 +12,7 @@ using Robust.Shared.Serialization; namespace Content.Server.GameObjects { + [RegisterComponent] public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior, IExAct { /// diff --git a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs index 1c0647e244..686b097f46 100644 --- a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs @@ -5,6 +5,7 @@ using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Movement { + [RegisterComponent] public class AiControllerComponent : Component, IMoverComponent { private string _logicName; diff --git a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs index 645463a437..889a0d08ac 100644 --- a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs @@ -12,6 +12,8 @@ namespace Content.Server.GameObjects.Components.Movement /// /// Moves the entity based on input from a KeyBindingInputComponent. /// + [RegisterComponent] + [ComponentReference(typeof(IMoverComponent))] public class PlayerInputMoverComponent : Component, IMoverComponent { private bool _movingUp; diff --git a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs index 70eb876a8e..f76a8aea58 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs @@ -4,6 +4,7 @@ using Content.Shared.GameObjects.Components.Movement; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; @@ -12,6 +13,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Movement { + [RegisterComponent] public class ServerPortalComponent : SharedPortalComponent { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs index 78d97a2125..fca5b45b79 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs @@ -9,7 +9,6 @@ using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Serialization; @@ -19,6 +18,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Movement { + [RegisterComponent] public class ServerTeleporterComponent : Component, IAfterAttack { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs b/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs index f5f0701ca4..a20b672cc9 100644 --- a/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs @@ -1,8 +1,8 @@ using Robust.Shared.GameObjects; -using Robust.Shared.Log; namespace Content.Server.GameObjects.Components.Movement { + [RegisterComponent] public class TeleportableComponent : Component { public override string Name => "Teleportable"; diff --git a/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs b/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs index 7d8a624f1a..c27c5874ec 100644 --- a/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs +++ b/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs @@ -4,6 +4,7 @@ using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components { + [RegisterComponent] public class PlaceableSurfaceComponent : Component, IAttackBy { public override string Name => "PlaceableSurface"; diff --git a/Content.Server/GameObjects/Components/Power/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcComponent.cs index 62206488fb..3e0b233f27 100644 --- a/Content.Server/GameObjects/Components/Power/ApcComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcComponent.cs @@ -3,15 +3,15 @@ using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Power; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.UserInterface; -using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.Audio; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.UserInterface; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; namespace Content.Server.GameObjects.Components.Power { + [RegisterComponent] + [ComponentReference(typeof(IActivate))] public sealed class ApcComponent : SharedApcComponent, IActivate { PowerStorageComponent Storage; diff --git a/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs b/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs index 11cdb8cb42..9316dd6be9 100644 --- a/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs +++ b/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs @@ -1,9 +1,9 @@ using System; +using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; -using SpriteComponent = Robust.Server.GameObjects.SpriteComponent; namespace Content.Server.GameObjects.Components.Power { @@ -23,6 +23,7 @@ namespace Content.Server.GameObjects.Components.Power /// /// Component that represents a light bulb. Can be broken, or burned, which turns them mostly useless. /// + [RegisterComponent] public class LightBulbComponent : Component { diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs index 5c25236961..fdaaf412be 100644 --- a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs @@ -1,8 +1,11 @@ using Content.Shared.GameObjects.Components.Power; using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; namespace Content.Server.GameObjects.Components.Power { + [RegisterComponent] + [ComponentReference(typeof(PowerStorageComponent))] public class PowerCellComponent : PowerStorageComponent { public override string Name => "PowerCell"; diff --git a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs index ef06753a2a..47d744180a 100644 --- a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs +++ b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs @@ -3,12 +3,13 @@ using System.Text; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Power; using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; -using Robust.Shared.Map; namespace Content.Server.GameObjects.Components.Power { + [RegisterComponent] public class PowerDebugTool : SharedPowerDebugTool, IAfterAttack { void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/Power/PowerDevice.cs b/Content.Server/GameObjects/Components/Power/PowerDevice.cs index 53a28dea75..f93930cc6c 100644 --- a/Content.Server/GameObjects/Components/Power/PowerDevice.cs +++ b/Content.Server/GameObjects/Components/Power/PowerDevice.cs @@ -1,22 +1,19 @@ -using Content.Server.GameObjects.EntitySystems; -using Robust.Server.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.GameObjects.Components; -using Robust.Shared.IoC; -using Robust.Shared.Serialization; -using Robust.Shared.Utility; -using System; +using System; using System.Collections.Generic; using System.Linq; +using Content.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; using Robust.Shared.ViewVariables; -using YamlDotNet.RepresentationModel; namespace Content.Server.GameObjects.Components.Power { /// /// Component that requires power to function /// + [RegisterComponent] public class PowerDeviceComponent : Component, EntitySystems.IExamine { public override string Name => "PowerDevice"; diff --git a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs index c469974411..c2ac6203a6 100644 --- a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs @@ -1,18 +1,13 @@ using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Serialization; -using Robust.Shared.Utility; -using System; using Robust.Shared.ViewVariables; -using YamlDotNet.RepresentationModel; namespace Content.Server.GameObjects.Components.Power { /// /// Component that creates power and supplies it to the powernet /// + [RegisterComponent] public class PowerGeneratorComponent : Component { public override string Name => "PowerGenerator"; diff --git a/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs index 7a4bbb39e9..e44ee1d910 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs @@ -1,10 +1,9 @@ -using Robust.Server.GameObjects; +using System; +using System.Linq; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.IoC; -using System; -using System.Linq; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Power @@ -12,6 +11,7 @@ namespace Content.Server.GameObjects.Components.Power /// /// Component that connects to the powernet /// + [RegisterComponent] public class PowerNodeComponent : Component { public override string Name => "PowerNode"; diff --git a/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs b/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs index 78ff050583..3d91440636 100644 --- a/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs @@ -1,22 +1,20 @@ -using Robust.Server.GameObjects; +using System.Collections.Generic; +using System.Linq; using Robust.Server.Interfaces.GameObjects; -using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Serialization; -using Robust.Shared.Utility; -using System; -using System.Collections.Generic; -using System.Linq; using Robust.Shared.ViewVariables; -using YamlDotNet.RepresentationModel; namespace Content.Server.GameObjects.Components.Power { /// /// Component that wirelessly connects and powers devices, connects to powernet via node and can be combined with internal storage component /// + [RegisterComponent] + [ComponentReference(typeof(PowerDeviceComponent))] public class PowerProviderComponent : PowerDeviceComponent { public override string Name => "PowerProvider"; diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs index 6b8ad3cd97..e2e661dbb9 100644 --- a/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs @@ -1,3 +1,4 @@ +using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -6,6 +7,8 @@ namespace Content.Server.GameObjects.Components.Power /// /// Feeds energy from the powernet and may have the ability to supply back into it /// + [RegisterComponent] + [ComponentReference(typeof(PowerStorageComponent))] public class PowerStorageNetComponent : PowerStorageComponent { public override string Name => "PowerStorage"; diff --git a/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs b/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs index cd0588c5b9..79771febfa 100644 --- a/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs @@ -1,20 +1,18 @@ -using Content.Server.GameObjects.EntitySystems; -using Robust.Server.GameObjects; +using System.Linq; +using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using System.Linq; -using Robust.Shared.Interfaces.GameObjects; -using Content.Server.GameObjects.Components.Interactable.Tools; using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.IoC; using Robust.Shared.ViewVariables; -using System; namespace Content.Server.GameObjects.Components.Power { /// /// Component to transfer power to nearby components, can create powernets and connect to nodes /// + [RegisterComponent] public class PowerTransferComponent : Component, IAttackBy { public override string Name => "PowerTransfer"; diff --git a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs index 651c129bf1..5804722fc0 100644 --- a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs @@ -17,6 +17,7 @@ namespace Content.Server.GameObjects.Components.Power /// /// Component that represents a wall light. It has a light bulb that can be replaced when broken. /// + [RegisterComponent] public class PoweredLightComponent : Component, IAttackHand, IAttackBy { public override string Name => "PoweredLight"; diff --git a/Content.Server/GameObjects/Components/Power/SmesComponent.cs b/Content.Server/GameObjects/Components/Power/SmesComponent.cs index 9576980b79..eba642ef27 100644 --- a/Content.Server/GameObjects/Components/Power/SmesComponent.cs +++ b/Content.Server/GameObjects/Components/Power/SmesComponent.cs @@ -1,5 +1,4 @@ -using System; -using Content.Shared.GameObjects.Components.Power; +using Content.Shared.GameObjects.Components.Power; using Content.Shared.Utility; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; @@ -11,6 +10,7 @@ namespace Content.Server.GameObjects.Components.Power /// This is operations that are specific to the SMES, like UI and visuals. /// Code interfacing with the powernet is handled in . /// + [RegisterComponent] public class SmesComponent : Component { public override string Name => "Smes"; diff --git a/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs index eb21642190..48051aa31d 100644 --- a/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs +++ b/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs @@ -1,14 +1,15 @@ using System.Collections.Generic; +using Content.Server.GameObjects.Components.Mobs; +using Content.Shared.GameObjects; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Physics; using Robust.Shared.Interfaces.GameObjects.Components; -using Content.Server.GameObjects.Components.Mobs; -using Content.Shared.GameObjects; +using Robust.Shared.Interfaces.Physics; namespace Content.Server.GameObjects.Components.Projectiles { + [RegisterComponent] public class ProjectileComponent : Component, ICollideSpecial, ICollideBehavior { public override string Name => "Projectile"; diff --git a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs index dd1f1198e6..4d3e716150 100644 --- a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs +++ b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs @@ -11,6 +11,7 @@ using Robust.Shared.IoC; namespace Content.Server.GameObjects.Components { + [RegisterComponent] class ThrownItemComponent : ProjectileComponent, ICollideBehavior { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Research/LatheComponent.cs b/Content.Server/GameObjects/Components/Research/LatheComponent.cs index 437a89fbd0..dad97a3d91 100644 --- a/Content.Server/GameObjects/Components/Research/LatheComponent.cs +++ b/Content.Server/GameObjects/Components/Research/LatheComponent.cs @@ -6,15 +6,16 @@ using Content.Shared.GameObjects.Components.Research; using Content.Shared.Research; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.UserInterface; -using Robust.Shared.IoC; -using Robust.Shared.Prototypes; using Robust.Shared.Timers; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Research { + [RegisterComponent] + [ComponentReference(typeof(IActivate))] public class LatheComponent : SharedLatheComponent, IAttackBy, IActivate { public const int VolumePerSheet = 3750; diff --git a/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs b/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs index f6fcb395d5..d43d5e052f 100644 --- a/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs +++ b/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using Content.Shared.GameObjects.Components.Research; using Content.Shared.Research; using Robust.Shared.GameObjects; @@ -6,6 +5,8 @@ using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Research { + [RegisterComponent] + [ComponentReference(typeof(SharedLatheDatabaseComponent))] public class LatheDatabaseComponent : SharedLatheDatabaseComponent { /// diff --git a/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs b/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs index 2d1d22f061..47c3958cd4 100644 --- a/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using Content.Shared.GameObjects.Components.Research; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.Network; using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Research { + [RegisterComponent] + [ComponentReference(typeof(SharedMaterialStorageComponent))] public class MaterialStorageComponent : SharedMaterialStorageComponent { protected override Dictionary Storage { get; set; } = new Dictionary(); diff --git a/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs b/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs index 05b6383eb5..96059435a7 100644 --- a/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs +++ b/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs @@ -1,29 +1,18 @@ -using System; -using System.Collections.Generic; -using Robust.Shared.GameObjects; -using Robust.Shared.Log; -using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; -using Content.Server.Interfaces; -using Content.Shared.GameObjects; -using Robust.Shared.Serialization; -using Robust.Shared.ViewVariables; -using Content.Server.GameObjects.EntitySystems; -using Robust.Server.GameObjects.EntitySystems; -using Content.Shared.Audio; -using Robust.Shared.Prototypes; -using Robust.Shared.IoC; +using Content.Server.GameObjects.EntitySystems; using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Sound { /// /// Simple sound emitter that emits sound on use in hand /// + [RegisterComponent] public class EmitSoundOnUseComponent : Component, IUse { /// - /// + /// public override string Name => "EmitSoundOnUse"; public string _soundName; diff --git a/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs b/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs index f7ed7e3aa4..1cf60c0bc5 100644 --- a/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs +++ b/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs @@ -1,33 +1,25 @@ using System; -using System.Collections.Generic; -using Robust.Shared.GameObjects; -using Robust.Shared.Log; -using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; -using Content.Server.Interfaces; -using Content.Shared.GameObjects; -using Robust.Shared.Serialization; -using Robust.Shared.ViewVariables; -using Content.Server.GameObjects.EntitySystems; -using Robust.Server.GameObjects.EntitySystems; using Content.Shared.Audio; -using Robust.Shared.Prototypes; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Maths; -using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Sound { /// /// Changes footstep sound /// + [RegisterComponent] public class FootstepModifierComponent : Component { #pragma warning disable 649 [Dependency] private readonly IPrototypeManager _prototypeManager; #pragma warning restore 649 /// - /// + /// private Random _footstepRandom; public override string Name => "FootstepModifier"; diff --git a/Content.Server/GameObjects/Components/Sound/SoundComponent.cs b/Content.Server/GameObjects/Components/Sound/SoundComponent.cs index 9a136031ea..975d90abbc 100644 --- a/Content.Server/GameObjects/Components/Sound/SoundComponent.cs +++ b/Content.Server/GameObjects/Components/Sound/SoundComponent.cs @@ -1,16 +1,11 @@ -using System.Collections.Generic; using Content.Shared.GameObjects.Components.Sound; -using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Audio; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; -using Robust.Shared.Log; -using Robust.Shared.Map; -using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Sound { + [RegisterComponent] public class SoundComponent : SharedSoundComponent { /// diff --git a/Content.Server/GameObjects/Components/Stack/StackComponent.cs b/Content.Server/GameObjects/Components/Stack/StackComponent.cs index c3cdc59077..40fbf6eb83 100644 --- a/Content.Server/GameObjects/Components/Stack/StackComponent.cs +++ b/Content.Server/GameObjects/Components/Stack/StackComponent.cs @@ -10,6 +10,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Stack { // TODO: Naming and presentation and such could use some improvement. + [RegisterComponent] public class StackComponent : Component, IAttackBy, IExamine { private const string SerializationCache = "stack"; diff --git a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs index 811b102a65..5ab4fbbe4b 100644 --- a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs +++ b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs @@ -1,10 +1,8 @@ -using Content.Server.Interfaces.GameObjects; -using Content.Shared.Maths; -using System; -using Robust.Shared.GameObjects; -using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; +using System; +using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; +using Content.Shared.Maths; +using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -15,6 +13,7 @@ namespace Content.Server.GameObjects /// informing others of the current temperature, /// and taking fire damage from high temperature. /// + [RegisterComponent] public class TemperatureComponent : Component, ITemperatureComponent { /// diff --git a/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs b/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs index b41bd35bbd..19d77f4ad7 100644 --- a/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs +++ b/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs @@ -1,14 +1,15 @@ using System; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Triggers; using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Serialization; -using Robust.Shared.GameObjects; -using Content.Server.GameObjects.EntitySystems; -using Content.Shared.GameObjects.Components.Triggers; namespace Content.Server.GameObjects.Components.Triggers { + [RegisterComponent] public class OnUseTimerTriggerComponent : Component, IUse { #pragma warning disable 649 @@ -28,7 +29,7 @@ namespace Content.Server.GameObjects.Components.Triggers public override void Initialize() { - base.Initialize(); + base.Initialize(); } bool IUse.UseEntity(UseEntityEventArgs eventArgs) @@ -41,4 +42,4 @@ namespace Content.Server.GameObjects.Components.Triggers return true; } } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs index e37772a956..6f9cb85961 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs @@ -1,14 +1,15 @@ -using Robust.Shared.GameObjects; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Maths; -using Robust.Server.Interfaces.GameObjects; using Robust.Shared.Serialization; -using Content.Shared.GameObjects; -using Robust.Shared.Interfaces.Map; namespace Content.Server.GameObjects.Components.Weapon.Melee { + [RegisterComponent] public class MeleeWeaponComponent : Component, IAttack { #pragma warning disable 649 diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs index 6a58ff3a46..5df47f000b 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs @@ -1,11 +1,13 @@ using System; -using Content.Shared.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Power; -using Robust.Shared.Serialization; +using Content.Shared.GameObjects.Components.Power; using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan { + [RegisterComponent] public class HitscanWeaponCapacitorComponent : PowerCellComponent { private AppearanceComponent _appearance; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs index b5cb365b9b..1d4998b3ea 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs @@ -1,6 +1,13 @@ -using Content.Shared.GameObjects; +using System; +using Content.Server.GameObjects.Components.Power; +using Content.Server.GameObjects.Components.Sound; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects; +using Content.Shared.Interfaces; +using Content.Shared.Physics; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.Audio; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.EntitySystemMessages; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Physics; @@ -10,16 +17,10 @@ using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Serialization; -using System; -using Content.Server.GameObjects.Components.Sound; -using Robust.Shared.GameObjects; -using Content.Server.GameObjects.EntitySystems; -using Content.Server.GameObjects.Components.Power; -using Content.Shared.Interfaces; -using Content.Shared.Physics; namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan { + [RegisterComponent] public class HitscanWeaponComponent : Component, IAttackBy { private const float MaxLength = 20; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs index adbacdd85a..93176615a1 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs @@ -3,6 +3,7 @@ using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile { + [RegisterComponent] public class BallisticBulletComponent : Component { public override string Name => "BallisticBullet"; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs index 4ee7e2a16a..8595fbf30b 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs @@ -11,6 +11,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile { + [RegisterComponent] public class BallisticMagazineComponent : Component, IMapInit { public override string Name => "BallisticMagazine"; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs index ff56a12062..7b6dccfe06 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs @@ -8,6 +8,7 @@ using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.Audio; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Serialization; @@ -16,6 +17,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile { + [RegisterComponent] public class BallisticMagazineWeaponComponent : BallisticWeaponComponent, IUse, IAttackBy, IMapInit { public override string Name => "BallisticMagazineWeapon"; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs index 0c82bd11cc..fe03f74eb8 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs @@ -1,18 +1,17 @@ using System; -using Robust.Shared.GameObjects; -using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Weapons.Ranged; using Robust.Server.Interfaces.Player; +using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Timers; namespace Content.Server.GameObjects.Components.Weapon.Ranged { + [RegisterComponent] public sealed class RangedWeaponComponent : SharedRangedWeaponComponent { private TimeSpan _lastFireTime; diff --git a/Content.Shared/Chemistry/Solution.cs b/Content.Shared/Chemistry/Solution.cs index ef305605fe..472503b4df 100644 --- a/Content.Shared/Chemistry/Solution.cs +++ b/Content.Shared/Chemistry/Solution.cs @@ -55,7 +55,7 @@ namespace Content.Shared.Chemistry } /// - /// Adds a given quantity of a reagent directly into the solution. + /// Adds a given quantity of a reagent directly into the solution. /// /// The prototype ID of the reagent to add. /// The quantity in milli-units. @@ -193,7 +193,7 @@ namespace Content.Shared.Chemistry return newSolution; } - + public void AddSolution(Solution otherSolution) { for (var i = 0; i < otherSolution._contents.Count; i++) @@ -232,7 +232,7 @@ namespace Content.Shared.Chemistry newSolution._contents.Add(reagent); volume += reagent.Quantity; } - + newSolution.TotalVolume = volume; return newSolution; } @@ -257,7 +257,7 @@ namespace Content.Shared.Chemistry } #region Enumeration - + public IEnumerator GetEnumerator() { return _contents.GetEnumerator(); diff --git a/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs b/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs index 2514c9cdfc..63e07d9b16 100644 --- a/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs +++ b/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs @@ -14,6 +14,7 @@ namespace Content.Shared.GameObjects.Components.Materials /// Component to store data such as "this object is made out of steel". /// This is not a storage system for say smelteries. /// + [RegisterComponent] public class MaterialComponent : Component { public const string SerializationCache = "mat"; diff --git a/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs b/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs index 536a4f573a..9d3f01becf 100644 --- a/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs @@ -7,6 +7,7 @@ namespace Content.Shared.GameObjects.Components.Mobs /// /// Component required for a player to be able to examine things. /// + [RegisterComponent] public sealed class ExaminerComponent : Component { public override string Name => "Examiner"; From a7f1520d1f0fa130b4a7e4b1b79862a809206b9a Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 16:45:54 +0200 Subject: [PATCH 27/31] Fix speech bubble UI blocking world interaction. --- Content.Client/Chat/ChatManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs index 0f923df1eb..585f61862f 100644 --- a/Content.Client/Chat/ChatManager.cs +++ b/Content.Client/Chat/ChatManager.cs @@ -81,7 +81,10 @@ namespace Content.Client.Chat { _netManager.RegisterNetMessage(MsgChatMessage.NAME, _onChatMessage); - _speechBubbleRoot = new Control(); + _speechBubbleRoot = new Control + { + MouseFilter = Control.MouseFilterMode.Ignore + }; _speechBubbleRoot.SetAnchorPreset(Control.LayoutPreset.Wide); _userInterfaceManager.StateRoot.AddChild(_speechBubbleRoot); _speechBubbleRoot.SetPositionFirst(); @@ -328,7 +331,7 @@ namespace Content.Client.Chat { // Word is STILL too long. // Truncate it with an ellipse. - messages.Add($"{word.Substring(0, SingleBubbleCharLimit-3)}..."); + messages.Add($"{word.Substring(0, SingleBubbleCharLimit - 3)}..."); currentWordLength = 0; continue; } From e95bf0a642ceaa4c4ccda5a83eb0416c8a3e6d8f Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 22:39:51 +0200 Subject: [PATCH 28/31] Fix duplicate mop definition. --- Resources/Prototypes/Entities/items/mop.yml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 Resources/Prototypes/Entities/items/mop.yml diff --git a/Resources/Prototypes/Entities/items/mop.yml b/Resources/Prototypes/Entities/items/mop.yml deleted file mode 100644 index 66e0856a06..0000000000 --- a/Resources/Prototypes/Entities/items/mop.yml +++ /dev/null @@ -1,12 +0,0 @@ -- type: entity - name: Extra-Grip Mop - parent: BaseItem - id: MopItem - description: A mop that cant be stopped, viscera cleanup detail awaits - components: - - type: Sprite - texture: Objects/mop.png - - type: Icon - texture: Objects/mop.png - - type: Item - Size: 10 From d5ec234fd3fef853b7f599e3945825adc354a9f2 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 31 Jul 2019 22:42:36 +0200 Subject: [PATCH 29/31] Ignore some client components on the server. --- Content.Server/EntryPoint.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 7d3a279492..04f1e61272 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -32,7 +32,10 @@ namespace Content.Server { "ConstructionGhost", "IconSmooth", - "SubFloorHide" + "SubFloorHide", + "LowWall", + "Window", + "CharacterInfo" }; foreach (var ignoreName in registerIgnore) From 1d9d01b355147e8a3d1cc65266bb74915e299f31 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 1 Aug 2019 00:13:49 +0200 Subject: [PATCH 30/31] Update submodule. --- Content.Client/Parallax/ParallaxManager.cs | 6 +++--- RobustToolbox | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Client/Parallax/ParallaxManager.cs b/Content.Client/Parallax/ParallaxManager.cs index 74d18d0f47..f534472456 100644 --- a/Content.Client/Parallax/ParallaxManager.cs +++ b/Content.Client/Parallax/ParallaxManager.cs @@ -3,8 +3,6 @@ using System.IO; using System.Threading.Tasks; using Content.Client.Interfaces.Parallax; using Nett; -using SixLabors.ImageSharp; -using SixLabors.Primitives; using Robust.Client.Graphics; using Robust.Client.Interfaces.ResourceManagement; using Robust.Shared.Interfaces.Configuration; @@ -12,6 +10,8 @@ using Robust.Shared.Interfaces.Log; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Utility; +using SixLabors.ImageSharp; +using SixLabors.Primitives; namespace Content.Client.Parallax { @@ -39,7 +39,7 @@ namespace Content.Client.Parallax return; } - MemoryStream configStream = null; + Stream configStream = null; string contents; TomlTable table; try diff --git a/RobustToolbox b/RobustToolbox index fa10e1c330..85a4375905 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit fa10e1c330da9613d4598154a71cfeb7bdb6dd00 +Subproject commit 85a4375905e37a218f77a54525563c4410e53305 From 151d3a36723595631401507d7c888c02af6466e2 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 31 Jul 2019 16:38:24 -0700 Subject: [PATCH 31/31] Fixed HandsGui and added an icon to access worn inventories (#279) * Fixed HandsGui children so that HandsGui is clickable * Added TextureButton for opening Storage items * Update ClientInventoryComponent.cs Fixed HandleComponentState so that it only updates the inventory when there are changes. * Implemented storage button on Inventory Adds a small button on the bottom right of Storage items when inside the inventory. When the button is pressed it opens the Storage UI. --- .../HUD/Inventory/ClientInventoryComponent.cs | 23 +++++++++++-------- .../HumanInventoryInterfaceController.cs | 15 ++++++++---- .../HUD/Inventory/InventoryButton.cs | 19 ++++++++++++--- .../Inventory/InventoryInterfaceController.cs | 8 +++++++ Content.Client/UserInterface/HandsGui.cs | 3 +++ .../Components/GUI/InventoryComponent.cs | 6 +++++ .../Items/Storage/ServerStorageComponent.cs | 16 +++++++++---- .../Inventory/SharedInventoryComponent.cs | 15 ++++++++++++ 8 files changed, 84 insertions(+), 21 deletions(-) diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs index bdaeedcc82..bc3b6c039b 100644 --- a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs +++ b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs @@ -1,7 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Content.Client.GameObjects.Components.Clothing; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Inventory; +using Content.Shared.GameObjects.Components.Storage; using Robust.Client.GameObjects; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; @@ -77,15 +80,12 @@ namespace Content.Client.GameObjects foreach (var (slot, entityUid) in cast.Entities) { - if (_slots.ContainsKey(slot)) - { - _slots.Remove(slot); - _clearSlot(slot); - } - var entity = Owner.EntityManager.GetEntity(entityUid); - _slots[slot] = entity; - _setSlot(slot, entity); + if (!_slots.ContainsKey(slot) || _slots[slot] != entity) + { + _slots[slot] = entity; + _setSlot(slot, entity); + } doneSlots.Add(slot); } @@ -139,6 +139,11 @@ namespace Content.Client.GameObjects SendNetworkMessage(equipmessage); } + public void SendOpenStorageUIMessage(Slots slot) + { + SendNetworkMessage(new OpenSlotStorageUIMessage(slot)); + } + public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null) { diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/HumanInventoryInterfaceController.cs b/Content.Client/GameObjects/Components/HUD/Inventory/HumanInventoryInterfaceController.cs index d03851c073..9b23c3ef8d 100644 --- a/Content.Client/GameObjects/Components/HUD/Inventory/HumanInventoryInterfaceController.cs +++ b/Content.Client/GameObjects/Components/HUD/Inventory/HumanInventoryInterfaceController.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using Content.Client.GameObjects.Components.Storage; using Content.Client.Utility; using JetBrains.Annotations; using Robust.Client.Interfaces.GameObjects.Components; @@ -52,9 +53,11 @@ namespace Content.Client.GameObjects void AddButton(out InventoryButton variable, Slots slot, string textureName) { var texture = _resourceCache.GetTexture($"/Textures/UserInterface/Inventory/{textureName}.png"); - variable = new InventoryButton(slot, texture) + var storageTexture = _resourceCache.GetTexture($"/Textures/UserInterface/Inventory/back.png"); + variable = new InventoryButton(slot, texture, storageTexture) { - OnPressed = AddToInventory + OnPressed = AddToInventory, + OnStoragePressed = OpenStorage }; _inventoryButtons[slot].Add(variable); } @@ -89,11 +92,13 @@ namespace Content.Client.GameObjects } entity.TryGetComponent(out ISpriteComponent sprite); + var hasInventory = entity.HasComponent(); foreach (var button in buttons) { button.SpriteView.Sprite = sprite; button.OnPressed = RemoveFromInventory; + button.StorageButton.Visible = hasInventory; } } @@ -110,6 +115,7 @@ namespace Content.Client.GameObjects { button.SpriteView.Sprite = null; button.OnPressed = AddToInventory; + button.StorageButton.Visible = false; } } @@ -152,7 +158,8 @@ namespace Content.Client.GameObjects void AddButton(Slots slot, string textureName, Vector2 position) { var texture = resourceCache.GetTexture($"/Textures/UserInterface/Inventory/{textureName}.png"); - var button = new InventoryButton(slot, texture) + var storageTexture = resourceCache.GetTexture($"/Textures/UserInterface/Inventory/back.png"); + var button = new InventoryButton(slot, texture, storageTexture) { Position = position }; diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/InventoryButton.cs b/Content.Client/GameObjects/Components/HUD/Inventory/InventoryButton.cs index ecee121d0b..1bc30aae84 100644 --- a/Content.Client/GameObjects/Components/HUD/Inventory/InventoryButton.cs +++ b/Content.Client/GameObjects/Components/HUD/Inventory/InventoryButton.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Shared.GameObjects.Components.Inventory; using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; @@ -13,10 +13,12 @@ namespace Content.Client.GameObjects public BaseButton Button { get; } public SpriteView SpriteView { get; } + public BaseButton StorageButton { get; } public Action OnPressed { get; set; } + public Action OnStoragePressed { get; set; } - public InventoryButton(EquipmentSlotDefines.Slots slot, Texture texture) + public InventoryButton(EquipmentSlotDefines.Slots slot, Texture texture, Texture storageTexture) { Slot = slot; @@ -25,7 +27,7 @@ namespace Content.Client.GameObjects AddChild(Button = new TextureButton { TextureNormal = texture, - Scale = (2, 2), + Scale = (2, 2) }); Button.OnPressed += e => OnPressed?.Invoke(e); @@ -35,6 +37,17 @@ namespace Content.Client.GameObjects MouseFilter = MouseFilterMode.Ignore, Scale = (2, 2) }); + + AddChild(StorageButton = new TextureButton + { + TextureNormal = storageTexture, + Scale = (0.75f, 0.75f), + SizeFlagsHorizontal = SizeFlags.ShrinkEnd, + SizeFlagsVertical = SizeFlags.ShrinkEnd, + Visible = false + }); + + StorageButton.OnPressed += e => OnStoragePressed?.Invoke(e); } } } diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/InventoryInterfaceController.cs b/Content.Client/GameObjects/Components/HUD/Inventory/InventoryInterfaceController.cs index 9a6187e01c..d085df42de 100644 --- a/Content.Client/GameObjects/Components/HUD/Inventory/InventoryInterfaceController.cs +++ b/Content.Client/GameObjects/Components/HUD/Inventory/InventoryInterfaceController.cs @@ -75,5 +75,13 @@ namespace Content.Client.GameObjects Owner.SendEquipMessage(control.Slot); } + + protected void OpenStorage(BaseButton.ButtonEventArgs args) + { + args.Button.Pressed = false; + var control = (InventoryButton)args.Button.Parent; + + Owner.SendOpenStorageUIMessage(control.Slot); + } } } diff --git a/Content.Client/UserInterface/HandsGui.cs b/Content.Client/UserInterface/HandsGui.cs index 7d54b88c55..7a3dfbbf56 100644 --- a/Content.Client/UserInterface/HandsGui.cs +++ b/Content.Client/UserInterface/HandsGui.cs @@ -60,6 +60,7 @@ namespace Content.Client.UserInterface AddChild(new TextureRect { + MouseFilter = MouseFilterMode.Ignore, Texture = TextureHandLeft, Size = _handL.Size, Position = _handL.TopLeft, @@ -68,6 +69,7 @@ namespace Content.Client.UserInterface AddChild(new TextureRect { + MouseFilter = MouseFilterMode.Ignore, Texture = TextureHandRight, Size = _handR.Size, Position = _handR.TopLeft, @@ -76,6 +78,7 @@ namespace Content.Client.UserInterface AddChild(ActiveHandRect = new TextureRect { + MouseFilter = MouseFilterMode.Ignore, Texture = TextureHandActive, Size = _handL.Size, Position = _handL.TopLeft, diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 54b01700b3..0f71bd3b92 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -263,6 +263,12 @@ namespace Content.Server.GameObjects if (playerentity == Owner) HandleInventoryMessage(msg); break; + case OpenSlotStorageUIMessage msg: + ItemComponent item = GetSlotItem(msg.Slot); + ServerStorageComponent storage; + if (item.Owner.TryGetComponent(out storage)) + storage.OpenStorageUI(Owner); + break; } } diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index f03d04cf91..b50a8b9ff4 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -34,6 +34,7 @@ namespace Content.Server.GameObjects [Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IPlayerManager _playerManager; [Dependency] private readonly IEntityManager _entityManager; + [Dependency] private readonly IEntitySystemManager _entitySystemManager; #pragma warning restore 649 private Container storage; @@ -174,12 +175,18 @@ namespace Content.Server.GameObjects bool IUse.UseEntity(UseEntityEventArgs eventArgs) { _ensureInitialCalculated(); - var user_session = eventArgs.User.GetComponent().playerSession; + OpenStorageUI(eventArgs.User); + return false; + } + + public void OpenStorageUI(IEntity Character) + { + _ensureInitialCalculated(); + var user_session = Character.GetComponent().playerSession; Logger.DebugS("Storage", "Storage (UID {0}) \"used\" by player session (UID {1}).", Owner.Uid, user_session.AttachedEntityUid); SubscribeSession(user_session); SendNetworkMessage(new OpenStorageUIMessage(), user_session.ConnectedClient); UpdateClientInventory(user_session); - return false; } /// @@ -301,16 +308,15 @@ namespace Content.Server.GameObjects entity.GetComponent().WorldPosition = ourtransform.WorldPosition; } } - } break; - + } case CloseStorageUIMessage _: { var session = _playerManager.GetSessionByChannel(netChannel); UnsubscribeSession(session); - } break; + } } } diff --git a/Content.Shared/GameObjects/Components/Inventory/SharedInventoryComponent.cs b/Content.Shared/GameObjects/Components/Inventory/SharedInventoryComponent.cs index ac97f9a54d..6464f2fbe8 100644 --- a/Content.Shared/GameObjects/Components/Inventory/SharedInventoryComponent.cs +++ b/Content.Shared/GameObjects/Components/Inventory/SharedInventoryComponent.cs @@ -78,5 +78,20 @@ namespace Content.Shared.GameObjects Unequip = 1 } } + + /// + /// Component message for opening the Storage UI of item in Slot + /// + [Serializable, NetSerializable] + public class OpenSlotStorageUIMessage : ComponentMessage + { + public Slots Slot; + + public OpenSlotStorageUIMessage(Slots slot) + { + Directed = true; + Slot = slot; + } + } } }