1
0

RgbLightControllerSystem.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. using System.Linq;
  2. using Content.Client.Items.Systems;
  3. using Content.Shared.Clothing;
  4. using Content.Shared.Hands;
  5. using Content.Shared.Inventory.Events;
  6. using Content.Shared.Light;
  7. using Content.Shared.Light.Components;
  8. using Robust.Client.GameObjects;
  9. using Robust.Shared.GameStates;
  10. using Robust.Shared.Map.Components;
  11. using Robust.Shared.Timing;
  12. using static Robust.Client.GameObjects.SpriteComponent;
  13. namespace Content.Client.Light
  14. {
  15. public sealed class RgbLightControllerSystem : SharedRgbLightControllerSystem
  16. {
  17. [Dependency] private readonly IGameTiming _gameTiming = default!;
  18. [Dependency] private readonly ItemSystem _itemSystem = default!;
  19. [Dependency] private readonly SharedPointLightSystem _lights = default!;
  20. public override void Initialize()
  21. {
  22. base.Initialize();
  23. SubscribeLocalEvent<RgbLightControllerComponent, ComponentHandleState>(OnHandleState);
  24. SubscribeLocalEvent<RgbLightControllerComponent, ComponentShutdown>(OnComponentShutdown);
  25. SubscribeLocalEvent<RgbLightControllerComponent, ComponentStartup>(OnComponentStart);
  26. SubscribeLocalEvent<RgbLightControllerComponent, GotUnequippedEvent>(OnGotUnequipped);
  27. SubscribeLocalEvent<RgbLightControllerComponent, EquipmentVisualsUpdatedEvent>(OnEquipmentVisualsUpdated);
  28. SubscribeLocalEvent<RgbLightControllerComponent, HeldVisualsUpdatedEvent>(OnHeldVisualsUpdated);
  29. }
  30. private void OnComponentStart(EntityUid uid, RgbLightControllerComponent rgb, ComponentStartup args)
  31. {
  32. GetOriginalColors(uid, rgb);
  33. // trigger visuals updated events
  34. _itemSystem.VisualsChanged(uid);
  35. }
  36. private void OnComponentShutdown(EntityUid uid, RgbLightControllerComponent rgb, ComponentShutdown args)
  37. {
  38. if (LifeStage(uid) >= EntityLifeStage.Terminating)
  39. return;
  40. ResetOriginalColors(uid, rgb);
  41. // and reset any in-hands or clothing sprites
  42. _itemSystem.VisualsChanged(uid);
  43. }
  44. private void OnGotUnequipped(EntityUid uid, RgbLightControllerComponent rgb, GotUnequippedEvent args)
  45. {
  46. rgb.Holder = null;
  47. rgb.HolderLayers = null;
  48. }
  49. private void OnHeldVisualsUpdated(EntityUid uid, RgbLightControllerComponent rgb, HeldVisualsUpdatedEvent args)
  50. {
  51. if (args.RevealedLayers.Count == 0)
  52. {
  53. rgb.Holder = null;
  54. rgb.HolderLayers = null;
  55. return;
  56. }
  57. rgb.Holder = args.User;
  58. rgb.HolderLayers = new();
  59. if (!TryComp(args.User, out SpriteComponent? sprite))
  60. return;
  61. foreach (var key in args.RevealedLayers)
  62. {
  63. if (!sprite.LayerMapTryGet(key, out var index) || sprite[index] is not Layer layer)
  64. continue;
  65. if (layer.ShaderPrototype == "unshaded")
  66. rgb.HolderLayers.Add(key);
  67. }
  68. }
  69. private void OnEquipmentVisualsUpdated(EntityUid uid, RgbLightControllerComponent rgb, EquipmentVisualsUpdatedEvent args)
  70. {
  71. rgb.Holder = args.Equipee;
  72. rgb.HolderLayers = new();
  73. if (!TryComp(args.Equipee, out SpriteComponent? sprite))
  74. return;
  75. foreach (var key in args.RevealedLayers)
  76. {
  77. if (!sprite.LayerMapTryGet(key, out var index) || sprite[index] is not Layer layer)
  78. continue;
  79. if (layer.ShaderPrototype == "unshaded")
  80. rgb.HolderLayers.Add(key);
  81. }
  82. }
  83. private void OnHandleState(EntityUid uid, RgbLightControllerComponent rgb, ref ComponentHandleState args)
  84. {
  85. if (args.Current is not RgbLightControllerState state)
  86. return;
  87. ResetOriginalColors(uid, rgb);
  88. rgb.CycleRate = state.CycleRate;
  89. rgb.Layers = state.Layers;
  90. GetOriginalColors(uid, rgb);
  91. }
  92. private void GetOriginalColors(EntityUid uid, RgbLightControllerComponent? rgb = null, PointLightComponent? light = null, SpriteComponent? sprite = null)
  93. {
  94. if (!Resolve(uid, ref rgb, ref sprite, ref light))
  95. return;
  96. rgb.OriginalLightColor = light.Color;
  97. rgb.OriginalLayerColors = new();
  98. var layerCount = sprite.AllLayers.Count();
  99. // if layers is null, get unshaded layers
  100. if (rgb.Layers == null)
  101. {
  102. rgb.Layers = new();
  103. for (var i = 0; i < layerCount; i++)
  104. {
  105. if (sprite[i] is Layer layer && layer.ShaderPrototype == "unshaded")
  106. {
  107. rgb.Layers.Add(i);
  108. rgb.OriginalLayerColors[i] = layer.Color;
  109. }
  110. }
  111. return;
  112. }
  113. foreach (var index in rgb.Layers.ToArray())
  114. {
  115. if (index < layerCount)
  116. rgb.OriginalLayerColors[index] = sprite[index].Color;
  117. else
  118. {
  119. // admeme fuck-ups or bad yaml?
  120. Log.Warning($"RGB light attempted to use invalid sprite index {index} on entity {ToPrettyString(uid)}");
  121. rgb.Layers.Remove(index);
  122. }
  123. }
  124. }
  125. private void ResetOriginalColors(EntityUid uid, RgbLightControllerComponent? rgb = null, PointLightComponent? light = null, SpriteComponent? sprite = null)
  126. {
  127. if (!Resolve(uid, ref rgb, ref sprite, ref light, false))
  128. return;
  129. _lights.SetColor(uid, rgb.OriginalLightColor, light);
  130. if (rgb.Layers == null || rgb.OriginalLayerColors == null)
  131. return;
  132. foreach (var (layer, color) in rgb.OriginalLayerColors)
  133. {
  134. sprite.LayerSetColor(layer, color);
  135. }
  136. }
  137. public override void FrameUpdate(float frameTime)
  138. {
  139. var lightQuery = EntityQueryEnumerator<RgbLightControllerComponent, PointLightComponent, SpriteComponent>();
  140. while (lightQuery.MoveNext(out var uid, out var rgb, out var light, out var sprite))
  141. {
  142. var color = GetCurrentRgbColor(_gameTiming.RealTime, rgb.CreationTick.Value * _gameTiming.TickPeriod, (uid, rgb));
  143. _lights.SetColor(uid, color, light);
  144. if (rgb.Layers != null)
  145. {
  146. foreach (var index in rgb.Layers)
  147. {
  148. if (sprite.TryGetLayer(index, out var layer))
  149. layer.Color = color;
  150. }
  151. }
  152. // is the entity being held by someone?
  153. if (rgb.HolderLayers == null || !TryComp(rgb.Holder, out SpriteComponent? holderSprite))
  154. continue;
  155. foreach (var layer in rgb.HolderLayers)
  156. {
  157. if (holderSprite.LayerMapTryGet(layer, out var index))
  158. holderSprite.LayerSetColor(index, color);
  159. }
  160. }
  161. var mapQuery = EntityQueryEnumerator<MapLightComponent, RgbLightControllerComponent>();
  162. while (mapQuery.MoveNext(out var uid, out var map, out var rgb))
  163. {
  164. var color = GetCurrentRgbColor(_gameTiming.RealTime, rgb.CreationTick.Value * _gameTiming.TickPeriod, (uid, rgb));
  165. map.AmbientLightColor = color;
  166. }
  167. }
  168. public static Color GetCurrentRgbColor(TimeSpan curTime, TimeSpan offset, Entity<RgbLightControllerComponent> rgb)
  169. {
  170. var delta = (float)(curTime - offset).TotalSeconds;
  171. var entOffset = Math.Abs(rgb.Owner.Id * 0.09817f);
  172. var hue = (delta * rgb.Comp.CycleRate + entOffset) % 1;
  173. return Color.FromHsv(new Vector4(
  174. MathF.Abs(hue),
  175. 1.0f,
  176. 1.0f,
  177. 1.0f
  178. ));
  179. }
  180. }
  181. }