1
0

GridPainter.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Numerics;
  6. using System.Runtime.InteropServices;
  7. using Content.Shared.Decals;
  8. using Robust.Client.GameObjects;
  9. using Robust.Shared.GameObjects;
  10. using Robust.Shared.Map;
  11. using Robust.Shared.Map.Components;
  12. using Robust.Shared.Timing;
  13. using Robust.Shared.Utility;
  14. using SixLabors.ImageSharp;
  15. using static Robust.UnitTesting.RobustIntegrationTest;
  16. namespace Content.MapRenderer.Painters
  17. {
  18. public sealed class GridPainter
  19. {
  20. private readonly EntityPainter _entityPainter;
  21. private readonly DecalPainter _decalPainter;
  22. private readonly IEntityManager _cEntityManager;
  23. private readonly IEntityManager _sEntityManager;
  24. private readonly IMapManager _sMapManager;
  25. private readonly ConcurrentDictionary<EntityUid, List<EntityData>> _entities;
  26. private readonly Dictionary<EntityUid, List<DecalData>> _decals;
  27. public GridPainter(ClientIntegrationInstance client, ServerIntegrationInstance server)
  28. {
  29. _entityPainter = new EntityPainter(client, server);
  30. _decalPainter = new DecalPainter(client, server);
  31. _cEntityManager = client.ResolveDependency<IEntityManager>();
  32. _sEntityManager = server.ResolveDependency<IEntityManager>();
  33. _sMapManager = server.ResolveDependency<IMapManager>();
  34. _entities = GetEntities();
  35. _decals = GetDecals();
  36. }
  37. public void Run(Image gridCanvas, EntityUid gridUid, MapGridComponent grid)
  38. {
  39. var stopwatch = new Stopwatch();
  40. stopwatch.Start();
  41. if (!_entities.TryGetValue(gridUid, out var entities))
  42. {
  43. Console.WriteLine($"No entities found on grid {gridUid}");
  44. return;
  45. }
  46. // Decals are always painted before entities, and are also optional.
  47. if (_decals.TryGetValue(gridUid, out var decals))
  48. _decalPainter.Run(gridCanvas, CollectionsMarshal.AsSpan(decals));
  49. _entityPainter.Run(gridCanvas, entities);
  50. Console.WriteLine($"{nameof(GridPainter)} painted grid {gridUid} in {(int) stopwatch.Elapsed.TotalMilliseconds} ms");
  51. }
  52. private ConcurrentDictionary<EntityUid, List<EntityData>> GetEntities()
  53. {
  54. var stopwatch = new Stopwatch();
  55. stopwatch.Start();
  56. var components = new ConcurrentDictionary<EntityUid, List<EntityData>>();
  57. foreach (var serverEntity in _sEntityManager.GetEntities())
  58. {
  59. var clientEntity = _cEntityManager.GetEntity(_sEntityManager.GetNetEntity(serverEntity));
  60. if (!_cEntityManager.TryGetComponent(clientEntity, out SpriteComponent? sprite))
  61. {
  62. continue;
  63. }
  64. var prototype = _sEntityManager.GetComponent<MetaDataComponent>(serverEntity).EntityPrototype;
  65. if (prototype == null)
  66. {
  67. continue;
  68. }
  69. var transform = _sEntityManager.GetComponent<TransformComponent>(serverEntity);
  70. if (_sEntityManager.TryGetComponent(transform.GridUid, out MapGridComponent? grid))
  71. {
  72. var position = transform.LocalPosition;
  73. var (x, y) = TransformLocalPosition(position, grid);
  74. var data = new EntityData(serverEntity, sprite, x, y);
  75. components.GetOrAdd(transform.GridUid.Value, _ => new List<EntityData>()).Add(data);
  76. }
  77. }
  78. Console.WriteLine($"Found {components.Values.Sum(l => l.Count)} entities on {components.Count} grids in {(int) stopwatch.Elapsed.TotalMilliseconds} ms");
  79. return components;
  80. }
  81. private Dictionary<EntityUid, List<DecalData>> GetDecals()
  82. {
  83. var stopwatch = new Stopwatch();
  84. stopwatch.Start();
  85. var decals = new Dictionary<EntityUid, List<DecalData>>();
  86. var query = _sEntityManager.AllEntityQueryEnumerator<MapGridComponent>();
  87. while (query.MoveNext(out var uid, out var grid))
  88. {
  89. // TODO this needs to use the client entity manager because the client
  90. // actually has the correct z-indices for decals for some reason when the server doesn't,
  91. // BUT can't do that yet because the client hasn't actually received everything yet
  92. // for some reason decal moment i guess.
  93. if (_sEntityManager.TryGetComponent<DecalGridComponent>(uid, out var comp))
  94. {
  95. foreach (var chunk in comp.ChunkCollection.ChunkCollection.Values)
  96. {
  97. foreach (var decal in chunk.Decals.Values)
  98. {
  99. var (x, y) = TransformLocalPosition(decal.Coordinates, grid);
  100. decals.GetOrNew(uid).Add(new DecalData(decal, x, y));
  101. }
  102. }
  103. }
  104. }
  105. Console.WriteLine($"Found {decals.Values.Sum(l => l.Count)} decals on {decals.Count} grids in {(int) stopwatch.Elapsed.TotalMilliseconds} ms");
  106. return decals;
  107. }
  108. private static (float x, float y) TransformLocalPosition(Vector2 position, MapGridComponent grid)
  109. {
  110. var xOffset = (int) -grid.LocalAABB.Left;
  111. var yOffset = (int) -grid.LocalAABB.Bottom;
  112. var tileSize = grid.TileSize;
  113. var x = (position.X + xOffset) * tileSize * TilePainter.TileImageSize;
  114. var y = (position.Y + yOffset) * tileSize * TilePainter.TileImageSize;
  115. return (x, y);
  116. }
  117. }
  118. }