Biome marker layer tweaks (#23663)
* Biome marker layer tweaks - Ensure veins get spawned at great perf cost (it's time-sliced anyway). - Bump asteroids from 6 nodes to 10 nodes. * Fixes * magnet * Magnet dictates wreck spawn * Update Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerPostGen.cs * mraow
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Atmos;
|
||||
@@ -553,54 +554,19 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
||||
bool emptyTiles = true)
|
||||
{
|
||||
DebugTools.Assert(count > 0);
|
||||
var remainingTiles = _tilePool.Get();
|
||||
var nodeEntities = new Dictionary<Vector2i, EntityUid?>();
|
||||
var nodeMask = new Dictionary<Vector2i, string?>();
|
||||
|
||||
var frontier = new ValueList<Vector2i>(32);
|
||||
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth idk
|
||||
// Get the total amount of groups to spawn across the entire chunk.
|
||||
// We treat a null entity mask as requiring nothing else on the tile
|
||||
|
||||
spawnSet = new Dictionary<Vector2i, string?>();
|
||||
var visited = _tilePool.Get();
|
||||
existingEnts = new HashSet<EntityUid>();
|
||||
|
||||
// Pick a random tile then BFS outwards from it
|
||||
// It will bias edge tiles significantly more but will make the CPU cry less.
|
||||
for (var i = 0; i < count; i++)
|
||||
// Okay so originally we picked a random tile and BFS outwards
|
||||
// the problem is if you somehow get a cooked frontier then it might drop entire veins
|
||||
// hence we'll grab all valid tiles up front and use that as possible seeds.
|
||||
// It's hella more expensive but stops issues.
|
||||
for (var x = bounds.Left; x < bounds.Right; x++)
|
||||
{
|
||||
var groupSize = rand.Next(layerProto.MinGroupSize, layerProto.MaxGroupSize + 1);
|
||||
var startNodeX = rand.Next(bounds.Left, bounds.Right);
|
||||
var startNodeY = rand.Next(bounds.Bottom, bounds.Top);
|
||||
var startNode = new Vector2i(startNodeX, startNodeY);
|
||||
frontier.Clear();
|
||||
frontier.Add(startNode);
|
||||
visited.Add(startNode);
|
||||
|
||||
while (groupSize >= 0 && frontier.Count > 0)
|
||||
for (var y = bounds.Bottom; y < bounds.Top; y++)
|
||||
{
|
||||
var frontierIndex = rand.Next(frontier.Count);
|
||||
var node = frontier[frontierIndex];
|
||||
frontier.RemoveSwap(frontierIndex);
|
||||
|
||||
// Add neighbors regardless.
|
||||
for (var x = -1; x <= 1; x++)
|
||||
{
|
||||
for (var y = -1; y <= 1; y++)
|
||||
{
|
||||
if (x != 0 && y != 0)
|
||||
continue;
|
||||
|
||||
var neighbor = new Vector2i(node.X + x, node.Y + y);
|
||||
|
||||
// Check if it's inbounds.
|
||||
if (!bounds.Contains(neighbor))
|
||||
continue;
|
||||
|
||||
if (!visited.Add(neighbor))
|
||||
continue;
|
||||
|
||||
frontier.Add(neighbor);
|
||||
}
|
||||
}
|
||||
var node = new Vector2i(x, y);
|
||||
|
||||
// Empty tile, skip if relevant.
|
||||
if (!emptyTiles && (!_mapSystem.TryGetTile(grid, node, out var tile) || tile.IsEmpty))
|
||||
@@ -631,21 +597,77 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
||||
}
|
||||
|
||||
DebugTools.Assert(layerProto.EntityMask.Count == 0 || !string.IsNullOrEmpty(proto));
|
||||
|
||||
// Don't fight other layers.
|
||||
if (!spawnSet.TryAdd(node, proto))
|
||||
continue;
|
||||
|
||||
groupSize--;
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
existingEnts.Add(existing.Value);
|
||||
}
|
||||
remainingTiles.Add(node);
|
||||
nodeEntities.Add(node, existing);
|
||||
nodeMask.Add(node, proto);
|
||||
}
|
||||
}
|
||||
|
||||
_tilePool.Return(visited);
|
||||
var frontier = new ValueList<Vector2i>(32);
|
||||
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth idk
|
||||
// Get the total amount of groups to spawn across the entire chunk.
|
||||
// We treat a null entity mask as requiring nothing else on the tile
|
||||
|
||||
spawnSet = new Dictionary<Vector2i, string?>();
|
||||
existingEnts = new HashSet<EntityUid>();
|
||||
|
||||
// Iterate the group counts and pathfind out each group.
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var groupSize = rand.Next(layerProto.MinGroupSize, layerProto.MaxGroupSize + 1);
|
||||
|
||||
// While we have remaining tiles keep iterating
|
||||
while (groupSize >= 0 && remainingTiles.Count > 0)
|
||||
{
|
||||
var startNode = rand.PickAndTake(remainingTiles);
|
||||
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 = rand.Next(frontier.Count);
|
||||
var node = frontier[frontierIndex];
|
||||
frontier.RemoveSwap(frontierIndex);
|
||||
remainingTiles.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++)
|
||||
{
|
||||
if (x != 0 && y != 0)
|
||||
continue;
|
||||
|
||||
var neighbor = new Vector2i(node.X + x, node.Y + y);
|
||||
|
||||
if (frontier.Contains(neighbor) || !remainingTiles.Contains(neighbor))
|
||||
continue;
|
||||
|
||||
frontier.Add(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
// Tile valid salad so add it.
|
||||
var mask = nodeMask[node];
|
||||
spawnSet.Add(node, mask);
|
||||
groupSize--;
|
||||
|
||||
if (nodeEntities.TryGetValue(node, out var existing))
|
||||
{
|
||||
Del(existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupSize > 0)
|
||||
{
|
||||
Log.Warning($"Found remaining group size for ore veins!");
|
||||
}
|
||||
}
|
||||
|
||||
_tilePool.Return(remainingTiles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user