1
0

StealthSystem.cs 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using Content.Client.Interactable.Components;
  2. using Content.Client.StatusIcon;
  3. using Content.Shared.Stealth;
  4. using Content.Shared.Stealth.Components;
  5. using Robust.Client.GameObjects;
  6. using Robust.Client.Graphics;
  7. using Robust.Shared.Prototypes;
  8. namespace Content.Client.Stealth;
  9. public sealed class StealthSystem : SharedStealthSystem
  10. {
  11. [Dependency] private readonly IPrototypeManager _protoMan = default!;
  12. [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
  13. private ShaderInstance _shader = default!;
  14. public override void Initialize()
  15. {
  16. base.Initialize();
  17. _shader = _protoMan.Index<ShaderPrototype>("Stealth").InstanceUnique();
  18. SubscribeLocalEvent<StealthComponent, ComponentShutdown>(OnShutdown);
  19. SubscribeLocalEvent<StealthComponent, ComponentStartup>(OnStartup);
  20. SubscribeLocalEvent<StealthComponent, BeforePostShaderRenderEvent>(OnShaderRender);
  21. }
  22. public override void SetEnabled(EntityUid uid, bool value, StealthComponent? component = null)
  23. {
  24. if (!Resolve(uid, ref component) || component.Enabled == value)
  25. return;
  26. base.SetEnabled(uid, value, component);
  27. SetShader(uid, value, component);
  28. }
  29. private void SetShader(EntityUid uid, bool enabled, StealthComponent? component = null, SpriteComponent? sprite = null)
  30. {
  31. if (!Resolve(uid, ref component, ref sprite, false))
  32. return;
  33. sprite.Color = Color.White;
  34. sprite.PostShader = enabled ? _shader : null;
  35. sprite.GetScreenTexture = enabled;
  36. sprite.RaiseShaderEvent = enabled;
  37. if (!enabled)
  38. {
  39. if (component.HadOutline && !TerminatingOrDeleted(uid))
  40. EnsureComp<InteractionOutlineComponent>(uid);
  41. return;
  42. }
  43. if (TryComp(uid, out InteractionOutlineComponent? outline))
  44. {
  45. RemCompDeferred(uid, outline);
  46. component.HadOutline = true;
  47. }
  48. }
  49. private void OnStartup(EntityUid uid, StealthComponent component, ComponentStartup args)
  50. {
  51. SetShader(uid, component.Enabled, component);
  52. }
  53. private void OnShutdown(EntityUid uid, StealthComponent component, ComponentShutdown args)
  54. {
  55. if (!Terminating(uid))
  56. SetShader(uid, false, component);
  57. }
  58. private void OnShaderRender(EntityUid uid, StealthComponent component, BeforePostShaderRenderEvent args)
  59. {
  60. // Distortion effect uses screen coordinates. If a player moves, the entities appear to move on screen. this
  61. // makes the distortion very noticeable.
  62. // So we need to use relative screen coordinates. The reference frame we use is the parent's position on screen.
  63. // this ensures that if the Stealth is not moving relative to the parent, its relative screen position remains
  64. // unchanged.
  65. var parent = Transform(uid).ParentUid;
  66. if (!parent.IsValid())
  67. return; // should never happen, but lets not kill the client.
  68. var parentXform = Transform(parent);
  69. var reference = args.Viewport.WorldToLocal(_transformSystem.GetWorldPosition(parentXform));
  70. reference.X = -reference.X;
  71. var visibility = GetVisibility(uid, component);
  72. // actual visual visibility effect is limited to +/- 1.
  73. visibility = Math.Clamp(visibility, -1f, 1f);
  74. _shader.SetParameter("reference", reference);
  75. _shader.SetParameter("visibility", visibility);
  76. visibility = MathF.Max(0, visibility);
  77. args.Sprite.Color = new Color(visibility, visibility, 1, 1);
  78. }
  79. }