Revert biome rework (#38724)

* Revert "Fix world generation (#38713)"

This reverts commit 10fa6ff4af.

* Revert "Biome rework (#37735)"

This reverts commit fe7b96147c.
This commit is contained in:
Pieter-Jan Briers
2025-07-03 20:48:04 +02:00
committed by GitHub
parent 047a49a505
commit e99fc501a6
116 changed files with 3541 additions and 3009 deletions

View File

@@ -151,8 +151,7 @@ public sealed partial class DungeonJob
if (found)
continue;
var ent = _entManager.SpawnEntity(gen.Entity, _maps.GridTileToLocal(_gridUid, _grid, tile));
AddLoadedEntity(tile, ent);
_entManager.SpawnEntity(gen.Entity, _maps.GridTileToLocal(_gridUid, _grid, tile));
}
}
}

View File

@@ -0,0 +1,74 @@
using System.Threading.Tasks;
using Content.Server.Parallax;
using Content.Shared.Maps;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Map;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="BiomeDunGen"/>
/// </summary>
private async Task PostGen(BiomeDunGen dunGen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
{
if (!_prototype.TryIndex(dunGen.BiomeTemplate, out var indexedBiome))
return;
var biomeSystem = _entManager.System<BiomeSystem>();
var seed = random.Next();
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid);
while (tiles.MoveNext(out var tileRef))
{
var node = tileRef.Value.GridIndices;
if (reservedTiles.Contains(node))
continue;
if (dunGen.TileMask is not null)
{
if (!dunGen.TileMask.Contains(((ContentTileDefinition)_tileDefManager[tileRef.Value.Tile.TypeId]).ID))
continue;
}
// Need to set per-tile to override data.
if (biomeSystem.TryGetTile(node, indexedBiome.Layers, seed, (_gridUid, _grid), out var tile))
{
_maps.SetTile(_gridUid, _grid, node, tile.Value);
}
if (biomeSystem.TryGetDecals(node, indexedBiome.Layers, seed, (_gridUid, _grid), out var decals))
{
foreach (var decal in decals)
{
_decals.TryAddDecal(decal.ID, new EntityCoordinates(_gridUid, decal.Position), out _);
}
}
if (biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile ?? tileRef.Value.Tile, seed, (_gridUid, _grid), out var entityProto))
{
var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector));
var xform = xformQuery.Get(ent);
if (!xform.Comp.Anchored)
{
_transform.AnchorEntity(ent, xform);
}
// TODO: Engine bug with SpawnAtPosition
DebugTools.Assert(xform.Comp.Anchored);
}
await SuspendDungeon();
if (!ValidateResume())
return;
}
}
}

View File

@@ -0,0 +1,105 @@
using System.Threading.Tasks;
using Content.Server.Parallax;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Parallax.Biomes.Markers;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Random.Helpers;
using Robust.Shared.Map;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="BiomeMarkerLayerDunGen"/>
/// </summary>
private async Task PostGen(BiomeMarkerLayerDunGen dunGen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
{
// If we're adding biome then disable it and just use for markers.
if (_entManager.EnsureComponent(_gridUid, out BiomeComponent biomeComp))
{
biomeComp.Enabled = false;
}
var biomeSystem = _entManager.System<BiomeSystem>();
var weightedRandom = _prototype.Index(dunGen.MarkerTemplate);
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
var templates = new Dictionary<string, int>();
for (var i = 0; i < dunGen.Count; i++)
{
var template = weightedRandom.Pick(random);
var count = templates.GetOrNew(template);
count++;
templates[template] = count;
}
foreach (var (template, count) in templates)
{
var markerTemplate = _prototype.Index<BiomeMarkerLayerPrototype>(template);
var bounds = new Box2i();
foreach (var tile in dungeon.RoomTiles)
{
bounds = bounds.UnionTile(tile);
}
await SuspendDungeon();
if (!ValidateResume())
return;
biomeSystem.GetMarkerNodes(_gridUid, biomeComp, _grid, markerTemplate, true, bounds, count,
random, out var spawnSet, out var existing, false);
await SuspendDungeon();
if (!ValidateResume())
return;
var checkTile = reservedTiles.Count > 0;
foreach (var ent in existing)
{
if (checkTile && reservedTiles.Contains(_maps.LocalToTile(_gridUid, _grid, _xformQuery.GetComponent(ent).Coordinates)))
{
continue;
}
_entManager.DeleteEntity(ent);
await SuspendDungeon();
if (!ValidateResume())
return;
}
foreach (var (node, mask) in spawnSet)
{
if (reservedTiles.Contains(node))
continue;
string? proto;
if (mask != null && markerTemplate.EntityMask.TryGetValue(mask, out var maskedProto))
{
proto = maskedProto;
}
else
{
proto = markerTemplate.Prototype;
}
var ent = _entManager.SpawnAtPosition(proto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector));
var xform = xformQuery.Get(ent);
if (!xform.Comp.Anchored)
_transform.AnchorEntity(ent, xform);
await SuspendDungeon();
if (!ValidateResume())
return;
}
}
}
}

View File

