Fix dungeon spawn + ftl overlap (#31413)

* Fix dungeon spawn + ftl overlap

* Better fixes
This commit is contained in:
metalgearsloth
2024-08-25 14:48:29 +10:00
committed by GitHub
parent d7bbb94857
commit 60b34b57f3
4 changed files with 110 additions and 45 deletions

View File

@@ -4,6 +4,7 @@ using Content.Server.Decals;
using Content.Server.NPC.Components;
using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
using Content.Server.Shuttles.Systems;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Maps;
using Content.Shared.Procedural;
@@ -51,6 +52,8 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
private readonly EntityUid _gridUid;
private readonly MapGridComponent _grid;
private readonly EntityCoordinates? _targetCoordinates;
private readonly ISawmill _sawmill;
public DungeonJob(
@@ -70,6 +73,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
EntityUid gridUid,
int seed,
Vector2i position,
EntityCoordinates? targetCoordinates = null,
CancellationToken cancellation = default) : base(maxTime, cancellation)
{
_sawmill = sawmill;
@@ -94,6 +98,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
_gridUid = gridUid;
_seed = seed;
_position = position;
_targetCoordinates = targetCoordinates;
}
/// <summary>
@@ -151,6 +156,12 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
// To make it slightly more deterministic treat this RNG as separate ig.
// Post-processing after finishing loading.
if (_targetCoordinates != null)
{
var oldMap = _xformQuery.Comp(_gridUid).MapUid;
_entManager.System<ShuttleSystem>().TryFTLProximity(_gridUid, _targetCoordinates.Value);
_entManager.DeleteEntity(oldMap);
}
// Defer splitting so they don't get spammed and so we don't have to worry about tracking the grid along the way.
_grid.CanSplit = true;

View File

@@ -183,11 +183,16 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
return mapId;
}
/// <summary>
/// Generates a dungeon in the background with the specified config.
/// </summary>
/// <param name="coordinates">Coordinates to move the dungeon to afterwards. Will delete the original map</param>
public void GenerateDungeon(DungeonConfig gen,
EntityUid gridUid,
MapGridComponent grid,
Vector2i position,
int seed)
int seed,
EntityCoordinates? coordinates = null)
{
var cancelToken = new CancellationTokenSource();
var job = new DungeonJob.DungeonJob(
@@ -207,6 +212,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
gridUid,
seed,
position,
coordinates,
cancelToken.Token);
_dungeonJobs.Add(job, cancelToken);
@@ -238,6 +244,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
gridUid,
seed,
position,
null,
cancelToken.Token);
_dungeonJobs.Add(job, cancelToken);

View File

