| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- using System.Numerics;
- using System.Threading.Tasks;
- using Content.Shared.Maps;
- using Content.Shared.Procedural;
- using Content.Shared.Procedural.DungeonGenerators;
- using Robust.Shared.Map;
- using Robust.Shared.Random;
- using Robust.Shared.Utility;
- namespace Content.Server.Procedural.DungeonJob;
- public sealed partial class DungeonJob
- {
- /// <summary>
- /// <see cref="NoiseDunGen"/>
- /// </summary>
- private async Task<Dungeon> GenerateNoiseDunGen(
- Vector2i position,
- NoiseDunGen dungen,
- HashSet<Vector2i> reservedTiles,
- int seed,
- Random random)
- {
- var tiles = new List<(Vector2i, Tile)>();
- var matrix = Matrix3Helpers.CreateTranslation(position);
- foreach (var layer in dungen.Layers)
- {
- layer.Noise.SetSeed(seed);
- }
- // First we have to find a seed tile, then floodfill from there until we get to noise
- // at which point we floodfill the entire noise.
- var iterations = dungen.Iterations;
- var area = new Box2i();
- var frontier = new Queue<Vector2i>();
- var rooms = new List<DungeonRoom>();
- var tileCount = 0;
- var tileCap = random.NextGaussian(dungen.TileCap, dungen.CapStd);
- var visited = new HashSet<Vector2i>();
- while (iterations > 0 && tileCount < tileCap)
- {
- var roomTiles = new HashSet<Vector2i>();
- iterations--;
- // Get a random exterior tile to start floodfilling from.
- var edge = random.Next(4);
- Vector2i seedTile;
- switch (edge)
- {
- case 0:
- seedTile = new Vector2i(random.Next(area.Left - 2, area.Right + 1), area.Bottom - 2);
- break;
- case 1:
- seedTile = new Vector2i(area.Right + 1, random.Next(area.Bottom - 2, area.Top + 1));
- break;
- case 2:
- seedTile = new Vector2i(random.Next(area.Left - 2, area.Right + 1), area.Top + 1);
- break;
- case 3:
- seedTile = new Vector2i(area.Left - 2, random.Next(area.Bottom - 2, area.Top + 1));
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- DebugTools.Assert(!visited.Contains(seedTile));
- var noiseFill = false;
- frontier.Clear();
- visited.Add(seedTile);
- frontier.Enqueue(seedTile);
- area = area.UnionTile(seedTile);
- var roomArea = new Box2i(seedTile, seedTile + Vector2i.One);
- // Time to floodfill again
- while (frontier.TryDequeue(out var node) && tileCount < tileCap)
- {
- var foundNoise = false;
- foreach (var layer in dungen.Layers)
- {
- var value = layer.Noise.GetNoise(node.X, node.Y);
- if (value < layer.Threshold)
- continue;
- foundNoise = true;
- noiseFill = true;
- // Still want the tile to gen as normal but can't do anything with it.
- if (reservedTiles.Contains(node))
- break;
- roomArea = roomArea.UnionTile(node);
- var tileDef = _tileDefManager[layer.Tile];
- var variant = _tile.PickVariant((ContentTileDefinition) tileDef, random);
- var adjusted = Vector2.Transform(node + _grid.TileSizeHalfVector, matrix).Floored();
- tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant)));
- roomTiles.Add(adjusted);
- tileCount++;
- break;
- }
- // Don't get neighbors if they don't have noise.
- // only if we've already found any noise.
- if (noiseFill && !foundNoise)
- continue;
- for (var x = -1; x <= 1; x++)
- {
- for (var y = -1; y <= 1; y++)
- {
- // Cardinals only
- if (x != 0 && y != 0)
- continue;
- var neighbor = new Vector2i(node.X + x, node.Y + y);
- if (!visited.Add(neighbor))
- continue;
- area = area.UnionTile(neighbor);
- frontier.Enqueue(neighbor);
- }
- }
- await SuspendIfOutOfTime();
- ValidateResume();
- }
- var center = Vector2.Zero;
- foreach (var tile in roomTiles)
- {
- center += tile + _grid.TileSizeHalfVector;
- }
- center /= roomTiles.Count;
- rooms.Add(new DungeonRoom(roomTiles, center, roomArea, new HashSet<Vector2i>()));
- await SuspendIfOutOfTime();
- ValidateResume();
- }
- _maps.SetTiles(_gridUid, _grid, tiles);
- var dungeon = new Dungeon(rooms);
- return dungeon;
- }
- }
|