@@ -32,10 +32,7 @@ public sealed partial class DungeonJob
if (!_anchorable.TileFree((_gridUid, _grid), neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue;
var tile = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
tiles.Add((neighbor, tile));
AddLoadedTile(neighbor, tile);
DebugTools.Assert(dungeon.AllTiles.Contains(neighbor));
tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
}
foreach (var index in dungeon.CorridorExteriorTiles)
@@ -46,10 +43,7 @@ public sealed partial class DungeonJob
if (!_anchorable.TileFree((_gridUid, _grid), index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue;
var tile = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
tiles.Add((index, tile));
AddLoadedTile(index, tile);
DebugTools.Assert(dungeon.AllTiles.Contains(index));
tiles.Add((index, _tile.GetVariantTile((ContentTileDefinition)tileDef, random)));
}
_maps.SetTiles(_gridUid, _grid, tiles);
@@ -88,21 +82,18 @@ public sealed partial class DungeonJob
}
if (isCorner)
{
var uid = _entManager.SpawnEntity(cornerWall, _maps.GridTileToLocal(_gridUid, _grid, index.Index));
AddLoadedEntity(index.Index, uid);
}
_entManager.SpawnEntity(cornerWall, _maps.GridTileToLocal(_gridUid, _grid, index.Index));
if (!isCorner)
_entManager.SpawnEntity(wall, _maps.GridTileToLocal(_gridUid, _grid, index.Index));
if (i % 20 == 0)
{
var uid = _entManager.SpawnEntity(wall, _maps.GridTileToLocal(_gridUid, _grid, index.Index));
AddLoadedEntity(index.Index, uid);
await SuspendDungeon();
if (!ValidateResume())
return;
}
await SuspendDungeon();
if (!ValidateResume())
return;
}
}
}

View File

@@ -1,42 +0,0 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonGenerators;
using Content.Shared.Procedural.PostGeneration;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="BiomeDunGen"/>
/// </summary>
private async Task<Dungeon> PostGen(ChunkDunGen dunGen, HashSet<Vector2i> reservedTiles, Random random)
{
var dungeon = new Dungeon();
var tiles = new HashSet<Vector2i>();
var tr = _position + new Vector2i(dunGen.Size, dunGen.Size);
var oldSeed = dunGen.Noise?.GetSeed() ?? 0;
dunGen.Noise?.SetSeed(_seed + oldSeed);
for (var x = 0; x < dunGen.Size; x++)
{
for (var y = 0; y < dunGen.Size; y++)
{
var index = new Vector2i(_position.X + x, _position.Y + y);
if (reservedTiles.Contains(index))
continue;
if (dunGen.Noise?.GetNoise(x, y) < dunGen.Threshold)
continue;
tiles.Add(index);
}
}
dunGen.Noise?.SetSeed(oldSeed);
var room = new DungeonRoom(tiles, (tr - _position) / 2 + _position, new Box2i(_position, tr), new HashSet<Vector2i>());
dungeon.AddRoom(room);
return dungeon;
}
}

View File

@@ -94,14 +94,12 @@ public sealed partial class DungeonJob
var setTiles = new List<(Vector2i, Tile)>();
var tileDef = (ContentTileDefinition) _tileDefManager[gen.Tile];
foreach (var node in corridorTiles)
foreach (var tile in corridorTiles)
{
if (reservedTiles.Contains(node))
if (reservedTiles.Contains(tile))
continue;
var tile = _tile.GetVariantTile(tileDef, random);
setTiles.Add((node, tile));
AddLoadedTile(node, tile);
setTiles.Add((tile, _tile.GetVariantTile(tileDef, random)));
}
_maps.SetTiles(_gridUid, _grid, setTiles);

View File

@@ -48,13 +48,7 @@ public sealed partial class DungeonJob
var protos = _entTable.GetSpawns(contents, random);
var coords = _maps.ToCenterCoordinates(_gridUid, tile, _grid);
var uids = _entManager.SpawnEntitiesAttachedTo(coords, protos);
foreach (var uid in uids)
{
AddLoadedEntity(tile, uid);
}
_entManager.SpawnEntitiesAttachedTo(coords, protos);
await SuspendIfOutOfTime();
if (!ValidateResume())

View File

@@ -83,8 +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 var did, color: decks.Color);
AddLoadedDecal(tile, did);
_decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color);
}
}
@@ -97,8 +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 var did, color: decks.Color);
AddLoadedDecal(tile, did);
_decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color);
}
continue;
@@ -113,8 +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 var did, color: decks.Color);
AddLoadedDecal(tile, did);
_decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color);
}
}
}

View File

@@ -28,7 +28,7 @@ public sealed partial class DungeonJob
Random random)
{
var tiles = new List<(Vector2i, Tile)>();
var matrix = Matrix3Helpers.CreateTranslation(_position + position);
var matrix = Matrix3Helpers.CreateTranslation(position);
foreach (var layer in dungen.Layers)
{
@@ -76,9 +76,7 @@ public sealed partial class DungeonJob
break;
}
var tile = new Tile(tileDef.TileId, variant: variant);
tiles.Add((adjusted, tile));
AddLoadedTile(adjusted, tile);
tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant)));
roomTiles.Add(adjusted);
break;
}
@@ -103,8 +101,6 @@ public sealed partial class DungeonJob
{
switch (distance)
{
case DunGenDistanceSquared:
return dx * dx + dy * dy;
case DunGenEuclideanSquaredDistance:
return MathF.Min(1f, (dx * dx + dy * dy) / MathF.Sqrt(2));
case DunGenSquareBump:

View File

@@ -196,9 +196,7 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(index))
continue;
var tile = new Tile(_tileDefManager[fallbackTile.Value].TileId);
tiles.Add((index, tile));
AddLoadedTile(index, tile);
tiles.Add((index, new Tile(_tileDefManager[fallbackTile.Value].TileId)));
}
}
@@ -232,14 +230,7 @@ public sealed partial class DungeonJob
var dungeonMatty = Matrix3x2.Multiply(matty, dungeonTransform);
// The expensive bit yippy.
var data = _dungeon.SpawnRoom(_gridUid, _grid, dungeonMatty, room, reservedTiles);
_data.Merge(data);
await SuspendDungeon();
if (!ValidateResume())
return dungeon;
_dungeon.SpawnRoom(_gridUid, _grid, dungeonMatty, room, reservedTiles);
var roomCenter = (room.Offset + room.Size / 2f) * _grid.TileSize;
var roomTiles = new HashSet<Vector2i>(room.Size.X * room.Size.Y);

