/// <summary> /// An entity holding this item is requesting visual information for in-hand sprites. /// </summary> private void OnGetVisuals(EntityUid uid, SharedItemComponent item, GetInhandVisualsEvent args) { var defaultKey = $"inhand-{args.Location.ToString().ToLowerInvariant()}"; // try get explicit visuals if (item.InhandVisuals == null || !item.InhandVisuals.TryGetValue(args.Location, out var layers)) { // get defaults if (!TryGetDefaultVisuals(uid, item, defaultKey, out layers)) { return; } } var i = 0; foreach (var layer in layers) { var key = layer.MapKeys?.FirstOrDefault(); if (key == null) { key = i == 0 ? defaultKey : $"{defaultKey}-{i}"; i++; } args.Layers.Add((key, layer)); } }
private void OnGetHeldVisuals(EntityUid uid, ToggleableLightVisualsComponent component, GetInhandVisualsEvent args) { if (!TryComp(uid, out AppearanceComponent? appearance) || !appearance.TryGetData(ToggleableLightVisuals.Enabled, out bool enabled) || !enabled) { return; } if (!component.InhandVisuals.TryGetValue(args.Location, out var layers)) { return; } var modulate = appearance.TryGetData(ToggleableLightVisuals.Color, out Color color); 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)); } }
/// <summary> /// Update the players sprite with new in-hand visuals. /// </summary> private void UpdateHandVisuals(EntityUid uid, EntityUid held, Hand hand, HandsComponent?handComp = null, SpriteComponent?sprite = null) { if (!Resolve(uid, ref handComp, ref sprite, false)) { return; } if (uid == _playerManager.LocalPlayer?.ControlledEntity) { UpdateGui(); } if (!handComp.ShowInHands) { return; } // Remove old layers. We could also just set them to invisible, but as items may add arbitrary layers, this // may eventually bloat the player with lots of layers. if (handComp.RevealedLayers.TryGetValue(hand.Location, out var revealedLayers)) { foreach (var key in revealedLayers) { sprite.RemoveLayer(key); } revealedLayers.Clear(); } else { revealedLayers = new(); handComp.RevealedLayers[hand.Location] = revealedLayers; } if (hand.HeldEntity == null) { // the held item was removed. RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers)); return; } var ev = new GetInhandVisualsEvent(uid, hand.Location); RaiseLocalEvent(held, ev, false); if (ev.Layers.Count == 0) { RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers)); return; } // add the new layers foreach (var(key, layerData) in ev.Layers) { if (!revealedLayers.Add(key)) { Logger.Warning($"Duplicate key for in-hand visuals: {key}. Are multiple components attempting to modify the same layer? Entity: {ToPrettyString(held)}"); continue; } var index = sprite.LayerMapReserveBlank(key); // In case no RSI is given, use the item's base RSI as a default. This cuts down on a lot of unnecessary yaml entries. if (layerData.RsiPath == null && layerData.TexturePath == null && sprite[index].Rsi == null && TryComp(held, out SpriteComponent? clothingSprite)) { sprite.LayerSetRSI(index, clothingSprite.BaseRSI); } sprite.LayerSetData(index, layerData); } RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers)); }