1
0

MappingCommand.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System.Linq;
  2. using Content.Server.Administration;
  3. using Content.Server.GameTicking;
  4. using Content.Shared.Administration;
  5. using Content.Shared.CCVar;
  6. using Robust.Shared.Configuration;
  7. using Robust.Shared.Console;
  8. using Robust.Shared.ContentPack;
  9. using Robust.Shared.EntitySerialization;
  10. using Robust.Shared.EntitySerialization.Systems;
  11. using Robust.Shared.Map;
  12. using Robust.Shared.Map.Components;
  13. using Robust.Shared.Utility;
  14. namespace Content.Server.Mapping
  15. {
  16. [AdminCommand(AdminFlags.Server | AdminFlags.Mapping)]
  17. sealed class MappingCommand : IConsoleCommand
  18. {
  19. [Dependency] private readonly IEntityManager _entities = default!;
  20. [Dependency] private readonly IMapManager _map = default!;
  21. [Dependency] private readonly IConfigurationManager _cfg = default!;
  22. public string Command => "mapping";
  23. public string Description => Loc.GetString("cmd-mapping-desc");
  24. public string Help => Loc.GetString("cmd-mapping-help");
  25. public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
  26. {
  27. switch (args.Length)
  28. {
  29. case 1:
  30. return CompletionResult.FromHint(Loc.GetString("cmd-hint-mapping-id"));
  31. case 2:
  32. var res = IoCManager.Resolve<IResourceManager>();
  33. var opts = CompletionHelper.UserFilePath(args[1], res.UserData)
  34. .Concat(CompletionHelper.ContentFilePath(args[1], res));
  35. return CompletionResult.FromHintOptions(opts, Loc.GetString("cmd-hint-mapping-path"));
  36. case 3:
  37. return CompletionResult.FromHintOptions(["false", "true"], Loc.GetString("cmd-mapping-hint-grid"));
  38. }
  39. return CompletionResult.Empty;
  40. }
  41. public void Execute(IConsoleShell shell, string argStr, string[] args)
  42. {
  43. if (shell.Player is not { } player)
  44. {
  45. shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
  46. return;
  47. }
  48. if (args.Length > 3)
  49. {
  50. shell.WriteLine(Help);
  51. return;
  52. }
  53. #if DEBUG
  54. shell.WriteLine(Loc.GetString("cmd-mapping-warning"));
  55. #endif
  56. // For backwards compatibility, isGrid is optional and we allow mappers to try load grids without explicitly
  57. // specifying that they are loading a grid. Currently content is not allowed to override a map's MapId, so
  58. // without engine changes this needs to be done by brute force by just trying to load it as a map first.
  59. // This can result in errors being logged if the file is actually a grid, but the command should still work.
  60. // yipeeee
  61. bool? isGrid = args.Length < 3 ? null : bool.Parse(args[2]);
  62. MapId mapId;
  63. string? toLoad = null;
  64. var mapSys = _entities.System<SharedMapSystem>();
  65. Entity<MapGridComponent>? grid = null;
  66. // Get the map ID to use
  67. if (args.Length > 0)
  68. {
  69. if (!int.TryParse(args[0], out var intMapId))
  70. {
  71. shell.WriteError(Loc.GetString("cmd-mapping-failure-integer", ("arg", args[0])));
  72. return;
  73. }
  74. mapId = new MapId(intMapId);
  75. // no loading null space
  76. if (mapId == MapId.Nullspace)
  77. {
  78. shell.WriteError(Loc.GetString("cmd-mapping-nullspace"));
  79. return;
  80. }
  81. if (mapSys.MapExists(mapId))
  82. {
  83. shell.WriteError(Loc.GetString("cmd-mapping-exists", ("mapId", mapId)));
  84. return;
  85. }
  86. // either load a map or create a new one.
  87. if (args.Length <= 1)
  88. {
  89. mapSys.CreateMap(mapId, runMapInit: false);
  90. }
  91. else
  92. {
  93. var path = new ResPath(args[1]);
  94. toLoad = path.FilenameWithoutExtension;
  95. var opts = new DeserializationOptions {StoreYamlUids = true};
  96. var loader = _entities.System<MapLoaderSystem>();
  97. if (isGrid == true)
  98. {
  99. mapSys.CreateMap(mapId, runMapInit: false);
  100. if (!loader.TryLoadGrid(mapId, path, out grid, opts))
  101. {
  102. shell.WriteError(Loc.GetString("cmd-mapping-error"));
  103. mapSys.DeleteMap(mapId);
  104. return;
  105. }
  106. }
  107. else if (!loader.TryLoadMapWithId(mapId, path, out _, out _, opts))
  108. {
  109. if (isGrid == false)
  110. {
  111. shell.WriteError(Loc.GetString("cmd-mapping-error"));
  112. return;
  113. }
  114. // isGrid was not specified and loading it as a map failed, so we fall back to trying to load
  115. // the file as a grid
  116. shell.WriteLine(Loc.GetString("cmd-mapping-try-grid"));
  117. mapSys.CreateMap(mapId, runMapInit: false);
  118. if (!loader.TryLoadGrid(mapId, path, out grid, opts))
  119. {
  120. shell.WriteError(Loc.GetString("cmd-mapping-error"));
  121. mapSys.DeleteMap(mapId);
  122. return;
  123. }
  124. }
  125. }
  126. // was the map actually created or did it fail somehow?
  127. if (!mapSys.MapExists(mapId))
  128. {
  129. shell.WriteError(Loc.GetString("cmd-mapping-error"));
  130. return;
  131. }
  132. }
  133. else
  134. {
  135. mapSys.CreateMap(out mapId, runMapInit: false);
  136. }
  137. // map successfully created. run misc helpful mapping commands
  138. if (player.AttachedEntity is { Valid: true } playerEntity &&
  139. _entities.GetComponent<MetaDataComponent>(playerEntity).EntityPrototype?.ID != GameTicker.AdminObserverPrototypeName)
  140. {
  141. shell.ExecuteCommand("aghost");
  142. }
  143. // don't interrupt mapping with events or auto-shuttle
  144. shell.ExecuteCommand("changecvar events.enabled false");
  145. shell.ExecuteCommand("changecvar shuttle.auto_call_time 0");
  146. var auto = _entities.System<MappingSystem>();
  147. if (grid != null)
  148. auto.ToggleAutosave(grid.Value.Owner, toLoad ?? "NEWGRID");
  149. else
  150. auto.ToggleAutosave(mapId, toLoad ?? "NEWMAP");
  151. shell.ExecuteCommand($"tp 0 0 {mapId}");
  152. shell.RemoteExecuteCommand("mappingclientsidesetup");
  153. DebugTools.Assert(mapSys.IsPaused(mapId));
  154. if (args.Length != 2)
  155. shell.WriteLine(Loc.GetString("cmd-mapping-success", ("mapId", mapId)));
  156. else if (grid == null)
  157. shell.WriteLine(Loc.GetString("cmd-mapping-success-load", ("mapId", mapId), ("path", args[1])));
  158. else
  159. shell.WriteLine(Loc.GetString("cmd-mapping-success-load-grid", ("mapId", mapId), ("path", args[1])));
  160. }
  161. }
  162. }