View File

@@ -42,7 +42,6 @@ public sealed partial class DungeonJob
}
replacements.Add((node, tile));
AddLoadedTile(node, tile);
break;
}

View File

@@ -71,17 +71,14 @@ public sealed partial class DungeonJob
isValid = true;
// Entrance wew
var tileVariant = _tile.GetVariantTile(tileDef, random);
_maps.SetTile(_gridUid, _grid, tile, tileVariant);
AddLoadedTile(tile, tileVariant);
_maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile(tileDef, random));
ClearDoor(dungeon, _grid, tile);
var gridCoords = _maps.GridTileToLocal(_gridUid, _grid, tile);
// Need to offset the spawn to avoid spawning in the room.
foreach (var ent in _entTable.GetSpawns(contents, random))
{
var uid = _entManager.SpawnAtPosition(ent, gridCoords);
AddLoadedEntity(tile, uid);
_entManager.SpawnAtPosition(ent, gridCoords);
}
// Clear out any biome tiles nearby to avoid blocking it

View File

@@ -51,7 +51,6 @@ public sealed partial class DungeonJob
foreach (var ent in entities)
{
var uid = _entManager.SpawnAtPosition(ent, _maps.GridTileToLocal(_gridUid, _grid, tile));
AddLoadedEntity(tile, uid);
_entManager.RemoveComponent<GhostRoleComponent>(uid);
_entManager.RemoveComponent<GhostTakeoverAvailableComponent>(uid);
npcs.SleepNPC(uid);

View File

@@ -35,9 +35,7 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(neighbor))
continue;
var tile = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
tiles.Add((neighbor, tile));
AddLoadedTile(neighbor, tile);
tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
spawnPositions.Add(neighbor);
}
}
@@ -47,12 +45,7 @@ public sealed partial class DungeonJob
foreach (var entrance in spawnPositions)
{
var uids = _entManager.SpawnEntitiesAttachedTo(_maps.GridTileToLocal(_gridUid, _grid, entrance), _entTable.GetSpawns(contents, random));
foreach (var uid in uids)
{
AddLoadedEntity(entrance, uid);
}
_entManager.SpawnEntitiesAttachedTo(_maps.GridTileToLocal(_gridUid, _grid, entrance), _entTable.GetSpawns(contents, random));
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Numerics;
using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.NPC;
@@ -14,22 +13,15 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="ExteriorDunGen"/>
/// </summary>
private async Task<List<Dungeon>> GenerateExteriorDungen(int runCount, int maxRuns, Vector2i position, ExteriorDunGen dungen, HashSet<Vector2i> reservedTiles, Random random)
private async Task<List<Dungeon>> GenerateExteriorDungen(Vector2i position, ExteriorDunGen dungen, HashSet<Vector2i> reservedTiles, Random random)
{
DebugTools.Assert(_grid.ChunkCount > 0);
var aabb = new Box2i(_grid.LocalAABB.BottomLeft.Floored(), _grid.LocalAABB.TopRight.Floored());
// TODO: Cross-layer seeding. Need this because we need to be able to spread the dungeons out.
var angle = new Random(_seed).NextAngle();
var divisors = new Angle(Angle.FromDegrees(360) / maxRuns);
// Offset each dungeon so they don't generate on top of each other.
for (var i = 0; i < runCount; i++)
{
angle += (random.NextFloat(0.6f, 1.4f)) * divisors;
}
var angle = random.NextAngle();
var distance = Math.Max(aabb.Width / 2f + 1f, aabb.Height / 2f + 1f);
var startTile = new Vector2i(0, (int) distance).Rotate(angle);
Vector2i? dungeonSpawn = null;
@@ -55,19 +47,9 @@ public sealed partial class DungeonJob
};
}
// Move it further in based on the spawn angle.
if (dungen.Penetration.Y > 0)
{
var penetration = random.Next(dungen.Penetration.X, dungen.Penetration.Y);
var diff = dungeonSpawn.Value - startTile;
var diffVec = new Vector2(diff.X, diff.Y);
dungeonSpawn = (diffVec.Normalized() * (penetration + diffVec.Length())).Floored() + startTile;
}
var subConfig = _prototype.Index(dungen.Proto);
var config = _prototype.Index(dungen.Proto);
var nextSeed = random.Next();
var (dungeons, newReserved) = await GetDungeons(dungeonSpawn.Value, subConfig, subConfig.Layers, nextSeed, new Random(nextSeed), reserved: reservedTiles);
reservedTiles.UnionWith(newReserved);
var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Layers, reservedTiles, nextSeed, new Random(nextSeed));
return dungeons;
}

View File

@@ -105,9 +105,7 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(neighbor))
continue;
var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
tiles.Add((neighbor, tileVariant));
AddLoadedTile(neighbor, tileVariant);
tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
index++;
takenTiles.Add(neighbor);
}
@@ -121,13 +119,7 @@ public sealed partial class DungeonJob
{
var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile.Item1);
var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random));
foreach (var uid in uids)
{
AddLoadedEntity(tile.Item1, uid);
}
_entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random));
await SuspendDungeon();
if (!ValidateResume())

