1
0

CloningConsoleSystem.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using System.Linq;
  2. using Content.Server.Administration.Logs;
  3. using Content.Server.Cloning.Components;
  4. using Content.Server.DeviceLinking.Systems;
  5. using Content.Server.Medical.Components;
  6. using Content.Server.Power.EntitySystems;
  7. using Content.Shared.UserInterface;
  8. using Content.Shared.Cloning;
  9. using Content.Shared.Cloning.CloningConsole;
  10. using Content.Shared.Database;
  11. using Content.Shared.DeviceLinking;
  12. using Content.Shared.DeviceLinking.Events;
  13. using Content.Shared.IdentityManagement;
  14. using Content.Shared.Mind;
  15. using Content.Shared.Mobs.Components;
  16. using Content.Shared.Mobs.Systems;
  17. using Content.Shared.Power;
  18. using Robust.Server.GameObjects;
  19. using Robust.Server.Player;
  20. namespace Content.Server.Cloning
  21. {
  22. public sealed class CloningConsoleSystem : EntitySystem
  23. {
  24. [Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
  25. [Dependency] private readonly IAdminLogManager _adminLogger = default!;
  26. [Dependency] private readonly IPlayerManager _playerManager = default!;
  27. [Dependency] private readonly CloningPodSystem _cloningPodSystem = default!;
  28. [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
  29. [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
  30. [Dependency] private readonly PowerReceiverSystem _powerReceiverSystem = default!;
  31. [Dependency] private readonly SharedMindSystem _mindSystem = default!;
  32. public override void Initialize()
  33. {
  34. base.Initialize();
  35. SubscribeLocalEvent<CloningConsoleComponent, ComponentInit>(OnInit);
  36. SubscribeLocalEvent<CloningConsoleComponent, UiButtonPressedMessage>(OnButtonPressed);
  37. SubscribeLocalEvent<CloningConsoleComponent, AfterActivatableUIOpenEvent>(OnUIOpen);
  38. SubscribeLocalEvent<CloningConsoleComponent, PowerChangedEvent>(OnPowerChanged);
  39. SubscribeLocalEvent<CloningConsoleComponent, MapInitEvent>(OnMapInit);
  40. SubscribeLocalEvent<CloningConsoleComponent, NewLinkEvent>(OnNewLink);
  41. SubscribeLocalEvent<CloningConsoleComponent, PortDisconnectedEvent>(OnPortDisconnected);
  42. SubscribeLocalEvent<CloningConsoleComponent, AnchorStateChangedEvent>(OnAnchorChanged);
  43. }
  44. private void OnInit(EntityUid uid, CloningConsoleComponent component, ComponentInit args)
  45. {
  46. _signalSystem.EnsureSourcePorts(uid, CloningConsoleComponent.ScannerPort, CloningConsoleComponent.PodPort);
  47. }
  48. private void OnButtonPressed(EntityUid uid, CloningConsoleComponent consoleComponent, UiButtonPressedMessage args)
  49. {
  50. if (!_powerReceiverSystem.IsPowered(uid))
  51. return;
  52. switch (args.Button)
  53. {
  54. case UiButton.Clone:
  55. if (consoleComponent.GeneticScanner != null && consoleComponent.CloningPod != null)
  56. TryClone(uid, consoleComponent.CloningPod.Value, consoleComponent.GeneticScanner.Value, consoleComponent: consoleComponent);
  57. break;
  58. }
  59. UpdateUserInterface(uid, consoleComponent);
  60. }
  61. private void OnPowerChanged(EntityUid uid, CloningConsoleComponent component, ref PowerChangedEvent args)
  62. {
  63. UpdateUserInterface(uid, component);
  64. }
  65. private void OnMapInit(EntityUid uid, CloningConsoleComponent component, MapInitEvent args)
  66. {
  67. if (!TryComp<DeviceLinkSourceComponent>(uid, out var receiver))
  68. return;
  69. foreach (var port in receiver.Outputs.Values.SelectMany(ports => ports))
  70. {
  71. if (TryComp<MedicalScannerComponent>(port, out var scanner))
  72. {
  73. component.GeneticScanner = port;
  74. scanner.ConnectedConsole = uid;
  75. }
  76. if (TryComp<CloningPodComponent>(port, out var pod))
  77. {
  78. component.CloningPod = port;
  79. pod.ConnectedConsole = uid;
  80. }
  81. }
  82. }
  83. private void OnNewLink(EntityUid uid, CloningConsoleComponent component, NewLinkEvent args)
  84. {
  85. if (TryComp<MedicalScannerComponent>(args.Sink, out var scanner) && args.SourcePort == CloningConsoleComponent.ScannerPort)
  86. {
  87. component.GeneticScanner = args.Sink;
  88. scanner.ConnectedConsole = uid;
  89. }
  90. if (TryComp<CloningPodComponent>(args.Sink, out var pod) && args.SourcePort == CloningConsoleComponent.PodPort)
  91. {
  92. component.CloningPod = args.Sink;
  93. pod.ConnectedConsole = uid;
  94. }
  95. RecheckConnections(uid, component.CloningPod, component.GeneticScanner, component);
  96. }
  97. private void OnPortDisconnected(EntityUid uid, CloningConsoleComponent component, PortDisconnectedEvent args)
  98. {
  99. if (args.Port == CloningConsoleComponent.ScannerPort)
  100. component.GeneticScanner = null;
  101. if (args.Port == CloningConsoleComponent.PodPort)
  102. component.CloningPod = null;
  103. UpdateUserInterface(uid, component);
  104. }
  105. private void OnUIOpen(EntityUid uid, CloningConsoleComponent component, AfterActivatableUIOpenEvent args)
  106. {
  107. UpdateUserInterface(uid, component);
  108. }
  109. private void OnAnchorChanged(EntityUid uid, CloningConsoleComponent component, ref AnchorStateChangedEvent args)
  110. {
  111. if (args.Anchored)
  112. {
  113. RecheckConnections(uid, component.CloningPod, component.GeneticScanner, component);
  114. return;
  115. }
  116. UpdateUserInterface(uid, component);
  117. }
  118. public void UpdateUserInterface(EntityUid consoleUid, CloningConsoleComponent consoleComponent)
  119. {
  120. if (!_uiSystem.HasUi(consoleUid, CloningConsoleUiKey.Key))
  121. return;
  122. if (!_powerReceiverSystem.IsPowered(consoleUid))
  123. {
  124. _uiSystem.CloseUis(consoleUid);
  125. return;
  126. }
  127. var newState = GetUserInterfaceState(consoleComponent);
  128. _uiSystem.SetUiState(consoleUid, CloningConsoleUiKey.Key, newState);
  129. }
  130. public void TryClone(EntityUid uid, EntityUid cloningPodUid, EntityUid scannerUid, CloningPodComponent? cloningPod = null, MedicalScannerComponent? scannerComp = null, CloningConsoleComponent? consoleComponent = null)
  131. {
  132. if (!Resolve(uid, ref consoleComponent) || !Resolve(cloningPodUid, ref cloningPod) || !Resolve(scannerUid, ref scannerComp))
  133. return;
  134. if (!Transform(cloningPodUid).Anchored || !Transform(scannerUid).Anchored)
  135. return;
  136. if (!consoleComponent.CloningPodInRange || !consoleComponent.GeneticScannerInRange)
  137. return;
  138. var body = scannerComp.BodyContainer.ContainedEntity;
  139. if (body is null)
  140. return;
  141. if (!_mindSystem.TryGetMind(body.Value, out var mindId, out var mind))
  142. return;
  143. if (mind.UserId.HasValue == false || mind.Session == null)
  144. return;
  145. if (_cloningPodSystem.TryCloning(cloningPodUid, body.Value, (mindId, mind), cloningPod, scannerComp.CloningFailChanceMultiplier))
  146. _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(uid)} successfully cloned {ToPrettyString(body.Value)}.");
  147. }
  148. public void RecheckConnections(EntityUid console, EntityUid? cloningPod, EntityUid? scanner, CloningConsoleComponent? consoleComp = null)
  149. {
  150. if (!Resolve(console, ref consoleComp))
  151. return;
  152. if (scanner != null)
  153. {
  154. Transform(scanner.Value).Coordinates.TryDistance(EntityManager, Transform((console)).Coordinates, out float scannerDistance);
  155. consoleComp.GeneticScannerInRange = scannerDistance <= consoleComp.MaxDistance;
  156. }
  157. if (cloningPod != null)
  158. {
  159. Transform(cloningPod.Value).Coordinates.TryDistance(EntityManager, Transform((console)).Coordinates, out float podDistance);
  160. consoleComp.CloningPodInRange = podDistance <= consoleComp.MaxDistance;
  161. }
  162. UpdateUserInterface(console, consoleComp);
  163. }
  164. private CloningConsoleBoundUserInterfaceState GetUserInterfaceState(CloningConsoleComponent consoleComponent)
  165. {
  166. ClonerStatus clonerStatus = ClonerStatus.Ready;
  167. // genetic scanner info
  168. string scanBodyInfo = Loc.GetString("generic-unknown");
  169. bool scannerConnected = false;
  170. bool scannerInRange = consoleComponent.GeneticScannerInRange;
  171. if (consoleComponent.GeneticScanner != null && TryComp<MedicalScannerComponent>(consoleComponent.GeneticScanner, out var scanner))
  172. {
  173. scannerConnected = true;
  174. EntityUid? scanBody = scanner.BodyContainer.ContainedEntity;
  175. // GET STATE
  176. if (scanBody == null || !HasComp<MobStateComponent>(scanBody))
  177. clonerStatus = ClonerStatus.ScannerEmpty;
  178. else
  179. {
  180. scanBodyInfo = MetaData(scanBody.Value).EntityName;
  181. if (!_mobStateSystem.IsDead(scanBody.Value))
  182. {
  183. clonerStatus = ClonerStatus.ScannerOccupantAlive;
  184. }
  185. else
  186. {
  187. if (!_mindSystem.TryGetMind(scanBody.Value, out _, out var mind) ||
  188. mind.UserId == null ||
  189. !_playerManager.TryGetSessionById(mind.UserId.Value, out _))
  190. {
  191. clonerStatus = ClonerStatus.NoMindDetected;
  192. }
  193. }
  194. }
  195. }
  196. // cloning pod info
  197. var cloneBodyInfo = Loc.GetString("generic-unknown");
  198. bool clonerConnected = false;
  199. bool clonerMindPresent = false;
  200. bool clonerInRange = consoleComponent.CloningPodInRange;
  201. if (consoleComponent.CloningPod != null && TryComp<CloningPodComponent>(consoleComponent.CloningPod, out var clonePod)
  202. && Transform(consoleComponent.CloningPod.Value).Anchored)
  203. {
  204. clonerConnected = true;
  205. EntityUid? cloneBody = clonePod.BodyContainer.ContainedEntity;
  206. clonerMindPresent = clonePod.Status == CloningPodStatus.Cloning;
  207. if (HasComp<ActiveCloningPodComponent>(consoleComponent.CloningPod))
  208. {
  209. if (cloneBody != null)
  210. cloneBodyInfo = Identity.Name(cloneBody.Value, EntityManager);
  211. clonerStatus = ClonerStatus.ClonerOccupied;
  212. }
  213. }
  214. else
  215. {
  216. clonerStatus = ClonerStatus.NoClonerDetected;
  217. }
  218. return new CloningConsoleBoundUserInterfaceState(
  219. scanBodyInfo,
  220. cloneBodyInfo,
  221. clonerMindPresent,
  222. clonerStatus,
  223. scannerConnected,
  224. scannerInRange,
  225. clonerConnected,
  226. clonerInRange
  227. );
  228. }
  229. }
  230. }