Skip to content

Commit

Permalink
Destroy lingering shuttle grids on sale. (#2379)
Browse files Browse the repository at this point in the history
* Add grid lifecycle to shuttles

* Entity deletion on grid removal cleanup

* System call for grid cleanup, use in other systems

---------

Co-authored-by: Dvir <[email protected]>
  • Loading branch information
whatston3 and dvir001 authored Nov 8, 2024
1 parent 496ab63 commit 335f7a4
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 40 deletions.
4 changes: 4 additions & 0 deletions Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
using Content.Shared.Tiles;
using Content.Server._NF.Smuggling.Components;
using Content.Shared._NF.ShuttleRecords;
using Content.Server.StationEvents.Components;

namespace Content.Server.Shipyard.Systems;

Expand Down Expand Up @@ -290,6 +291,9 @@ private void OnPurchaseMessage(EntityUid shipyardConsoleUid, ShipyardConsoleComp
prot.PreventArtifactTriggers = true;
}

// Ensure cleanup on ship sale
EnsureComp<LinkedLifecycleGridParentComponent>(shuttleUid);

var sellValue = 0;
if (!voucherUsed)
{
Expand Down
29 changes: 5 additions & 24 deletions Content.Server/Worldgen/Systems/LocalityLoaderSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
using Robust.Shared.Map; // Frontier
using Content.Server._NF.Salvage; // Frontier

using EntityPosition = (Robust.Shared.GameObjects.EntityUid Entity, Robust.Shared.Map.EntityCoordinates Coordinates); // Frontier
using EntityPosition = (Robust.Shared.GameObjects.EntityUid Entity, Robust.Shared.Map.EntityCoordinates Coordinates);
using Content.Server.StationEvents.Events; // Frontier

namespace Content.Server.Worldgen.Systems;

Expand All @@ -17,15 +18,10 @@ namespace Content.Server.Worldgen.Systems;
public sealed class LocalityLoaderSystem : BaseWorldSystem
{
[Dependency] private readonly TransformSystem _xformSys = default!;

// Frontier
private List<(Entity<TransformComponent> Entity, EntityUid MapUid, Vector2 LocalPosition)> _detachEnts = new(); // Frontier
private EntityQuery<SpaceDebrisComponent> _debrisQuery;
private readonly List<(EntityUid Debris, List<EntityPosition> Entity)> _terminatingDebris = [];
[Dependency] private readonly LinkedLifecycleGridSystem _linkedLifecycleGrid = default!;

public override void Initialize()
{
_debrisQuery = GetEntityQuery<SpaceDebrisComponent>();
SubscribeLocalEvent<SpaceDebrisComponent, EntityTerminatingEvent>(OnDebrisDespawn);
}
// Frontier
Expand Down Expand Up @@ -91,23 +87,8 @@ private void OnDebrisDespawn(EntityUid entity, SpaceDebrisComponent component, E
}
}

var mobQuery = AllEntityQuery<HumanoidAppearanceComponent, MobStateComponent, TransformComponent>();
_detachEnts.Clear();

while (mobQuery.MoveNext(out var mobUid, out _, out _, out var xform))
{
if (xform.GridUid == null || entity != xform.GridUid.Value || xform.MapUid == null)
continue;

// Can't parent directly to map as it runs grid traversal.
_detachEnts.Add(((mobUid, xform), xform.MapUid.Value, _xformSys.GetWorldPosition(xform)));
_xformSys.DetachParentToNull(mobUid, xform);
}

foreach (var detachEnt in _detachEnts)
{
_xformSys.SetCoordinates(detachEnt.Entity.Owner, new EntityCoordinates(detachEnt.MapUid, detachEnt.LocalPosition));
}
// Do not delete the grid, it is being deleted.
_linkedLifecycleGrid.UnparentPlayersFromGrid(entity, false);
}
}
// Frontier
Expand Down
6 changes: 4 additions & 2 deletions Content.Server/_NF/Smuggling/DeadDropSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.StationEvents.Events;
using Content.Shared._NF.CCVar;
using Content.Shared._NF.Smuggling.Prototypes;
using Content.Shared.Database;
Expand Down Expand Up @@ -47,6 +48,7 @@ public sealed class DeadDropSystem : EntitySystem
[Dependency] private readonly SectorServiceSystem _sectorService = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly SharedGameTicker _ticker = default!;
[Dependency] private readonly LinkedLifecycleGridSystem _linkedLifecycleGrid = default!;
private ISawmill _sawmill = default!;

private readonly Queue<EntityUid> _drops = [];
Expand Down Expand Up @@ -490,7 +492,7 @@ private void SendDeadDrop(EntityUid uid, DeadDropComponent component, EntityUid
//removes the first element of the queue
var entityToRemove = _drops.Dequeue();
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{entityToRemove} queued for deletion");
EntityManager.QueueDeleteEntity(entityToRemove);
_linkedLifecycleGrid.UnparentPlayersFromGrid(entityToRemove, true);
}
}

Expand Down Expand Up @@ -611,7 +613,7 @@ private void SendDeadDrop(EntityUid uid, DeadDropComponent component, EntityUid
}
}