View File

@@ -18,45 +18,21 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(tile))
continue;
await SuspendDungeon();
if (!ValidateResume())
return;
if (!_maps.TryGetTileDef(_grid, tile, out var tileDef))
continue;
if (fill.AllowedTiles != null && !fill.AllowedTiles.Contains(tileDef.ID))
continue;
// If noise then check it matches.
if (fill.ReservedNoise != null)
{
var value = fill.ReservedNoise.GetNoise(tile.X, tile.Y);
if (fill.DistanceConfig != null)
{
// Need to get dx - dx in a range from -1 -> 1
var dx = 2 * tile.X / fill.Size.X;
var dy = 2 * tile.Y / fill.Size.Y;
var distance = GetDistance(dx, dy, fill.DistanceConfig);
value = MathHelper.Lerp(value, 1f - distance, fill.DistanceConfig.BlendWeight);
}
value *= (fill.Invert ? -1 : 1);
if (value < fill.Threshold)
continue;
}
if (!_anchorable.TileFree((_gridUid, _grid), tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue;
var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile);
var uid = _entManager.SpawnEntity(fill.Entity, gridPos);
_entManager.SpawnEntity(fill.Entity, gridPos);
AddLoadedEntity(tile, uid);
await SuspendDungeon();
if (!ValidateResume())
break;
}
}
}

View File

@@ -52,8 +52,6 @@ public sealed partial class DungeonJob
}
}
}
dungeon.RefreshAllTiles();
}
private void WidenCorridor(Dungeon dungeon, float width, ICollection<Vector2i> corridorTiles)

View File

@@ -81,16 +81,9 @@ public sealed partial class DungeonJob
{
var tile = validTiles[j];
var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile);
var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
_maps.SetTile(_gridUid, _grid, tile, tileVariant);
AddLoadedTile(tile, tileVariant);
_maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random));
foreach (var uid in uids)
{
AddLoadedEntity(tile, uid);
}
_entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random));
}
if (validTiles.Count > 0)

View File

@@ -113,17 +113,10 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(weh))
continue;
var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
_maps.SetTile(_gridUid, _grid, weh, tileVariant);
AddLoadedTile(weh, tileVariant);
_maps.SetTile(_gridUid, _grid, weh, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
var coords = _maps.GridTileToLocal(_gridUid, _grid, weh);
var uids = _entManager.SpawnEntitiesAttachedTo(coords, _entTable.GetSpawns(contents, random));
foreach (var uid in uids)
{
AddLoadedEntity(weh, uid);
}
_entManager.SpawnEntitiesAttachedTo(coords, _entTable.GetSpawns(contents, random));
}
break;

View File

@@ -18,7 +18,6 @@ public sealed partial class DungeonJob
// Grab all of the room bounds
// Then, work out connections between them
var roomBorders = new Dictionary<DungeonRoom, HashSet<Vector2i>>(dungeon.Rooms.Count);
var flank = gen.Flank;
foreach (var room in dungeon.Rooms)
{
@@ -108,30 +107,18 @@ public sealed partial class DungeonJob
continue;
width--;
var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
_maps.SetTile(_gridUid, _grid, node, tileVariant);
AddLoadedTile(node, tileVariant);
_maps.SetTile(_gridUid, _grid, node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
if (flankContents != null && nodeDistances.Count - i <= 2)
{
var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(flankContents, random));
foreach (var uid in uids)
{
AddLoadedEntity(node, uid);
}
_entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(flankContents, random));
}
else
{
// Iterate neighbors and check for blockers, if so bulldoze
ClearDoor(dungeon, _grid, node);
var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random));
foreach (var uid in uids)
{
AddLoadedEntity(node, uid);
}
_entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random));
}
if (width == 0)

View File

@@ -49,7 +49,6 @@ public sealed partial class DungeonJob
_entManager.RemoveComponent<GhostRoleComponent>(uid);
_entManager.RemoveComponent<GhostTakeoverAvailableComponent>(uid);
npcs.SleepNPC(uid);
AddLoadedEntity(tile, uid);
}
break;

View File

@@ -98,9 +98,7 @@ public sealed partial class DungeonJob
var variant = _tile.PickVariant((ContentTileDefinition) tileDef, random);
var adjusted = Vector2.Transform(node + _grid.TileSizeHalfVector, matrix).Floored();
var tileVariant = new Tile(tileDef.TileId, variant: variant);
tiles.Add((adjusted, tileVariant));
AddLoadedTile(adjusted, tileVariant);
tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant)));
roomTiles.Add(adjusted);
tileCount++;
break;
@@ -129,7 +127,8 @@ public sealed partial class DungeonJob
}
}
await SuspendDungeon();
await SuspendIfOutOfTime();
ValidateResume();
}
var center = Vector2.Zero;
@@ -141,7 +140,8 @@ public sealed partial class DungeonJob
center /= roomTiles.Count;
rooms.Add(new DungeonRoom(roomTiles, center, roomArea, new HashSet<Vector2i>()));
await SuspendDungeon();
await SuspendIfOutOfTime();
ValidateResume();
}
_maps.SetTiles(_gridUid, _grid, tiles);

View File

