1
0

TrayScannerSystem.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using Content.Shared.Hands.EntitySystems;
  2. using Content.Shared.Inventory;
  3. using Content.Shared.SubFloor;
  4. using Robust.Client.Animations;
  5. using Robust.Client.GameObjects;
  6. using Robust.Client.Player;
  7. using Robust.Shared.Map;
  8. using Robust.Shared.Timing;
  9. namespace Content.Client.SubFloor;
  10. public sealed class TrayScannerSystem : SharedTrayScannerSystem
  11. {
  12. [Dependency] private readonly IGameTiming _timing = default!;
  13. [Dependency] private readonly IPlayerManager _player = default!;
  14. [Dependency] private readonly AnimationPlayerSystem _animation = default!;
  15. [Dependency] private readonly EntityLookupSystem _lookup = default!;
  16. [Dependency] private readonly InventorySystem _inventory = default!;
  17. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  18. [Dependency] private readonly SharedHandsSystem _hands = default!;
  19. [Dependency] private readonly SharedTransformSystem _transform = default!;
  20. [Dependency] private readonly TrayScanRevealSystem _trayScanReveal = default!;
  21. private const string TRayAnimationKey = "trays";
  22. private const double AnimationLength = 0.3;
  23. public const LookupFlags Flags = LookupFlags.Static | LookupFlags.Sundries | LookupFlags.Approximate;
  24. public override void Update(float frameTime)
  25. {
  26. base.Update(frameTime);
  27. if (!_timing.IsFirstTimePredicted)
  28. return;
  29. // TODO: Multiple viewports or w/e
  30. var player = _player.LocalEntity;
  31. var xformQuery = GetEntityQuery<TransformComponent>();
  32. if (!xformQuery.TryGetComponent(player, out var playerXform))
  33. return;
  34. var playerPos = _transform.GetWorldPosition(playerXform, xformQuery);
  35. var playerMap = playerXform.MapID;
  36. var range = 0f;
  37. HashSet<Entity<SubFloorHideComponent>> inRange;
  38. var scannerQuery = GetEntityQuery<TrayScannerComponent>();
  39. // TODO: Should probably sub to player attached changes / inventory changes but inventory's
  40. // API is extremely skrungly. If this ever shows up on dottrace ping me and laugh.
  41. var canSee = false;
  42. // TODO: Common iterator for both systems.
  43. if (_inventory.TryGetContainerSlotEnumerator(player.Value, out var enumerator))
  44. {
  45. while (enumerator.MoveNext(out var slot))
  46. {
  47. foreach (var ent in slot.ContainedEntities)
  48. {
  49. if (!scannerQuery.TryGetComponent(ent, out var sneakScanner) || !sneakScanner.Enabled)
  50. continue;
  51. canSee = true;
  52. range = MathF.Max(range, sneakScanner.Range);
  53. }
  54. }
  55. }
  56. foreach (var hand in _hands.EnumerateHands(player.Value))
  57. {
  58. if (!scannerQuery.TryGetComponent(hand.HeldEntity, out var heldScanner) || !heldScanner.Enabled)
  59. continue;
  60. range = MathF.Max(heldScanner.Range, range);
  61. canSee = true;
  62. }
  63. inRange = new HashSet<Entity<SubFloorHideComponent>>();
  64. if (canSee)
  65. {
  66. _lookup.GetEntitiesInRange(playerMap, playerPos, range, inRange, flags: Flags);
  67. foreach (var (uid, comp) in inRange)
  68. {
  69. if (comp.IsUnderCover || _trayScanReveal.IsUnderRevealingEntity(uid))
  70. EnsureComp<TrayRevealedComponent>(uid);
  71. }
  72. }
  73. var revealedQuery = AllEntityQuery<TrayRevealedComponent, SpriteComponent>();
  74. var subfloorQuery = GetEntityQuery<SubFloorHideComponent>();
  75. while (revealedQuery.MoveNext(out var uid, out _, out var sprite))
  76. {
  77. // Revealing
  78. // Add buffer range to avoid flickers.
  79. if (subfloorQuery.TryGetComponent(uid, out var subfloor) &&
  80. inRange.Contains((uid, subfloor)))
  81. {
  82. // Due to the fact client is predicting this server states will reset it constantly
  83. if ((!_appearance.TryGetData(uid, SubFloorVisuals.ScannerRevealed, out bool value) || !value) &&
  84. sprite.Color.A > SubfloorRevealAlpha)
  85. {
  86. sprite.Color = sprite.Color.WithAlpha(0f);
  87. }
  88. SetRevealed(uid, true);
  89. if (sprite.Color.A >= SubfloorRevealAlpha || _animation.HasRunningAnimation(uid, TRayAnimationKey))
  90. continue;
  91. _animation.Play(uid, new Animation()
  92. {
  93. Length = TimeSpan.FromSeconds(AnimationLength),
  94. AnimationTracks =
  95. {
  96. new AnimationTrackComponentProperty()
  97. {
  98. ComponentType = typeof(SpriteComponent),
  99. Property = nameof(SpriteComponent.Color),
  100. KeyFrames =
  101. {
  102. new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), 0f),
  103. new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(SubfloorRevealAlpha), (float) AnimationLength)
  104. }
  105. }
  106. }
  107. }, TRayAnimationKey);
  108. }
  109. // Hiding
  110. else
  111. {
  112. // Hidden completely so unreveal and reset the alpha.
  113. if (sprite.Color.A <= 0f)
  114. {
  115. SetRevealed(uid, false);
  116. RemCompDeferred<TrayRevealedComponent>(uid);
  117. sprite.Color = sprite.Color.WithAlpha(1f);
  118. continue;
  119. }
  120. SetRevealed(uid, true);
  121. if (_animation.HasRunningAnimation(uid, TRayAnimationKey))
  122. continue;
  123. _animation.Play(uid, new Animation()
  124. {
  125. Length = TimeSpan.FromSeconds(AnimationLength),
  126. AnimationTracks =
  127. {
  128. new AnimationTrackComponentProperty()
  129. {
  130. ComponentType = typeof(SpriteComponent),
  131. Property = nameof(SpriteComponent.Color),
  132. KeyFrames =
  133. {
  134. new AnimationTrackProperty.KeyFrame(sprite.Color, 0f),
  135. new AnimationTrackProperty.KeyFrame(sprite.Color.WithAlpha(0f), (float) AnimationLength)
  136. }
  137. }
  138. }
  139. }, TRayAnimationKey);
  140. }
  141. }
  142. }
  143. private void SetRevealed(EntityUid uid, bool value)
  144. {
  145. _appearance.SetData(uid, SubFloorVisuals.ScannerRevealed, value);
  146. }
  147. }