]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Ore + entitytable fixes (#37675)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Wed, 21 May 2025 16:43:17 +0000 (02:43 +1000)
committerGitHub <noreply@github.com>
Wed, 21 May 2025 16:43:17 +0000 (12:43 -0400)
* Ore + entitytable fixes

Iterate every dungeon not just last.

* Big shot

* Fixes

Content.Server/Procedural/DungeonJob/DungeonJob.EntityTableDunGen.cs
Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs
Content.Server/Procedural/DungeonJob/DungeonJob.cs
Content.Shared/Procedural/DungeonLayers/EntityTableDunGen.cs

index 8f9be8227249d9bf3a4702702ea6369d7178b41b..05d33a4b8cf541f40531ff1a031f9a879291acf1 100644 (file)
@@ -14,22 +14,31 @@ public sealed partial class DungeonJob
 {
     private async Task PostGen(
         EntityTableDunGen gen,
-        Dungeon dungeon,
+        List<Dungeon> dungeons,
+        HashSet<Vector2i> reservedTiles,
         Random random)
     {
-        var availableRooms = new ValueList<DungeonRoom>();
-        availableRooms.AddRange(dungeon.Rooms);
-        var availableTiles = new ValueList<Vector2i>(dungeon.AllTiles);
-
         var count = random.Next(gen.MinCount, gen.MaxCount + 1);
         var npcs = _entManager.System<NPCSystem>();
 
-        for (var i = 0; i < count; i++)
+        foreach (var dungeon in dungeons)
         {
-            while (availableTiles.Count > 0)
+            var availableRooms = new ValueList<DungeonRoom>();
+            availableRooms.AddRange(dungeon.Rooms);
+            var availableTiles = new ValueList<Vector2i>(dungeon.AllTiles);
+
+            while (availableTiles.Count > 0 && count > 0)
             {
                 var tile = availableTiles.RemoveSwap(random.Next(availableTiles.Count));
 
+                await SuspendDungeon();
+
+                if (!ValidateResume())
+                    return;
+
+                if (reservedTiles.Contains(tile))
+                    continue;
+
                 if (!_anchorable.TileFree(_grid,
                         tile,
                         (int) CollisionGroup.MachineLayer,
@@ -47,13 +56,18 @@ public sealed partial class DungeonJob
                     npcs.SleepNPC(uid);
                 }
 
-                break;
+                count--;
             }
 
-            await SuspendDungeon();
-
-            if (!ValidateResume())
+            if (gen.PerDungeon)
+            {
+                count = random.Next(gen.MinCount, gen.MaxCount + 1);
+            }
+            // Stop if count is 0, otherwise go to next dungeon.
+            else if (count == 0)
+            {
                 return;
+            }
         }
     }
 }
index 679eecb4f7754580d220dcd19660cd05320c8b2e..78ab2b7a0d28ac54abf581b3db35dcf5eae36b20 100644 (file)
@@ -15,131 +15,136 @@ public sealed partial class DungeonJob
     /// </summary>
     private async Task PostGen(
         OreDunGen gen,
-        Dungeon dungeon,
+        List<Dungeon> dungeons,
+        HashSet<Vector2i> reservedTiles,
         Random random)
     {
-        // Doesn't use dungeon data because layers and we don't need top-down support at the moment.
-
-        var emptyTiles = false;
-        var replaceEntities = new Dictionary<Vector2i, EntityUid>();
-        var availableTiles = new List<Vector2i>();
-
-        foreach (var node in dungeon.AllTiles)
+        foreach (var dungeon in dungeons)
         {
-            // Empty tile, skip if relevant.
-            if (!emptyTiles && (!_maps.TryGetTile(_grid, node, out var tile) || tile.IsEmpty))
-                continue;
-
-            // Check if it's a valid spawn, if so then use it.
-            var enumerator = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, node);
-            var found = false;
-
-            // We use existing entities as a mark to spawn in place
-            // OR
-            // We check for any existing entities to see if we can spawn there.
-            while (enumerator.MoveNext(out var uid))
+            var emptyTiles = false;
+            var replaceEntities = new Dictionary<Vector2i, EntityUid>();
+            var availableTiles = new List<Vector2i>();
+
+            foreach (var node in dungeon.AllTiles)
             {
-                // We can't replace so just stop here.
-                if (gen.Replacement == null)
-                    break;
+                if (reservedTiles.Contains(node))
+                    continue;
 
-                var prototype = _entManager.GetComponent<MetaDataComponent>(uid.Value).EntityPrototype;
+                // Empty tile, skip if relevant.
+                if (!emptyTiles && (!_maps.TryGetTile(_grid, node, out var tile) || tile.IsEmpty))
+                    continue;
 
-                if (prototype?.ID == gen.Replacement)
-                {
-                    replaceEntities[node] = uid.Value;
-                    found = true;
-                    break;
-                }
-            }
+                // Check if it's a valid spawn, if so then use it.
+                var enumerator = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, node);
+                var found = false;
 
-            if (!found)
-                continue;
+                // We use existing entities as a mark to spawn in place
+                // OR
+                // We check for any existing entities to see if we can spawn there.
+                while (enumerator.MoveNext(out var uid))
+                {
+                    // We can't replace so just stop here.
+                    if (gen.Replacement == null)
+                        break;
 
-            // Add it to valid nodes.
-            availableTiles.Add(node);
+                    var prototype = _entManager.GetComponent<MetaDataComponent>(uid.Value).EntityPrototype;
 
-            await SuspendDungeon();
+                    if (prototype?.ID == gen.Replacement)
+                    {
+                        replaceEntities[node] = uid.Value;
+                        found = true;
+                        break;
+                    }
+                }
 
-            if (!ValidateResume())
-                return;
-        }
+                if (!found)
+                    continue;
 
-        var remapping = new Dictionary<EntProtoId, EntProtoId>();
+                // Add it to valid nodes.
+                availableTiles.Add(node);
 
-        // TODO: Move this to engine
-        if (_prototype.TryIndex(gen.Entity, out var proto) &&
-            proto.Components.TryGetComponent("EntityRemap", out var comps))
-        {
-            var remappingComp = (EntityRemapComponent) comps;
-            remapping = remappingComp.Mask;
-        }
+                await SuspendDungeon();
 
-        var frontier = new ValueList<Vector2i>(32);
+                if (!ValidateResume())
+                    return;
+            }
 