@@ -19,26 +19,12 @@ public sealed partial class DungeonJob
HashSet<Vector2i> reservedTiles,
Random random)
{
var emptyTiles = false;
var replaceEntities = new Dictionary<Vector2i, EntityUid>();
var availableTiles = new List<Vector2i>();
var remapName = _entManager.ComponentFactory.GetComponentName<EntityRemapComponent>();
var replacementRemapping = new Dictionary<EntProtoId, EntProtoId>();
if (_prototype.TryIndex(gen.Replacement, out var replacementProto) &&
replacementProto.Components.TryGetComponent(remapName, out var replacementComps))
{
var remappingComp = (EntityRemapComponent) replacementComps;
replacementRemapping = remappingComp.Mask;
}
if (gen.Replacement != null)
{
replacementRemapping[gen.Replacement.Value] = gen.Entity;
}
foreach (var dungeon in dungeons)
{
var emptyTiles = false;
var replaceEntities = new Dictionary<Vector2i, EntityUid>();
var availableTiles = new List<Vector2i>();
foreach (var node in dungeon.AllTiles)
{
if (reservedTiles.Contains(node))
@@ -55,23 +41,19 @@ public sealed partial class DungeonJob
// We use existing entities as a mark to spawn in place
// OR
// We check for any existing entities to see if we can spawn there.
// We can't replace so just stop here.
if (gen.Replacement != null)
while (enumerator.MoveNext(out var uid))
{
while (enumerator.MoveNext(out var uid))
// We can't replace so just stop here.
if (gen.Replacement == null)
break;
var prototype = _entManager.GetComponent<MetaDataComponent>(uid.Value).EntityPrototype;
if (prototype?.ID == gen.Replacement)
{
var prototype = _entManager.GetComponent<MetaDataComponent>(uid.Value).EntityPrototype;
if (string.IsNullOrEmpty(prototype?.ID))
continue;
// It has a valid remapping so take it over.
if (replacementRemapping.ContainsKey(prototype.ID))
{
replaceEntities[node] = uid.Value;
found = true;
break;
}
replaceEntities[node] = uid.Value;
found = true;
break;
}
}
@@ -86,86 +68,83 @@ public sealed partial class DungeonJob
if (!ValidateResume())
return;
}
}
var remapping = new Dictionary<EntProtoId, EntProtoId>();
var remapping = new Dictionary<EntProtoId, EntProtoId>();
// TODO: Move this to engine
if (_prototype.TryIndex(gen.Entity, out var proto) &&
proto.Components.TryGetComponent(remapName, out var comps))
{
var remappingComp = (EntityRemapComponent) comps;
remapping = remappingComp.Mask;
}
var frontier = new ValueList<Vector2i>(32);
// Iterate the group counts and pathfind out each group.
for (var i = 0; i < gen.Count; i++)
{
var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1);
// While we have remaining tiles keep iterating
while (groupSize > 0 && availableTiles.Count > 0)
// TODO: Move this to engine
if (_prototype.TryIndex(gen.Entity, out var proto) &&
proto.Components.TryGetComponent("EntityRemap", out var comps))
{
var startNode = random.PickAndTake(availableTiles);
frontier.Clear();
frontier.Add(startNode);
// This essentially may lead to a vein being split in multiple areas but the count matters more than position.
while (frontier.Count > 0 && groupSize > 0)
{
// Need to pick a random index so we don't just get straight lines of ores.
var frontierIndex = random.Next(frontier.Count);
var node = frontier[frontierIndex];
frontier.RemoveSwap(frontierIndex);
availableTiles.Remove(node);
// Add neighbors if they're valid, worst case we add no more and pick another random seed tile.
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
var neighbor = new Vector2i(node.X + x, node.Y + y);
if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor))
continue;
frontier.Add(neighbor);
}
}
var prototype = gen.Entity;
// May have been deleted while iteration was suspended.
if (replaceEntities.TryGetValue(node, out var existingEnt) && _entManager.TryGetComponent(existingEnt, out MetaDataComponent? metadata))
{
var existingProto = metadata.EntityPrototype;
_entManager.DeleteEntity(existingEnt);
if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped))
{
prototype = remapped;
}
}
// Tile valid salad so add it.
var uid = _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node));
AddLoadedEntity(node, uid);
groupSize--;
await SuspendDungeon();
if (!ValidateResume())
return;
}
var remappingComp = (EntityRemapComponent) comps;
remapping = remappingComp.Mask;
}
if (groupSize > 0)
var frontier = new ValueList<Vector2i>(32);
// Iterate the group counts and pathfind out each group.
for (var i = 0; i < gen.Count; i++)
{
// Not super worried depending on the gen it's fine.
_sawmill.Debug($"Found remaining group size for ore veins of {gen.Replacement ?? "null"} / {gen.Entity}!");
await SuspendDungeon();
if (!ValidateResume())
return;
var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1);
// While we have remaining tiles keep iterating
while (groupSize > 0 && availableTiles.Count > 0)
{
var startNode = random.PickAndTake(availableTiles);
frontier.Clear();
frontier.Add(startNode);
// This essentially may lead to a vein being split in multiple areas but the count matters more than position.
while (frontier.Count > 0 && groupSize > 0)
{
// Need to pick a random index so we don't just get straight lines of ores.
var frontierIndex = random.Next(frontier.Count);
var node = frontier[frontierIndex];
frontier.RemoveSwap(frontierIndex);
availableTiles.Remove(node);
// Add neighbors if they're valid, worst case we add no more and pick another random seed tile.
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
var neighbor = new Vector2i(node.X + x, node.Y + y);
if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor))
continue;
frontier.Add(neighbor);
}
}
var prototype = gen.Entity;
if (replaceEntities.TryGetValue(node, out var existingEnt))
{
var existingProto = _entManager.GetComponent<MetaDataComponent>(existingEnt).EntityPrototype;
_entManager.DeleteEntity(existingEnt);
if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped))
{
prototype = remapped;
}
}
// Tile valid salad so add it.
_entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node));
groupSize--;
}
}
if (groupSize > 0)
{
_sawmill.Warning($"Found remaining group size for ore veins of {gen.Replacement ?? "null"}!");
}
}
}
}

