Make ore loot use walls as a mask (#16377)

This commit is contained in:
metalgearsloth
2023-05-15 12:01:29 +10:00
committed by GitHub
parent 7065341171
commit ea4440be44
9 changed files with 187 additions and 135 deletions

View File

@@ -5,9 +5,9 @@ using Content.Shared.Decals;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Parallax.Biomes.Layers;
using Content.Shared.Parallax.Biomes.Markers;
using Content.Shared.Parallax.Biomes.Points;
using Robust.Server.Player;
using Robust.Shared;
using Robust.Shared.Collections;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Map;
@@ -326,6 +326,9 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
{
var markers = _markerChunks[component];
var loadedMarkers = component.LoadedMarkers;
var spawnSet = new HashSet<Vector2i>();
var spawns = new List<Vector2i>();
var frontier = new Queue<Vector2i>();
foreach (var (layer, chunks) in markers)
{
@@ -334,45 +337,112 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
if (loadedMarkers.TryGetValue(layer, out var mobChunks) && mobChunks.Contains(chunk))
continue;
spawns.Clear();
spawnSet.Clear();
var layerProto = _proto.Index<BiomeMarkerLayerPrototype>(layer);
var buffer = layerProto.Radius / 2f;
mobChunks ??= new HashSet<Vector2i>();
mobChunks.Add(chunk);
loadedMarkers[layer] = mobChunks;
var rand = new Random(noise.GetSeed() + chunk.X * 8 + chunk.Y);
var rand = new Random(noise.GetSeed() + chunk.X * 8 + chunk.Y + layerProto.GetHashCode());
// We treat a null entity mask as requiring nothing else on the tile
var lower = (int) Math.Floor(buffer);
var upper = (int) Math.Ceiling(layerProto.Size - buffer);
// TODO: Okay this is inefficient as FUCK
// I think the ideal is pick a random tile then BFS outwards from it probably ig
// It will bias edge tiles significantly more but will make the CPU cry less.
for (var x = lower; x <= upper; x++)
{
for (var y = lower; y <= upper; y++)
{
var index = new Vector2i(x + chunk.X, y + chunk.Y);
TryGetEntity(index, component.Layers, component.Noise, grid, out var proto);
if (proto != layerProto.EntityMask)
{
continue;
}
spawns.Add(index);
spawnSet.Add(index);
}
}
// Load NOW
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth idk
var count = (int) ((layerProto.Size - buffer) * (layerProto.Size - buffer) / (layerProto.Radius * layerProto.Radius));
count = Math.Min(count, layerProto.MaxCount);
for (var i = 0; i < count; i++)
{
for (var j = 0; j < 5; j++)
if (spawns.Count == 0)
break;
var index = rand.Next(spawns.Count);
var point = spawns[index];
spawns.RemoveSwap(index);
// Point was potentially used in BFS search below but we hadn't updated the list yet.
if (!spawnSet.Remove(point))
{
var point = new Vector2(
chunk.X + buffer + rand.NextFloat() * (layerProto.Size - buffer),
chunk.Y + buffer + rand.NextFloat() * (layerProto.Size - buffer));
i--;
continue;
}
var coords = new EntityCoordinates(gridUid, point);
var tile = grid.LocalToTile(coords);
// BFS search
frontier.Enqueue(point);
var groupCount = layerProto.GroupCount;
// Blocked spawn, try again.
if (grid.GetAnchoredEntitiesEnumerator(tile).MoveNext(out _))
while (frontier.TryDequeue(out var node) && groupCount > 0)
{
var enumerator = grid.GetAnchoredEntitiesEnumerator(node);
if (enumerator.MoveNext(out _))
continue;
for (var k = 0; k < layerProto.GroupCount; k++)
// Need to ensure the tile under it has loaded for anchoring.
if (TryGetBiomeTile(node, component.Layers, component.Noise, grid, out var tile))
{
// If it is a ghost role then purge it
// TODO: This is *kind* of a bandaid but natural mobs spawns needs a lot more work.
// Ideally we'd just have ghost role and non-ghost role variants for some stuff.
var uid = EntityManager.CreateEntityUninitialized(layerProto.Prototype, new EntityCoordinates(gridUid, point));
RemComp<GhostTakeoverAvailableComponent>(uid);
RemComp<GhostRoleComponent>(uid);
EntityManager.InitializeAndStartEntity(uid);
grid.SetTile(node, tile.Value);
}
break;
// If it is a ghost role then purge it
// TODO: This is *kind* of a bandaid but natural mobs spawns needs a lot more work.
// Ideally we'd just have ghost role and non-ghost role variants for some stuff.
var uid = EntityManager.CreateEntityUninitialized(layerProto.Prototype, new EntityCoordinates(gridUid, node));
RemComp<GhostTakeoverAvailableComponent>(uid);
RemComp<GhostRoleComponent>(uid);
EntityManager.InitializeAndStartEntity(uid);
groupCount--;
for (var x = -1; x <= 1; x++)
{
for (var y = -1; y <= 1; y++)
{
if (x != 0 && y != 0)
continue;
var neighbor = new Vector2i(x + node.X, y + node.Y);
if (!spawnSet.Contains(neighbor))
continue;
frontier.Enqueue(neighbor);
// Rather than doing some uggo remove check on the list we'll defer it until later
spawnSet.Remove(neighbor);
}
}
}
// Add the unused nodes back in
foreach (var node in frontier)
{
spawnSet.Add(node);
}
frontier.Clear();
}
}
}