MapPainter.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Content.IntegrationTests;
  6. using Content.Server.GameTicking;
  7. using Content.Server.Maps;
  8. using Robust.Client.GameObjects;
  9. using Robust.Server.GameObjects;
  10. using Robust.Server.Player;
  11. using Robust.Shared.GameObjects;
  12. using Robust.Shared.Map;
  13. using Robust.Shared.Map.Components;
  14. using Robust.Shared.Maths;
  15. using Robust.Shared.Prototypes;
  16. using Robust.Shared.Timing;
  17. using SixLabors.ImageSharp;
  18. using SixLabors.ImageSharp.PixelFormats;
  19. using SixLabors.ImageSharp.Processing;
  20. namespace Content.MapRenderer.Painters
  21. {
  22. public sealed class MapPainter
  23. {
  24. public static async IAsyncEnumerable<RenderedGridImage<Rgba32>> Paint(string map)
  25. {
  26. var stopwatch = new Stopwatch();
  27. stopwatch.Start();
  28. await using var pair = await PoolManager.GetServerClient(new PoolSettings
  29. {
  30. DummyTicker = false,
  31. Connected = true,
  32. Fresh = true,
  33. // Seriously whoever made MapPainter use GameMapPrototype I wish you step on a lego one time.
  34. Map = map,
  35. });
  36. var server = pair.Server;
  37. var client = pair.Client;
  38. Console.WriteLine($"Loaded client and server in {(int) stopwatch.Elapsed.TotalMilliseconds} ms");
  39. stopwatch.Restart();
  40. var cEntityManager = client.ResolveDependency<IClientEntityManager>();
  41. var cPlayerManager = client.ResolveDependency<Robust.Client.Player.IPlayerManager>();
  42. await client.WaitPost(() =>
  43. {
  44. if (cEntityManager.TryGetComponent(cPlayerManager.LocalEntity, out SpriteComponent? sprite))
  45. {
  46. sprite.Visible = false;
  47. }
  48. });
  49. var sEntityManager = server.ResolveDependency<IServerEntityManager>();
  50. var sPlayerManager = server.ResolveDependency<IPlayerManager>();
  51. await pair.RunTicksSync(10);
  52. await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
  53. var sMapManager = server.ResolveDependency<IMapManager>();
  54. var tilePainter = new TilePainter(client, server);
  55. var entityPainter = new GridPainter(client, server);
  56. Entity<MapGridComponent>[] grids = null!;
  57. var xformQuery = sEntityManager.GetEntityQuery<TransformComponent>();
  58. var xformSystem = sEntityManager.System<SharedTransformSystem>();
  59. await server.WaitPost(() =>
  60. {
  61. var playerEntity = sPlayerManager.Sessions.Single().AttachedEntity;
  62. if (playerEntity.HasValue)
  63. {
  64. sEntityManager.DeleteEntity(playerEntity.Value);
  65. }
  66. var mapId = sEntityManager.System<GameTicker>().DefaultMap;
  67. grids = sMapManager.GetAllGrids(mapId).ToArray();
  68. foreach (var (uid, _) in grids)
  69. {
  70. var gridXform = xformQuery.GetComponent(uid);
  71. xformSystem.SetWorldRotation(gridXform, Angle.Zero);
  72. }
  73. });
  74. await pair.RunTicksSync(10);
  75. await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
  76. foreach (var (uid, grid) in grids)
  77. {
  78. // Skip empty grids
  79. if (grid.LocalAABB.IsEmpty())
  80. {
  81. Console.WriteLine($"Warning: Grid {uid} was empty. Skipping image rendering.");
  82. continue;
  83. }
  84. var tileXSize = grid.TileSize * TilePainter.TileImageSize;
  85. var tileYSize = grid.TileSize * TilePainter.TileImageSize;
  86. var bounds = grid.LocalAABB;
  87. var left = bounds.Left;
  88. var right = bounds.Right;
  89. var top = bounds.Top;
  90. var bottom = bounds.Bottom;
  91. var w = (int) Math.Ceiling(right - left) * tileXSize;
  92. var h = (int) Math.Ceiling(top - bottom) * tileYSize;
  93. var gridCanvas = new Image<Rgba32>(w, h);
  94. await server.WaitPost(() =>
  95. {
  96. tilePainter.Run(gridCanvas, uid, grid);
  97. entityPainter.Run(gridCanvas, uid, grid);
  98. gridCanvas.Mutate(e => e.Flip(FlipMode.Vertical));
  99. });
  100. var renderedImage = new RenderedGridImage<Rgba32>(gridCanvas)
  101. {
  102. GridUid = uid,
  103. Offset = xformSystem.GetWorldPosition(uid),
  104. };
  105. yield return renderedImage;
  106. }
  107. // We don't care if it fails as we have already saved the images.
  108. try
  109. {
  110. await pair.CleanReturnAsync();
  111. }
  112. catch
  113. {
  114. // ignored
  115. }
  116. }
  117. }
  118. }