Decouple Lights from Toggleable Visuals (and headphone music notes bugfix) (#35341)
* - Combine enum keys `ToggleableLightVisuals` and `ToggleVisuals` into `ToggleableVisuals` - Rename `ToggleableLightVisualsComponent` to `ToggleableVisualsComponent` and `ToggleableLightVisualsSystem` to `ToggleableVisualsSystem` - (The `SpriteLayer` field on the component is now required because the old default of `light` doesn't make sense anymore) - Make it so that `ToggleableVisualsComponent` works even when there's not a light attached to the entity - (Amazingly this seems to have only applied to Headphones, but I can only imagine there are many other things people would like to do with simple toggleable visuals) - Explicitly make `ItemTogglePointLightComponent`'s purpose to make `ToggleVisualsComponent` apply to `PointLightComponent`s on the same entity. - Add field `ToggleableVisualsColorModulatesLights`, which makes the `Color` appearance value of `ToggleableVisuals` modulate the color of lights on the same entity - Lots of prototype updates to uptake the above * fix bad merge * unbork robust * blindly letting rider reformat stuff * I guess I never cleaned up these imports at all
This commit is contained in:
140
Content.Client/Toggleable/ToggleableVisualsSystem.cs
Normal file
140
Content.Client/Toggleable/ToggleableVisualsSystem.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Clothing;
|
||||
using Content.Client.Items.Systems;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Light.Components;
|
||||
using Content.Shared.Toggleable;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Toggleable;
|
||||
|
||||
/// <summary>
|
||||
/// Implements the behavior of <see cref="ToggleableVisualsComponent"/> by reacting to
|
||||
/// <see cref="AppearanceChangeEvent"/>, for the sprite directly; <see cref="OnGetHeldVisuals"/> for the
|
||||
/// in-hand visuals; and <see cref="OnGetEquipmentVisuals"/> for the clothing visuals.
|
||||
/// </summary>
|
||||
/// <see cref="ToggleableVisualsComponent"/>
|
||||
public sealed class ToggleableVisualsSystem : VisualizerSystem<ToggleableVisualsComponent>
|
||||
{
|
||||
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||
[Dependency] private readonly SharedPointLightSystem _pointLight = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ToggleableVisualsComponent, GetInhandVisualsEvent>(OnGetHeldVisuals,
|
||||
after: [typeof(ItemSystem)]);
|
||||
SubscribeLocalEvent<ToggleableVisualsComponent, GetEquipmentVisualsEvent>(OnGetEquipmentVisuals,
|
||||
after: [typeof(ClientClothingSystem)]);
|
||||
}
|
||||
|
||||
protected override void OnAppearanceChange(EntityUid uid,
|
||||
ToggleableVisualsComponent component,
|
||||
ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!AppearanceSystem.TryGetData<bool>(uid, ToggleableVisuals.Enabled, out var enabled, args.Component))
|
||||
return;
|
||||
|
||||
var modulateColor =
|
||||
AppearanceSystem.TryGetData<Color>(uid, ToggleableVisuals.Color, out var color, args.Component);
|
||||
|
||||
// Update the item's sprite
|
||||
if (args.Sprite != null && component.SpriteLayer != null &&
|
||||
SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.SpriteLayer, out var layer, false))
|
||||
{
|
||||
SpriteSystem.LayerSetVisible((uid, args.Sprite), layer, enabled);
|
||||
if (modulateColor)
|
||||
SpriteSystem.LayerSetColor((uid, args.Sprite), component.SpriteLayer, color);
|
||||
}
|
||||
|
||||
// If there's a `ItemTogglePointLightComponent` that says to apply the color to attached lights, do so.
|
||||
if (TryComp<ItemTogglePointLightComponent>(uid, out var toggleLights) &&
|
||||
TryComp(uid, out PointLightComponent? light))
|
||||
{
|
||||
DebugTools.Assert(!light.NetSyncEnabled,
|
||||
$"{typeof(ItemTogglePointLightComponent)} requires point lights without net-sync");
|
||||
_pointLight.SetEnabled(uid, enabled, light);
|
||||
if (modulateColor && toggleLights.ToggleableVisualsColorModulatesLights)
|
||||
{
|
||||
_pointLight.SetColor(uid, color, light);
|
||||
}
|
||||
}
|
||||
|
||||
// update clothing & in-hand visuals.
|
||||
_item.VisualsChanged(uid);
|
||||
}
|
||||
|
||||
private void OnGetEquipmentVisuals(EntityUid uid,
|
||||
ToggleableVisualsComponent component,
|
||||
GetEquipmentVisualsEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out AppearanceComponent? appearance)
|
||||
|| !AppearanceSystem.TryGetData<bool>(uid, ToggleableVisuals.Enabled, out var enabled, appearance)
|
||||
|| !enabled)
|
||||
return;
|
||||
|
||||
if (!TryComp(args.Equipee, out InventoryComponent? inventory))
|
||||
return;
|
||||
List<PrototypeLayerData>? layers = null;
|
||||
|
||||
// attempt to get species specific data
|
||||
if (inventory.SpeciesId != null)
|
||||
component.ClothingVisuals.TryGetValue($"{args.Slot}-{inventory.SpeciesId}", out layers);
|
||||
|
||||
// No species specific data. Try to default to generic data.
|
||||
if (layers == null && !component.ClothingVisuals.TryGetValue(args.Slot, out layers))
|
||||
return;
|
||||
|
||||
var modulateColor = AppearanceSystem.TryGetData<Color>(uid, ToggleableVisuals.Color, out var color, appearance);
|
||||
|
||||
var i = 0;
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
var key = layer.MapKeys?.FirstOrDefault();
|
||||
if (key == null)
|
||||
{
|
||||
key = i == 0 ? $"{args.Slot}-toggle" : $"{args.Slot}-toggle-{i}";
|
||||
i++;
|
||||
}
|
||||
|
||||
if (modulateColor)
|
||||
layer.Color = color;
|
||||
|
||||
args.Layers.Add((key, layer));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetHeldVisuals(EntityUid uid, ToggleableVisualsComponent component, GetInhandVisualsEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out AppearanceComponent? appearance)
|
||||
|| !AppearanceSystem.TryGetData<bool>(uid, ToggleableVisuals.Enabled, out var enabled, appearance)
|
||||
|| !enabled)
|
||||
return;
|
||||
|
||||
if (!component.InhandVisuals.TryGetValue(args.Location, out var layers))
|
||||
return;
|
||||
|
||||
var modulateColor = AppearanceSystem.TryGetData<Color>(uid, ToggleableVisuals.Color, out var color, appearance);
|
||||
|
||||
var i = 0;
|
||||
var defaultKey = $"inhand-{args.Location.ToString().ToLowerInvariant()}-toggle";
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
var key = layer.MapKeys?.FirstOrDefault();
|
||||
if (key == null)
|
||||
{
|
||||
key = i == 0 ? defaultKey : $"{defaultKey}-{i}";
|
||||
i++;
|
||||
}
|
||||
|
||||
if (modulateColor)
|
||||
layer.Color = color;
|
||||
|
||||
args.Layers.Add((key, layer));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user