1
0

FTLDiskCommand.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using Content.Server.Administration;
  2. using Content.Server.Labels;
  3. using Content.Shared.Administration;
  4. using Content.Shared.Hands.Components;
  5. using Content.Shared.Hands.EntitySystems;
  6. using Content.Shared.Shuttles.Components;
  7. using Content.Shared.Storage;
  8. using Content.Shared.Storage.EntitySystems;
  9. using Robust.Shared.Console;
  10. using Robust.Shared.Map.Components;
  11. using Robust.Shared.Prototypes;
  12. using Robust.Shared.Utility;
  13. namespace Content.Server.Shuttles.Commands;
  14. /// <summary>
  15. /// Creates FTL disks, to maps, grids, or entities.
  16. /// </summary>
  17. [AdminCommand(AdminFlags.Fun)]
  18. public sealed class FTLDiskCommand : LocalizedCommands
  19. {
  20. [Dependency] private readonly IEntityManager _entManager = default!;
  21. [Dependency] private readonly IEntitySystemManager _entSystemManager = default!;
  22. public override string Command => "ftldisk";
  23. [ValidatePrototypeId<EntityPrototype>]
  24. public const string CoordinatesDisk = "CoordinatesDisk";
  25. [ValidatePrototypeId<EntityPrototype>]
  26. public const string DiskCase = "DiskCase";
  27. public override void Execute(IConsoleShell shell, string argStr, string[] args)
  28. {
  29. if (args.Length == 0)
  30. {
  31. shell.WriteError(Loc.GetString("shell-need-minimum-one-argument"));
  32. return;
  33. }
  34. var player = shell.Player;
  35. if (player == null)
  36. {
  37. shell.WriteLine(Loc.GetString("shell-only-players-can-run-this-command"));
  38. return;
  39. }
  40. if (player.AttachedEntity == null)
  41. {
  42. shell.WriteLine(Loc.GetString("shell-must-be-attached-to-entity"));
  43. return;
  44. }
  45. EntityUid entity = player.AttachedEntity.Value;
  46. var coords = _entManager.GetComponent<TransformComponent>(entity).Coordinates;
  47. var handsSystem = _entSystemManager.GetEntitySystem<SharedHandsSystem>();
  48. var labelSystem = _entSystemManager.GetEntitySystem<LabelSystem>();
  49. var mapSystem = _entSystemManager.GetEntitySystem<SharedMapSystem>();
  50. var storageSystem = _entSystemManager.GetEntitySystem<SharedStorageSystem>();
  51. foreach (var destinations in args)
  52. {
  53. DebugTools.AssertNotNull(destinations);
  54. // make sure destination is an id.
  55. EntityUid dest;
  56. if (_entManager.TryParseNetEntity(destinations, out var nullableDest))
  57. {
  58. DebugTools.AssertNotNull(nullableDest);
  59. dest = (EntityUid) nullableDest;
  60. // we need to go to a map, so check if the EntID is something else then try for its map
  61. if (!_entManager.HasComponent<MapComponent>(dest))
  62. {
  63. if (!_entManager.TryGetComponent<TransformComponent>(dest, out var entTransform))
  64. {
  65. shell.WriteLine(Loc.GetString("cmd-ftldisk-no-transform", ("destination", destinations)));
  66. continue;
  67. }
  68. if (!mapSystem.TryGetMap(entTransform.MapID, out var mapDest))
  69. {
  70. shell.WriteLine(Loc.GetString("cmd-ftldisk-no-map", ("destination", destinations)));
  71. continue;
  72. }
  73. DebugTools.AssertNotNull(mapDest);
  74. dest = mapDest!.Value; // explicit cast here should be fine since the previous if should catch it.
  75. }
  76. // find and verify the map is not somehow unusable.
  77. if (!_entManager.TryGetComponent<MapComponent>(dest, out var mapComp)) // We have to check for a MapComponent here and above since we could have changed our dest entity.
  78. {
  79. shell.WriteLine(Loc.GetString("cmd-ftldisk-no-map-comp", ("destination", destinations), ("map", dest)));
  80. continue;
  81. }
  82. if (mapComp.MapInitialized == false)
  83. {
  84. shell.WriteLine(Loc.GetString("cmd-ftldisk-map-not-init", ("destination", destinations), ("map", dest)));
  85. continue;
  86. }
  87. if (mapComp.MapPaused == true)
  88. {
  89. shell.WriteLine(Loc.GetString("cmd-ftldisk-map-paused", ("destination", destinations), ("map", dest)));
  90. continue;
  91. }
  92. // check if our destination works already, if not, make it.
  93. if (!_entManager.TryGetComponent<FTLDestinationComponent>(dest, out var ftlDestComp))
  94. {
  95. FTLDestinationComponent ftlDest = _entManager.AddComponent<FTLDestinationComponent>(dest);
  96. ftlDest.RequireCoordinateDisk = true;
  97. if (_entManager.HasComponent<MapGridComponent>(dest))
  98. {
  99. ftlDest.BeaconsOnly = true;
  100. shell.WriteLine(Loc.GetString("cmd-ftldisk-planet", ("destination", destinations), ("map", dest)));
  101. }
  102. }
  103. else
  104. {
  105. // we don't do these automatically, since it isn't clear what the correct resolution is. Instead we provide feedback to the user and carry on like they know what theyre doing.
  106. if (ftlDestComp.Enabled == false)
  107. shell.WriteLine(Loc.GetString("cmd-ftldisk-already-dest-not-enabled", ("destination", destinations), ("map", dest)));
  108. if (ftlDestComp.BeaconsOnly == true)
  109. shell.WriteLine(Loc.GetString("cmd-ftldisk-requires-ftl-point", ("destination", destinations), ("map", dest)));
  110. }
  111. // create the FTL disk
  112. EntityUid cdUid = _entManager.SpawnEntity(CoordinatesDisk, coords);
  113. var cd = _entManager.EnsureComponent<ShuttleDestinationCoordinatesComponent>(cdUid);
  114. cd.Destination = dest;
  115. _entManager.Dirty(cdUid, cd);
  116. // create disk case
  117. EntityUid cdCaseUid = _entManager.SpawnEntity(DiskCase, coords);
  118. // apply labels
  119. if (_entManager.TryGetComponent<MetaDataComponent>(dest, out var meta) && meta != null && meta.EntityName != null)
  120. {
  121. labelSystem.Label(cdUid, meta.EntityName);
  122. labelSystem.Label(cdCaseUid, meta.EntityName);
  123. }
  124. // if the case has a storage, try to place the disk in there and then the case inhand
  125. if (_entManager.TryGetComponent<StorageComponent>(cdCaseUid, out var storage) && storageSystem.Insert(cdCaseUid, cdUid, out _, storageComp: storage, playSound: false))
  126. {
  127. if (_entManager.TryGetComponent<HandsComponent>(entity, out var handsComponent) && handsSystem.TryGetEmptyHand(entity, out var emptyHand, handsComponent))
  128. {
  129. handsSystem.TryPickup(entity, cdCaseUid, emptyHand, checkActionBlocker: false, handsComp: handsComponent);
  130. }
  131. }
  132. else // the case was messed up, put disk inhand
  133. {
  134. _entManager.DeleteEntity(cdCaseUid); // something went wrong so just yeet the chaf
  135. if (_entManager.TryGetComponent<HandsComponent>(entity, out var handsComponent) && handsSystem.TryGetEmptyHand(entity, out var emptyHand, handsComponent))
  136. {
  137. handsSystem.TryPickup(entity, cdUid, emptyHand, checkActionBlocker: false, handsComp: handsComponent);
  138. }
  139. }
  140. }
  141. else
  142. {
  143. shell.WriteLine(Loc.GetString("shell-invalid-entity-uid", ("uid", destinations)));
  144. }
  145. }
  146. }
  147. public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
  148. {
  149. if (args.Length >= 1)
  150. return CompletionResult.FromHintOptions(CompletionHelper.MapUids(_entManager), Loc.GetString("cmd-ftldisk-hint"));
  151. return CompletionResult.Empty;
  152. }
  153. }