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.Map; using Robust.Shared.Serialization; using static Robust.Client.GameObjects.SpriteComponent; namespace Content.Client.GameObjects.Components.IconSmoothing { // TODO: Potential improvements: // Defer updating of these. // Get told by somebody to use a loop. /// /// Makes sprites of other grid-aligned entities like us connect. /// /// /// The system is based on Baystation12's smoothwalling, and thus will work with those. /// 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 { private string _smoothKey; private string _stateBase; private IconSmoothingMode _mode; public override string Name => "IconSmooth"; 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. /// public string SmoothKey => _smoothKey; /// /// 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(); SnapGrid = Owner.GetComponent(); Sprite = Owner.GetComponent(); } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); 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 += 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(); } private void SnapGridOnPositionChanged() { Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode)); _lastPosition = (Owner.Transform.GridID, SnapGrid.Position); } [SuppressMessage("ReSharper", "InconsistentNaming")] public enum CornerLayers { SE, NE, NW, SW, } } /// /// 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, } }