Eris low walls & windows.

Still needs work blocked by better entity parenting, but oh well.
This commit is contained in:
Pieter-Jan Briers
2019-07-26 13:53:06 +02:00
parent a162564516
commit d906bcda03
54 changed files with 575 additions and 156 deletions

View File

@@ -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 <c>base</c> equal to the prefix of the corner states in the sprite base RSI.
/// Any objects with the same <c>key</c> will connect.
/// </remarks>
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<IEntity> 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
{

View File

@@ -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.
/// <summary>
/// Override of icon smoothing to handle the specific complexities of low walls.
/// </summary>
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<IEntity> 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,
}
}
}

View File

@@ -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<ISpriteComponent>();
_snapGrid = Owner.GetComponent<SnapGridComponent>();
}
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);
}
}
}