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.Toggleable; using Robust.Client.GameObjects; using Robust.Shared.Utility; using System.Linq; namespace Content.Client.Toggleable; public sealed class ToggleableLightVisualsSystem : VisualizerSystem { [Dependency] private readonly SharedItemSystem _itemSys = default!; [Dependency] private readonly SharedPointLightSystem _lights = default!; [Dependency] private readonly SpriteSystem _sprite = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnGetHeldVisuals, after: new[] { typeof(ItemSystem) }); SubscribeLocalEvent(OnGetEquipmentVisuals, after: new[] { typeof(ClientClothingSystem) }); } protected override void OnAppearanceChange(EntityUid uid, ToggleableLightVisualsComponent component, ref AppearanceChangeEvent args) { if (!AppearanceSystem.TryGetData(uid, ToggleableLightVisuals.Enabled, out var enabled, args.Component)) return; var modulate = AppearanceSystem.TryGetData(uid, ToggleableLightVisuals.Color, out var color, args.Component); // Update the item's sprite if (args.Sprite != null && component.SpriteLayer != null && _sprite.LayerMapTryGet((uid, args.Sprite), component.SpriteLayer, out var layer, false)) { _sprite.LayerSetVisible((uid, args.Sprite), layer, enabled); if (modulate) _sprite.LayerSetColor((uid, args.Sprite), layer, color); } // Update any point-lights if (TryComp(uid, out PointLightComponent? light)) { DebugTools.Assert(!light.NetSyncEnabled, "light visualizers require point lights without net-sync"); _lights.SetEnabled(uid, enabled, light); if (enabled && modulate) { _lights.SetColor(uid, color, light); } } // update clothing & in-hand visuals. _itemSys.VisualsChanged(uid); } /// /// Add the unshaded light overlays to any clothing sprites. /// private void OnGetEquipmentVisuals(EntityUid uid, ToggleableLightVisualsComponent component, GetEquipmentVisualsEvent args) { if (!TryComp(uid, out AppearanceComponent? appearance) || !AppearanceSystem.TryGetData(uid, ToggleableLightVisuals.Enabled, out var enabled, appearance) || !enabled) return; if (!TryComp(args.Equipee, out InventoryComponent? inventory)) return; List? 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 modulate = AppearanceSystem.TryGetData(uid, ToggleableLightVisuals.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 (modulate) layer.Color = color; args.Layers.Add((key, layer)); } } private void OnGetHeldVisuals(EntityUid uid, ToggleableLightVisualsComponent component, GetInhandVisualsEvent args) { if (!TryComp(uid, out AppearanceComponent? appearance) || !AppearanceSystem.TryGetData(uid, ToggleableLightVisuals.Enabled, out var enabled, appearance) || !enabled) return; if (!component.InhandVisuals.TryGetValue(args.Location, out var layers)) return; var modulate = AppearanceSystem.TryGetData(uid, ToggleableLightVisuals.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 (modulate) layer.Color = color; args.Layers.Add((key, layer)); } } }