Revert biome rework (#38724)
* Revert "Fix world generation (#38713)" This reverts commit10fa6ff4af. * Revert "Biome rework (#37735)" This reverts commitfe7b96147c.
This commit is contained in:
committed by
GitHub
parent
047a49a505
commit
e99fc501a6
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
74
Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs
Normal file
74
Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -42,7 +42,6 @@ public sealed partial class DungeonJob
|
||||
}
|
||||
|
||||
replacements.Add((node, tile));
|
||||
AddLoadedTile(node, tile);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +52,6 @@ public sealed partial class DungeonJob
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dungeon.RefreshAllTiles();
|
||||
}
|
||||
|
||||
private void WidenCorridor(Dungeon dungeon, float width, ICollection<Vector2i> corridorTiles)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -49,7 +49,6 @@ public sealed partial class DungeonJob
|
||||
_entManager.RemoveComponent<GhostRoleComponent>(uid);
|
||||
_entManager.RemoveComponent<GhostTakeoverAvailableComponent>(uid);
|
||||
npcs.SleepNPC(uid);
|
||||
AddLoadedEntity(tile, uid);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"}!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user