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,6 +1,5 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'salvage-expedition-window-title'}"
|
|
||||||
MinSize="800 360">
|
MinSize="800 360">
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<BoxContainer Orientation="Horizontal" Name="ProgressionBox" Visible="False">
|
<BoxContainer Orientation="Horizontal" Name="ProgressionBox" Visible="False">
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public sealed class SalvageExpeditionConsoleBoundUserInterface : BoundUserInterf
|
|||||||
{
|
{
|
||||||
base.Open();
|
base.Open();
|
||||||
_window = new OfferingWindow();
|
_window = new OfferingWindow();
|
||||||
|
_window.Title = Loc.GetString("salvage-expedition-window-title");
|
||||||
_window.OnClose += Close;
|
_window.OnClose += Close;
|
||||||
_window?.OpenCenteredLeft();
|
_window?.OpenCenteredLeft();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public sealed class SalvageMagnetBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
base.Open();
|
base.Open();
|
||||||
_window = new OfferingWindow();
|
_window = new OfferingWindow();
|
||||||
|
_window.Title = Loc.GetString("salvage-magnet-window-title");
|
||||||
_window.OnClose += Close;
|
_window.OnClose += Close;
|
||||||
_window.OpenCenteredLeft();
|
_window.OpenCenteredLeft();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Atmos;
|
using Content.Server.Atmos;
|
||||||
@@ -553,54 +554,19 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
|||||||
bool emptyTiles = true)
|
bool emptyTiles = true)
|
||||||
{
|
{
|
||||||
DebugTools.Assert(count > 0);
|
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);
|
// Okay so originally we picked a random tile and BFS outwards
|
||||||
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth idk
|
// the problem is if you somehow get a cooked frontier then it might drop entire veins
|
||||||
// Get the total amount of groups to spawn across the entire chunk.
|
// hence we'll grab all valid tiles up front and use that as possible seeds.
|
||||||
// We treat a null entity mask as requiring nothing else on the tile
|
// It's hella more expensive but stops issues.
|
||||||
|
for (var x = bounds.Left; x < bounds.Right; x++)
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
var groupSize = rand.Next(layerProto.MinGroupSize, layerProto.MaxGroupSize + 1);
|
for (var y = bounds.Bottom; y < bounds.Top; y++)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
var frontierIndex = rand.Next(frontier.Count);
|
var node = new Vector2i(x, y);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty tile, skip if relevant.
|
// Empty tile, skip if relevant.
|
||||||
if (!emptyTiles && (!_mapSystem.TryGetTile(grid, node, out var tile) || tile.IsEmpty))
|
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));
|
DebugTools.Assert(layerProto.EntityMask.Count == 0 || !string.IsNullOrEmpty(proto));
|
||||||
|
remainingTiles.Add(node);
|
||||||
|
nodeEntities.Add(node, existing);
|
||||||
|
nodeMask.Add(node, proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Don't fight other layers.
|
var frontier = new ValueList<Vector2i>(32);
|
||||||
if (!spawnSet.TryAdd(node, proto))
|
// 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;
|
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--;
|
groupSize--;
|
||||||
|
|
||||||
if (existing != null)
|
if (nodeEntities.TryGetValue(node, out var existing))
|
||||||
{
|
{
|
||||||
existingEnts.Add(existing.Value);
|
Del(existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_tilePool.Return(visited);
|
if (groupSize > 0)
|
||||||
|
{
|
||||||
|
Log.Warning($"Found remaining group size for ore veins!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_tilePool.Return(remainingTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -317,20 +317,29 @@ public sealed partial class SalvageSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var magnetGridUid = _xformQuery.GetComponent(magnet.Owner).GridUid;
|
var magnetXform = _xformQuery.GetComponent(magnet.Owner);
|
||||||
Box2 attachedBounds = Box2.Empty;
|
var magnetGridUid = magnetXform.GridUid;
|
||||||
MapId mapId = MapId.Nullspace;
|
var attachedBounds = new Box2Rotated();
|
||||||
|
var mapId = MapId.Nullspace;
|
||||||
|
Angle worldAngle;
|
||||||
|
|
||||||
if (magnetGridUid != null)
|
if (magnetGridUid != null)
|
||||||
{
|
{
|
||||||
var magnetGridXform = _xformQuery.GetComponent(magnetGridUid.Value);
|
var magnetGridXform = _xformQuery.GetComponent(magnetGridUid.Value);
|
||||||
attachedBounds = _transform.GetWorldMatrix(magnetGridXform)
|
var (gridPos, gridRot) = _transform.GetWorldPositionRotation(magnetGridXform);
|
||||||
.TransformBox(_gridQuery.GetComponent(magnetGridUid.Value).LocalAABB);
|
var gridAABB = _gridQuery.GetComponent(magnetGridUid.Value).LocalAABB;
|
||||||
|
|
||||||
|
attachedBounds = new Box2Rotated(gridAABB.Translated(gridPos), gridRot, gridPos);
|
||||||
|
|
||||||
|
worldAngle = (gridRot + magnetXform.LocalRotation) - MathF.PI / 2;
|
||||||
mapId = magnetGridXform.MapID;
|
mapId = magnetGridXform.MapID;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
worldAngle = _random.NextAngle();
|
||||||
|
}
|
||||||
|
|
||||||
if (!TryGetSalvagePlacementLocation(mapId, attachedBounds, bounds!.Value, out var spawnLocation, out var spawnAngle))
|
if (!TryGetSalvagePlacementLocation(mapId, attachedBounds, bounds!.Value, worldAngle, out var spawnLocation, out var spawnAngle))
|
||||||
{
|
{
|
||||||
Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-spawn-no-debris-available");
|
Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-spawn-no-debris-available");
|
||||||
_mapManager.DeleteMap(salvMap);
|
_mapManager.DeleteMap(salvMap);
|
||||||
@@ -376,26 +385,25 @@ public sealed partial class SalvageSystem
|
|||||||
RaiseLocalEvent(ref active);
|
RaiseLocalEvent(ref active);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetSalvagePlacementLocation(MapId mapId, Box2 attachedBounds, Box2 bounds, out MapCoordinates coords, out Angle angle)
|
private bool TryGetSalvagePlacementLocation(MapId mapId, Box2Rotated attachedBounds, Box2 bounds, Angle worldAngle, out MapCoordinates coords, out Angle angle)
|
||||||
{
|
{
|
||||||
const float OffsetRadiusMin = 4f;
|
// Grid intersection only does AABB atm.
|
||||||
const float OffsetRadiusMax = 16f;
|
var attachedAABB = attachedBounds.CalcBoundingBox();
|
||||||
|
|
||||||
var minDistance = (attachedBounds.Height < attachedBounds.Width ? attachedBounds.Width : attachedBounds.Height) / 2f;
|
var minDistance = (attachedAABB.Height < attachedAABB.Width ? attachedAABB.Width : attachedAABB.Height) / 2f;
|
||||||
var minActualDistance = bounds.Height < bounds.Width ? minDistance + bounds.Width / 2f : minDistance + bounds.Height / 2f;
|
var minActualDistance = bounds.Height < bounds.Width ? minDistance + bounds.Width / 2f : minDistance + bounds.Height / 2f;
|
||||||
|
|
||||||
var attachedCenter = attachedBounds.Center;
|
var attachedCenter = attachedAABB.Center;
|
||||||
|
var fraction = 0.25f;
|
||||||
angle = _random.NextAngle();
|
|
||||||
|
|
||||||
// Thanks 20kdc
|
// Thanks 20kdc
|
||||||
for (var i = 0; i < 20; i++)
|
for (var i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
var randomPos = attachedCenter +
|
var randomPos = attachedCenter +
|
||||||
_random.NextAngle().ToVec() * (minActualDistance +
|
worldAngle.ToVec() * (minActualDistance * fraction);
|
||||||
_random.NextFloat(OffsetRadiusMin, OffsetRadiusMax));
|
|
||||||
var finalCoords = new MapCoordinates(randomPos, mapId);
|
var finalCoords = new MapCoordinates(randomPos, mapId);
|
||||||
|
|
||||||
|
angle = _random.NextAngle();
|
||||||
var box2 = Box2.CenteredAround(finalCoords.Position, bounds.Size);
|
var box2 = Box2.CenteredAround(finalCoords.Position, bounds.Size);
|
||||||
var box2Rot = new Box2Rotated(box2, angle, finalCoords.Position);
|
var box2Rot = new Box2Rotated(box2, angle, finalCoords.Position);
|
||||||
|
|
||||||
@@ -404,7 +412,7 @@ public sealed partial class SalvageSystem
|
|||||||
if (_mapManager.FindGridsIntersecting(finalCoords.MapId, box2Rot).Any())
|
if (_mapManager.FindGridsIntersecting(finalCoords.MapId, box2Rot).Any())
|
||||||
{
|
{
|
||||||
// Bump it further and further just in case.
|
// Bump it further and further just in case.
|
||||||
minActualDistance += 4f;
|
fraction += 0.25f;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,6 +420,7 @@ public sealed partial class SalvageSystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
angle = Angle.Zero;
|
||||||
coords = MapCoordinates.Nullspace;
|
coords = MapCoordinates.Nullspace;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ salvage-system-announcement-spawn-no-debris-available = No debris could be recov
|
|||||||
salvage-system-announcement-arrived = A piece of salvagable debris has been pulled in. Estimated hold time: {$timeLeft} seconds.
|
salvage-system-announcement-arrived = A piece of salvagable debris has been pulled in. Estimated hold time: {$timeLeft} seconds.
|
||||||
salvage-asteroid-name = Asteroid
|
salvage-asteroid-name = Asteroid
|
||||||
|
|
||||||
|
salvage-magnet-window-title = Salvage magnet
|
||||||
salvage-expedition-window-progression = Progression
|
salvage-expedition-window-progression = Progression
|
||||||
|
|
||||||
salvage-magnet-resources = {$resource ->
|
salvage-magnet-resources = {$resource ->
|
||||||
@@ -19,8 +20,10 @@ salvage-magnet-resources = {$resource ->
|
|||||||
|
|
||||||
salvage-magnet-resources-count = {$count ->
|
salvage-magnet-resources-count = {$count ->
|
||||||
[1] (Poor)
|
[1] (Poor)
|
||||||
[2] (Rich)
|
[2] (Moderate)
|
||||||
[3] (Rich)
|
[3] (Moderate)
|
||||||
|
[4] (Rich)
|
||||||
|
[5] (Rich)
|
||||||
*[other] (Extraordinary)
|
*[other] (Extraordinary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user