From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 18 Nov 2023 07:08:20 +0000 (+1100) Subject: Fix biome marker layer command (#21278) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=1fa5aaf92e39e764b079635eef4d35dd1b70272a;p=space-station-14.git Fix biome marker layer command (#21278) --- diff --git a/Content.Server/Parallax/BiomeSystem.Commands.cs b/Content.Server/Parallax/BiomeSystem.Commands.cs index 2792581292..0360c1deb7 100644 --- a/Content.Server/Parallax/BiomeSystem.Commands.cs +++ b/Content.Server/Parallax/BiomeSystem.Commands.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.Parallax.Biomes; @@ -5,6 +6,7 @@ using Content.Shared.Parallax.Biomes.Layers; using Content.Shared.Parallax.Biomes.Markers; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Parallax; @@ -151,14 +153,27 @@ public sealed partial class BiomeSystem return; } - biome.MarkerLayers.Add(args[1]); + if (!biome.MarkerLayers.Add(args[1])) + { + return; + } + + biome.ForcedMarkerLayers.Add(args[1]); } private CompletionResult AddMarkerLayerCallbackHelper(IConsoleShell shell, string[] args) { if (args.Length == 1) { - return CompletionResult.FromHintOptions(CompletionHelper.Components(args[0], EntityManager), "Biome"); + var allQuery = AllEntityQuery(); + var options = new List(); + + while (allQuery.MoveNext(out var mapComp, out _)) + { + options.Add(new CompletionOption(mapComp.MapId.ToString())); + } + + return CompletionResult.FromHintOptions(options, "Biome"); } if (args.Length == 2) diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index 2687c8a690..9a2357e708 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -44,6 +44,8 @@ public sealed partial class BiomeSystem : SharedBiomeSystem [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + private EntityQuery _xformQuery; + private readonly HashSet _handledEntities = new(); private const float DefaultLoadRange = 16f; private float _loadRange = DefaultLoadRange; @@ -68,6 +70,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem { base.Initialize(); Log.Level = LogLevel.Debug; + _xformQuery = GetEntityQuery(); SubscribeLocalEvent(OnBiomeMapInit); SubscribeLocalEvent(OnFTLStarted); SubscribeLocalEvent(OnShuttleFlatten); @@ -393,6 +396,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem return; // Get the set of spawned nodes to avoid overlap. + var forced = component.ForcedMarkerLayers.Contains(layer); var spawnSet = _tilePool.Get(); var frontier = new ValueList(32); @@ -460,8 +464,9 @@ public sealed partial class BiomeSystem : SharedBiomeSystem // 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. @@ -499,6 +504,15 @@ public sealed partial class BiomeSystem : SharedBiomeSystem 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); + } + } } } @@ -531,79 +545,97 @@ public sealed partial class BiomeSystem : SharedBiomeSystem }); } + 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); } } - /// - /// Loads a particular queued chunk for a biome. - /// - private void LoadChunk( + private void LoadMarkerChunk( BiomeComponent component, EntityUid gridUid, MapGridComponent grid, Vector2i chunk, - int seed, - List<(Vector2i, Tile)> tiles, - EntityQuery 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(layer); + + foreach (var node in nodes) { - var layerProto = ProtoManager.Index(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(uid); - RemComp(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(uid); + RemComp(uid); + EntityManager.InitializeAndStartEntity(uid); + modified.Add(node); + } } + if (modified.Count == 0) + _tilePool.Return(modified); + + component.PendingMarkers.Remove(chunk); + } + + /// + /// Loads a particular queued chunk for a biome. + /// + 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++) { @@ -653,7 +685,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem 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); } diff --git a/Content.Shared/Parallax/Biomes/BiomeComponent.cs b/Content.Shared/Parallax/Biomes/BiomeComponent.cs index 498619a17d..18aa55312c 100644 --- a/Content.Shared/Parallax/Biomes/BiomeComponent.cs +++ b/Content.Shared/Parallax/Biomes/BiomeComponent.cs @@ -2,6 +2,7 @@ using Content.Shared.Parallax.Biomes.Layers; using Content.Shared.Parallax.Biomes.Markers; using Robust.Shared.GameStates; using Robust.Shared.Noise; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; @@ -68,8 +69,14 @@ public sealed partial class BiomeComponent : Component [DataField("loadedMarkers", customTypeSerializer:typeof(PrototypeIdDictionarySerializer, BiomeMarkerLayerPrototype>))] public Dictionary> LoadedMarkers = new(); - [DataField("markerLayers", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List MarkerLayers = new(); + [DataField] + public HashSet> MarkerLayers = new(); + + /// + /// One-tick forcing of marker layers to bulldoze any entities in the way. + /// + [DataField] + public HashSet> ForcedMarkerLayers = new(); #endregion }