using System; using System.Collections.Generic; using System.Linq; using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.Interfaces; using Robust.Client.GameObjects; using Robust.Client.Graphics.Overlays; using Robust.Client.Interfaces.Graphics.Overlays; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Reflection; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Players; using Robust.Shared.ViewVariables; namespace Content.Client.GameObjects.Components.Mobs { /// /// A character UI component which shows the current damage state of the mob (living/dead) /// [RegisterComponent] [ComponentReference(typeof(SharedOverlayEffectsComponent))] public sealed class ClientOverlayEffectsComponent : SharedOverlayEffectsComponent//, ICharacterUI { /// /// A list of overlay containers representing the current overlays applied /// private List _currentEffects = new List(); [ViewVariables(VVAccess.ReadOnly)] public List ActiveOverlays { get => _currentEffects; set => SetEffects(value); } #pragma warning disable 649 // Required dependencies [Dependency] private readonly IOverlayManager _overlayManager; [Dependency] private readonly IReflectionManager _reflectionManager; [Dependency] private readonly IClientNetManager _netManager; #pragma warning restore 649 public override void Initialize() { base.Initialize(); UpdateOverlays(); } public override void HandleMessage(ComponentMessage message, IComponent component) { switch (message) { case PlayerAttachedMsg _: UpdateOverlays(); break; case PlayerDetachedMsg _: ActiveOverlays.ForEach(o => _overlayManager.RemoveOverlay(o.ID)); break; } } public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null) { base.HandleNetworkMessage(message, netChannel, session); if (message is OverlayEffectComponentMessage overlayMessage) { SetEffects(overlayMessage.Overlays); } } private void UpdateOverlays() { _currentEffects = _overlayManager.AllOverlays .Where(overlay => Enum.IsDefined(typeof(SharedOverlayID), overlay.ID)) .Select(overlay => new OverlayContainer(overlay.ID)) .ToList(); foreach (var overlayContainer in ActiveOverlays) { if (!_overlayManager.HasOverlay(overlayContainer.ID)) { if (TryCreateOverlay(overlayContainer, out var overlay)) { _overlayManager.AddOverlay(overlay); } } } SendNetworkMessage(new ResendOverlaysMessage(), _netManager.ServerChannel); } private void SetEffects(List newOverlays) { foreach (var container in ActiveOverlays.ToArray()) { if (!newOverlays.Contains(container)) { RemoveOverlay(container); } } foreach (var container in newOverlays) { if (!ActiveOverlays.Contains(container)) { AddOverlay(container); } else { UpdateOverlayConfiguration(container, _overlayManager.GetOverlay(container.ID)); } } _currentEffects = newOverlays; } private void RemoveOverlay(OverlayContainer container) { ActiveOverlays.Remove(container); _overlayManager.RemoveOverlay(container.ID); } private void AddOverlay(OverlayContainer container) { if (_overlayManager.HasOverlay(container.ID)) { return; } ActiveOverlays.Add(container); if (TryCreateOverlay(container, out var overlay)) { _overlayManager.AddOverlay(overlay); } else { Logger.ErrorS("overlay", $"Could not add overlay {container.ID}"); } } private void UpdateOverlayConfiguration(OverlayContainer container, Overlay overlay) { var configurableTypes = overlay.GetType() .GetInterfaces() .Where(type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IConfigurable<>) && container.Parameters.Exists(p => p.GetType() == type.GenericTypeArguments.First())) .ToList(); if (configurableTypes.Count > 0) { foreach (var type in configurableTypes) { var method = type.GetMethod(nameof(IConfigurable.Configure)); var parameter = container.Parameters .First(p => p.GetType() == type.GenericTypeArguments.First()); method!.Invoke(overlay, new []{ parameter }); } } } private bool TryCreateOverlay(OverlayContainer container, out Overlay overlay) { var overlayTypes = _reflectionManager.GetAllChildren(); var overlayType = overlayTypes.FirstOrDefault(t => t.Name == container.ID); if (overlayType != null) { overlay = Activator.CreateInstance(overlayType) as Overlay; UpdateOverlayConfiguration(container, overlay); return true; } overlay = default; return false; } } }