-        // Iterate the group counts and pathfind out each group.
-        for (var i = 0; i < gen.Count; i++)
-        {
-            await SuspendDungeon();
+            var remapping = new Dictionary<EntProtoId, EntProtoId>();
 
-            if (!ValidateResume())
-                return;
+            // TODO: Move this to engine
+            if (_prototype.TryIndex(gen.Entity, out var proto) &&
+                proto.Components.TryGetComponent("EntityRemap", out var comps))
+            {
+                var remappingComp = (EntityRemapComponent) comps;
+                remapping = remappingComp.Mask;
+            }
 
-            var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1);
+            var frontier = new ValueList<Vector2i>(32);
 
-            // While we have remaining tiles keep iterating
-            while (groupSize > 0 && availableTiles.Count > 0)
+            // Iterate the group counts and pathfind out each group.
+            for (var i = 0; i < gen.Count; i++)
             {
-                var startNode = random.PickAndTake(availableTiles);
-                frontier.Clear();
-                frontier.Add(startNode);
+                await SuspendDungeon();
+
+                if (!ValidateResume())
+                    return;
+
+                var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1);
 
-                // This essentially may lead to a vein being split in multiple areas but the count matters more than position.
-                while (frontier.Count > 0 && groupSize > 0)
+                // While we have remaining tiles keep iterating
+                while (groupSize > 0 && availableTiles.Count > 0)
                 {
-                    // Need to pick a random index so we don't just get straight lines of ores.
-                    var frontierIndex = random.Next(frontier.Count);
-                    var node = frontier[frontierIndex];
-                    frontier.RemoveSwap(frontierIndex);
-                    availableTiles.Remove(node);
-
-                    // Add neighbors if they're valid, worst case we add no more and pick another random seed tile.
-                    for (var x = -1; x <= 1; x++)
+                    var startNode = random.PickAndTake(availableTiles);
+                    frontier.Clear();
+                    frontier.Add(startNode);
+
+                    // This essentially may lead to a vein being split in multiple areas but the count matters more than position.
+                    while (frontier.Count > 0 && groupSize > 0)
                     {
-                        for (var y = -1; y <= 1; y++)
+                        // Need to pick a random index so we don't just get straight lines of ores.
+                        var frontierIndex = random.Next(frontier.Count);
+                        var node = frontier[frontierIndex];
+                        frontier.RemoveSwap(frontierIndex);
+                        availableTiles.Remove(node);
+
+                        // Add neighbors if they're valid, worst case we add no more and pick another random seed tile.
+                        for (var x = -1; x <= 1; x++)
                         {
-                            var neighbor = new Vector2i(node.X + x, node.Y + y);
+                            for (var y = -1; y <= 1; y++)
+                            {
+                                var neighbor = new Vector2i(node.X + x, node.Y + y);
 
-                            if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor))
-                                continue;
+                                if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor))
+                                    continue;
 
