using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Content.IntegrationTests; using Robust.Client.GameObjects; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Maths; using Robust.Shared.Timing; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; namespace Content.MapRenderer.Painters { public sealed class MapPainter { public static async IAsyncEnumerable> Paint(string map) { var stopwatch = new Stopwatch(); stopwatch.Start(); await using var pair = await PoolManager.GetServerClient(new PoolSettings { DummyTicker = false, Connected = true, Fresh = true, Map = map }); var server = pair.Server; var client = pair.Client; Console.WriteLine($"Loaded client and server in {(int) stopwatch.Elapsed.TotalMilliseconds} ms"); stopwatch.Restart(); var cEntityManager = client.ResolveDependency(); var cPlayerManager = client.ResolveDependency(); await client.WaitPost(() => { if (cEntityManager.TryGetComponent(cPlayerManager.LocalEntity, out SpriteComponent? sprite)) { sprite.Visible = false; } }); var sEntityManager = server.ResolveDependency(); var sPlayerManager = server.ResolveDependency(); await pair.RunTicksSync(10); await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()); var sMapManager = server.ResolveDependency(); var tilePainter = new TilePainter(client, server); var entityPainter = new GridPainter(client, server); Entity[] grids = null!; var xformQuery = sEntityManager.GetEntityQuery(); var xformSystem = sEntityManager.System(); await server.WaitPost(() => { var playerEntity = sPlayerManager.Sessions.Single().AttachedEntity; if (playerEntity.HasValue) { sEntityManager.DeleteEntity(playerEntity.Value); } var mapId = sMapManager.GetAllMapIds().Last(); grids = sMapManager.GetAllGrids(mapId).ToArray(); foreach (var (uid, _) in grids) { var gridXform = xformQuery.GetComponent(uid); xformSystem.SetWorldRotation(gridXform, Angle.Zero); } }); await pair.RunTicksSync(10); await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()); foreach (var (uid, grid) in grids) { // Skip empty grids if (grid.LocalAABB.IsEmpty()) { Console.WriteLine($"Warning: Grid {uid} was empty. Skipping image rendering."); continue; } var tileXSize = grid.TileSize * TilePainter.TileImageSize; var tileYSize = grid.TileSize * TilePainter.TileImageSize; var bounds = grid.LocalAABB; var left = bounds.Left; var right = bounds.Right; var top = bounds.Top; var bottom = bounds.Bottom; var w = (int) Math.Ceiling(right - left) * tileXSize; var h = (int) Math.Ceiling(top - bottom) * tileYSize; var gridCanvas = new Image(w, h); await server.WaitPost(() => { tilePainter.Run(gridCanvas, uid, grid); entityPainter.Run(gridCanvas, uid, grid); gridCanvas.Mutate(e => e.Flip(FlipMode.Vertical)); }); var renderedImage = new RenderedGridImage(gridCanvas) { GridUid = uid, Offset = xformSystem.GetWorldPosition(uid), }; yield return renderedImage; } // We don't care if it fails as we have already saved the images. try { await pair.CleanReturnAsync(); } catch { // ignored } } } }