Skip to content

Commit

Permalink
Prevent ghosts from spawning on terminating maps/grids (#28099)
Browse files Browse the repository at this point in the history
* Extra checks to prevent ghosts spawning on terminating maps/grids

* Add test for grid deletion
  • Loading branch information
Tayrtahn authored May 20, 2024
1 parent 4ed12b6 commit fa06783
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 9 deletions.
16 changes: 16 additions & 0 deletions Content.IntegrationTests/Tests/Minds/GhostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,20 @@ public async Task TestGridGhostOnQueueDelete()
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();
}

}
15 changes: 11 additions & 4 deletions Content.Server/GameTicking/GameTicker.Spawning.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,16 @@ public void SpawnObserver(ICommonSession player)
public EntityCoordinates GetObserverSpawnPoint()
{
_possiblePositions.Clear();

foreach (var (point, transform) in EntityManager.EntityQuery<SpawnPointComponent, TransformComponent>(true))
var spawnPointQuery = EntityManager.EntityQueryEnumerator<SpawnPointComponent, TransformComponent>();
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;
}

_possiblePositions.Add(transform.Coordinates);
}
Expand Down Expand Up @@ -415,7 +420,9 @@ public EntityCoordinates GetObserverSpawnPoint()

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.
Expand Down
28 changes: 23 additions & 5 deletions Content.Server/Ghost/GhostSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,23 +409,41 @@ public bool DoGhostBooEvent(EntityUid target)
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,
bool canReturn = false)
{
if (!Resolve(mind, ref mind.Comp))
return null;

// Test if the map is being deleted
var mapUid = spawnPosition?.GetMapUid(EntityManager);
if (mapUid == null || TerminatingOrDeleted(mapUid.Value))
// Test if the map or grid is being deleted
if (!IsValidSpawnPosition(spawnPosition))
spawnPosition = null;

// If it's bad, look for a valid point to spawn
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}"
+ " \"{ToPrettyString(mind)}\"");
+ $" \"{ToPrettyString(mind)}\"");
_minds.TransferTo(mind.Owner, null, createGhost: false, mind: mind.Comp);
return null;
}
Expand Down

0 comments on commit fa06783

Please sign in to comment.