@@ -66,7 +66,7 @@ public sealed partial class ShuttleSystem
/// <summary>
/// How many times we try to proximity warp close to something before falling back to map-wideAABB.
/// </summary>
private const int FTLProximityIterations = 3;
private const int FTLProximityIterations = 5;
private readonly HashSet<EntityUid> _lookupEnts = new();
private readonly HashSet<EntityUid> _immuneEnts = new();
@@ -321,7 +321,7 @@ public sealed partial class ShuttleSystem
hyperspace.TargetCoordinates = config.Coordinates;
hyperspace.TargetAngle = config.Angle;
}
else if (TryGetFTLProximity(shuttleUid, target, out var coords, out var targAngle))
else if (TryGetFTLProximity(shuttleUid, new EntityCoordinates(target, Vector2.Zero), out var coords, out var targAngle))
{
hyperspace.TargetCoordinates = coords;
hyperspace.TargetAngle = targAngle;
@@ -377,10 +377,11 @@ public sealed partial class ShuttleSystem
var fromMatrix = _transform.GetWorldMatrix(xform);
var fromRotation = _transform.GetWorldRotation(xform);
var width = Comp<MapGridComponent>(uid).LocalAABB.Width;
var grid = Comp<MapGridComponent>(uid);
var width = grid.LocalAABB.Width;
var ftlMap = EnsureFTLMap();
var body = _physicsQuery.GetComponent(entity);
var shuttleCenter = body.LocalCenter;
var shuttleCenter = grid.LocalAABB.Center;
// Leave audio at the old spot
// Just so we don't clip
@@ -500,6 +501,7 @@ public sealed partial class ShuttleSystem
// Position ftl
else
{
// TODO: This should now use tryftlproximity
mapId = target.GetMapId(EntityManager);
_transform.SetCoordinates(uid, xform, target, rotation: entity.Comp1.TargetAngle);
}
@@ -698,16 +700,23 @@ public sealed partial class ShuttleSystem
}
/// <summary>
/// Tries to get the target position to FTL near to another grid.
/// Tries to get the target position to FTL near the target coordinates.
/// If the target coordinates have a mapgrid then will try to offset the AABB.
/// </summary>
private bool TryGetFTLProximity(EntityUid shuttleUid, EntityUid targetUid,
/// <param name="minOffset">Min offset for the final FTL.</param>
/// <param name="maxOffset">Max offset for the final FTL from the box we spawn.</param>
private bool TryGetFTLProximity(
EntityUid shuttleUid,
EntityCoordinates targetCoordinates,
out EntityCoordinates coordinates, out Angle angle,
float minOffset = 0f, float maxOffset = 64f,
TransformComponent? xform = null, TransformComponent? targetXform = null)
{
DebugTools.Assert(minOffset < maxOffset);
coordinates = EntityCoordinates.Invalid;
angle = Angle.Zero;
if (!Resolve(targetUid, ref targetXform) ||
if (!Resolve(targetCoordinates.EntityId, ref targetXform) ||
targetXform.MapUid == null ||
!targetXform.MapUid.Value.IsValid() ||
!Resolve(shuttleUid, ref xform))
@@ -715,26 +724,24 @@ public sealed partial class ShuttleSystem
return false;
}
var xformQuery = GetEntityQuery<TransformComponent>();
var shuttleAABB = Comp<MapGridComponent>(shuttleUid).LocalAABB;
Box2 targetLocalAABB;
// Spawn nearby.
// We essentially expand the Box2 of the target area until nothing else is added then we know it's valid.
// Can't just get an AABB of every grid as we may spawn very far away.
if (TryComp<MapGridComponent>(targetXform.GridUid, out var targetGrid))
{
targetLocalAABB = targetGrid.LocalAABB;
}
else
{
targetLocalAABB = new Box2();
}
var targetAABB = _transform.GetWorldMatrix(targetXform, xformQuery)
.TransformBox(targetLocalAABB).Enlarged(shuttleAABB.Size.Length());
var nearbyGrids = new HashSet<EntityUid>();
var shuttleAABB = Comp<MapGridComponent>(shuttleUid).LocalAABB;
// Start with small point.
// If our target pos is offset we mot even intersect our target's AABB so we don't include it.
var targetLocalAABB = Box2.CenteredAround(targetCoordinates.Position, Vector2.One);
// How much we expand the target AABB be.
// We half it because we only need the width / height in each direction if it's placed at a particular spot.
var expansionAmount = MathF.Max(shuttleAABB.Width / 2f, shuttleAABB.Height / 2f);
// Expand the starter AABB so we have something to query to start with.
var targetAABB = _transform.GetWorldMatrix(targetXform)
.TransformBox(targetLocalAABB)
.Enlarged(expansionAmount);
var iteration = 0;
var lastCount = nearbyGrids.Count;
var mapId = targetXform.MapID;
@@ -743,15 +750,21 @@ public sealed partial class ShuttleSystem
while (iteration < FTLProximityIterations)
{
grids.Clear();
_mapManager.FindGridsIntersecting(mapId, targetAABB, ref grids);
// We pass in an expanded offset here so we can safely do a random offset later.
// We don't include this in the actual targetAABB because then we would be double-expanding it.
// Once in this loop, then again when placing the shuttle later.
// Note that targetAABB already has expansionAmount factored in already.
_mapManager.FindGridsIntersecting(mapId, targetAABB.Enlarged(maxOffset), ref grids);
foreach (var grid in grids)
{
if (!nearbyGrids.Add(grid))
continue;
targetAABB = targetAABB.Union(_transform.GetWorldMatrix(grid, xformQuery)
.TransformBox(Comp<MapGridComponent>(grid).LocalAABB));
// Include the other grid's AABB (expanded by ours) as well.
targetAABB = targetAABB.Union(
_transform.GetWorldMatrix(grid)
.TransformBox(Comp<MapGridComponent>(grid).LocalAABB.Enlarged(expansionAmount)));
}
// Can do proximity
@@ -760,7 +773,6 @@ public sealed partial class ShuttleSystem
break;
}
targetAABB = targetAABB.Enlarged(shuttleAABB.Size.Length() / 2f);
iteration++;
lastCount = nearbyGrids.Count;
@@ -775,13 +787,15 @@ public sealed partial class ShuttleSystem
if (nearbyGrids.Contains(uid))
continue;
targetAABB = targetAABB.Union(_transform.GetWorldMatrix(uid, xformQuery)
.TransformBox(Comp<MapGridComponent>(uid).LocalAABB));
targetAABB = targetAABB.Union(
_transform.GetWorldMatrix(uid)
.TransformBox(Comp<MapGridComponent>(uid).LocalAABB.Enlarged(expansionAmount)));
}
break;
}
// Now we have a targetAABB. This has already been expanded to account for our fat ass.
Vector2 spawnPos;
if (TryComp<PhysicsComponent>(shuttleUid, out var shuttleBody))
@@ -790,21 +804,32 @@ public sealed partial class ShuttleSystem
_physics.SetAngularVelocity(shuttleUid, 0f, body: shuttleBody);
}
// TODO: This should prefer the position's angle instead.
// TODO: This is pretty crude for multiple landings.
if (nearbyGrids.Count > 1 || !HasComp<MapComponent>(targetXform.GridUid))
{
var minRadius = (MathF.Max(targetAABB.Width, targetAABB.Height) + MathF.Max(shuttleAABB.Width, shuttleAABB.Height)) / 2f;
spawnPos = targetAABB.Center + _random.NextVector2(minRadius, minRadius + 64f);
// Pick a random angle
var offsetAngle = _random.NextAngle();
// Our valid spawn positions are <targetAABB width / height + offset> away.
var minRadius = MathF.Max(targetAABB.Width / 2f, targetAABB.Height / 2f);
spawnPos = targetAABB.Center + offsetAngle.RotateVec(new Vector2(_random.NextFloat(minRadius + minOffset, minRadius + maxOffset), 0f));
}
else if (shuttleBody != null)
{
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetXform, xformQuery);
var transform = new Transform(targetPos, targetRot);
spawnPos = Robust.Shared.Physics.Transform.Mul(transform, -shuttleBody.LocalCenter);
(spawnPos, angle) = _transform.GetWorldPositionRotation(targetXform);
}
else
{
spawnPos = _transform.GetWorldPosition(targetXform, xformQuery);
spawnPos = _transform.GetWorldPosition(targetXform);
}
var offset = Vector2.Zero;
// Offset it because transform does not correspond to AABB position.
if (TryComp(shuttleUid, out MapGridComponent? shuttleGrid))
{
offset = -shuttleGrid.LocalAABB.Center;
}
if (!HasComp<MapComponent>(targetXform.GridUid))
@@ -816,7 +841,11 @@ public sealed partial class ShuttleSystem
angle = Angle.Zero;
}
coordinates = new EntityCoordinates(targetXform.MapUid.Value, spawnPos);
// Rotate our localcenter around so we spawn exactly where we "think" we should (center of grid on the dot).
var transform = new Transform(spawnPos, angle);
spawnPos = Robust.Shared.Physics.Transform.Mul(transform, offset);
coordinates = new EntityCoordinates(targetXform.MapUid.Value, spawnPos - offset);
return true;
}
@@ -833,13 +862,31 @@ public sealed partial class ShuttleSystem
return false;
}
if (!TryGetFTLProximity(shuttleUid, targetUid, out var coords, out var angle, xform, targetXform))
if (!TryGetFTLProximity(shuttleUid, new EntityCoordinates(targetUid, Vector2.Zero), out var coords, out var angle, xform: xform, targetXform: targetXform))
return false;
_transform.SetCoordinates(shuttleUid, xform, coords, rotation: angle);
return true;
}
/// <summary>
/// Tries to FTL to the target coordinates; will move nearby if not possible.
/// </summary>
public bool TryFTLProximity(Entity<TransformComponent?> shuttle, EntityCoordinates targetCoordinates)
{
if (!Resolve(shuttle.Owner, ref shuttle.Comp) ||
_transform.GetMap(targetCoordinates)?.IsValid() != true)
{
return false;
}
if (!TryGetFTLProximity(shuttle, targetCoordinates, out var coords, out var angle))
return false;
_transform.SetCoordinates(shuttle, shuttle.Comp, coords, rotation: angle);
return true;
}
/// <summary>
/// Flattens / deletes everything under the grid upon FTL.
/// </summary>
@@ -861,7 +908,6 @@ public sealed partial class ShuttleSystem
var aabb = fixture.Shape.ComputeAABB(transform, 0);
// Shift it slightly
aabb = aabb.Translated(-grid.TileSizeHalfVector);
// Create a small border around it.
aabb = aabb.Enlarged(0.2f);
aabbs.Add(aabb);

