Resolves ApcVisualizer is Obsolete (#13898)

This commit is contained in:
TemporalOroboros
2023-05-07 19:17:29 -07:00
committed by GitHub
parent 3581db962c
commit 0658acd7cb
30 changed files with 490 additions and 185 deletions

View File

@@ -1,45 +0,0 @@
using Content.Shared.APC;
using Robust.Client.GameObjects;
namespace Content.Client.Power.APC
{
public sealed class ApcVisualizer : AppearanceVisualizer
{
public static readonly Color LackColor = Color.FromHex("#d1332e");
public static readonly Color ChargingColor = Color.FromHex("#2e8ad1");
public static readonly Color FullColor = Color.FromHex("#3db83b");
public static readonly Color EmagColor = Color.FromHex("#1f48d6");
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var ent = IoCManager.Resolve<IEntityManager>();
var sprite = ent.GetComponent<SpriteComponent>(component.Owner);
if (component.TryGetData<ApcChargeState>(ApcVisuals.ChargeState, out var chargeState))
{
if (ent.TryGetComponent(component.Owner, out SharedPointLightComponent? light))
{
light.Color = chargeState switch
{
ApcChargeState.Lack => LackColor,
ApcChargeState.Charging => ChargingColor,
ApcChargeState.Full => FullColor,
ApcChargeState.Emag => EmagColor,
_ => LackColor
};
}
}
}
enum ApcVisualLayers : byte
{
ChargeState,
Lock,
Equipment,
Lighting,
Environment,
}
}
}

View File

@@ -0,0 +1,107 @@
using Content.Shared.APC;
namespace Content.Client.Power.APC;
[RegisterComponent]
[Access(typeof(ApcVisualizerSystem))]
public sealed class ApcVisualsComponent : Component
{
#region Indicators
#region Locks
/// <summary>
/// The number of lock indicators on the APC.
/// </summary>
[DataField("numLockIndicators")]
[ViewVariables(VVAccess.ReadWrite)]
public byte LockIndicators = 2;
/// <summary>
/// The prefix used for the sprite state suffix of the lock indicator lights.
/// Valid states are of the form \<BASE\>\<PREFIX\>\<IDX>\-\<STATE\>
/// </summary>
[DataField("lockIndicatorPrefix")]
[ViewVariables(VVAccess.ReadWrite)]
public string LockPrefix = "lock";
/// <summary>
/// The suffixes used for the sprite state suffix of the lock indicator lights.
/// Valid states are of the form \<PREFIX\>\<IDX\>-\<STATE\>
/// </summary>
[DataField("lockIndicatorSuffixes")]
[ViewVariables(VVAccess.ReadWrite)]
public string[] LockSuffixes = new string[(byte)(2 << (sbyte)ApcLockState.LogWidth)]{"unlocked", "locked"};
#endregion Locks
#region Channels
/// <summary>
/// The number of output channel indicator lights on the APC.
/// </summary>
[DataField("numChannelIndicators")]
[ViewVariables(VVAccess.ReadWrite)]
public byte ChannelIndicators = 3;
/// <summary>
/// The prefix used for the sprite state suffix of the channel indicator lights.
/// Valid states are of the form \<BASE\>\<PREFIX\>\<IDX\>-\<STATE\>
/// </summary>
[DataField("channelIndicatorPrefix")]
[ViewVariables(VVAccess.ReadWrite)]
public string ChannelPrefix = "channel";
/// <summary>
/// The suffixes used for the sprite state suffix of the channel indicator lights.
/// Valid states are of the form \<PREFIX\>\<IDX\>-\<STATE\>
/// </summary>
[DataField("channelIndicatorSuffixes")]
[ViewVariables(VVAccess.ReadWrite)]
public string[] ChannelSuffixes = new string[(byte)(2 << (sbyte)ApcChannelState.LogWidth)]{"auto_off", "manual_off", "auto_on", "manual_on"};
#endregion Channels
#endregion Indicators
#region Screen
/// <summary>
/// The prefix used to construct the sprite state suffix used for the screen overlay.
/// Valid sprite states are of the form \<PREFIX\>-\<SUFFIX\>.
/// </summary>
[DataField("screenStatePrefix")]
[ViewVariables(VVAccess.ReadWrite)]
public string ScreenPrefix = "display";
/// <summary>
/// The suffix used to construct the sprite state suffix used for the screen overlay.
/// Valid sprite states are of the form \<PREFIX\>-\<STATE\>.
/// </summary>
[DataField("screenStateSuffixes")]
[ViewVariables(VVAccess.ReadWrite)]
public string[] ScreenSuffixes = new string[(byte)ApcChargeState.NumStates]{"lack", "charging", "full", "remote"};
/// <summary>
/// The colors of the light emitted by the APC given a particular display state.
/// </summary>
[DataField("screenColors")]
[ViewVariables(VVAccess.ReadWrite)]
public Color[] ScreenColors = new Color[(byte)ApcChargeState.NumStates]{Color.FromHex("#d1332e"), Color.FromHex("#2e8ad1"), Color.FromHex("#3db83b"), Color.FromHex("#ffac1c")};
/// <summary>
/// The sprite state of the unlit overlay used for the APC screen when the APC has been emagged.
/// </summary>
[DataField("emaggedScreenState")]
[ViewVariables(VVAccess.ReadWrite)]
public string EmaggedScreenState = "emag-unlit";
/// <summary>
/// The sprite state of the unlit overlay used for the APC screen when the APC has been emagged.
/// </summary>
[DataField("emaggedScreenColor")]
[ViewVariables(VVAccess.ReadWrite)]
public Color EmaggedScreenColor = Color.FromHex("#1f48d6");
#endregion Screen
}

