ChunkingSystem.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System.Linq;
  2. using Content.Shared.Decals;
  3. using Microsoft.Extensions.ObjectPool;
  4. using Robust.Shared;
  5. using Robust.Shared.Configuration;
  6. using Robust.Shared.Enums;
  7. using Robust.Shared.Map;
  8. using Robust.Shared.Map.Components;
  9. using Robust.Shared.Player;
  10. using Robust.Shared.Utility;
  11. using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
  12. namespace Content.Shared.Chunking;
  13. /// <summary>
  14. /// This system just exists to provide some utility functions for other systems that chunk data that needs to be
  15. /// sent to players. In particular, see <see cref="GetChunksForSession"/>.
  16. /// </summary>
  17. public sealed class ChunkingSystem : EntitySystem
  18. {
  19. [Dependency] private readonly IConfigurationManager _configurationManager = default!;
  20. [Dependency] private readonly IMapManager _mapManager = default!;
  21. [Dependency] private readonly SharedTransformSystem _transform = default!;
  22. private EntityQuery<TransformComponent> _xformQuery;
  23. private Box2 _baseViewBounds;
  24. public override void Initialize()
  25. {
  26. base.Initialize();
  27. _xformQuery = GetEntityQuery<TransformComponent>();
  28. Subs.CVar(_configurationManager, CVars.NetMaxUpdateRange, OnPvsRangeChanged, true);
  29. }
  30. private void OnPvsRangeChanged(float value)
  31. {
  32. _baseViewBounds = Box2.UnitCentered.Scale(value);
  33. }
  34. public Dictionary<NetEntity, HashSet<Vector2i>> GetChunksForSession(
  35. ICommonSession session,
  36. int chunkSize,
  37. ObjectPool<HashSet<Vector2i>> indexPool,
  38. ObjectPool<Dictionary<NetEntity, HashSet<Vector2i>>> viewerPool,
  39. float? viewEnlargement = null)
  40. {
  41. var chunks = viewerPool.Get();
  42. DebugTools.Assert(chunks.Count == 0);
  43. if (session.Status != SessionStatus.InGame || session.AttachedEntity is not {} player)
  44. return chunks;
  45. var enlargement = viewEnlargement ?? chunkSize;
  46. AddViewerChunks(player, chunks, indexPool, chunkSize, enlargement);
  47. foreach (var uid in session.ViewSubscriptions)
  48. {
  49. AddViewerChunks(uid, chunks, indexPool, chunkSize, enlargement);
  50. }
  51. return chunks;
  52. }
  53. private void AddViewerChunks(EntityUid viewer,
  54. Dictionary<NetEntity, HashSet<Vector2i>> chunks,
  55. ObjectPool<HashSet<Vector2i>> indexPool,
  56. int chunkSize,
  57. float viewEnlargement)
  58. {
  59. if (!_xformQuery.TryGetComponent(viewer, out var xform))
  60. return;
  61. var pos = _transform.GetWorldPosition(xform);
  62. var bounds = _baseViewBounds.Translated(pos).Enlarged(viewEnlargement);
  63. var state = new QueryState(chunks, indexPool, chunkSize, bounds, _transform, EntityManager);
  64. _mapManager.FindGridsIntersecting(xform.MapID, bounds, ref state, AddGridChunks, true);
  65. }
  66. private static bool AddGridChunks(
  67. EntityUid uid,
  68. MapGridComponent grid,
  69. ref QueryState state)
  70. {
  71. var netGrid = state.EntityManager.GetNetEntity(uid);
  72. if (!state.Chunks.TryGetValue(netGrid, out var set))
  73. {
  74. state.Chunks[netGrid] = set = state.Pool.Get();
  75. DebugTools.Assert(set.Count == 0);
  76. }
  77. var aabb = state.Transform.GetInvWorldMatrix(uid).TransformBox(state.Bounds);
  78. var enumerator = new ChunkIndicesEnumerator(aabb, state.ChunkSize);
  79. while (enumerator.MoveNext(out var indices))
  80. {
  81. set.Add(indices.Value);
  82. }
  83. return true;
  84. }
  85. private readonly struct QueryState
  86. {
  87. public readonly Dictionary<NetEntity, HashSet<Vector2i>> Chunks;
  88. public readonly ObjectPool<HashSet<Vector2i>> Pool;
  89. public readonly int ChunkSize;
  90. public readonly Box2 Bounds;
  91. public readonly SharedTransformSystem Transform;
  92. public readonly EntityManager EntityManager;
  93. public QueryState(
  94. Dictionary<NetEntity, HashSet<Vector2i>> chunks,
  95. ObjectPool<HashSet<Vector2i>> pool,
  96. int chunkSize,
  97. Box2 bounds,
  98. SharedTransformSystem transform,
  99. EntityManager entityManager)
  100. {
  101. Chunks = chunks;
  102. Pool = pool;
  103. ChunkSize = chunkSize;
  104. Bounds = bounds;
  105. Transform = transform;
  106. EntityManager = entityManager;
  107. }
  108. }
  109. }