View File

@@ -85,7 +85,7 @@ public sealed partial class ShuttleSystem
_mapManager.DeleteMap(mapId);
}
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, DungeonSpawnGroup group, out EntityUid spawned)
{
spawned = EntityUid.Invalid;
@@ -110,11 +110,12 @@ public sealed partial class ShuttleSystem
spawnCoords = spawnCoords.Offset(_random.NextVector2(distancePadding + group.MinimumDistance, distancePadding + group.MaximumDistance));
}
var spawnMapCoords = _transform.ToMapCoordinates(spawnCoords);
_maps.CreateMap(out var mapId);
var spawnedGrid = _mapManager.CreateGridEntity(mapId);
_transform.SetMapCoordinates(spawnedGrid, spawnMapCoords);
_dungeon.GenerateDungeon(dungeonProto, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next());
_transform.SetMapCoordinates(spawnedGrid, new MapCoordinates(Vector2.Zero, mapId));
_dungeon.GenerateDungeon(dungeonProto, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next(), spawnCoords);
spawned = spawnedGrid.Owner;
return true;
@@ -192,7 +193,7 @@ public sealed partial class ShuttleSystem
switch (group)
{
case DungeonSpawnGroup dungeon:
if (!TryDungeonSpawn(targetGrid.Value, mapId, dungeon, out spawned))
if (!TryDungeonSpawn(targetGrid.Value, dungeon, out spawned))
continue;
break;