// Generates a random hint from a given set of entities (grabs the first N, N randomly generated between min/max),
// Generates a random hint from a given set of entities (grabs the first N, N randomly generated between min/max),
public string GenerateRandomHint(List<(EntityUid station, EntityUid ent)>? entityList = null)
{
if (entityList == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
using System.Numerics;
using Content.Server.StationEvents.Components;
using Content.Shared.Buckle.Components;
using Content.Shared.Humanoid;
using Content.Shared.Mech.Components;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Mobs.Components;
using Content.Shared.Vehicle.Components;
using Robust.Shared.Map;

namespace Content.Server.StationEvents.Events;

public sealed class LinkedLifecycleGridSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;

public override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -48,6 +60,96 @@ private void OnMasterRemoved(EntityUid uid, LinkedLifecycleGridParentComponent c

// Destroy child entities
foreach (var entity in component.LinkedEntities)
QueueDel(entity);
UnparentPlayersFromGrid(entity, true);
}

// Try to get parent of entity where appropriate.
private (EntityUid, TransformComponent) GetParentToReparent(EntityUid uid, TransformComponent xform)
{
if (TryComp<RiderComponent>(uid, out var rider) && rider.Vehicle != null)
{
var vehicleXform = Transform(rider.Vehicle.Value);
if (vehicleXform.MapUid != null)
{
return (rider.Vehicle.Value, vehicleXform);
}
}
if (TryComp<MechPilotComponent>(uid, out var mechPilot))
{
var mechXform = Transform(mechPilot.Mech);
if (mechXform.MapUid != null)
{
return (mechPilot.Mech, mechXform);
}
}
return (uid, xform);
}

// Returns a list of entities to reparent on a grid.
// Useful if you need to do your own bookkeeping.
public List<(Entity<TransformComponent> Entity, EntityUid MapUid, Vector2 LocalPosition)> GetEntitiesToReparent(EntityUid grid)
{
List<(Entity<TransformComponent> Entity, EntityUid MapUid, Vector2 LocalPosition)> reparentEntities = new();
HashSet<EntityUid> handledEntities = new();

// Get humanoids
var mobQuery = AllEntityQuery<HumanoidAppearanceComponent, MobStateComponent, TransformComponent>();
while (mobQuery.MoveNext(out var mobUid, out _, out _, out var xform))
{
handledEntities.Add(mobUid);

if (xform.GridUid == null || xform.MapUid == null || xform.GridUid != grid)
continue;

var (targetUid, targetXform) = GetParentToReparent(mobUid, xform);

reparentEntities.Add(((targetUid, targetXform), targetXform.MapUid!.Value, _transform.GetWorldPosition(targetXform)));
}

// Get occupied MindContainers
var mindQuery = AllEntityQuery<MindContainerComponent, TransformComponent>();
while (mindQuery.MoveNext(out var mobUid, out var mindContainer, out var xform))
{
if (xform.GridUid == null || xform.MapUid == null || xform.GridUid != grid)
continue;

// Not player-controlled, nothing to lose
if (_mind.GetMind(mobUid, mindContainer) == null)
continue;

// Already handled
if (handledEntities.Contains(mobUid))
continue;

var (targetUid, targetXform) = GetParentToReparent(mobUid, xform);

reparentEntities.Add(((targetUid, targetXform), targetXform.MapUid!.Value, _transform.GetWorldPosition(targetXform)));
}

return reparentEntities;
}

// Deletes a grid, reparenting every humanoid and player character that's on it.
public void UnparentPlayersFromGrid(EntityUid grid, bool deleteGrid)
{
if (MetaData(grid).EntityLifeStage >= EntityLifeStage.Terminating)
return;

var reparentEntities = GetEntitiesToReparent(grid);

foreach (var target in reparentEntities)
{
// Move the target and all of its children (for bikes, mechs, etc.)
_transform.DetachEntity(target.Entity.Owner, target.Entity.Comp);
}

// Deletion has to happen before grid traversal re-parents players.
if (deleteGrid)
Del(grid);

foreach (var target in reparentEntities)
{
_transform.SetCoordinates(target.Entity.Owner, new EntityCoordinates(target.MapUid, target.LocalPosition));
}
}
}
18 changes: 5 additions & 13 deletions Content.Server/_NF/StationEvents/Events/BluespaceErrorRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ public sealed class BluespaceErrorRule : StationEventSystem<BluespaceErrorRuleCo
[Dependency] private readonly ShuttleSystem _shuttle = default!;
[Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly CargoSystem _cargo = default!;

private List<(Entity<TransformComponent> Entity, EntityUid MapUid, Vector2 LocalPosition)> _playerMobs = new();
[Dependency] private readonly LinkedLifecycleGridSystem _linkedLifecycleGrid = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -216,25 +215,18 @@ protected override void Ended(EntityUid uid, BluespaceErrorRuleComponent compone
}
}

var mobQuery = AllEntityQuery<HumanoidAppearanceComponent, MobStateComponent, TransformComponent>();
_playerMobs.Clear();

while (mobQuery.MoveNext(out var mobUid, out _, out _, out var xform))
var playerMobs = _linkedLifecycleGrid.GetEntitiesToReparent(gridUid);
foreach (var mob in playerMobs)
{
if (xform.GridUid == null || xform.MapUid == null || xform.GridUid != gridUid)
continue;

// Can't parent directly to map as it runs grid traversal.
_playerMobs.Add(((mobUid, xform), xform.MapUid.Value, _transform.GetWorldPosition(xform)));
_transform.DetachEntity(mobUid, xform);
_transform.DetachEntity(mob.Entity.Owner, mob.Entity.Comp);
}

var gridValue = _pricing.AppraiseGrid(gridUid, null);

// Deletion has to happen before grid traversal re-parents players.
Del(gridUid);

foreach (var mob in _playerMobs)
foreach (var mob in playerMobs)
{
_transform.SetCoordinates(mob.Entity.Owner, new EntityCoordinates(mob.MapUid, mob.LocalPosition));
}
Expand Down

0 comments on commit 335f7a4

Please sign in to comment.