From 4afccdd5dbb17e4f2cc8829264bda1750e45bce4 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sun, 18 May 2025 03:10:30 +1000 Subject: [PATCH] DungeonData rework (#37172) * DungeonData rework Back to fields, serializes better, just make new layers dumby. * wawawewa * Fix this * Fixes * review * thanks fork * fix --- ...toCabling.cs => DungeonJob.AutoCabling.cs} | 10 +- ...ob.PostGenBiome.cs => DungeonJob.Biome.cs} | 4 +- ...ayer.cs => DungeonJob.BiomeMarkerLayer.cs} | 2 +- ...daryWall.cs => DungeonJob.BoundaryWall.cs} | 22 +- ...Clutter.cs => DungeonJob.CornerClutter.cs} | 17 +- ...tGenCorridor.cs => DungeonJob.Corridor.cs} | 10 +- ...utter.cs => DungeonJob.CorridorClutter.cs} | 10 +- ...cs => DungeonJob.CorridorDecalSkirting.cs} | 13 +- .../DungeonJob/DungeonJob.DunGenFill.cs | 54 --- .../DungeonJob/DungeonJob.DunGenPrefab.cs | 40 +- .../DungeonJob.DunGenReplaceTile.cs | 56 +-- ...rance.cs => DungeonJob.DungeonEntrance.cs} | 14 +- ...ceFlank.cs => DungeonJob.EntranceFlank.cs} | 15 +- ...nGenExterior.cs => DungeonJob.Exterior.cs} | 5 +- ...Window.cs => DungeonJob.ExternalWindow.cs} | 17 +- .../Procedural/DungeonJob/DungeonJob.Fill.cs | 39 ++ ...onJob.PostGen.cs => DungeonJob.Helpers.cs} | 4 +- ...Window.cs => DungeonJob.InternalWindow.cs} | 15 +- ...tGenJunction.cs => DungeonJob.Junction.cs} | 15 +- ...tion.cs => DungeonJob.MiddleConnection.cs} | 23 +- ...eonJob.MobDunGen.cs => DungeonJob.Mobs.cs} | 7 +- ...Job.DunGenNoise.cs => DungeonJob.Noise.cs} | 0 ...geonJob.OreDunGen.cs => DungeonJob.Ore.cs} | 0 .../DungeonJob.PostGenDungeonConnector.cs | 6 - ...Entrance.cs => DungeonJob.RoomEntrance.cs} | 28 +- ...s => DungeonJob.SplineDungeonConnector.cs} | 18 +- ...enWallMount.cs => DungeonJob.WallMount.cs} | 38 +- ...nJob.PostGenWorm.cs => DungeonJob.Worm.cs} | 10 +- .../Procedural/DungeonJob/DungeonJob.cs | 92 ++-- .../EntityTable/EntityTableSystem.cs | 6 + Content.Shared/Procedural/DungeonConfig.cs | 6 - Content.Shared/Procedural/DungeonData.cs | 105 ---- .../DungeonGenerators/PrefabDunGen.cs | 12 +- .../DungeonGenerators/PrototypeDunGen.cs | 24 + .../FillGridDunGen.cs | 5 +- .../Procedural/DungeonLayers/MobsDunGen.cs | 4 +- .../Procedural/Loot/BiomeTemplateLoot.cs | 5 +- .../PostGeneration/AutoCablingDunGen.cs | 12 +- .../PostGeneration/BoundaryWallDunGen.cs | 12 + .../PostGeneration/CornerClutterDunGen.cs | 11 +- .../PostGeneration/CorridorClutterDunGen.cs | 4 +- .../CorridorDecalSkirtingDunGen.cs | 10 +- .../PostGeneration/CorridorDunGen.cs | 10 +- .../PostGeneration/DungeonEntranceDunGen.cs | 16 +- .../PostGeneration/EntranceFlankDunGen.cs | 18 +- .../PostGeneration/ExternalWindowDunGen.cs | 19 +- .../PostGeneration/InternalWindowDunGen.cs | 18 +- .../PostGeneration/JunctionDunGen.cs | 16 +- .../PostGeneration/MiddleConnectionDunGen.cs | 14 + .../PostGeneration/RoomEntranceDunGen.cs | 19 +- .../SplineDungeonConnectorDunGen.cs | 9 + .../PostGeneration/WallMountDunGen.cs | 11 + .../PostGeneration/WormCorridorDunGen.cs | 6 + .../Salvage/SharedSalvageSystem.Magnet.cs | 4 - Content.Shared/Storage/EntitySpawnEntry.cs | 12 + .../Prototypes/Procedural/dungeon_configs.yml | 457 +++++++++++------- Resources/Prototypes/Procedural/vgroid.yml | 26 +- 57 files changed, 759 insertions(+), 696 deletions(-) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenAutoCabling.cs => DungeonJob.AutoCabling.cs} (92%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenBiome.cs => DungeonJob.Biome.cs} (94%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenBiomeMarkerLayer.cs => DungeonJob.BiomeMarkerLayer.cs} (97%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenBoundaryWall.cs => DungeonJob.BoundaryWall.cs} (80%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenCornerClutter.cs => DungeonJob.CornerClutter.cs} (69%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenCorridor.cs => DungeonJob.Corridor.cs} (89%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenCorridorClutter.cs => DungeonJob.CorridorClutter.cs} (82%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenCorridorDecalSkirting.cs => DungeonJob.CorridorDecalSkirting.cs} (93%) delete mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenDungeonEntrance.cs => DungeonJob.DungeonEntrance.cs} (88%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenEntranceFlank.cs => DungeonJob.EntranceFlank.cs} (66%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.DunGenExterior.cs => DungeonJob.Exterior.cs} (88%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenExternalWindow.cs => DungeonJob.ExternalWindow.cs} (86%) create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGen.cs => DungeonJob.Helpers.cs} (98%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenInternalWindow.cs => DungeonJob.InternalWindow.cs} (84%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenJunction.cs => DungeonJob.Junction.cs} (87%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenMiddleConnection.cs => DungeonJob.MiddleConnection.cs} (81%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.MobDunGen.cs => DungeonJob.Mobs.cs} (90%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.DunGenNoise.cs => DungeonJob.Noise.cs} (100%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.OreDunGen.cs => DungeonJob.Ore.cs} (100%) delete mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenRoomEntrance.cs => DungeonJob.RoomEntrance.cs} (59%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenSplineDungeonConnector.cs => DungeonJob.SplineDungeonConnector.cs} (85%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenWallMount.cs => DungeonJob.WallMount.cs} (52%) rename Content.Server/Procedural/DungeonJob/{DungeonJob.PostGenWorm.cs => DungeonJob.Worm.cs} (93%) delete mode 100644 Content.Shared/Procedural/DungeonData.cs rename Content.Shared/Procedural/{DungeonGenerators => DungeonLayers}/FillGridDunGen.cs (79%) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs similarity index 92% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs index 1ff28719fc..8c49a7d606 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs @@ -13,14 +13,8 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(AutoCablingDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(AutoCablingDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Entities.TryGetValue(DungeonDataKey.Cabling, out var ent)) - { - LogDataError(typeof(AutoCablingDunGen)); - return; - } - // There's a lot of ways you could do this. // For now we'll just connect every LV cable in the dungeon. var cableTiles = new HashSet(); @@ -157,7 +151,7 @@ public sealed partial class DungeonJob if (found) continue; - _entManager.SpawnEntity(ent, _maps.GridTileToLocal(_gridUid, _grid, tile)); + _entManager.SpawnEntity(gen.Entity, _maps.GridTileToLocal(_gridUid, _grid, tile)); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs similarity index 94% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs index 9e5f3bdcfc..ea2e7cfba1 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs @@ -14,7 +14,7 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(BiomeDunGen dunGen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(BiomeDunGen dunGen, Dungeon dungeon, HashSet reservedTiles, Random random) { if (!_prototype.TryIndex(dunGen.BiomeTemplate, out var indexedBiome)) return; @@ -31,7 +31,7 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(node)) continue; - + if (dunGen.TileMask is not null) { if (!dunGen.TileMask.Contains(((ContentTileDefinition) _tileDefManager[tileRef.Value.Tile.TypeId]).ID)) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs similarity index 97% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs index fb0eaa0157..abc74ddc4f 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs @@ -15,7 +15,7 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(BiomeMarkerLayerDunGen dunGen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(BiomeMarkerLayerDunGen dunGen, Dungeon dungeon, HashSet reservedTiles, Random random) { // If we're adding biome then disable it and just use for markers. if (_entManager.EnsureComponent(_gridUid, out BiomeComponent biomeComp)) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs similarity index 80% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs index 84697a56bc..b56a97d40b 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs @@ -12,27 +12,13 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(BoundaryWallDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(BoundaryWallDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var protoTileDef) || - !data.Entities.TryGetValue(DungeonDataKey.Walls, out var wall)) - { - _sawmill.Error($"Error finding dungeon data for {nameof(gen)}"); - return; - } - - var tileDef = _tileDefManager[protoTileDef]; + var tileDef = _tileDefManager[gen.Tile]; var tiles = new List<(Vector2i Index, Tile Tile)>(dungeon.RoomExteriorTiles.Count); - if (!data.Entities.TryGetValue(DungeonDataKey.CornerWalls, out var cornerWall)) - { - cornerWall = wall; - } - - if (cornerWall == default) - { - cornerWall = wall; - } + var wall = gen.Wall; + var cornerWall = gen.CornerWall ?? gen.Wall; // Spawn wall outline // - Tiles first diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs similarity index 69% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs index f785829850..e653ad4a4d 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.CornerClutter.cs @@ -1,8 +1,6 @@ using System.Threading.Tasks; using Content.Shared.Procedural; using Content.Shared.Procedural.PostGeneration; -using Content.Shared.Storage; -using Robust.Shared.Physics.Components; using Robust.Shared.Random; namespace Content.Server.Procedural.DungeonJob; @@ -12,16 +10,15 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(CornerClutterDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(CornerClutterDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.SpawnGroups.TryGetValue(DungeonDataKey.CornerClutter, out var corner)) - { - _sawmill.Error(Environment.StackTrace); - return; - } + var contentsTable = _prototype.Index(gen.Contents); foreach (var tile in dungeon.CorridorTiles) { + if (reservedTiles.Contains(tile)) + continue; + var blocked = _anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask); if (blocked) @@ -45,8 +42,8 @@ public sealed partial class DungeonJob if (random.Prob(gen.Chance)) { var coords = _maps.GridTileToLocal(_gridUid, _grid, tile); - var protos = EntitySpawnCollection.GetSpawns(_prototype.Index(corner).Entries, random); - _entManager.SpawnEntities(coords, protos); + var protos = contentsTable.Table.GetSpawns(random, _entManager, _prototype); + _entManager.SpawnEntitiesAttachedTo(coords, protos); } break; diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs similarity index 89% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs index 8ea79ffe54..bf9f910b94 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs @@ -12,14 +12,8 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(CorridorDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(CorridorDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto)) - { - LogDataError(typeof(CorridorDunGen)); - return; - } - var entrances = new List(dungeon.Rooms.Count); // Grab entrances @@ -98,7 +92,7 @@ public sealed partial class DungeonJob WidenCorridor(dungeon, gen.Width, corridorTiles); var setTiles = new List<(Vector2i, Tile)>(); - var tileDef = (ContentTileDefinition) _tileDefManager[tileProto]; + var tileDef = (ContentTileDefinition) _tileDefManager[gen.Tile]; foreach (var tile in corridorTiles) { diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorClutter.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs similarity index 82% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorClutter.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs index cb7c4b210c..e0be852733 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorClutter.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs @@ -12,10 +12,11 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(CorridorClutterDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(CorridorClutterDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { var physicsQuery = _entManager.GetEntityQuery(); var count = (int) Math.Ceiling(dungeon.CorridorTiles.Count * gen.Chance); + var contents = _prototype.Index(gen.Contents); while (count > 0) { @@ -42,9 +43,12 @@ public sealed partial class DungeonJob count--; - var protos = EntitySpawnCollection.GetSpawns(gen.Contents, random); + if (reservedTiles.Contains(tile)) + continue; + + var protos = _entTable.GetSpawns(contents, random); var coords = _maps.ToCenterCoordinates(_gridUid, tile, _grid); - _entManager.SpawnEntities(coords, protos); + _entManager.SpawnEntitiesAttachedTo(coords, protos); await SuspendIfOutOfTime(); if (!ValidateResume()) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs similarity index 93% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs index 3b516c3fa8..cd8737e6ec 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs @@ -13,13 +13,8 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(CorridorDecalSkirtingDunGen decks, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(CorridorDecalSkirtingDunGen decks, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Colors.TryGetValue(DungeonDataKey.Decals, out var color)) - { - _sawmill.Error(Environment.StackTrace); - } - var directions = new ValueList(4); var pocketDirections = new ValueList(4); var doorQuery = _entManager.GetEntityQuery(); @@ -88,7 +83,7 @@ public sealed partial class DungeonJob { // Decals not being centered biting my ass again var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: color); + _decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color); } } @@ -101,7 +96,7 @@ public sealed partial class DungeonJob { // Decals not being centered biting my ass again var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: color); + _decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color); } continue; @@ -116,7 +111,7 @@ public sealed partial class DungeonJob if (decks.CornerDecals.TryGetValue(dirFlag, out var cDir)) { var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: color); + _decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs deleted file mode 100644 index 77c615d378..0000000000 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Numerics; -using System.Threading.Tasks; -using Content.Shared.Maps; -using Content.Shared.Procedural; -using Content.Shared.Procedural.DungeonGenerators; - -namespace Content.Server.Procedural.DungeonJob; - -public sealed partial class DungeonJob -{ - /// - /// - /// - private async Task GenerateFillDunGen(FillGridDunGen fill, DungeonData data, HashSet reservedTiles) - { - if (!data.Entities.TryGetValue(DungeonDataKey.Fill, out var fillEnt)) - { - LogDataError(typeof(FillGridDunGen)); - return Dungeon.Empty; - } - - var roomTiles = new HashSet(); - var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); - - while (tiles.MoveNext(out var tileRef)) - { - var tile = tileRef.Value.GridIndices; - - if (reservedTiles.Contains(tile)) - continue; - - if (fill.AllowedTiles != null && !fill.AllowedTiles.Contains(((ContentTileDefinition) _tileDefManager[tileRef.Value.Tile.TypeId]).ID)) - continue; - - if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); - _entManager.SpawnEntity(fillEnt, gridPos); - - roomTiles.Add(tile); - - await SuspendDungeon(); - if (!ValidateResume()) - break; - } - - var dungeon = new Dungeon(); - var room = new DungeonRoom(roomTiles, Vector2.Zero, Box2i.Empty, new HashSet()); - dungeon.AddRoom(room); - - return dungeon; - } -} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs index 33bbeba4b5..8eb85e2cb8 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs @@ -14,15 +14,8 @@ public sealed partial class DungeonJob /// /// /// - private async Task GeneratePrefabDunGen(Vector2i position, DungeonData data, PrefabDunGen prefab, HashSet reservedTiles, Random random) + private async Task GeneratePrefabDunGen(Vector2i position, PrefabDunGen prefab, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.Whitelists.TryGetValue(DungeonDataKey.Rooms, out var roomWhitelist)) - { - LogDataError(typeof(PrefabDunGen)); - return Dungeon.Empty; - } - var preset = prefab.Presets[random.Next(prefab.Presets.Count)]; var gen = _prototype.Index(preset); @@ -50,9 +43,9 @@ public sealed partial class DungeonJob { var whitelisted = false; - if (roomWhitelist?.Tags != null) + if (prefab.RoomWhitelist?.Tags != null) { - foreach (var tag in roomWhitelist.Tags) + foreach (var tag in prefab.RoomWhitelist.Tags) { if (proto.Tags.Contains(tag)) { @@ -164,6 +157,7 @@ public sealed partial class DungeonJob // Then for overlaps choose either 1x1 / 3x1 // Pick a random tile for it and then expand outwards as relevant (weighted towards middle?) + var fallbackTile = prefab.FallbackTile; for (var i = 0; i < chosenPacks.Length; i++) { @@ -181,29 +175,35 @@ public sealed partial class DungeonJob Angle roomRotation = Angle.Zero; Matrix3x2 matty; + // If no room found then try rotated dimensions if (!roomProtos.TryGetValue(roomDimensions, out var roomProto)) { roomDimensions = new Vector2i(roomDimensions.Y, roomDimensions.X); + // If nothing at all then no valid rooms, try fallback tile and log it. if (!roomProtos.TryGetValue(roomDimensions, out roomProto)) { - matty = Matrix3x2.Multiply(packTransform, dungeonTransform); - - for (var x = roomSize.Left; x < roomSize.Right; x++) + if (fallbackTile != null) { - for (var y = roomSize.Bottom; y < roomSize.Top; y++) + matty = Matrix3x2.Multiply(packTransform, dungeonTransform); + + for (var x = roomSize.Left; x < roomSize.Right; x++) { - var index = Vector2.Transform(new Vector2(x, y) + _grid.TileSizeHalfVector - packCenter, matty).Floored(); + for (var y = roomSize.Bottom; y < roomSize.Top; y++) + { + var index = Vector2.Transform(new Vector2(x, y) + _grid.TileSizeHalfVector - packCenter, matty).Floored(); - if (reservedTiles.Contains(index)) - continue; + if (reservedTiles.Contains(index)) + continue; - tiles.Add((index, new Tile(_tileDefManager[tileProto].TileId))); + tiles.Add((index, new Tile(_tileDefManager[fallbackTile.Value].TileId))); + } } + + _maps.SetTiles(_gridUid, _grid, tiles); + tiles.Clear(); } - _maps.SetTiles(_gridUid, _grid, tiles); - tiles.Clear(); _sawmill.Error($"Unable to find room variant for {roomDimensions}, leaving empty."); continue; } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs index 6b36d10109..dfc0932915 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs @@ -12,49 +12,43 @@ public sealed partial class DungeonJob /// /// /// - private async Task GenerateTileReplacementDunGen(ReplaceTileDunGen gen, DungeonData data, HashSet reservedTiles, Random random) + private async Task GenerateTileReplacementDunGen(ReplaceTileDunGen gen, List dungeons, HashSet reservedTiles, Random random) { - var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); var replacements = new List<(Vector2i Index, Tile Tile)>(); - var reserved = new HashSet(); - while (tiles.MoveNext(out var tileRef)) + foreach (var dungeon in dungeons) { - var node = tileRef.Value.GridIndices; - - if (reservedTiles.Contains(node)) - continue; - - foreach (var layer in gen.Layers) + foreach (var node in dungeon.AllTiles) { - var value = layer.Noise.GetNoise(node.X, node.Y); - - if (value < layer.Threshold) + if (reservedTiles.Contains(node)) continue; - Tile tile; + foreach (var layer in gen.Layers) + { + var value = layer.Noise.GetNoise(node.X, node.Y); - if (random.Prob(gen.VariantWeight)) - { - tile = _tileDefManager.GetVariantTile(_prototype.Index(layer.Tile), random); - } - else - { - tile = new Tile(_prototype.Index(layer.Tile).TileId); + if (value < layer.Threshold) + continue; + + Tile tile; + + if (random.Prob(gen.VariantWeight)) + { + tile = _tileDefManager.GetVariantTile(_prototype.Index(layer.Tile), random); + } + else + { + tile = new Tile(_prototype.Index(layer.Tile).TileId); + } + + replacements.Add((node, tile)); + break; } - replacements.Add((node, tile)); - reserved.Add(node); - break; + await SuspendDungeon(); } - await SuspendDungeon(); + _maps.SetTiles(_gridUid, _grid, replacements); } - - _maps.SetTiles(_gridUid, _grid, replacements); - return new Dungeon(new List() - { - new DungeonRoom(reserved, _position, Box2i.Empty, new HashSet()), - }); } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs similarity index 88% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs index abc52f07c6..ef84fb77df 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs @@ -12,18 +12,12 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(DungeonEntranceDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(DungeonEntranceDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entrance)) - { - LogDataError(typeof(DungeonEntranceDunGen)); - return; - } - var rooms = new List(dungeon.Rooms); var roomTiles = new List(); - var tileDef = (ContentTileDefinition) _tileDefManager[tileProto]; + var tileDef = (ContentTileDefinition) _tileDefManager[gen.Tile]; + var contents = _prototype.Index(gen.Contents); for (var i = 0; i < gen.Count; i++) { @@ -82,7 +76,7 @@ public sealed partial class DungeonJob var gridCoords = _maps.GridTileToLocal(_gridUid, _grid, tile); // Need to offset the spawn to avoid spawning in the room. - foreach (var ent in EntitySpawnCollection.GetSpawns(_prototype.Index(entrance).Entries, random)) + foreach (var ent in _entTable.GetSpawns(contents, random)) { _entManager.SpawnAtPosition(ent, gridCoords); } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs similarity index 66% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs index 3a1c7a3779..1788c23cae 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs @@ -13,18 +13,12 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(EntranceFlankDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(EntranceFlankDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.EntranceFlank, out var flankProto)) - { - _sawmill.Error($"Unable to get dungeon data for {nameof(gen)}"); - return; - } - var tiles = new List<(Vector2i Index, Tile)>(); - var tileDef = _tileDefManager[tileProto]; + var tileDef = _tileDefManager[gen.Tile]; var spawnPositions = new ValueList(dungeon.Rooms.Count); + var contents = _prototype.Index(gen.Contents); foreach (var room in dungeon.Rooms) { @@ -48,11 +42,10 @@ public sealed partial class DungeonJob } _maps.SetTiles(_gridUid, _grid, tiles); - var entGroup = _prototype.Index(flankProto); foreach (var entrance in spawnPositions) { - _entManager.SpawnEntities(_maps.GridTileToLocal(_gridUid, _grid, entrance), EntitySpawnCollection.GetSpawns(entGroup.Entries, random)); + _entManager.SpawnEntitiesAttachedTo(_maps.GridTileToLocal(_gridUid, _grid, entrance), _entTable.GetSpawns(contents, random)); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs similarity index 88% rename from Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs index bb2c1cbbbf..92237dca2a 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs @@ -1,10 +1,8 @@ using System.Threading.Tasks; -using Content.Server.NPC.Pathfinding; using Content.Shared.Maps; using Content.Shared.NPC; using Content.Shared.Procedural; using Content.Shared.Procedural.DungeonGenerators; -using Robust.Shared.Collections; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -27,7 +25,6 @@ public sealed partial class DungeonJob var startTile = new Vector2i(0, (int) distance).Rotate(angle); Vector2i? dungeonSpawn = null; - var pathfinder = _entManager.System(); // Gridcast SharedPathfindingSystem.GridCast(startTile, position, tile => @@ -52,7 +49,7 @@ public sealed partial class DungeonJob var config = _prototype.Index(dungen.Proto); var nextSeed = random.Next(); - var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Data, config.Layers, reservedTiles, nextSeed, new Random(nextSeed)); + var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Layers, reservedTiles, nextSeed, new Random(nextSeed)); return dungeons; } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs similarity index 86% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs index 9a1b44ec91..f390620186 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs @@ -24,15 +24,8 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(ExternalWindowDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(ExternalWindowDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.Window, out var windowGroup)) - { - _sawmill.Error($"Unable to get dungeon data for {nameof(gen)}"); - return; - } - // Iterate every tile with N chance to spawn windows on that wall per cardinal dir. var chance = 0.25 / 3f; @@ -42,7 +35,7 @@ public sealed partial class DungeonJob random.Shuffle(validTiles); var tiles = new List<(Vector2i, Tile)>(); - var tileDef = _tileDefManager[tileProto]; + var tileDef = _tileDefManager[gen.Tile]; var count = Math.Floor(validTiles.Count * chance); var index = 0; var takenTiles = new HashSet(); @@ -120,15 +113,13 @@ public sealed partial class DungeonJob } _maps.SetTiles(_gridUid, _grid, tiles); - index = 0; - var spawnEntry = _prototype.Index(windowGroup); + var contents = _prototype.Index(gen.Contents); foreach (var tile in tiles) { var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile.Item1); - index += spawnEntry.Entries.Count; - _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(spawnEntry.Entries, random)); + _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); await SuspendDungeon(); if (!ValidateResume()) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs new file mode 100644 index 0000000000..43f453f29a --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task GenerateFillDunGen(FillGridDunGen fill, List dungeons, HashSet reservedTiles) + { + foreach (var dungeon in dungeons) + { + foreach (var tile in dungeon.AllTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + if (!_maps.TryGetTileDef(_grid, tile, out var tileDef)) + continue; + + if (fill.AllowedTiles != null && !fill.AllowedTiles.Contains(tileDef.ID)) + continue; + + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); + _entManager.SpawnEntity(fill.Entity, gridPos); + + await SuspendDungeon(); + if (!ValidateResume()) + break; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs similarity index 98% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs index 84e7563f33..c57757b421 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs @@ -10,9 +10,7 @@ namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { - /* - * Run after the main dungeon generation - */ + // Various helper methods. private static readonly ProtoId WallTag = "Wall"; diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs similarity index 84% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs index d3b8c6d2f5..c9b1481450 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs @@ -12,21 +12,14 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(InternalWindowDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(InternalWindowDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.Window, out var windowGroup)) - { - _sawmill.Error($"Unable to find dungeon data keys for {nameof(gen)}"); - return; - } - // Iterate every room and check if there's a gap beyond it that leads to another room within N tiles // If so then consider windows var minDistance = 4; var maxDistance = 6; - var tileDef = _tileDefManager[tileProto]; - var window = _prototype.Index(windowGroup); + var tileDef = _tileDefManager[gen.Tile]; + var contents = _prototype.Index(gen.Contents); foreach (var room in dungeon.Rooms) { @@ -90,7 +83,7 @@ public sealed partial class DungeonJob var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(window.Entries, random)); + _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); } if (validTiles.Count > 0) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs similarity index 87% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs index 700406eb89..b491f3df27 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs @@ -12,17 +12,10 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(JunctionDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(JunctionDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.Junction, out var junctionProto)) - { - _sawmill.Error($"Dungeon data keys are missing for {nameof(gen)}"); - return; - } - - var tileDef = _tileDefManager[tileProto]; - var entranceGroup = _prototype.Index(junctionProto); + var tileDef = _tileDefManager[gen.Tile]; + var contents = _prototype.Index(gen.Contents); // N-wide junctions foreach (var tile in dungeon.CorridorTiles) @@ -123,7 +116,7 @@ public sealed partial class DungeonJob _maps.SetTile(_gridUid, _grid, weh, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); var coords = _maps.GridTileToLocal(_gridUid, _grid, weh); - _entManager.SpawnEntities(coords, EntitySpawnCollection.GetSpawns(entranceGroup.Entries, random)); + _entManager.SpawnEntitiesAttachedTo(coords, _entTable.GetSpawns(contents, random)); } break; diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs similarity index 81% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs index 15d0f63423..f2ea97b6e6 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs @@ -13,19 +13,8 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(MiddleConnectionDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(MiddleConnectionDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entranceProto) || - !_prototype.TryIndex(entranceProto, out var entrance)) - { - _sawmill.Error($"Tried to run {nameof(MiddleConnectionDunGen)} without any dungeon data set which is unsupported"); - return; - } - - data.SpawnGroups.TryGetValue(DungeonDataKey.EntranceFlank, out var flankProto); - _prototype.TryIndex(flankProto, out var flank); - // Grab all of the room bounds // Then, work out connections between them var roomBorders = new Dictionary>(dungeon.Rooms.Count); @@ -67,7 +56,9 @@ public sealed partial class DungeonJob // TODO: Optional loops var roomConnections = new Dictionary>(); - var tileDef = _tileDefManager[tileProto]; + var tileDef = _tileDefManager[gen.Tile]; + _prototype.TryIndex(gen.Flank, out var flankContents); + var contents = _prototype.Index(gen.Contents); foreach (var (room, border) in roomBorders) { @@ -118,16 +109,16 @@ public sealed partial class DungeonJob width--; _maps.SetTile(_gridUid, _grid, node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - if (flank != null && nodeDistances.Count - i <= 2) + if (flankContents != null && nodeDistances.Count - i <= 2) { - _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(flank.Entries, random)); + _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(flankContents, random)); } else { // Iterate neighbors and check for blockers, if so bulldoze ClearDoor(dungeon, _grid, node); - _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(entrance.Entries, random)); + _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); } if (width == 0) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs similarity index 90% rename from Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs index 150849d2c5..cf1c239b0e 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs @@ -13,6 +13,9 @@ namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { + /// + /// + /// private async Task PostGen( MobsDunGen gen, Dungeon dungeon, @@ -21,8 +24,8 @@ public sealed partial class DungeonJob var availableRooms = new ValueList(); availableRooms.AddRange(dungeon.Rooms); var availableTiles = new ValueList(dungeon.AllTiles); + var contents = _prototype.Index(gen.Contents); - var entities = EntitySpawnCollection.GetSpawns(gen.Groups, random); var count = random.Next(gen.MinCount, gen.MaxCount + 1); var npcs = _entManager.System(); @@ -38,6 +41,8 @@ public sealed partial class DungeonJob continue; } + var entities = _entTable.GetSpawns(contents, random); + foreach (var ent in entities) { var uid = _entManager.SpawnAtPosition(ent, _maps.GridTileToLocal(_gridUid, _grid, tile)); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoise.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Noise.cs similarity index 100% rename from Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoise.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Noise.cs diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs similarity index 100% rename from Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs deleted file mode 100644 index 917b1ffc9c..0000000000 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Server.Procedural.DungeonJob; - -public sealed partial class DungeonJob -{ - -} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs similarity index 59% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs index 09d223e86c..a4a01b5f0b 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs @@ -12,23 +12,19 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(RoomEntranceDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(RoomEntranceDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || - !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entranceProtos) || - !_prototype.TryIndex(entranceProtos, out var entranceIn)) - { - LogDataError(typeof(RoomEntranceDunGen)); - return; - } - var setTiles = new List<(Vector2i, Tile)>(); - var tileDef = _tileDefManager[tileProto]; + var tileDef = _tileDefManager[gen.Tile]; + var contents = _prototype.Index(gen.Contents); foreach (var room in dungeon.Rooms) { foreach (var entrance in room.Entrances) { + if (reservedTiles.Contains(entrance)) + continue; + setTiles.Add((entrance, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); } } @@ -39,9 +35,17 @@ public sealed partial class DungeonJob { foreach (var entrance in room.Entrances) { - _entManager.SpawnEntities( + if (reservedTiles.Contains(entrance)) + continue; + + _entManager.SpawnEntitiesAttachedTo( _maps.GridTileToLocal(_gridUid, _grid, entrance), - EntitySpawnCollection.GetSpawns(entranceIn.Entries, random)); + _entTable.GetSpawns(contents, random)); + + await SuspendDungeon(); + + if (!ValidateResume()) + return; } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs similarity index 85% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs index 8fe2f36665..a131efd353 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs @@ -15,25 +15,14 @@ public sealed partial class DungeonJob /// private async Task PostGen( SplineDungeonConnectorDunGen gen, - DungeonData data, List dungeons, HashSet reservedTiles, Random random) { - // TODO: The path itself use the tile - // Widen it randomly (probably for each tile offset it by some changing amount). - // NOOP if (dungeons.Count <= 1) return Dungeon.Empty; - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var fallback) || - !data.Tiles.TryGetValue(DungeonDataKey.WidenTile, out var widen)) - { - LogDataError(typeof(SplineDungeonConnectorDunGen)); - return Dungeon.Empty; - } - var nodes = new List(); foreach (var dungeon in dungeons) @@ -57,7 +46,8 @@ public sealed partial class DungeonJob var tiles = new List<(Vector2i Index, Tile Tile)>(); var pathfinding = _entManager.System(); var allTiles = new HashSet(); - var fallbackTile = new Tile(_prototype.Index(fallback).TileId); + var pathTile = new Tile(_prototype.Index(gen.Tile).TileId); + var widen = _prototype.Index(gen.WidenTile ?? gen.Tile); foreach (var pair in tree) { @@ -112,7 +102,7 @@ public sealed partial class DungeonJob if (random.Prob(0.9f)) { - tile = new Tile(_prototype.Index(widen).TileId); + tile = new Tile(widen.TileId); } else { @@ -132,7 +122,7 @@ public sealed partial class DungeonJob continue; allTiles.Add(node); - tiles.Add((node, fallbackTile)); + tiles.Add((node, pathTile)); } _maps.SetTiles(_gridUid, _grid, tiles); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs similarity index 52% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs index d5c8587ea9..e01fa9b947 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Content.Shared.Maps; using Content.Shared.Procedural; using Content.Shared.Procedural.PostGeneration; using Content.Shared.Storage; @@ -11,25 +12,13 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(WallMountDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(WallMountDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto)) - { - _sawmill.Error($"Tried to run {nameof(WallMountDunGen)} without any dungeon data set which is unsupported"); - return; - } - - var tileDef = _prototype.Index(tileProto); - if (!data.SpawnGroups.TryGetValue(DungeonDataKey.WallMounts, out var spawnProto)) - { - // caves can have no walls - return; - } - var checkedTiles = new HashSet(); var allExterior = new HashSet(dungeon.CorridorExteriorTiles); allExterior.UnionWith(dungeon.RoomExteriorTiles); - var count = 0; + var tileDef = (ContentTileDefinition) _tileDefManager[gen.Tile]; + var contents = _prototype.Index(gen.Contents); foreach (var neighbor in allExterior) { @@ -40,21 +29,18 @@ public sealed partial class DungeonJob if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor)) continue; + if (reservedTiles.Contains(neighbor)) + continue; + _maps.SetTile(_gridUid, _grid, neighbor, _tile.GetVariantTile(tileDef, random)); var gridPos = _maps.GridTileToLocal(_gridUid, _grid, neighbor); - var protoNames = EntitySpawnCollection.GetSpawns(_prototype.Index(spawnProto).Entries, random); + var protoNames = _entTable.GetSpawns(contents, random); - _entManager.SpawnEntities(gridPos, protoNames); - count += protoNames.Count; + _entManager.SpawnEntitiesAttachedTo(gridPos, protoNames); - if (count > 20) - { - count -= 20; - await SuspendDungeon(); - - if (!ValidateResume()) - return; - } + await SuspendDungeon(); + if (!ValidateResume()) + return; } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWorm.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Worm.cs similarity index 93% rename from Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWorm.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.Worm.cs index 6fd00e5482..7367b9147a 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWorm.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Worm.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using Content.Shared.Maps; using Content.Shared.Procedural; using Content.Shared.Procedural.PostGeneration; using Robust.Shared.Collections; @@ -14,19 +15,14 @@ public sealed partial class DungeonJob /// /// /// - private async Task PostGen(WormCorridorDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + private async Task PostGen(WormCorridorDunGen gen, Dungeon dungeon, HashSet reservedTiles, Random random) { - if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || !_prototype.TryIndex(tileProto, out var tileDef)) - { - _sawmill.Error($"Tried to run {nameof(WormCorridorDunGen)} without any dungeon data set which is unsupported"); - return; - } - var networks = new List<(Vector2i Start, HashSet Network)>(); // List of places to start from. var worm = new ValueList(); var startAngles = new Dictionary(); + var tileDef = (ContentTileDefinition) _tileDefManager[gen.Tile]; foreach (var room in dungeon.Rooms) { diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.cs index cdb5eb0805..58583f833d 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Threading; using System.Threading.Tasks; using Content.Server.Decals; @@ -6,6 +7,7 @@ using Content.Server.NPC.HTN; using Content.Server.NPC.Systems; using Content.Server.Shuttles.Systems; using Content.Shared.Construction.EntitySystems; +using Content.Shared.EntityTable; using Content.Shared.Maps; using Content.Shared.Procedural; using Content.Shared.Procedural.DungeonGenerators; @@ -37,6 +39,7 @@ public sealed partial class DungeonJob : Job> private readonly DecalSystem _decals; private readonly DungeonSystem _dungeon; private readonly EntityLookupSystem _lookup; + private readonly EntityTableSystem _entTable; private readonly TagSystem _tags; private readonly TileSystem _tile; private readonly SharedMapSystem _maps; @@ -88,6 +91,7 @@ public sealed partial class DungeonJob : Job> _tile = tile; _tags = _entManager.System(); _maps = _entManager.System(); + _entTable = _entManager.System(); _transform = transform; _physicsQuery = _entManager.GetEntityQuery(); @@ -108,13 +112,20 @@ public sealed partial class DungeonJob : Job> private async Task> GetDungeons( Vector2i position, DungeonConfig config, - DungeonData data, List layers, HashSet reservedTiles, int seed, - Random random) + Random random, + List? existing = null) { var dungeons = new List(); + + // Don't pass dungeons back up the "stack". They are ref types though it's a caller problem if they start trying to mutate it. + if (existing != null) + { + dungeons.AddRange(existing); + } + var count = random.Next(config.MinCount, config.MaxCount + 1); for (var i = 0; i < count; i++) @@ -123,10 +134,25 @@ public sealed partial class DungeonJob : Job> foreach (var layer in layers) { - await RunLayer(dungeons, data, position, layer, reservedTiles, seed, random); + 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) { reservedTiles.UnionWith(dungeon.AllTiles); @@ -152,7 +178,7 @@ public sealed partial class DungeonJob : Job> // Tiles we can no longer generate on due to being reserved elsewhere. var reservedTiles = new HashSet(); - var dungeons = await GetDungeons(position, _gen, _gen.Data, _gen.Layers, reservedTiles, _seed, random); + var dungeons = await GetDungeons(position, _gen, _gen.Layers, reservedTiles, _seed, random); // To make it slightly more deterministic treat this RNG as separate ig. // Post-processing after finishing loading. @@ -181,7 +207,6 @@ public sealed partial class DungeonJob : Job> private async Task RunLayer( List dungeons, - DungeonData data, Vector2i position, IDunGenLayer layer, HashSet reservedTiles, @@ -200,52 +225,52 @@ public sealed partial class DungeonJob : Job> switch (layer) { case AutoCablingDunGen cabling: - await PostGen(cabling, data, dungeons[^1], reservedTiles, random); + await PostGen(cabling, dungeons[^1], reservedTiles, random); break; case BiomeMarkerLayerDunGen markerPost: - await PostGen(markerPost, data, dungeons[^1], reservedTiles, random); + await PostGen(markerPost, dungeons[^1], reservedTiles, random); break; case BiomeDunGen biome: - await PostGen(biome, data, dungeons[^1], reservedTiles, random); + await PostGen(biome, dungeons[^1], reservedTiles, random); break; case BoundaryWallDunGen boundary: - await PostGen(boundary, data, dungeons[^1], reservedTiles, random); + await PostGen(boundary, dungeons[^1], reservedTiles, random); break; case CornerClutterDunGen clutter: - await PostGen(clutter, data, dungeons[^1], reservedTiles, random); + await PostGen(clutter, dungeons[^1], reservedTiles, random); break; case CorridorClutterDunGen corClutter: - await PostGen(corClutter, data, dungeons[^1], reservedTiles, random); + await PostGen(corClutter, dungeons[^1], reservedTiles, random); break; case CorridorDunGen cordor: - await PostGen(cordor, data, dungeons[^1], reservedTiles, random); + await PostGen(cordor, dungeons[^1], reservedTiles, random); break; case CorridorDecalSkirtingDunGen decks: - await PostGen(decks, data, dungeons[^1], reservedTiles, random); + await PostGen(decks, dungeons[^1], reservedTiles, random); break; case EntranceFlankDunGen flank: - await PostGen(flank, data, dungeons[^1], reservedTiles, random); + await PostGen(flank, dungeons[^1], reservedTiles, random); break; case ExteriorDunGen exterior: dungeons.AddRange(await GenerateExteriorDungen(position, exterior, reservedTiles, random)); break; case FillGridDunGen fill: - dungeons.Add(await GenerateFillDunGen(fill, data, reservedTiles)); + await GenerateFillDunGen(fill, dungeons, reservedTiles); break; case JunctionDunGen junc: - await PostGen(junc, data, dungeons[^1], reservedTiles, random); + await PostGen(junc, dungeons[^1], reservedTiles, random); break; case MiddleConnectionDunGen dordor: - await PostGen(dordor, data, dungeons[^1], reservedTiles, random); + await PostGen(dordor, dungeons[^1], reservedTiles, random); break; case DungeonEntranceDunGen entrance: - await PostGen(entrance, data, dungeons[^1], reservedTiles, random); + await PostGen(entrance, dungeons[^1], reservedTiles, random); break; case ExternalWindowDunGen externalWindow: - await PostGen(externalWindow, data, dungeons[^1], reservedTiles, random); + await PostGen(externalWindow, dungeons[^1], reservedTiles, random); break; case InternalWindowDunGen internalWindow: - await PostGen(internalWindow, data, dungeons[^1], reservedTiles, random); + await PostGen(internalWindow, dungeons[^1], reservedTiles, random); break; case MobsDunGen mob: await PostGen(mob, dungeons[^1], random); @@ -263,31 +288,40 @@ public sealed partial class DungeonJob : Job> await PostGen(ore, dungeons[^1], random); break; case PrefabDunGen prefab: - dungeons.Add(await GeneratePrefabDunGen(position, data, prefab, reservedTiles, random)); + dungeons.Add(await GeneratePrefabDunGen(position, prefab, reservedTiles, random)); break; case PrototypeDunGen prototypo: var groupConfig = _prototype.Index(prototypo.Proto); position = (position + random.NextPolarVector2(groupConfig.MinOffset, groupConfig.MaxOffset)).Floored(); - var dataCopy = groupConfig.Data.Clone(); - dataCopy.Apply(data); + switch (prototypo.InheritDungeons) + { + case DungeonInheritance.All: + dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random, existing: dungeons)); + break; + case DungeonInheritance.Last: + dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random, existing: dungeons.GetRange(dungeons.Count - 1, 1))); + break; + case DungeonInheritance.None: + dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random)); + break; + } - dungeons.AddRange(await GetDungeons(position, groupConfig, dataCopy, groupConfig.Layers, reservedTiles, seed, random)); break; case ReplaceTileDunGen replace: - dungeons.Add(await GenerateTileReplacementDunGen(replace, data, reservedTiles, random)); + await GenerateTileReplacementDunGen(replace, dungeons, reservedTiles, random); break; case RoomEntranceDunGen rEntrance: - await PostGen(rEntrance, data, dungeons[^1], reservedTiles, random); + await PostGen(rEntrance, dungeons[^1], reservedTiles, random); break; case SplineDungeonConnectorDunGen spline: - dungeons.Add(await PostGen(spline, data, dungeons, reservedTiles, random)); + dungeons.Add(await PostGen(spline, dungeons, reservedTiles, random)); break; case WallMountDunGen wall: - await PostGen(wall, data, dungeons[^1], reservedTiles, random); + await PostGen(wall, dungeons[^1], reservedTiles, random); break; case WormCorridorDunGen worm: - await PostGen(worm, data, dungeons[^1], reservedTiles, random); + await PostGen(worm, dungeons[^1], reservedTiles, random); break; default: throw new NotImplementedException(); diff --git a/Content.Shared/EntityTable/EntityTableSystem.cs b/Content.Shared/EntityTable/EntityTableSystem.cs index ff499e6760..eab8b87ad7 100644 --- a/Content.Shared/EntityTable/EntityTableSystem.cs +++ b/Content.Shared/EntityTable/EntityTableSystem.cs @@ -9,6 +9,12 @@ public sealed class EntityTableSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; + public IEnumerable GetSpawns(EntityTablePrototype entTableProto, System.Random? rand = null) + { + // convenient + return GetSpawns(entTableProto.Table, rand); + } + public IEnumerable GetSpawns(EntityTableSelector? table, System.Random? rand = null) { if (table == null) diff --git a/Content.Shared/Procedural/DungeonConfig.cs b/Content.Shared/Procedural/DungeonConfig.cs index 2c2adc1803..7c84b1a6a3 100644 --- a/Content.Shared/Procedural/DungeonConfig.cs +++ b/Content.Shared/Procedural/DungeonConfig.cs @@ -5,12 +5,6 @@ namespace Content.Shared.Procedural; [Virtual, DataDefinition] public partial class DungeonConfig { - /// - /// - /// - [DataField] - public DungeonData Data = DungeonData.Empty; - /// /// The secret sauce, procedural generation layers that get run. /// diff --git a/Content.Shared/Procedural/DungeonData.cs b/Content.Shared/Procedural/DungeonData.cs deleted file mode 100644 index f15d974555..0000000000 --- a/Content.Shared/Procedural/DungeonData.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Linq; -using Content.Shared.Maps; -using Content.Shared.Storage; -using Content.Shared.Whitelist; -using Robust.Shared.Prototypes; -using Robust.Shared.Utility; - -namespace Content.Shared.Procedural; - -/// -/// Used to set dungeon values for all layers. -/// -/// -/// This lets us share data between different dungeon configs without having to repeat entire configs. -/// -[DataRecord] -public sealed partial class DungeonData -{ - // I hate this but it also significantly reduces yaml bloat if we add like 10 variations on the same set of layers - // e.g. science rooms, engi rooms, cargo rooms all under PlanetBase for example. - // without having to do weird nesting. It also means we don't need to copy-paste the same prototype across several layers - // The alternative is doing like, - // 2 layer prototype, 1 layer with the specified data, 3 layer prototype, 2 layers with specified data, etc. - // As long as we just keep the code clean over time it won't be bad to maintain. - - public static DungeonData Empty = new(); - - public Dictionary Colors = new(); - public Dictionary Entities = new(); - public Dictionary> SpawnGroups = new(); - public Dictionary> Tiles = new(); - public Dictionary Whitelists = new(); - - /// - /// Applies the specified data to this data. - /// - public void Apply(DungeonData data) - { - // Copy-paste moment. - foreach (var color in data.Colors) - { - Colors[color.Key] = color.Value; - } - - foreach (var color in data.Entities) - { - Entities[color.Key] = color.Value; - } - - foreach (var color in data.SpawnGroups) - { - SpawnGroups[color.Key] = color.Value; - } - - foreach (var color in data.Tiles) - { - Tiles[color.Key] = color.Value; - } - - foreach (var color in data.Whitelists) - { - Whitelists[color.Key] = color.Value; - } - } - - public DungeonData Clone() - { - return new DungeonData - { - // Only shallow clones but won't matter for DungeonJob purposes. - Colors = Colors.ShallowClone(), - Entities = Entities.ShallowClone(), - SpawnGroups = SpawnGroups.ShallowClone(), - Tiles = Tiles.ShallowClone(), - Whitelists = Whitelists.ShallowClone(), - }; - } -} - -public enum DungeonDataKey : byte -{ - // Colors - Decals, - - // Entities - Cabling, - CornerWalls, - Fill, - Junction, - Walls, - - // SpawnGroups - CornerClutter, - Entrance, - EntranceFlank, - WallMounts, - Window, - - // Tiles - FallbackTile, - WidenTile, - - // Whitelists - Rooms, -} diff --git a/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs index aeb24d0144..a9a6d12de4 100644 --- a/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs @@ -1,3 +1,5 @@ +using Content.Shared.Maps; +using Content.Shared.Whitelist; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonGenerators; @@ -6,10 +8,6 @@ namespace Content.Shared.Procedural.DungeonGenerators; /// Places rooms in pre-selected pack layouts. Chooses rooms from the specified whitelist. /// /// -/// DungeonData keys are: -/// - FallbackTile -/// - Rooms -/// public sealed partial class PrefabDunGen : IDunGenLayer { /// @@ -17,4 +15,10 @@ public sealed partial class PrefabDunGen : IDunGenLayer /// [DataField(required: true)] public List> Presets = new(); + + [DataField] + public EntityWhitelist? RoomWhitelist; + + [DataField] + public ProtoId? FallbackTile; } diff --git a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs index 2772c97977..89a4ab216a 100644 --- a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs @@ -8,6 +8,30 @@ namespace Content.Shared.Procedural.DungeonGenerators; /// public sealed partial class PrototypeDunGen : IDunGenLayer { + /// + /// Should we pass in the current level's dungeons to the prototype. + /// + [DataField] + public DungeonInheritance InheritDungeons = DungeonInheritance.None; + [DataField(required: true)] public ProtoId Proto; } + +public enum DungeonInheritance : byte +{ + /// + /// Don't inherit any of the current layer's dungeons for this + /// + None, + + /// + /// Inherit only the last dungeon ran. + /// + Last, + + /// + /// Inherit all of the current layer's dungeons. + /// + All, +} diff --git a/Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs b/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs similarity index 79% rename from Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs index 53c7dd8c66..363de0a511 100644 --- a/Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs @@ -1,7 +1,7 @@ using Content.Shared.Maps; using Robust.Shared.Prototypes; -namespace Content.Shared.Procedural.DungeonGenerators; +namespace Content.Shared.Procedural.DungeonLayers; /// /// Fills unreserved tiles with the specified entity prototype. @@ -17,4 +17,7 @@ public sealed partial class FillGridDunGen : IDunGenLayer /// [DataField] public HashSet>? AllowedTiles; + + [DataField(required: true)] + public EntProtoId Entity; } diff --git a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs index 30b502efe0..5525341eb9 100644 --- a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs @@ -1,4 +1,6 @@ +using Content.Shared.EntityTable; using Content.Shared.Storage; +using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; @@ -17,5 +19,5 @@ public sealed partial class MobsDunGen : IDunGenLayer public int MaxCount = 1; [DataField(required: true)] - public List Groups = new(); + public ProtoId Contents; } diff --git a/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs b/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs index 1947779768..e4968b6e42 100644 --- a/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs +++ b/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs @@ -1,4 +1,5 @@ using Content.Shared.Parallax.Biomes; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Procedural.Loot; @@ -8,6 +9,6 @@ namespace Content.Shared.Procedural.Loot; /// public sealed partial class BiomeTemplateLoot : IDungeonLoot { - [DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Prototype = string.Empty; + [DataField("proto", required: true)] + public ProtoId Prototype = string.Empty; } diff --git a/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs b/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs index 5afad7edb1..f6588aee41 100644 --- a/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs @@ -1,10 +1,12 @@ +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Runs cables throughout the dungeon. /// -/// -/// DungeonData keys are: -/// - Cabling -/// -public sealed partial class AutoCablingDunGen : IDunGenLayer; +public sealed partial class AutoCablingDunGen : IDunGenLayer +{ + [DataField(required: true)] + public EntProtoId Entity; +} diff --git a/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs b/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs index 4151527f8a..19e9d67343 100644 --- a/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs @@ -1,3 +1,6 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// @@ -13,6 +16,15 @@ public sealed partial class BoundaryWallDunGen : IDunGenLayer { [DataField] public BoundaryWallFlags Flags = BoundaryWallFlags.Corridors | BoundaryWallFlags.Rooms; + + [DataField(required: true)] + public EntProtoId Wall; + + [DataField] + public EntProtoId? CornerWall; + + [DataField(required: true)] + public ProtoId Tile; } [Flags] diff --git a/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs b/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs index 2a904281c8..dc048cfb55 100644 --- a/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs @@ -1,14 +1,17 @@ +using Content.Shared.EntityTable; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Spawns entities inside corners. /// -/// -/// Dungeon data keys are: -/// - CornerClutter -/// public sealed partial class CornerClutterDunGen : IDunGenLayer { [DataField] public float Chance = 0.50f; + + [DataField(required:true)] + public ProtoId Contents = new(); } diff --git a/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs index 5b397b40df..8e3d092d1b 100644 --- a/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs @@ -1,4 +1,6 @@ +using Content.Shared.EntityTable; using Content.Shared.Storage; +using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; @@ -14,5 +16,5 @@ public sealed partial class CorridorClutterDunGen : IDunGenLayer /// The default starting bulbs /// [DataField(required: true)] - public List Contents = new(); + public ProtoId Contents; } diff --git a/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs index e609043655..fac9dc97da 100644 --- a/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs @@ -1,7 +1,3 @@ -using Content.Shared.Decals; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; - namespace Content.Shared.Procedural.PostGeneration; /// @@ -26,4 +22,10 @@ public sealed partial class CorridorDecalSkirtingDunGen : IDunGenLayer /// [DataField] public Dictionary CornerDecals = new(); + + /// + /// Optional color to apply to the decals. + /// + [DataField] + public Color? Color; } diff --git a/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs index 6d75cd9cb2..b36c6f9b64 100644 --- a/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs @@ -1,12 +1,11 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Connects room entrances via corridor segments. /// -/// -/// Dungeon data keys are: -/// - FallbackTile -/// public sealed partial class CorridorDunGen : IDunGenLayer { /// @@ -23,4 +22,7 @@ public sealed partial class CorridorDunGen : IDunGenLayer /// [DataField] public float Width = 3f; + + [DataField(required: true)] + public ProtoId Tile; } diff --git a/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs b/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs index 40cc95f5fc..406054cfdc 100644 --- a/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs @@ -1,13 +1,13 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Selects [count] rooms and places external doors to them. /// -/// -/// Dungeon data keys are: -/// - Entrance -/// - FallbackTile -/// public sealed partial class DungeonEntranceDunGen : IDunGenLayer { /// @@ -15,4 +15,10 @@ public sealed partial class DungeonEntranceDunGen : IDunGenLayer /// [DataField] public int Count = 1; + + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents; } diff --git a/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs b/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs index 27baa48ec6..f9be6caf6a 100644 --- a/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs @@ -1,11 +1,17 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Spawns entities on either side of an entrance. /// -/// -/// Dungeon data keys are: -/// - FallbackTile -/// - -/// -public sealed partial class EntranceFlankDunGen : IDunGenLayer; +public sealed partial class EntranceFlankDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents = new(); +} diff --git a/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs b/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs index 0b29344b90..fc992ea7b8 100644 --- a/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs @@ -1,11 +1,18 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// If external areas are found will try to generate windows. /// -/// -/// Dungeon data keys are: -/// - EntranceFlank -/// - FallbackTile -/// -public sealed partial class ExternalWindowDunGen : IDunGenLayer; +public sealed partial class ExternalWindowDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents; +} diff --git a/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs b/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs index 11b1c6a785..22a4839ce2 100644 --- a/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs @@ -1,11 +1,17 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// If internal areas are found will try to generate windows. /// -/// -/// Dungeon data keys are: -/// - FallbackTile -/// - Window -/// -public sealed partial class InternalWindowDunGen : IDunGenLayer; +public sealed partial class InternalWindowDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents; +} diff --git a/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs b/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs index 899f271621..f18f63ddfe 100644 --- a/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs @@ -1,13 +1,13 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Places the specified entities at junction areas. /// -/// -/// Dungeon data keys are: -/// - Entrance -/// - FallbackTile -/// public sealed partial class JunctionDunGen : IDunGenLayer { /// @@ -15,4 +15,10 @@ public sealed partial class JunctionDunGen : IDunGenLayer /// [DataField] public int Width = 3; + + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents; } diff --git a/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs b/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs index a5758c1498..a1040fef9b 100644 --- a/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs @@ -1,3 +1,8 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// @@ -16,4 +21,13 @@ public sealed partial class MiddleConnectionDunGen : IDunGenLayer /// [DataField] public int Count = 1; + + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents; + + [DataField] + public ProtoId? Flank; } diff --git a/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs b/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs index d3b5672dcb..1436f7473d 100644 --- a/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs @@ -1,11 +1,18 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// /// Places tiles / entities onto room entrances. /// -/// -/// DungeonData keys are: -/// - Entrance -/// - FallbackTile -/// -public sealed partial class RoomEntranceDunGen : IDunGenLayer; +public sealed partial class RoomEntranceDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId Tile; + + [DataField] + public ProtoId Contents; +} diff --git a/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs b/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs index ec8349c671..d2f5a2126a 100644 --- a/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs @@ -1,3 +1,6 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// @@ -5,6 +8,12 @@ namespace Content.Shared.Procedural.PostGeneration; /// public sealed partial class SplineDungeonConnectorDunGen : IDunGenLayer { + [DataField(required: true)] + public ProtoId Tile; + + [DataField] + public ProtoId? WidenTile; + /// /// Will divide the distance between the start and end points so that no subdivision is more than these metres away. /// diff --git a/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs b/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs index a5c790cb22..2a47146ca6 100644 --- a/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs @@ -1,3 +1,8 @@ +using Content.Shared.EntityTable; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; /// @@ -10,4 +15,10 @@ public sealed partial class WallMountDunGen : IDunGenLayer /// [DataField] public double Prob = 0.1; + + [DataField(required: true)] + public ProtoId Tile; + + [DataField(required: true)] + public ProtoId Contents; } diff --git a/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs b/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs index b71e845a73..a587d03a7c 100644 --- a/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs @@ -1,3 +1,6 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + namespace Content.Shared.Procedural.PostGeneration; // Ime a worm @@ -32,4 +35,7 @@ public sealed partial class WormCorridorDunGen : IDunGenLayer /// [DataField] public float Width = 3f; + + [DataField(required: true)] + public ProtoId Tile; } diff --git a/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs b/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs index c041722479..3950b1b72b 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs @@ -50,12 +50,8 @@ public abstract partial class SharedSalvageSystem var configProto =_proto.Index(configId); var layers = new Dictionary(); - var data = new DungeonData(); - data.Apply(configProto.Data); - var config = new DungeonConfig { - Data = data, Layers = new(configProto.Layers), MaxCount = configProto.MaxCount, MaxOffset = configProto.MaxOffset, diff --git a/Content.Shared/Storage/EntitySpawnEntry.cs b/Content.Shared/Storage/EntitySpawnEntry.cs index 480863692e..c00d9e100b 100644 --- a/Content.Shared/Storage/EntitySpawnEntry.cs +++ b/Content.Shared/Storage/EntitySpawnEntry.cs @@ -76,6 +76,18 @@ public static class EntitySpawnCollection public float CumulativeProbability { get; set; } = 0f; } + public static List GetSpawns(ProtoId proto, IPrototypeManager? protoManager = null, IRobustRandom? random = null) + { + IoCManager.Resolve(ref protoManager, ref random); + return GetSpawns(protoManager.Index(proto).Entries, random); + } + + public static List GetSpawns(ProtoId proto, System.Random random, IPrototypeManager? protoManager = null) + { + IoCManager.Resolve(ref protoManager); + return GetSpawns(protoManager.Index(proto).Entries, random); + } + /// /// Using a collection of entity spawn entries, picks a random list of entity prototypes to spawn from that collection. /// diff --git a/Resources/Prototypes/Procedural/dungeon_configs.yml b/Resources/Prototypes/Procedural/dungeon_configs.yml index c296aafad6..5da9592995 100644 --- a/Resources/Prototypes/Procedural/dungeon_configs.yml +++ b/Resources/Prototypes/Procedural/dungeon_configs.yml @@ -1,8 +1,11 @@ -# Base configs +# Setups - type: dungeonConfig - id: PlanetBase + id: Experiment layers: - !type:PrefabDunGen + roomWhitelist: + tags: + - SalvageExperiment presets: - Bucket - Wow @@ -11,28 +14,49 @@ - !type:CorridorDunGen width: 3 + tile: FloorSteel - !type:DungeonEntranceDunGen count: 2 + tile: FloorSteel + contents: BaseAirlock - !type:RoomEntranceDunGen + tile: FloorSteel + contents: BaseAirlock - !type:EntranceFlankDunGen + tile: FloorSteel + contents: BaseWindow - !type:ExternalWindowDunGen + tile: FloorSteel + contents: BaseWindow - !type:WallMountDunGen + contents: ScienceLabsWalls + tile: FloorSteel - !type:BoundaryWallDunGen + wall: WallSolid + cornerWall: WallReinforced + tile: FloorSteel - !type:JunctionDunGen width: 1 + tile: FloorSteel + contents: BaseAirlock - !type:JunctionDunGen + width: 3 + tile: FloorSteel + contents: BaseAirlock - !type:AutoCablingDunGen + entity: CableApcExtension - !type:CornerClutterDunGen + contents: BaseClutter - !type:CorridorDecalSkirtingDunGen cardinalDecals: @@ -51,44 +75,8 @@ NorthWest: BrickTileWhiteInnerNw NorthEast: BrickTileWhiteInnerNe -# Setups -- type: dungeonConfig - id: Experiment - data: - colors: - Decals: "#D381C996" - entities: - Cabling: CableApcExtension - CornerWalls: WallReinforced - Walls: WallSolid - spawnGroups: - CornerClutter: BaseClutter - Entrance: BaseAirlock - EntranceFlank: BaseWindow - Junction: BaseAirlock - WallMounts: ScienceLabsWalls - Window: BaseWindow - tiles: - FallbackTile: FloorSteel - whitelists: - Rooms: - tags: - - SalvageExperiment - layers: - - !type:PrototypeDunGen - proto: PlanetBase - - type: dungeonConfig id: Haunted - data: - entities: - Walls: WallRock - tiles: - FallbackTile: FloorCaveDrought - whitelists: - Rooms: - tags: - - Mineshaft layers: - !type:PrefabDunGen presets: @@ -99,183 +87,304 @@ - !type:WormCorridorDunGen width: 3 + tile: FloorCaveDrought - !type:CorridorClutterDunGen - contents: - - id: FloraStalagmite + contents: HauntedClutter - !type:BoundaryWallDunGen + tile: FloorCaveDrought + wall: WallRock + +- type: entityTable + id: HauntedClutter + table: !type:GroupSelector + children: + - id: FloraStalagmite - type: dungeonConfig id: LavaBrig - data: - colors: - Decals: "#DE3A3A96" - entities: - Cabling: CableApcExtension - CornerWalls: WallReinforced - Walls: WallSolid - spawnGroups: - CornerClutter: BaseClutter - Entrance: LavaBrigEntrance - EntranceFlank: BaseWindow - Junction: BaseAirlock - WallMounts: ScienceLabsWalls - Window: BaseWindow - tiles: - FallbackTile: FloorDark - whitelists: - Rooms: - tags: - - LavaBrig layers: - - !type:PrototypeDunGen - proto: PlanetBase + - !type:PrefabDunGen + roomWhitelist: + tags: + - LavaBrig + presets: + - Bucket + - Wow + - SpaceShip + - Tall + + - !type:CorridorDunGen + width: 3 + tile: FloorDark + + - !type:DungeonEntranceDunGen + count: 2 + tile: FloorDark + contents: LavaBrigEntrance + + - !type:RoomEntranceDunGen + tile: FloorDark + contents: BaseAirlock + + - !type:EntranceFlankDunGen + tile: FloorDark + contents: BaseWindow + + - !type:ExternalWindowDunGen + tile: FloorDark + contents: BaseWindow + + - !type:WallMountDunGen + contents: ScienceLabsWalls + tile: FloorDark + + - !type:BoundaryWallDunGen + wall: WallSolid + cornerWall: WallReinforced + tile: FloorDark + + - !type:JunctionDunGen + width: 1 + tile: FloorDark + contents: BaseAirlock + + - !type:JunctionDunGen + width: 3 + tile: FloorDark + contents: BaseAirlock + + - !type:AutoCablingDunGen + entity: CableApcExtension + + - !type:CornerClutterDunGen + contents: BaseClutter + + - !type:CorridorDecalSkirtingDunGen + cardinalDecals: + South: BrickTileWhiteLineS + East: BrickTileWhiteLineE + North: BrickTileWhiteLineN + West: BrickTileWhiteLineW + cornerDecals: + SouthEast: BrickTileWhiteCornerSe + SouthWest: BrickTileWhiteCornerSw + NorthEast: BrickTileWhiteCornerNe + NorthWest: BrickTileWhiteCornerNw + pocketDecals: + SouthWest: BrickTileWhiteInnerSw + SouthEast: BrickTileWhiteInnerSe + NorthWest: BrickTileWhiteInnerNw + NorthEast: BrickTileWhiteInnerNe - type: dungeonConfig id: Mineshaft - data: - entities: - Cabling: Catwalk - spawnGroups: - CornerClutter: MineshaftClutter - Entrance: BaseWoodWall - EntranceFlank: BaseWoodWall - Junction: BaseWoodSupport - Window: BaseWoodWall - tiles: - FallbackTile: FloorCaveDrought - whitelists: - Rooms: - tags: - - Mineshaft layers: - - !type:PrototypeDunGen - proto: PlanetBase + - !type:PrefabDunGen + roomWhitelist: + tags: + - Mineshaft + presets: + - Bucket + - Wow + - SpaceShip + - Tall + + - !type:CorridorDunGen + width: 3 + tile: FloorCaveDrought + + - !type:DungeonEntranceDunGen + count: 2 + tile: FloorCaveDrought + contents: BaseWoodWall + + - !type:RoomEntranceDunGen + tile: FloorCaveDrought + contents: BaseWoodWall + + - !type:EntranceFlankDunGen + tile: FloorCaveDrought + contents: BaseWoodWall + + - !type:ExternalWindowDunGen + tile: FloorCaveDrought + contents: BaseWoodWall + + # No wallmounts + + # No boundary wall + + - !type:JunctionDunGen + width: 1 + tile: FloorCaveDrought + contents: BaseWoodSupport + + - !type:JunctionDunGen + width: 3 + tile: FloorCaveDrought + contents: BaseWoodSupport + + - !type:AutoCablingDunGen + entity: Catwalk + + - !type:CornerClutterDunGen + contents: MineshaftClutter + +# TODO: Check decal skirting fix contents in code. - type: dungeonConfig id: SnowyLabs - data: - colors: - Decals: "#4cc7aa96" - entities: - Cabling: CableApcExtension - CornerWalls: WallSilver - Walls: WallSilver - spawnGroups: - CornerClutter: BaseClutter - Entrance: SnowyLabsEntrance - EntranceFlank: BaseWindow - Junction: BaseAirlock - WallMounts: SnowyLabsWalls - Window: BaseWindow - tiles: - FallbackTile: FloorSteel - whitelists: - Rooms: - tags: - - SnowyLabs layers: - - !type:PrototypeDunGen - proto: PlanetBase + - !type:PrefabDunGen + roomWhitelist: + tags: + - SnowyLabs + presets: + - Bucket + - Wow + - SpaceShip + - Tall + + - !type:CorridorDunGen + width: 3 + tile: FloorSteel + + - !type:DungeonEntranceDunGen + count: 2 + tile: FloorSteel + contents: BaseAirlock + + - !type:RoomEntranceDunGen + tile: FloorSteel + contents: BaseAirlock + + - !type:EntranceFlankDunGen + tile: FloorSteel + contents: BaseWindow + + - !type:ExternalWindowDunGen + tile: FloorSteel + contents: BaseWindow + + - !type:WallMountDunGen + contents: SnowyLabsWalls + tile: FloorSteel + + - !type:BoundaryWallDunGen + wall: WallSilver + tile: FloorSteel + + - !type:JunctionDunGen + width: 1 + tile: FloorSteel + contents: BaseAirlock + + - !type:JunctionDunGen + width: 3 + tile: FloorSteel + contents: BaseAirlock + + - !type:AutoCablingDunGen + entity: CableApcExtension # Spawn groups # Basic -- type: entitySpawnEntry +- type: entityTable id: BaseClutter - entries: - - id: PottedPlantRandom - amount: 1 + table: !type:GroupSelector + children: + - id: PottedPlantRandom + amount: 1 -- type: entitySpawnEntry +- type: entityTable id: BaseAirlock - entries: - - id: CableApcExtension - - id: AirlockGlass + table: !type:GroupSelector + children: + - id: CableApcExtension + - id: AirlockGlass -- type: entitySpawnEntry +- type: entityTable id: BaseWindow - entries: - - id: Grille - - id: Window + table: !type:GroupSelector + children: + - id: Grille + - id: Window # Lava brig -- type: entitySpawnEntry +- type: entityTable id: LavaBrigEntrance - entries: - - id: CableApcExtension - - id: AirlockSecurityGlassLocked + table: !type:GroupSelector + children: + - id: CableApcExtension + - id: AirlockSecurityGlassLocked # Mineshaft -- type: entitySpawnEntry +- type: entityTable id: BaseWoodWall - entries: - - id: RandomWoodenWall + table: !type:GroupSelector + children: + - id: RandomWoodenWall -- type: entitySpawnEntry +- type: entityTable id: BaseWoodSupport - entries: - - id: RandomWoodenSupport + table: !type:GroupSelector + children: + - id: RandomWoodenSupport -- type: entitySpawnEntry +- type: entityTable id: MineshaftClutter - entries: - - id: RandomStalagmiteOrCrystal - amount: 1 + table: !type:GroupSelector + children: + - id: RandomStalagmiteOrCrystal + amount: 1 -- type: entitySpawnEntry +- type: entityTable id: MineshaftWalls - entries: - # Ore - - id: WallRockSalt - prob: 0.6 - orGroup: content - - id: WallRockCoal - prob: 0.6 - orGroup: content - - id: WallRockTin - prob: 0.4 - orGroup: content - - id: WallMining - prob: 0.8 - orGroup: content + table: !type:GroupSelector + children: + # Ore + - id: WallRockSalt + prob: 0.6 + - id: WallRockCoal + prob: 0.6 + - id: WallRockTin + prob: 0.4 + - id: WallMining + prob: 0.8 # Science lab -- type: entitySpawnEntry +- type: entityTable id: ScienceLabsWalls - entries: - # Posters - - id: RandomPosterLegit - orGroup: content - - id: ExtinguisherCabinetFilled - prob: 0.2 - orGroup: content - - id: RandomPainting - prob: 0.05 - orGroup: content - - id: IntercomCommon - prob: 0.1 - orGroup: content + table: !type:GroupSelector + children: + # Posters + - id: RandomPosterLegit + - id: ExtinguisherCabinetFilled + prob: 0.2 + - id: RandomPainting + prob: 0.05 + - id: IntercomCommon + prob: 0.1 # Snowy labs -- type: entitySpawnEntry +- type: entityTable id: SnowyLabsEntrance - entries: - - id: CableApcExtension - - id: AirlockFreezerHydroponicsLocked + table: !type:GroupSelector + children: + - id: CableApcExtension + - id: AirlockFreezerHydroponicsLocked -- type: entitySpawnEntry +- type: entityTable id: SnowyLabsWalls - entries: - # Posters - - id: RandomPosterLegit - orGroup: content - - id: ExtinguisherCabinetFilled - prob: 0.2 - orGroup: content - - id: RandomPainting - prob: 0.05 - orGroup: content - - id: IntercomScience - prob: 0.1 - orGroup: content + table: !type:GroupSelector + children: + # Posters + - id: RandomPosterLegit + - id: ExtinguisherCabinetFilled + prob: 0.2 + - id: RandomPainting + prob: 0.05 + - id: IntercomScience + prob: 0.1 diff --git a/Resources/Prototypes/Procedural/vgroid.yml b/Resources/Prototypes/Procedural/vgroid.yml index e9044720cc..7547072c4d 100644 --- a/Resources/Prototypes/Procedural/vgroid.yml +++ b/Resources/Prototypes/Procedural/vgroid.yml @@ -18,6 +18,7 @@ proto: VGRoidSmaller - !type:PrototypeDunGen proto: VGRoidSmallPaths + inheritDungeons: All - !type:EntityTableDunGen minCount: 7 maxCount: 12 @@ -26,6 +27,7 @@ # Fill - !type:PrototypeDunGen proto: VGRoidFill + inheritDungeons: All # Ores - !type:OreDunGen replacement: IronRock @@ -135,14 +137,12 @@ - type: dungeonConfig id: VGRoidExterior reserveTiles: true - data: - tiles: - FallbackTile: PlatingAsteroid - WidenTile: FloorAsteroidSand layers: - !type:PrototypeDunGen proto: VGRoidExteriorDungeons - !type:SplineDungeonConnectorDunGen + tile: PlatingAsteroid + widenTile: FloorAsteroidSand - type: dungeonConfig id: VGRoidExteriorDungeons @@ -185,7 +185,12 @@ - !type:MobsDunGen minCount: 8 maxCount: 15 - groups: + contents: VGRoidExteriorDungeonsMobs + +- type: entityTable + id: VGRoidExteriorDungeonsMobs + table: !type:GroupSelector + children: - id: SalvageSpawnerMobMiningAsteroid amount: 1 @@ -215,7 +220,12 @@ - !type:MobsDunGen minCount: 25 maxCount: 35 - groups: + contents: VGRoidSmallPathsMobs + +- type: entityTable + id: VGRoidSmallPathsMobs + table: !type:GroupSelector + children: - id: SalvageSpawnerMobMiningAsteroid amount: 1 @@ -225,10 +235,8 @@ # Fill with rocks. - type: dungeonConfig id: VGRoidFill - data: - entities: - Fill: IronRock layers: - !type:FillGridDunGen + entity: IronRock allowedTiles: - FloorAsteroidSand