diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index 24f52e8351..7e484e6eee 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -90,6 +90,7 @@ + diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 6b9bcbdcd4..ac22770bb2 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -3,7 +3,7 @@ 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.SmoothWalling; +using Content.Client.GameObjects.Components.IconSmoothing; using Content.Client.GameObjects.Components.Storage; using Content.Client.GameObjects.Components.Weapons.Ranged; using Content.Client.GameTicking; diff --git a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs index 18db2fb3e2..e416f4d69c 100644 --- a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs +++ b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs @@ -1,18 +1,14 @@ -using System; -using System.Collections.Generic; -using Content.Shared.GameObjects; +using System.Diagnostics.CodeAnalysis; +using Content.Client.GameObjects.EntitySystems; +using JetBrains.Annotations; using SS14.Client.Interfaces.GameObjects.Components; using SS14.Shared.GameObjects; using SS14.Shared.GameObjects.Components.Transform; -using SS14.Shared.Interfaces.GameObjects; -using SS14.Shared.Interfaces.Map; -using SS14.Shared.IoC; using SS14.Shared.Map; -using SS14.Shared.Maths; using SS14.Shared.Serialization; using static SS14.Client.GameObjects.SpriteComponent; -namespace Content.Client.GameObjects.Components.SmoothWalling +namespace Content.Client.GameObjects.Components.IconSmoothing { // TODO: Potential improvements: // Defer updating of these. @@ -25,212 +21,115 @@ namespace Content.Client.GameObjects.Components.SmoothWalling /// 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 class IconSmoothComponent : Component, IComponentDebug + public sealed class IconSmoothComponent : Component { + private string _smoothKey; + private string _stateBase; + private IconSmoothingMode _mode; + public override string Name => "IconSmooth"; - ISpriteComponent Sprite; - SnapGridComponent SnapGrid; - - /// - /// Prepended to the RSI state. - /// - string StateBase; + internal ISpriteComponent Sprite { get; private set; } + internal SnapGridComponent SnapGrid { get; private set; } + private (GridId, MapIndices) _lastPosition; /// /// We will smooth with other objects with the same key. /// - string SmoothKey; + public string SmoothKey => _smoothKey; - IconSmoothComponent[] Neighbors = new IconSmoothComponent[8]; - // "Use an array". - // Nah. I'm too lazy. This is easy to understand compared to the enum value fuckery if I used an array. - // Deal with it. - CornerFill CornerSE; - CornerFill CornerNE; - CornerFill CornerNW; - CornerFill CornerSW; + /// + /// Prepended to the RSI state. + /// + public string StateBase => _stateBase; + + /// + /// Mode that controls how the icon should be selected. + /// + public IconSmoothingMode Mode => _mode; + + /// + /// Used by to reduce redundant updates. + /// + internal int UpdateGeneration { get; set; } public override void Initialize() { base.Initialize(); - var state0 = $"{StateBase}0"; SnapGrid = Owner.GetComponent(); Sprite = Owner.GetComponent(); - Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0)); - Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None); - Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0)); - Sprite.LayerSetDirOffset(CornerLayers.NE, DirectionOffset.CounterClockwise); - Sprite.LayerMapSet(CornerLayers.NW, Sprite.AddLayerState(state0)); - Sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip); - Sprite.LayerMapSet(CornerLayers.SW, Sprite.AddLayerState(state0)); - Sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise); } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); - serializer.DataFieldCached(ref StateBase, "base", ""); - serializer.DataFieldCached(ref SmoothKey, "key", null); + + serializer.DataFieldCached(ref _stateBase, "base", ""); + serializer.DataFieldCached(ref _smoothKey, "key", null); + serializer.DataFieldCached(ref _mode, "mode", IconSmoothingMode.Corners); } public override void Startup() { base.Startup(); - SnapGrid.OnPositionChanged += SnapGridPositionChanged; - - UpdateConnections(true); - UpdateIcon(); + SnapGrid.OnPositionChanged += SnapGridOnPositionChanged; + Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode)); + var state0 = $"{StateBase}0"; + if (Mode == IconSmoothingMode.Corners) + { + Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0)); + Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None); + Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0)); + Sprite.LayerSetDirOffset(CornerLayers.NE, DirectionOffset.CounterClockwise); + Sprite.LayerMapSet(CornerLayers.NW, Sprite.AddLayerState(state0)); + Sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip); + Sprite.LayerMapSet(CornerLayers.SW, Sprite.AddLayerState(state0)); + Sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise); + } } public override void Shutdown() { + SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged; + Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode)); + base.Shutdown(); - - SnapGrid.OnPositionChanged -= SnapGridPositionChanged; - SayGoodbyes(); } - void SayGoodbyes() + private void SnapGridOnPositionChanged() { - foreach (var neighbor in Neighbors) - { - // Goodbye neighbor. - neighbor?.UpdateConnections(false); - neighbor?.UpdateIcon(); - } + Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode)); + _lastPosition = (Owner.Transform.GridID, SnapGrid.Position); } - void SnapGridPositionChanged() - { - SayGoodbyes(); - UpdateConnections(true); - UpdateIcon(); - } - - void UpdateIcon() - { - // Try to turn this into a loop without hard to understand bit fuckery or 20 lines of helper functions. - // Challenge: do it in less lines. - // I dare you. - // No cheating like putting everything on a single line. Proper code conventions. - // This comment does not count, btw. - - 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}"); - } - - void UpdateConnections(bool propagate) - { - for (int i = 0; i < Neighbors.Length; i++) - { - var found = false; - var dir = (Direction)i; - foreach (var entity in SnapGrid.GetInDir(dir)) - { - if (entity.TryGetComponent(out IconSmoothComponent smooth) && smooth.SmoothKey == SmoothKey) - { - Neighbors[i] = smooth; - if (propagate) - { - smooth.UpdateConnections(false); - smooth.UpdateIcon(); - } - // Temptation to use goto: 10. - found = true; - break; - } - } - - if (!found) - { - Neighbors[i] = null; - } - } - - CornerNE = CornerSE = CornerNW = CornerSW = CornerFill.None; - - // "Use a loop". - // Well screw that I did the exact same thing while writing lighting corner population code in BYOND. - // This is 10x easier to understand and write than a complex loop working with the internet mapping of direction flags. - if (Neighbors[(int)Direction.North] != null) - { - CornerNE |= CornerFill.CounterClockwise; - CornerNW |= CornerFill.Clockwise; - } - if (Neighbors[(int)Direction.NorthEast] != null) - { - CornerNE |= CornerFill.Diagonal; - } - if (Neighbors[(int)Direction.East] != null) - { - CornerNE |= CornerFill.Clockwise; - CornerSE |= CornerFill.CounterClockwise; - } - if (Neighbors[(int)Direction.SouthEast] != null) - { - CornerSE |= CornerFill.Diagonal; - } - if (Neighbors[(int)Direction.South] != null) - { - CornerSE |= CornerFill.Clockwise; - CornerSW |= CornerFill.CounterClockwise; - } - if (Neighbors[(int)Direction.SouthWest] != null) - { - CornerSW |= CornerFill.Diagonal; - } - if (Neighbors[(int)Direction.West] != null) - { - CornerSW |= CornerFill.Clockwise; - CornerNW |= CornerFill.CounterClockwise; - } - if (Neighbors[(int)Direction.NorthWest] != null) - { - CornerNW |= CornerFill.Diagonal; - } - } - - public string GetDebugString() - { - return string.Format( - "N/NE/E/SE/S/SW/W/NW: {0}/{1}/{2}/{3}/{4}/{5}/{6}/{7} cfill NE/SE/SW/NW: {8}/{9}/{10}/{11}", - Neighbors[(int)Direction.North]?.Owner?.Uid, - Neighbors[(int)Direction.NorthEast]?.Owner?.Uid, - Neighbors[(int)Direction.East]?.Owner?.Uid, - Neighbors[(int)Direction.SouthEast]?.Owner?.Uid, - Neighbors[(int)Direction.South]?.Owner?.Uid, - Neighbors[(int)Direction.SouthWest]?.Owner?.Uid, - Neighbors[(int)Direction.West]?.Owner?.Uid, - Neighbors[(int)Direction.NorthWest]?.Owner?.Uid, - CornerNE, CornerSE, CornerSW, CornerNW - ); - } - - enum CornerLayers + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum CornerLayers { SE, NE, NW, SW, } + } - [Flags] - 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, - } + /// + /// Controls the mode with which icon smoothing is calculated. + /// + [PublicAPI] + public enum IconSmoothingMode + { + /// + /// Each icon is made up of 4 corners, each of which can get a different state depending on + /// adjacent entities clockwise, counter-clockwise and diagonal with the corner. + /// + Corners, + + /// + /// There are 16 icons, only one of which is used at once. + /// The icon selected is a bit field made up of the cardinal direction flags that have adjacent entities. + /// + CardinalFlags, } } diff --git a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs new file mode 100644 index 0000000000..77aa222196 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Content.Client.GameObjects.Components.IconSmoothing; +using JetBrains.Annotations; +using SS14.Client.Interfaces.GameObjects.Components; +using SS14.Shared.GameObjects; +using SS14.Shared.GameObjects.Components.Transform; +using SS14.Shared.GameObjects.Systems; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.Interfaces.Map; +using SS14.Shared.IoC; +using SS14.Shared.Map; +using SS14.Shared.Maths; + +namespace Content.Client.GameObjects.EntitySystems +{ + /// + /// Entity system implementing the logic for + /// + [UsedImplicitly] + internal sealed class IconSmoothSystem : EntitySystem + { +#pragma warning disable 649 + [Dependency] private readonly IMapManager _mapManager; +#pragma warning restore 649 + + private readonly Queue _dirtyEntities = new Queue(); + + private int _generation; + + public override void SubscribeEvents() + { + base.SubscribeEvents(); + + SubscribeEvent(HandleDirtyEvent); + } + + public override void Initialize() + { + base.Initialize(); + + IoCManager.InjectDependencies(this); + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + if (_dirtyEntities.Count == 0) + { + return; + } + + _generation += 1; + + // Performance: This could be spread over multiple updates, or made parallel. + while (_dirtyEntities.Count > 0) + { + CalculateNewSprite(_dirtyEntities.Dequeue()); + } + } + + private void HandleDirtyEvent(object sender, IconSmoothDirtyEvent ev) + { + // Yes, we updates ALL smoothing entities surrounding us even if they would never smooth with us. + // This is simpler to implement. If you want to optimize it be my guest. + if (sender is IEntity senderEnt && senderEnt.IsValid() && + senderEnt.HasComponent()) + { + var snapGrid = senderEnt.GetComponent(); + + _dirtyEntities.Enqueue(senderEnt); + AddValidEntities(snapGrid.GetInDir(Direction.North)); + AddValidEntities(snapGrid.GetInDir(Direction.South)); + AddValidEntities(snapGrid.GetInDir(Direction.East)); + AddValidEntities(snapGrid.GetInDir(Direction.West)); + if (ev.Mode == IconSmoothingMode.Corners) + { + + AddValidEntities(snapGrid.GetInDir(Direction.NorthEast)); + AddValidEntities(snapGrid.GetInDir(Direction.SouthEast)); + AddValidEntities(snapGrid.GetInDir(Direction.SouthWest)); + AddValidEntities(snapGrid.GetInDir(Direction.NorthWest)); + } + } + else if (ev.LastPosition.HasValue) + { + // Entity is no longer valid, update around the last position it was at. + var grid = _mapManager.GetGrid(ev.LastPosition.Value.grid); + var pos = ev.LastPosition.Value.pos; + + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 0), ev.Offset)); + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, 0), ev.Offset)); + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(0, 1), ev.Offset)); + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(0, -1), ev.Offset)); + if (ev.Mode == IconSmoothingMode.Corners) + { + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 1), ev.Offset)); + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, -1), ev.Offset)); + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, 1), ev.Offset)); + AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, -1), ev.Offset)); + } + } + } + + private void AddValidEntities(IEnumerable candidates) + { + foreach (var entity in candidates) + { + if (entity.HasComponent()) + { + _dirtyEntities.Enqueue(entity); + } + } + } + + private void AddValidEntities(IEnumerable candidates) + { + AddValidEntities(candidates.Select(c => c.Owner)); + } + + private void CalculateNewSprite(IEntity entity) + { + // The generation check prevents updating an entity multiple times per tick. + // As it stands now, it's totally possible for something to get queued twice. + // Generation on the component is set after an update so we can cull updates that happened this generation. + if (!entity.IsValid() + || !entity.TryGetComponent(out IconSmoothComponent smoothing) + || smoothing.UpdateGeneration == _generation) + { + 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.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, + } + } + + /// + /// Event raised by a when it needs to be recalculated. + /// + public sealed class IconSmoothDirtyEvent : EntitySystemMessage + { + public IconSmoothDirtyEvent((GridId grid, MapIndices pos)? lastPosition, SnapGridOffset offset, IconSmoothingMode mode) + { + LastPosition = lastPosition; + Offset = offset; + Mode = mode; + } + + public (GridId grid, MapIndices pos)? LastPosition { get; } + public SnapGridOffset Offset { get; } + public IconSmoothingMode Mode { get; } + } +} diff --git a/Resources/Prototypes/Entities/Power.yml b/Resources/Prototypes/Entities/Power.yml index e9a96b26f7..7487ddadd2 100644 --- a/Resources/Prototypes/Entities/Power.yml +++ b/Resources/Prototypes/Entities/Power.yml @@ -6,12 +6,20 @@ - type: Clickable - type: BoundingBox - type: Sprite + netsync: false drawdepth: BelowFloor color: Red - texture: Objects/eightdirwire.png + sprite: Objects/power_cable.rsi + state: cable_0 - type: Icon texture: Objects/eightdirwire.png - type: PowerTransfer + - type: SnapGrid + offset: Center + - type: IconSmooth + base: cable_ + key: power_cables + mode: CardinalFlags snap: - Wire diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_0.png b/Resources/Textures/Objects/power_cable.rsi/cable_0.png new file mode 100644 index 0000000000..580528df53 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_0.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_1.png b/Resources/Textures/Objects/power_cable.rsi/cable_1.png new file mode 100644 index 0000000000..fdebed5fa9 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_1.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_10.png b/Resources/Textures/Objects/power_cable.rsi/cable_10.png new file mode 100644 index 0000000000..17c40b2276 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_10.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_11.png b/Resources/Textures/Objects/power_cable.rsi/cable_11.png new file mode 100644 index 0000000000..76b20ffa8d Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_11.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_12.png b/Resources/Textures/Objects/power_cable.rsi/cable_12.png new file mode 100644 index 0000000000..8364d69509 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_12.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_13.png b/Resources/Textures/Objects/power_cable.rsi/cable_13.png new file mode 100644 index 0000000000..6f03458fd3 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_13.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_14.png b/Resources/Textures/Objects/power_cable.rsi/cable_14.png new file mode 100644 index 0000000000..6cdb9d20bc Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_14.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_15.png b/Resources/Textures/Objects/power_cable.rsi/cable_15.png new file mode 100644 index 0000000000..d45a733324 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_15.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_2.png b/Resources/Textures/Objects/power_cable.rsi/cable_2.png new file mode 100644 index 0000000000..ce3ffea8a4 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_2.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_3.png b/Resources/Textures/Objects/power_cable.rsi/cable_3.png new file mode 100644 index 0000000000..2edb689b55 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_3.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_4.png b/Resources/Textures/Objects/power_cable.rsi/cable_4.png new file mode 100644 index 0000000000..fb782f3cad Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_4.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_5.png b/Resources/Textures/Objects/power_cable.rsi/cable_5.png new file mode 100644 index 0000000000..6e0ffe9db5 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_5.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_6.png b/Resources/Textures/Objects/power_cable.rsi/cable_6.png new file mode 100644 index 0000000000..2d855fe035 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_6.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_7.png b/Resources/Textures/Objects/power_cable.rsi/cable_7.png new file mode 100644 index 0000000000..e382deeda1 Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_7.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_8.png b/Resources/Textures/Objects/power_cable.rsi/cable_8.png new file mode 100644 index 0000000000..408fdf51ea Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_8.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_9.png b/Resources/Textures/Objects/power_cable.rsi/cable_9.png new file mode 100644 index 0000000000..2b988d3ffe Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_9.png differ diff --git a/Resources/Textures/Objects/power_cable.rsi/meta.json b/Resources/Textures/Objects/power_cable.rsi/meta.json new file mode 100644 index 0000000000..7e3b1a9d68 --- /dev/null +++ b/Resources/Textures/Objects/power_cable.rsi/meta.json @@ -0,0 +1,73 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "cable_0", + "directions": 1 + }, + { + "name": "cable_1", + "directions": 1 + }, + { + "name": "cable_2", + "directions": 1 + }, + { + "name": "cable_3", + "directions": 1 + }, + { + "name": "cable_4", + "directions": 1 + }, + { + "name": "cable_5", + "directions": 1 + }, + { + "name": "cable_6", + "directions": 1 + }, + { + "name": "cable_7", + "directions": 1 + }, + { + "name": "cable_8", + "directions": 1 + }, + { + "name": "cable_9", + "directions": 1 + }, + { + "name": "cable_10", + "directions": 1 + }, + { + "name": "cable_11", + "directions": 1 + }, + { + "name": "cable_12", + "directions": 1 + }, + { + "name": "cable_13", + "directions": 1 + }, + { + "name": "cable_14", + "directions": 1 + }, + { + "name": "cable_15", + "directions": 1 + }, + ] +}