-                            frontier.Add(neighbor);
+                                frontier.Add(neighbor);
+                            }
                         }
-                    }
 
-                    var prototype = gen.Entity;
-
-                    if (replaceEntities.TryGetValue(node, out var existingEnt))
-                    {
-                        var existingProto = _entManager.GetComponent<MetaDataComponent>(existingEnt).EntityPrototype;
-                        _entManager.DeleteEntity(existingEnt);
+                        var prototype = gen.Entity;
 
-                        if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped))
+                        if (replaceEntities.TryGetValue(node, out var existingEnt))
                         {
-                            prototype = remapped;
+                            var existingProto = _entManager.GetComponent<MetaDataComponent>(existingEnt).EntityPrototype;
+                            _entManager.DeleteEntity(existingEnt);
+
+                            if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped))
+                            {
+                                prototype = remapped;
+                            }
                         }
-                    }
 
-                    // Tile valid salad so add it.
-                    _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node));
+                        // Tile valid salad so add it.
+                        _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node));
 
-                    groupSize--;
+                        groupSize--;
+                    }
                 }
-            }
 
-            if (groupSize > 0)
-            {
-                _sawmill.Warning($"Found remaining group size for ore veins of {gen.Replacement ?? "null"}!");
+                if (groupSize > 0)
+                {
+                    _sawmill.Warning($"Found remaining group size for ore veins of {gen.Replacement ?? "null"}!");
+                }
             }
         }
     }
index 58583f833d3825676088d1524fe5b9c25eedb2cf..f2bd5a4394cc635fb05d2b1fce355a2efb5094a8 100644 (file)
@@ -134,27 +134,15 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
 
             foreach (var layer in layers)
             {
+                var dungCount = dungeons.Count;
                 await RunLayer(dungeons, position, layer, reservedTiles, seed, random);
 
                 if (config.ReserveTiles)
                 {
-                    // Remove any dungeons passed in so we don't interfere with them
-                    // This is kinda goofy but okay for now.
-                    if (existing != null)
-                    {
-                        for (var j = 0; j < dungeons.Count; j++)
-                        {
-                            var dung = dungeons[j];
-
-                            if (existing.Contains(dung))
-                            {
-                                dungeons.RemoveSwap(j);
-                            }
-                        }
-                    }
-
-                    foreach (var dungeon in dungeons)
+                    // Reserve tiles on any new dungeons.
+                    for (var d = dungCount; d < dungeons.Count; d++)
                     {
+                        var dungeon = dungeons[d];
                         reservedTiles.UnionWith(dungeon.AllTiles);
                     }
                 }
@@ -202,6 +190,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
             npcSystem.WakeNPC(npc.Owner, npc.Comp);
         }
 
+        _sawmill.Info($"Finished generating dungeon {_gen} with seed {_seed}");
         return dungeons;
     }
 
@@ -276,7 +265,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
                 await PostGen(mob, dungeons[^1], random);
                 break;
             case EntityTableDunGen entityTable:
-                await PostGen(entityTable, dungeons[^1], random);
+                await PostGen(entityTable, dungeons, reservedTiles, random);
                 break;
             case NoiseDistanceDunGen distance:
                 dungeons.Add(await GenerateNoiseDistanceDunGen(position, distance, reservedTiles, seed, random));
@@ -285,7 +274,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
                 dungeons.Add(await GenerateNoiseDunGen(position, noise, reservedTiles, seed, random));
                 break;
             case OreDunGen ore:
-                await PostGen(ore, dungeons[^1], random);
+                await PostGen(ore, dungeons, reservedTiles, random);
                 break;
             case PrefabDunGen prefab:
                 dungeons.Add(await GeneratePrefabDunGen(position, prefab, reservedTiles, random));
index 71e9bae0cc17578386c9ee48191263ee125d2f58..9f1990956983dc5c3573412e5ae293e251713b7e 100644 (file)
@@ -18,4 +18,10 @@ public sealed partial class EntityTableDunGen : IDunGenLayer
 
     [DataField(required: true)]
     public EntityTableSelector Table;
+
+    /// <summary>
+    /// Should the count be per dungeon or across all dungeons.
+    /// </summary>
+    [DataField]
+    public bool PerDungeon;
 }