View File

@@ -1,38 +0,0 @@
using System.Threading.Tasks;
using Content.Server.Light.EntitySystems;
using Content.Shared.Light.Components;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
public async Task RoofGen(RoofDunGen roof, List<Dungeon> dungeons, HashSet<Vector2i> reservedTiles, Random random)
{
var roofComp = _entManager.EnsureComponent<RoofComponent>(_gridUid);
var noise = roof.Noise;
var oldSeed = noise?.GetSeed() ?? 0;
noise?.SetSeed(_seed + oldSeed);
var rooves = _entManager.System<RoofSystem>();
foreach (var dungeon in dungeons)
{
foreach (var tile in dungeon.AllTiles)
{
if (reservedTiles.Contains(tile))
continue;
var value = noise?.GetNoise(tile.X, tile.Y) ?? 1f;
if (value < roof.Threshold)
continue;
rooves.SetRoof((_gridUid, _grid, roofComp), tile, true);
}
}
noise?.SetSeed(oldSeed);
}
}

View File

@@ -25,9 +25,7 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(entrance))
continue;
var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random);
setTiles.Add((entrance, tileVariant));
AddLoadedTile(entrance, tileVariant);
setTiles.Add((entrance, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
}
}
@@ -40,15 +38,10 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(entrance))
continue;
var uids = _entManager.SpawnEntitiesAttachedTo(
_entManager.SpawnEntitiesAttachedTo(
_maps.GridTileToLocal(_gridUid, _grid, entrance),
_entTable.GetSpawns(contents, random));
foreach (var uid in uids)
{
AddLoadedEntity(entrance, uid);
}
await SuspendDungeon();
if (!ValidateResume())

View File

@@ -1,64 +0,0 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="SampleDecalDunGen"/>
/// </summary>
private async Task PostGen(SampleDecalDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
{
var oldSeed = gen.Noise.GetSeed();
gen.Noise.SetSeed(_seed + oldSeed);
foreach (var dungeon in dungeons)
{
foreach (var tile in dungeon.AllTiles)
{
if (reservedTiles.Contains(tile))
continue;
var invert = gen.Invert;
var value = gen.Noise.GetNoise(tile.X, tile.Y);
value = invert ? value * -1 : value;
if (value < gen.Threshold)
continue;
// Not allowed
if (!_maps.TryGetTileRef(_gridUid, _grid, tile, out var tileRef) ||
!gen.AllowedTiles.Contains(_tileDefManager[tileRef.Tile.TypeId].ID))
{
continue;
}
// Occupied?
if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue;
_decals.TryAddDecal(random.Pick(gen.Decals), new EntityCoordinates(_gridUid, tile), out var did);
AddLoadedDecal(tile, did);
if (gen.ReserveTiles)
{
reservedTiles.Add(tile);
}
await SuspendDungeon();
if (!ValidateResume())
return;
}
}
gen.Noise.SetSeed(oldSeed);
}
}

View File

@@ -1,62 +0,0 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="SampleEntityDunGen"/>
/// </summary>
private async Task PostGen(
SampleEntityDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
{
var oldSeed = gen.Noise.GetSeed();
gen.Noise.SetSeed(_seed + oldSeed);
foreach (var dungeon in dungeons)
{
foreach (var tile in dungeon.AllTiles)
{
if (reservedTiles.Contains(tile))
continue;
var invert = gen.Invert;
var value = gen.Noise.GetNoise(tile.X, tile.Y);
value = invert ? value * -1 : value;
if (value < gen.Threshold)
continue;
// Not allowed
if (!_maps.TryGetTileRef(_gridUid, _grid, tile, out var tileRef) ||
!gen.AllowedTiles.Contains(_tileDefManager[tileRef.Tile.TypeId].ID))
{
continue;
}
var gridTile = _maps.GridTileToLocal(_gridUid, _grid, tile);
var uid = _entManager.SpawnAttachedTo(random.Pick(gen.Entities), gridTile);
AddLoadedEntity(tile, uid);
if (gen.ReserveTiles)
{
reservedTiles.Add(tile);
}
await SuspendDungeon();
if (!ValidateResume())
return;
}
}
gen.Noise.SetSeed(oldSeed);
}
}

View File

@@ -1,66 +0,0 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
using Robust.Shared.Map;
using Robust.Shared.Noise;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="SampleTileDunGen"/>
/// </summary>
private async Task PostGen(SampleTileDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
{
var noise = gen.Noise;
var oldSeed = noise.GetSeed();
noise.SetSeed(_seed + oldSeed);
var tiles = new List<(Vector2i Index, Tile Tile)>();
var tileDef = _prototype.Index(gen.Tile);
var variants = tileDef.PlacementVariants.Length;
foreach (var dungeon in dungeons)
{
foreach (var tile in dungeon.AllTiles)
{
if (reservedTiles.Contains(tile))
continue;
var invert = gen.Invert;
var value = noise.GetNoise(tile.X, tile.Y);
value = invert ? value * -1 : value;
if (value < gen.Threshold)
continue;
var variantValue = (noise.GetNoise(tile.X * 8, tile.Y * 8, variants) + 1f) * 100;
var variant = _tile.PickVariant(tileDef, (int)variantValue);
var tileVariant = new Tile(tileDef.TileId, variant: variant);
tiles.Add((tile, tileVariant));
AddLoadedTile(tile, tileVariant);
await SuspendDungeon();
if (!ValidateResume())
return;
}
}
gen.Noise.SetSeed(oldSeed);
_maps.SetTiles(_gridUid, _grid, tiles);
if (gen.ReserveTiles)
{
foreach (var tile in tiles)
{
reservedTiles.Add(tile.Index);
}
}
}
}

View File

@@ -2,7 +2,6 @@ using System.Numerics;
using System.Threading.Tasks;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Map;
using Robust.Shared.Random;
@@ -12,10 +11,10 @@ namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob
{
/// <summary>
/// <see cref="Shared.Procedural.DungeonLayers.SplineDungeonConnectorDunGen"/>
/// <see cref="SplineDungeonConnectorDunGen"/>
/// </summary>
private async Task<Dungeon> PostGen(
Shared.Procedural.DungeonLayers.SplineDungeonConnectorDunGen gen,
SplineDungeonConnectorDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
@@ -60,7 +59,6 @@ public sealed partial class DungeonJob
{
Start = pair.Start,
End = pair.End,
Diagonals = false,
TileCost = node =>
{
// We want these to get prioritised internally and into space if it's a space dungeon.
@@ -112,7 +110,6 @@ public sealed partial class DungeonJob
}
tiles.Add((node, tile));
AddLoadedTile(node, tile);
}
_maps.SetTiles(_gridUid, _grid, tiles);
@@ -126,7 +123,6 @@ public sealed partial class DungeonJob
allTiles.Add(node);
tiles.Add((node, pathTile));
AddLoadedTile(node, pathTile);
}
_maps.SetTiles(_gridUid, _grid, tiles);

View File

@@ -32,18 +32,11 @@ public sealed partial class DungeonJob
if (reservedTiles.Contains(neighbor))
continue;
var tileVariant = _tile.GetVariantTile(tileDef, random);
_maps.SetTile(_gridUid, _grid, neighbor, tileVariant);
AddLoadedTile(neighbor, tileVariant);
_maps.SetTile(_gridUid, _grid, neighbor, _tile.GetVariantTile(tileDef, random));
var gridPos = _maps.GridTileToLocal(_gridUid, _grid, neighbor);
var protoNames = _entTable.GetSpawns(contents, random);
var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, protoNames);
foreach (var uid in uids)
{
AddLoadedEntity(neighbor, uid);
}
_entManager.SpawnEntitiesAttachedTo(gridPos, protoNames);
await SuspendDungeon();
if (!ValidateResume())

View File

@@ -1,7 +1,8 @@
using System.Numerics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Decals;
using Content.Server.NPC.Components;
using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
using Content.Server.Shuttles.Systems;
@@ -22,10 +23,11 @@ using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using IDunGenLayer = Content.Shared.Procedural.IDunGenLayer;
namespace Content.Server.Procedural.DungeonJob;
public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
public sealed partial class DungeonJob : Job<List<Dungeon>>
{
public bool TimeSlice = true;
@@ -58,10 +60,6 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
private readonly ISawmill _sawmill;
private DungeonData _data = new();
private HashSet<Vector2i>? _reservedTiles;
public DungeonJob(
ISawmill sawmill,
double maxTime,
@@ -81,14 +79,12 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
int seed,
Vector2i position,
EntityCoordinates? targetCoordinates = null,
CancellationToken cancellation = default,
HashSet<Vector2i>? reservedTiles = null) : base(maxTime, cancellation)
CancellationToken cancellation = default) : base(maxTime, cancellation)
{
_sawmill = sawmill;
_entManager = entManager;
_prototype = prototype;
_tileDefManager = tileDefManager;
_reservedTiles = reservedTiles;
_anchorable = anchorable;
_decals = decals;
@@ -115,18 +111,17 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
/// <summary>
/// Gets the relevant dungeon, running recursively as relevant.
/// </summary>
/// <param name="reservedTiles">Should we reserve tiles even if the config doesn't specify.</param>
private async Task<(List<Dungeon>, HashSet<Vector2i>)> GetDungeons(
/// <param name="reserve">Should we reserve tiles even if the config doesn't specify.</param>
private async Task<List<Dungeon>> GetDungeons(
Vector2i position,
DungeonConfig config,
List<IDunGenLayer> layers,
HashSet<Vector2i> reservedTiles,
int seed,
Random random,
HashSet<Vector2i>? reserved = null,
List<Dungeon>? existing = null)
{
var dungeons = new List<Dungeon>();
var reservedTiles = reserved == null ? new HashSet<Vector2i>() : new HashSet<Vector2i>(reserved);
// 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)
@@ -142,8 +137,8 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
foreach (var layer in layers)
{
var dungCount = dungeons.Count;
await RunLayer(i, count, config, dungeons, position, layer, reservedTiles, seed, random);
var dungCount = dungeons.Count;
await RunLayer(dungeons, position, layer, reservedTiles, seed, random);
if (config.ReserveTiles)
{
@@ -157,23 +152,24 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
await SuspendDungeon();
if (!ValidateResume())
return (new List<Dungeon>(), new HashSet<Vector2i>());
return new List<Dungeon>();
}
}
// Only return the new dungeons and applicable reserved tiles.
return (dungeons[(existing?.Count ?? 0)..], config.ReturnReserved ? reservedTiles : new HashSet<Vector2i>());
return dungeons;
}
protected override async Task<(List<Dungeon>, DungeonData)> Process()
protected override async Task<List<Dungeon>?> Process()
{
_sawmill.Info($"Generating dungeon {_gen} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}");
_grid.CanSplit = false;
var random = new Random(_seed);
var oldTileCount = _reservedTiles?.Count ?? 0;
var position = (_position + random.NextPolarVector2(_gen.MinOffset, _gen.MaxOffset)).Floored();
var (dungeons, _) = await GetDungeons(position, _gen, _gen.Layers, _seed, random, reserved: _reservedTiles);
// Tiles we can no longer generate on due to being reserved elsewhere.
var reservedTiles = new HashSet<Vector2i>();
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.
@@ -185,7 +181,6 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
}
// Defer splitting so they don't get spammed and so we don't have to worry about tracking the grid along the way.
DebugTools.Assert(oldTileCount == (_reservedTiles?.Count ?? 0));
_grid.CanSplit = true;
_entManager.System<GridFixtureSystem>().CheckSplits(_gridUid);
var npcSystem = _entManager.System<NPCSystem>();
@@ -199,13 +194,10 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
}
_sawmill.Info($"Finished generating dungeon {_gen} with seed {_seed}");
return (dungeons, _data);
return dungeons;
}
private async Task RunLayer(
int runCount,
int maxRuns,
DungeonConfig config,
List<Dungeon> dungeons,
Vector2i position,
IDunGenLayer layer,
@@ -213,7 +205,7 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
int seed,
Random random)
{
// _sawmill.Debug($"Doing postgen {layer.GetType()} for {_gen} with seed {_seed}");
_sawmill.Debug($"Doing postgen {layer.GetType()} for {_gen} with seed {_seed}");
// If there's a way to just call the methods directly for the love of god tell me.
// Some of these don't care about reservedtiles because they only operate on dungeon tiles (which should
@@ -227,12 +219,15 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
case AutoCablingDunGen cabling:
await PostGen(cabling, dungeons[^1], reservedTiles, random);
break;
case BiomeMarkerLayerDunGen markerPost:
await PostGen(markerPost, dungeons[^1], reservedTiles, random);
break;
case BiomeDunGen biome:
await PostGen(biome, dungeons[^1], reservedTiles, random);
break;
case BoundaryWallDunGen boundary:
await PostGen(boundary, dungeons[^1], reservedTiles, random);
break;
case ChunkDunGen chunk:
dungeons.Add(await PostGen(chunk, reservedTiles, random));
break;
case CornerClutterDunGen clutter:
await PostGen(clutter, dungeons[^1], reservedTiles, random);
break;
@@ -249,7 +244,7 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
await PostGen(flank, dungeons[^1], reservedTiles, random);
break;
case ExteriorDunGen exterior:
dungeons.AddRange(await GenerateExteriorDungen(runCount, maxRuns, position, exterior, reservedTiles, random));
dungeons.AddRange(await GenerateExteriorDungen(position, exterior, reservedTiles, random));
break;
case FillGridDunGen fill:
await GenerateFillDunGen(fill, dungeons, reservedTiles);
@@ -290,67 +285,27 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
case PrototypeDunGen prototypo:
var groupConfig = _prototype.Index(prototypo.Proto);
position = (position + random.NextPolarVector2(groupConfig.MinOffset, groupConfig.MaxOffset)).Floored();
List<Dungeon>? inheritedDungeons = null;
HashSet<Vector2i>? inheritedReserved = null;
switch (prototypo.InheritReserved)
{
case ReservedInheritance.All:
inheritedReserved = new HashSet<Vector2i>(reservedTiles);
break;
case ReservedInheritance.None:
break;
default:
throw new NotImplementedException();
}
switch (prototypo.InheritDungeons)
{
case DungeonInheritance.All:
inheritedDungeons = dungeons;
dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random, existing: dungeons));
break;
case DungeonInheritance.Last:
inheritedDungeons = dungeons.GetRange(dungeons.Count - 1, 1);
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;
default:
throw new NotImplementedException();
}
var (newDungeons, newReserved) = await GetDungeons(position,
groupConfig,
groupConfig.Layers,
seed,
random,
reserved: inheritedReserved,
existing: inheritedDungeons);
dungeons.AddRange(newDungeons);
if (groupConfig.ReturnReserved)
{
reservedTiles.UnionWith(newReserved);
}
break;
case ReplaceTileDunGen replace:
await GenerateTileReplacementDunGen(replace, dungeons, reservedTiles, random);
break;
case RoofDunGen roof:
await RoofGen(roof, dungeons, reservedTiles, random);
break;
case RoomEntranceDunGen rEntrance:
await PostGen(rEntrance, dungeons[^1], reservedTiles, random);
break;
case SampleDecalDunGen sdec:
await PostGen(sdec, dungeons, reservedTiles, random);
break;
case SampleEntityDunGen sent:
await PostGen(sent, dungeons, reservedTiles, random);
break;
case SampleTileDunGen stile:
await PostGen(stile, dungeons, reservedTiles, random);
break;
case SplineDungeonConnectorDunGen spline:
dungeons.Add(await PostGen(spline, dungeons, reservedTiles, random));
break;
@@ -365,6 +320,11 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
}
}
private void LogDataError(Type type)
{
_sawmill.Error($"Unable to find dungeon data keys for {type}");
}
[Pure]
private bool ValidateResume()
{
@@ -386,19 +346,4 @@ public sealed partial class DungeonJob : Job<(List<Dungeon>, DungeonData)>
await SuspendIfOutOfTime();
}
private void AddLoadedEntity(Vector2i tile, EntityUid ent)
{
_data.Entities[ent] = tile;
}
private void AddLoadedDecal(Vector2 tile, uint decal)
{
_data.Decals[decal] = tile;
}
private void AddLoadedTile(Vector2i index, Tile tile)
{
_data.Tiles[index] = tile;
}
}