1
0

Program.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. using Content.IntegrationTests;
  9. using Content.MapRenderer.Painters;
  10. using Content.Server.Maps;
  11. using Newtonsoft.Json;
  12. using Robust.Shared.Prototypes;
  13. using SixLabors.ImageSharp;
  14. using SixLabors.ImageSharp.Formats.Webp;
  15. namespace Content.MapRenderer
  16. {
  17. internal sealed class Program
  18. {
  19. private const string NoMapsChosenMessage = "No maps were chosen";
  20. private static readonly Func<string, string> ChosenMapIdNotIntMessage = id => $"The chosen id is not a valid integer: {id}";
  21. private static readonly Func<int, string> NoMapFoundWithIdMessage = id => $"No map found with chosen id: {id}";
  22. private static readonly MapPainter MapPainter = new();
  23. internal static async Task Main(string[] args)
  24. {
  25. if (!CommandLineArguments.TryParse(args, out var arguments))
  26. return;
  27. PoolManager.Startup();
  28. if (arguments.Maps.Count == 0)
  29. {
  30. Console.WriteLine("Didn't specify any maps to paint! Loading the map list...");
  31. await using var pair = await PoolManager.GetServerClient();
  32. var mapIds = pair.Server
  33. .ResolveDependency<IPrototypeManager>()
  34. .EnumeratePrototypes<GameMapPrototype>()
  35. .Select(map => map.ID)
  36. .ToArray();
  37. Array.Sort(mapIds);
  38. Console.WriteLine("Map List");
  39. Console.WriteLine(string.Join('\n', mapIds.Select((id, i) => $"{i,3}: {id}")));
  40. Console.WriteLine("Select one, multiple separated by commas or \"all\":");
  41. Console.Write("> ");
  42. var input = Console.ReadLine();
  43. if (input == null)
  44. {
  45. Console.WriteLine(NoMapsChosenMessage);
  46. return;
  47. }
  48. var selectedIds = new List<int>();
  49. if (input is "all" or "\"all\"")
  50. {
  51. selectedIds = Enumerable.Range(0, mapIds.Length).ToList();
  52. }
  53. else
  54. {
  55. var inputArray = input.Split(',');
  56. if (inputArray.Length == 0)
  57. {
  58. Console.WriteLine(NoMapsChosenMessage);
  59. return;
  60. }
  61. foreach (var idString in inputArray)
  62. {
  63. if (!int.TryParse(idString.Trim(), out var id))
  64. {
  65. Console.WriteLine(ChosenMapIdNotIntMessage(idString));
  66. return;
  67. }
  68. selectedIds.Add(id);
  69. }
  70. }
  71. var selectedMapPrototypes = new List<string>();
  72. foreach (var id in selectedIds)
  73. {
  74. if (id < 0 || id >= mapIds.Length)
  75. {
  76. Console.WriteLine(NoMapFoundWithIdMessage(id));
  77. return;
  78. }
  79. selectedMapPrototypes.Add(mapIds[id]);
  80. }
  81. arguments.Maps.AddRange(selectedMapPrototypes);
  82. if (selectedMapPrototypes.Count == 0)
  83. {
  84. Console.WriteLine(NoMapsChosenMessage);
  85. return;
  86. }
  87. Console.WriteLine($"Selected maps: {string.Join(", ", selectedMapPrototypes)}");
  88. }
  89. if (arguments.ArgumentsAreFileNames)
  90. {
  91. Console.WriteLine("Retrieving map ids by map file names...");
  92. Console.Write("Fetching map prototypes... ");
  93. await using var pair = await PoolManager.GetServerClient();
  94. var mapPrototypes = pair.Server
  95. .ResolveDependency<IPrototypeManager>()
  96. .EnumeratePrototypes<GameMapPrototype>()
  97. .ToArray();
  98. Console.WriteLine("[Done]");
  99. var ids = new List<string>();
  100. foreach (var mapPrototype in mapPrototypes)
  101. {
  102. if (arguments.Maps.Contains(mapPrototype.MapPath.Filename))
  103. {
  104. ids.Add(mapPrototype.ID);
  105. Console.WriteLine($"Found map: {mapPrototype.MapName}");
  106. }
  107. }
  108. if (ids.Count == 0)
  109. {
  110. await Console.Error.WriteLineAsync("Found no maps for the given file names!");
  111. return;
  112. }
  113. arguments.Maps = ids;
  114. }
  115. await Run(arguments);
  116. PoolManager.Shutdown();
  117. }
  118. private static async Task Run(CommandLineArguments arguments)
  119. {
  120. Console.WriteLine($"Creating images for {arguments.Maps.Count} maps");
  121. var mapNames = new List<string>();
  122. foreach (var map in arguments.Maps)
  123. {
  124. Console.WriteLine($"Painting map {map}");
  125. var mapViewerData = new MapViewerData
  126. {
  127. Id = map,
  128. Name = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(map)
  129. };
  130. mapViewerData.ParallaxLayers.Add(LayerGroup.DefaultParallax());
  131. var directory = Path.Combine(arguments.OutputPath, map);
  132. var i = 0;
  133. try
  134. {
  135. await foreach (var renderedGrid in MapPainter.Paint(map))
  136. {
  137. var grid = renderedGrid.Image;
  138. Directory.CreateDirectory(directory);
  139. var fileName = Path.GetFileNameWithoutExtension(map);
  140. var savePath = $"{directory}{Path.DirectorySeparatorChar}{fileName}-{i}.{arguments.Format}";
  141. Console.WriteLine($"Writing grid of size {grid.Width}x{grid.Height} to {savePath}");
  142. switch (arguments.Format)
  143. {
  144. case OutputFormat.webp:
  145. var encoder = new WebpEncoder
  146. {
  147. Method = WebpEncodingMethod.BestQuality,
  148. FileFormat = WebpFileFormatType.Lossless,
  149. TransparentColorMode = WebpTransparentColorMode.Preserve
  150. };
  151. await grid.SaveAsync(savePath, encoder);
  152. break;
  153. default:
  154. case OutputFormat.png:
  155. await grid.SaveAsPngAsync(savePath);
  156. break;
  157. }
  158. grid.Dispose();
  159. mapViewerData.Grids.Add(new GridLayer(renderedGrid, Path.Combine(map, Path.GetFileName(savePath))));
  160. mapNames.Add(fileName);
  161. i++;
  162. }
  163. }
  164. catch (Exception ex)
  165. {
  166. Console.WriteLine($"Painting map {map} failed due to an internal exception:");
  167. Console.WriteLine(ex);
  168. continue;
  169. }
  170. if (arguments.ExportViewerJson)
  171. {
  172. var json = JsonConvert.SerializeObject(mapViewerData);
  173. await File.WriteAllTextAsync(Path.Combine(arguments.OutputPath, map, "map.json"), json);
  174. }
  175. }
  176. var mapNamesString = $"[{string.Join(',', mapNames.Select(s => $"\"{s}\""))}]";
  177. Console.WriteLine($@"::set-output name=map_names::{mapNamesString}");
  178. Console.WriteLine($"Processed {arguments.Maps.Count} maps.");
  179. Console.WriteLine($"It's now safe to manually exit the process (automatic exit in a few moments...)");
  180. }
  181. }
  182. }