ReplaySpectatorSystem.Spectate.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System.Numerics;
  2. using Content.Client.Replay.UI;
  3. using Content.Shared.Verbs;
  4. using Robust.Shared.Console;
  5. using Robust.Shared.Map;
  6. using Robust.Shared.Player;
  7. using Robust.Shared.Utility;
  8. namespace Content.Client.Replay.Spectator;
  9. // This partial class has methods for spawning a spectator ghost and "possessing" entitites.
  10. public sealed partial class ReplaySpectatorSystem
  11. {
  12. private void OnGetAlternativeVerbs(GetVerbsEvent<AlternativeVerb> ev)
  13. {
  14. if (_replayPlayback.Replay == null)
  15. return;
  16. ev.Verbs.Add(new AlternativeVerb
  17. {
  18. Priority = 100,
  19. Act = () => SpectateEntity(ev.Target),
  20. Text = Loc.GetString("replay-verb-spectate"),
  21. Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/vv.svg.192dpi.png"))
  22. });
  23. }
  24. public void SpectateEntity(EntityUid target)
  25. {
  26. if (_player.LocalSession == null)
  27. return;
  28. var old = _player.LocalEntity;
  29. if (old == target)
  30. {
  31. // un-visit
  32. SpawnSpectatorGhost(Transform(target).Coordinates, true);
  33. return;
  34. }
  35. EnsureComp<ReplaySpectatorComponent>(target);
  36. if (TryComp(target, out ActorComponent? actor))
  37. _player.SetLocalSession(actor.PlayerSession);
  38. else
  39. _player.SetAttachedEntity(_player.LocalSession, target);
  40. _stateMan.RequestStateChange<ReplaySpectateEntityState>();
  41. if (old == null)
  42. return;
  43. if (IsClientSide(old.Value))
  44. Del(old.Value);
  45. else
  46. RemComp<ReplaySpectatorComponent>(old.Value);
  47. }
  48. public TransformComponent SpawnSpectatorGhost(EntityCoordinates coords, bool gridAttach)
  49. {
  50. var old = _player.LocalEntity;
  51. var session = _player.GetSessionById(DefaultUser);
  52. _player.SetLocalSession(session);
  53. var ent = Spawn("ReplayObserver", coords);
  54. _eye.SetMaxZoom(ent, Vector2.One * 5);
  55. EnsureComp<ReplaySpectatorComponent>(ent);
  56. var xform = Transform(ent);
  57. if (gridAttach)
  58. _transform.AttachToGridOrMap(ent);
  59. _player.SetAttachedEntity(session, ent);
  60. if (old != null)
  61. {
  62. if (IsClientSide(old.Value))
  63. QueueDel(old.Value);
  64. else
  65. RemComp<ReplaySpectatorComponent>(old.Value);
  66. }
  67. _stateMan.RequestStateChange<ReplayGhostState>();
  68. _spectatorData = GetSpectatorData();
  69. return xform;
  70. }
  71. private void SpectateCommand(IConsoleShell shell, string argStr, string[] args)
  72. {
  73. if (args.Length == 0)
  74. {
  75. if (_player.LocalSession?.AttachedEntity is { } current)
  76. SpawnSpectatorGhost(new EntityCoordinates(current, default), true);
  77. else
  78. SpawnSpectatorGhost(default, true);
  79. return;
  80. }
  81. if (!NetEntity.TryParse(args[0], out var netEntity))
  82. {
  83. shell.WriteError(Loc.GetString("cmd-parse-failure-uid", ("arg", args[0])));
  84. return;
  85. }
  86. var uid = GetEntity(netEntity);
  87. if (!Exists(uid))
  88. {
  89. shell.WriteError(Loc.GetString("cmd-parse-failure-entity-exist", ("arg", args[0])));
  90. return;
  91. }
  92. SpectateEntity(uid);
  93. }
  94. private CompletionResult SpectateCompletions(IConsoleShell shell, string[] args)
  95. {
  96. if (args.Length != 1)
  97. return CompletionResult.Empty;
  98. return CompletionResult.FromHintOptions(CompletionHelper.NetEntities(args[0],
  99. EntityManager), Loc.GetString("cmd-replay-spectate-hint"));
  100. }
  101. }