View File

@@ -0,0 +1,106 @@
using Content.Shared.APC;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Power.APC;
public sealed class ApcVisualizerSystem : VisualizerSystem<ApcVisualsComponent>
{
protected override void OnAppearanceChange(EntityUid uid, ApcVisualsComponent comp, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
// Handle APC screen overlay:
if(!AppearanceSystem.TryGetData<ApcChargeState>(uid, ApcVisuals.ChargeState, out var chargeState, args.Component))
chargeState = ApcChargeState.Lack;
if (chargeState >= 0 && chargeState < ApcChargeState.NumStates)
{
args.Sprite.LayerSetState(ApcVisualLayers.ChargeState, $"{comp.ScreenPrefix}-{comp.ScreenSuffixes[(sbyte)chargeState]}");
// LockState does nothing currently. The backend doesn't exist.
if (AppearanceSystem.TryGetData<byte>(uid, ApcVisuals.LockState, out var lockStates, args.Component))
{
for(var i = 0; i < comp.LockIndicators; ++i)
{
var layer = ((byte)ApcVisualLayers.LockIndicatorOverlayStart + i);
sbyte lockState = (sbyte)((lockStates >> (i << (sbyte)ApcLockState.LogWidth)) & (sbyte)ApcLockState.All);
args.Sprite.LayerSetState(layer, $"{comp.LockPrefix}{i}-{comp.LockSuffixes[lockState]}");
args.Sprite.LayerSetVisible(layer, true);
}
}
// ChannelState does nothing currently. The backend doesn't exist.
if (AppearanceSystem.TryGetData<byte>(uid, ApcVisuals.ChannelState, out var channelStates, args.Component))
{
for(var i = 0; i < comp.ChannelIndicators; ++i)
{
var layer = ((byte)ApcVisualLayers.ChannelIndicatorOverlayStart + i);
sbyte channelState = (sbyte)((channelStates >> (i << (sbyte)ApcChannelState.LogWidth)) & (sbyte)ApcChannelState.All);
args.Sprite.LayerSetState(layer, $"{comp.ChannelPrefix}{i}-{comp.ChannelSuffixes[channelState]}");
args.Sprite.LayerSetVisible(layer, true);
}
}
if (TryComp<SharedPointLightComponent>(uid, out var light))
light.Color = comp.ScreenColors[(sbyte)chargeState];
}
else
{
/// Overrides all of the lock and channel indicators.
args.Sprite.LayerSetState(ApcVisualLayers.ChargeState, comp.EmaggedScreenState);
for(var i = 0; i < comp.LockIndicators; ++i)
{
var layer = ((byte)ApcVisualLayers.LockIndicatorOverlayStart + i);
args.Sprite.LayerSetVisible(layer, false);
}
for(var i = 0; i < comp.ChannelIndicators; ++i)
{
var layer = ((byte)ApcVisualLayers.ChannelIndicatorOverlayStart + i);
args.Sprite.LayerSetVisible(layer, false);
}
if (TryComp<SharedPointLightComponent>(uid, out var light))
light.Color = comp.EmaggedScreenColor;
}
}
}
enum ApcVisualLayers : byte
{
/// <summary>
/// The sprite layer used for the interface lock indicator light overlay.
/// </summary>
InterfaceLock = 0,
/// <summary>
/// The sprite layer used for the panel lock indicator light overlay.
/// </summary>
PanelLock = 1,
/// <summary>
/// The first of the lock indicator light layers.
/// </summary>
LockIndicatorOverlayStart = InterfaceLock,
/// <summary>
/// The sprite layer used for the equipment channel indicator light overlay.
/// </summary>
Equipment = 2,
/// <summary>
/// The sprite layer used for the lighting channel indicator light overlay.
/// </summary>
Lighting = 3,
/// <summary>
/// The sprite layer used for the environment channel indicator light overlay.
/// </summary>
Environment = 4,
/// <summary>
/// The first of the channel status indicator light layers.
/// </summary>
ChannelIndicatorOverlayStart = Equipment,
/// <summary>
/// The sprite layer used for the APC screen overlay.
/// </summary>
ChargeState = 5,
}