[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
+ private EntityQuery<TransformComponent> _xformQuery;
+
private readonly HashSet<EntityUid> _handledEntities = new();
private const float DefaultLoadRange = 16f;
private float _loadRange = DefaultLoadRange;
{
base.Initialize();
Log.Level = LogLevel.Debug;
+ _xformQuery = GetEntityQuery<TransformComponent>();
SubscribeLocalEvent<BiomeComponent, MapInitEvent>(OnBiomeMapInit);
SubscribeLocalEvent<FTLStartedEvent>(OnFTLStarted);
SubscribeLocalEvent<ShuttleFlattenEvent>(OnShuttleFlatten);
return;
// Get the set of spawned nodes to avoid overlap.
+ var forced = component.ForcedMarkerLayers.Contains(layer);
var spawnSet = _tilePool.Get();
var frontier = new ValueList<Vector2i>(32);
// Check if it's a valid spawn, if so then use it.
var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(gridUid, grid, node);
+ enumerator.MoveNext(out var existing);
- if (enumerator.MoveNext(out _))
+ if (!forced && existing != null)
continue;
// Check if mask matches // anything blocking.
layerMarkers.Add(node);
groupSize--;
spawnSet.Add(node);
+
+ if (forced && existing != null)
+ {
+ // Just lock anything so we can dump this
+ lock (component.PendingMarkers)
+ {
+ Del(existing.Value);
+ }
+ }
}
}
});
}
+ component.ForcedMarkerLayers.Clear();
var active = _activeChunks[component];
List<(Vector2i, Tile)>? tiles = null;
foreach (var chunk in active)
{
+ LoadMarkerChunk(component, gridUid, grid, chunk, seed);
+
if (!component.LoadedChunks.Add(chunk))
continue;
tiles ??= new List<(Vector2i, Tile)>(ChunkSize * ChunkSize);
// Load NOW!
- LoadChunk(component, gridUid, grid, chunk, seed, tiles, xformQuery);
+ LoadChunk(component, gridUid, grid, chunk, seed, tiles);
}
}
- /// <summary>
- /// Loads a particular queued chunk for a biome.
- /// </summary>
- private void LoadChunk(
+ private void LoadMarkerChunk(
BiomeComponent component,
EntityUid gridUid,
MapGridComponent grid,
Vector2i chunk,
- int seed,
- List<(Vector2i, Tile)> tiles,
- EntityQuery<TransformComponent> xformQuery)
+ int seed)
{
+ // Load any pending marker tiles first.
+ if (!component.PendingMarkers.TryGetValue(chunk, out var layers))
+ return;
+
+ // This needs to be done separately in case we try to add a marker layer and want to force it on existing
+ // loaded chunks.
component.ModifiedTiles.TryGetValue(chunk, out var modified);
modified ??= _tilePool.Get();
- // Load any pending marker tiles first.
- if (component.PendingMarkers.TryGetValue(chunk, out var layers))
+ foreach (var (layer, nodes) in layers)
{
- foreach (var (layer, nodes) in layers)
+ var layerProto = ProtoManager.Index<BiomeMarkerLayerPrototype>(layer);
+
+ foreach (var node in nodes)
{
- var layerProto = ProtoManager.Index<BiomeMarkerLayerPrototype>(layer);
+ if (modified.Contains(node))
+ continue;
- foreach (var node in nodes)
+ // Need to ensure the tile under it has loaded for anchoring.
+ if (TryGetBiomeTile(node, component.Layers, seed, grid, out var tile))
{
- if (modified.Contains(node))
- continue;
-
- // Need to ensure the tile under it has loaded for anchoring.
- if (TryGetBiomeTile(node, component.Layers, seed, grid, out var tile))
- {
- _mapSystem.SetTile(gridUid, grid, node, tile.Value);
- }
+ _mapSystem.SetTile(gridUid, grid, node, tile.Value);
+ }
- string? prototype;
+ string? prototype;
- if (TryGetEntity(node, component, grid, out var proto) &&
- layerProto.EntityMask.TryGetValue(proto, out var maskedProto))
- {
- prototype = maskedProto;
- }
- else
- {
- prototype = layerProto.Prototype;
- }
-
- // If it is a ghost role then purge it
- // TODO: This is *kind* of a bandaid but natural mobs spawns needs a lot more work.
- // Ideally we'd just have ghost role and non-ghost role variants for some stuff.
- var uid = EntityManager.CreateEntityUninitialized(prototype, _mapSystem.GridTileToLocal(gridUid, grid, node));
- RemComp<GhostTakeoverAvailableComponent>(uid);
- RemComp<GhostRoleComponent>(uid);
- EntityManager.InitializeAndStartEntity(uid);
- modified.Add(node);
+ if (TryGetEntity(node, component, grid, out var proto) &&
+ layerProto.EntityMask.TryGetValue(proto, out var maskedProto))
+ {
+ prototype = maskedProto;
+ }
+ else
+ {
+ prototype = layerProto.Prototype;
}
- }
- component.PendingMarkers.Remove(chunk);
+ // If it is a ghost role then purge it
+ // TODO: This is *kind* of a bandaid but natural mobs spawns needs a lot more work.
+ // Ideally we'd just have ghost role and non-ghost role variants for some stuff.
+ var uid = EntityManager.CreateEntityUninitialized(prototype, _mapSystem.GridTileToLocal(gridUid, grid, node));
+ RemComp<GhostTakeoverAvailableComponent>(uid);
+ RemComp<GhostRoleComponent>(uid);
+ EntityManager.InitializeAndStartEntity(uid);
+ modified.Add(node);
+ }
}
+ if (modified.Count == 0)
+ _tilePool.Return(modified);
+
+ component.PendingMarkers.Remove(chunk);
+ }
+
+ /// <summary>
+ /// Loads a particular queued chunk for a biome.
+ /// </summary>
+ private void LoadChunk(
+ BiomeComponent component,
+ EntityUid gridUid,
+ MapGridComponent grid,
+ Vector2i chunk,
+ int seed,
+ List<(Vector2i, Tile)> tiles)
+ {
+ component.ModifiedTiles.TryGetValue(chunk, out var modified);
+ modified ??= _tilePool.Get();
+
// Set tiles first
for (var x = 0; x < ChunkSize; x++)
{
var ent = Spawn(entPrototype, _mapSystem.GridTileToLocal(gridUid, grid, indices));
// At least for now unless we do lookups or smth, only work with anchoring.
- if (xformQuery.TryGetComponent(ent, out var xform) && !xform.Anchored)
+ if (_xformQuery.TryGetComponent(ent, out var xform) && !xform.Anchored)
{
_transform.AnchorEntity(ent, xform, gridUid, grid, indices);
}