Prevent ghosts from spawning on terminating maps/grids (#28099)

* Extra checks to prevent ghosts spawning on terminating maps/grids

* Add test for grid deletion
This commit is contained in:
Tayrtahn
2024-05-20 09:52:49 -04:00
committed by GitHub
parent 4ed12b60d3
commit fa06783986
3 changed files with 50 additions and 9 deletions

View File

@@ -156,4 +156,20 @@ public sealed class GhostTests
await data.Pair.CleanReturnAsync(); await data.Pair.CleanReturnAsync();
} }
[Test]
public async Task TestGhostGridNotTerminating()
{
var data = await SetupData();
Assert.DoesNotThrowAsync(async () =>
{
// Delete the grid
await data.Server.WaitPost(() => data.SEntMan.DeleteEntity(data.MapData.Grid.Owner));
});
await data.Pair.RunTicksSync(5);
await data.Pair.CleanReturnAsync();
}
} }

View File

@@ -369,11 +369,16 @@ namespace Content.Server.GameTicking
public EntityCoordinates GetObserverSpawnPoint() public EntityCoordinates GetObserverSpawnPoint()
{ {
_possiblePositions.Clear(); _possiblePositions.Clear();
var spawnPointQuery = EntityManager.EntityQueryEnumerator<SpawnPointComponent, TransformComponent>();
foreach (var (point, transform) in EntityManager.EntityQuery<SpawnPointComponent, TransformComponent>(true)) while (spawnPointQuery.MoveNext(out var uid, out var point, out var transform))
{ {
if (point.SpawnType != SpawnPointType.Observer) if (point.SpawnType != SpawnPointType.Observer
|| TerminatingOrDeleted(uid)
|| transform.MapUid == null
|| TerminatingOrDeleted(transform.MapUid.Value))
{
continue; continue;
}
_possiblePositions.Add(transform.Coordinates); _possiblePositions.Add(transform.Coordinates);
} }
@@ -415,7 +420,9 @@ namespace Content.Server.GameTicking
if (_mapManager.MapExists(DefaultMap)) if (_mapManager.MapExists(DefaultMap))
{ {
return new EntityCoordinates(_mapManager.GetMapEntityId(DefaultMap), Vector2.Zero); var mapUid = _mapManager.GetMapEntityId(DefaultMap);
if (!TerminatingOrDeleted(mapUid))
return new EntityCoordinates(mapUid, Vector2.Zero);
} }
// Just pick a point at this point I guess. // Just pick a point at this point I guess.

View File

@@ -409,23 +409,41 @@ namespace Content.Server.Ghost
return SpawnGhost(mind, spawnPosition, canReturn); return SpawnGhost(mind, spawnPosition, canReturn);
} }
private bool IsValidSpawnPosition(EntityCoordinates? spawnPosition)
{
if (spawnPosition?.IsValid(EntityManager) != true)
return false;
var mapUid = spawnPosition?.GetMapUid(EntityManager);
var gridUid = spawnPosition?.EntityId;
// Test if the map is being deleted
if (mapUid == null || TerminatingOrDeleted(mapUid.Value))
return false;
// Test if the grid is being deleted
if (gridUid != null && TerminatingOrDeleted(gridUid.Value))
return false;
return true;
}
public EntityUid? SpawnGhost(Entity<MindComponent?> mind, EntityCoordinates? spawnPosition = null, public EntityUid? SpawnGhost(Entity<MindComponent?> mind, EntityCoordinates? spawnPosition = null,
bool canReturn = false) bool canReturn = false)
{ {
if (!Resolve(mind, ref mind.Comp)) if (!Resolve(mind, ref mind.Comp))
return null; return null;
// Test if the map is being deleted // Test if the map or grid is being deleted
var mapUid = spawnPosition?.GetMapUid(EntityManager); if (!IsValidSpawnPosition(spawnPosition))
if (mapUid == null || TerminatingOrDeleted(mapUid.Value))
spawnPosition = null; spawnPosition = null;
// If it's bad, look for a valid point to spawn
spawnPosition ??= _ticker.GetObserverSpawnPoint(); spawnPosition ??= _ticker.GetObserverSpawnPoint();
if (!spawnPosition.Value.IsValid(EntityManager)) // Make sure the new point is valid too
if (!IsValidSpawnPosition(spawnPosition))
{ {
Log.Warning($"No spawn valid ghost spawn position found for {mind.Comp.CharacterName}" Log.Warning($"No spawn valid ghost spawn position found for {mind.Comp.CharacterName}"
+ " \"{ToPrettyString(mind)}\""); + $" \"{ToPrettyString(mind)}\"");
_minds.TransferTo(mind.Owner, null, createGhost: false, mind: mind.Comp); _minds.TransferTo(mind.Owner, null, createGhost: false, mind: mind.Comp);
return null; return null;
} }