Shuttle console + FTL rework (#24430)
* Add shuttle interior drawing back Just do it per-tile she'll be right, at least it's done with 1 draw call. * Revamp shuttle console * Bunch of cleanup work * Lables sortito * dok * Pixel alignment and colours * Fix a bunch of drawing bugs * Shuttle map drawing * Drawing fixes * Map parallax working finally * weh * Commit all my stuff * mic * deez * Update everything * Xamlify everything * uh * Rudimentary blocker range * My enemies have succeeded * Bunch of changes to FTL * Heaps of cleanup * Fix FTL bugs * FTL * weewoo * FTL fallback * wew * weh * Basic FTL working * FTL working * FTL destination fixes * a * Exclusion zones * Fix drawing / FTL * Beacons working * Coordinates drawing * Fix unknown map names * Dorks beginning * State + docking cleanup start * Basic dock drawing * Bunch of drawing fixes * Batching / color fixes * Cleanup and beacons support * weh * weh * Begin pings * First draft at map objects * Map fixup * Faster drawing * Fix perf + FTL * Cached drawing * Fix drawing * Best I got * strips * Back to lists but with caching * Final optimisation * Fix dock bounds * Docking work * stinker * kobolds * Btns * Docking vis working * Fix docking pre-vis * canasses * Helldivers 2 * a * Array life * Fix * Fix TODOs * liltenhead feature club * dorking * Merge artifacts * Last-minute touchup
This commit is contained in:
@@ -437,7 +437,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
if (xform.MapUid != arrivalsXform.MapUid)
|
||||
{
|
||||
if (arrivals.IsValid())
|
||||
_shuttles.FTLTravel(uid, shuttle, arrivals, dock: true);
|
||||
_shuttles.FTLToDock(uid, shuttle, arrivals);
|
||||
|
||||
comp.NextArrivalsTime = _timing.CurTime + TimeSpan.FromSeconds(tripTime);
|
||||
}
|
||||
@@ -447,7 +447,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
var targetGrid = _station.GetLargestGrid(data);
|
||||
|
||||
if (targetGrid != null)
|
||||
_shuttles.FTLTravel(uid, shuttle, targetGrid.Value, dock: true);
|
||||
_shuttles.FTLToDock(uid, shuttle, targetGrid.Value);
|
||||
|
||||
// The ArrivalsCooldown includes the trip there, so we only need to add the time taken for
|
||||
// the trip back.
|
||||
@@ -567,7 +567,7 @@ public sealed class ArrivalsSystem : EntitySystem
|
||||
var arrivalsComp = EnsureComp<ArrivalsShuttleComponent>(component.Shuttle);
|
||||
arrivalsComp.Station = uid;
|
||||
EnsureComp<ProtectedGridComponent>(uid);
|
||||
_shuttles.FTLTravel(component.Shuttle, shuttleComp, arrivals, hyperspaceTime: RoundStartFTLDuration, dock: true);
|
||||
_shuttles.FTLToDock(component.Shuttle, shuttleComp, arrivals, hyperspaceTime: RoundStartFTLDuration);
|
||||
arrivalsComp.NextTransfer = _timing.CurTime + TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.ArrivalsCooldown));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class DockingSystem
|
||||
{
|
||||
private void UpdateAutodock()
|
||||
{
|
||||
// Work out what we can autodock with, what we shouldn't, and when we should stop tracking.
|
||||
// Autodocking only stops when the client closes that dock viewport OR they lose pilotcomponent.
|
||||
var dockingQuery = GetEntityQuery<DockingComponent>();
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var recentQuery = GetEntityQuery<RecentlyDockedComponent>();
|
||||
var query = EntityQueryEnumerator<AutoDockComponent>();
|
||||
|
||||
while (query.MoveNext(out var dockUid, out var comp))
|
||||
{
|
||||
if (comp.Requesters.Count == 0 || !dockingQuery.TryGetComponent(dockUid, out var dock))
|
||||
{
|
||||
RemComp<AutoDockComponent>(dockUid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't re-dock if we're already docked or recently were.
|
||||
if (dock.Docked || recentQuery.HasComponent(dockUid))
|
||||
continue;
|
||||
|
||||
var dockable = GetDockable(dockUid, xformQuery.GetComponent(dockUid));
|
||||
|
||||
if (dockable == null)
|
||||
continue;
|
||||
|
||||
TryDock(dockUid, dock, dockable.Value);
|
||||
}
|
||||
|
||||
// Work out recent docks that have gone past their designated threshold.
|
||||
var checkedRecent = new HashSet<EntityUid>();
|
||||
var recentQueryEnumerator = EntityQueryEnumerator<RecentlyDockedComponent, TransformComponent>();
|
||||
|
||||
while (recentQueryEnumerator.MoveNext(out var uid, out var comp, out var xform))
|
||||
{
|
||||
if (!checkedRecent.Add(uid))
|
||||
continue;
|
||||
|
||||
if (!dockingQuery.HasComponent(uid))
|
||||
{
|
||||
RemCompDeferred<RecentlyDockedComponent>(uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!xformQuery.TryGetComponent(comp.LastDocked, out var otherXform))
|
||||
{
|
||||
RemCompDeferred<RecentlyDockedComponent>(uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
|
||||
var otherWorldPos = _transform.GetWorldPosition(otherXform, xformQuery);
|
||||
|
||||
if ((worldPos - otherWorldPos).Length() < comp.Radius)
|
||||
continue;
|
||||
|
||||
Log.Debug($"Removed RecentlyDocked from {ToPrettyString(uid)} and {ToPrettyString(comp.LastDocked)}");
|
||||
RemComp<RecentlyDockedComponent>(uid);
|
||||
RemComp<RecentlyDockedComponent>(comp.LastDocked);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRequestUndock(EntityUid uid, ShuttleConsoleComponent component, UndockRequestMessage args)
|
||||
{
|
||||
var dork = GetEntity(args.DockEntity);
|
||||
|
||||
Log.Debug($"Received undock request for {ToPrettyString(dork)}");
|
||||
|
||||
// TODO: Validation
|
||||
if (!TryComp<DockingComponent>(dork, out var dock) ||
|
||||
!dock.Docked ||
|
||||
HasComp<PreventPilotComponent>(Transform(uid).GridUid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Undock(dork, dock);
|
||||
}
|
||||
|
||||
private void OnRequestAutodock(EntityUid uid, ShuttleConsoleComponent component, AutodockRequestMessage args)
|
||||
{
|
||||
var dork = GetEntity(args.DockEntity);
|
||||
Log.Debug($"Received autodock request for {ToPrettyString(dork)}");
|
||||
var player = args.Session.AttachedEntity;
|
||||
|
||||
if (player == null ||
|
||||
!HasComp<DockingComponent>(dork) ||
|
||||
HasComp<PreventPilotComponent>(Transform(uid).GridUid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Validation
|
||||
var comp = EnsureComp<AutoDockComponent>(dork);
|
||||
comp.Requesters.Add(player.Value);
|
||||
}
|
||||
|
||||
private void OnRequestStopAutodock(EntityUid uid, ShuttleConsoleComponent component, StopAutodockRequestMessage args)
|
||||
{
|
||||
var dork = GetEntity(args.DockEntity);
|
||||
Log.Debug($"Received stop autodock request for {ToPrettyString(dork)}");
|
||||
|
||||
var player = args.Session.AttachedEntity;
|
||||
|
||||
// TODO: Validation
|
||||
if (player == null || !TryComp<AutoDockComponent>(dork, out var comp))
|
||||
return;
|
||||
|
||||
comp.Requesters.Remove(player.Value);
|
||||
|
||||
if (comp.Requesters.Count == 0)
|
||||
RemComp<AutoDockComponent>(dork);
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,13 @@ public sealed partial class DockingSystem
|
||||
|
||||
public Angle GetAngle(EntityUid uid, TransformComponent xform, EntityUid targetUid, TransformComponent targetXform, EntityQuery<TransformComponent> xformQuery)
|
||||
{
|
||||
var (shuttlePos, shuttleRot) = _transform.GetWorldPositionRotation(xform, xformQuery);
|
||||
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetXform, xformQuery);
|
||||
var (shuttlePos, shuttleRot) = _transform.GetWorldPositionRotation(xform);
|
||||
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetXform);
|
||||
|
||||
var shuttleCOM = Robust.Shared.Physics.Transform.Mul(new Transform(shuttlePos, shuttleRot),
|
||||
Comp<PhysicsComponent>(uid).LocalCenter);
|
||||
_physicsQuery.GetComponent(uid).LocalCenter);
|
||||
var targetCOM = Robust.Shared.Physics.Transform.Mul(new Transform(targetPos, targetRot),
|
||||
Comp<PhysicsComponent>(targetUid).LocalCenter);
|
||||
_physicsQuery.GetComponent(targetUid).LocalCenter);
|
||||
|
||||
var mapDiff = shuttleCOM - targetCOM;
|
||||
var angle = mapDiff.ToWorldAngle();
|
||||
@@ -36,7 +36,7 @@ public sealed partial class DockingSystem
|
||||
/// <summary>
|
||||
/// Checks if 2 docks can be connected by moving the shuttle directly onto docks.
|
||||
/// </summary>
|
||||
public bool CanDock(
|
||||
private bool CanDock(
|
||||
DockingComponent shuttleDock,
|
||||
TransformComponent shuttleDockXform,
|
||||
DockingComponent gridDock,
|
||||
@@ -119,37 +119,63 @@ public sealed partial class DockingSystem
|
||||
return GetDockingConfigPrivate(shuttleUid, targetGrid, shuttleDocks, gridDocks, priorityTag);
|
||||
}
|
||||
|
||||
private DockingConfig? GetDockingConfigPrivate(
|
||||
/// <summary>
|
||||
/// Tries to get a docking config at the specified coordinates and angle.
|
||||
/// </summary>
|
||||
public DockingConfig? GetDockingConfigAt(EntityUid shuttleUid,
|
||||
EntityUid targetGrid,
|
||||
EntityCoordinates coordinates,
|
||||
Angle angle)
|
||||
{
|
||||
var gridDocks = GetDocks(targetGrid);
|
||||
var shuttleDocks = GetDocks(shuttleUid);
|
||||
|
||||
var configs = GetDockingConfigs(shuttleUid, targetGrid, shuttleDocks, gridDocks);
|
||||
|
||||
foreach (var config in configs)
|
||||
{
|
||||
if (config.Coordinates.Equals(coordinates) && config.Angle.EqualsApprox(angle, 0.01))
|
||||
{
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all docking configs between the 2 grids.
|
||||
/// </summary>
|
||||
private List<DockingConfig> GetDockingConfigs(
|
||||
EntityUid shuttleUid,
|
||||
EntityUid targetGrid,
|
||||
List<(EntityUid, DockingComponent)> shuttleDocks,
|
||||
List<(EntityUid, DockingComponent)> gridDocks,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
if (gridDocks.Count <= 0)
|
||||
return null;
|
||||
List<(EntityUid, DockingComponent)> gridDocks)
|
||||
{
|
||||
var validDockConfigs = new List<DockingConfig>();
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var targetGridGrid = Comp<MapGridComponent>(targetGrid);
|
||||
var targetGridXform = xformQuery.GetComponent(targetGrid);
|
||||
if (gridDocks.Count <= 0)
|
||||
return validDockConfigs;
|
||||
|
||||
var targetGridGrid = _gridQuery.GetComponent(targetGrid);
|
||||
var targetGridXform = _xformQuery.GetComponent(targetGrid);
|
||||
var targetGridAngle = _transform.GetWorldRotation(targetGridXform).Reduced();
|
||||
var shuttleFixturesComp = Comp<FixturesComponent>(shuttleUid);
|
||||
var shuttleAABB = Comp<MapGridComponent>(shuttleUid).LocalAABB;
|
||||
var shuttleAABB = _gridQuery.GetComponent(shuttleUid).LocalAABB;
|
||||
|
||||
var isMap = HasComp<MapComponent>(targetGrid);
|
||||
|
||||
var validDockConfigs = new List<DockingConfig>();
|
||||
var grids = new List<Entity<MapGridComponent>>();
|
||||
if (shuttleDocks.Count > 0)
|
||||
{
|
||||
// We'll try all combinations of shuttle docks and see which one is most suitable
|
||||
foreach (var (dockUid, shuttleDock) in shuttleDocks)
|
||||
{
|
||||
var shuttleDockXform = xformQuery.GetComponent(dockUid);
|
||||
var shuttleDockXform = _xformQuery.GetComponent(dockUid);
|
||||
|
||||
foreach (var (gridDockUid, gridDock) in gridDocks)
|
||||
{
|
||||
var gridXform = xformQuery.GetComponent(gridDockUid);
|
||||
var gridXform = _xformQuery.GetComponent(gridDockUid);
|
||||
|
||||
if (!CanDock(
|
||||
shuttleDock, shuttleDockXform,
|
||||
@@ -167,15 +193,15 @@ public sealed partial class DockingSystem
|
||||
}
|
||||
|
||||
// Can't just use the AABB as we want to get bounds as tight as possible.
|
||||
var spawnPosition = new EntityCoordinates(targetGrid, matty.Transform(Vector2.Zero));
|
||||
spawnPosition = new EntityCoordinates(targetGridXform.MapUid!.Value, spawnPosition.ToMapPos(EntityManager, _transform));
|
||||
var gridPosition = new EntityCoordinates(targetGrid, matty.Transform(Vector2.Zero));
|
||||
var spawnPosition = new EntityCoordinates(targetGridXform.MapUid!.Value, gridPosition.ToMapPos(EntityManager, _transform));
|
||||
|
||||
// TODO: use tight bounds
|
||||
var dockedBounds = new Box2Rotated(shuttleAABB.Translated(spawnPosition.Position), targetAngle, spawnPosition.Position);
|
||||
|
||||
// Check if there's no intersecting grids (AKA oh god it's docking at cargo).
|
||||
grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(targetGridXform.MapID, dockedBounds, ref grids);
|
||||
_mapManager.FindGridsIntersecting(targetGridXform.MapID, dockedBounds, ref grids, includeMap: false);
|
||||
if (grids.Any(o => o.Owner != targetGrid && o.Owner != targetGridXform.MapUid))
|
||||
{
|
||||
continue;
|
||||
@@ -204,9 +230,9 @@ public sealed partial class DockingSystem
|
||||
|
||||
if (!CanDock(
|
||||
other,
|
||||
xformQuery.GetComponent(otherUid),
|
||||
_xformQuery.GetComponent(otherUid),
|
||||
otherGrid,
|
||||
xformQuery.GetComponent(otherGridUid),
|
||||
_xformQuery.GetComponent(otherGridUid),
|
||||
shuttleAABB,
|
||||
targetGridAngle,
|
||||
shuttleFixturesComp, targetGridGrid,
|
||||
@@ -234,7 +260,7 @@ public sealed partial class DockingSystem
|
||||
validDockConfigs.Add(new DockingConfig()
|
||||
{
|
||||
Docks = dockedPorts,
|
||||
Coordinates = spawnPosition,
|
||||
Coordinates = gridPosition,
|
||||
Area = dockedAABB,
|
||||
Angle = targetAngle,
|
||||
});
|
||||
@@ -242,9 +268,23 @@ public sealed partial class DockingSystem
|
||||
}
|
||||
}
|
||||
|
||||
return validDockConfigs;
|
||||
}
|
||||
|
||||
private DockingConfig? GetDockingConfigPrivate(
|
||||
EntityUid shuttleUid,
|
||||
EntityUid targetGrid,
|
||||
List<(EntityUid, DockingComponent)> shuttleDocks,
|
||||
List<(EntityUid, DockingComponent)> gridDocks,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
var validDockConfigs = GetDockingConfigs(shuttleUid, targetGrid, shuttleDocks, gridDocks);
|
||||
|
||||
if (validDockConfigs.Count <= 0)
|
||||
return null;
|
||||
|
||||
var targetGridAngle = _transform.GetWorldRotation(targetGrid).Reduced();
|
||||
|
||||
// Prioritise by priority docks, then by maximum connected ports, then by most similar angle.
|
||||
validDockConfigs = validDockConfigs
|
||||
.OrderByDescending(x => x.Docks.Any(docks =>
|
||||
|
||||
@@ -5,7 +5,10 @@ using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
@@ -17,27 +20,32 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems
|
||||
{
|
||||
public sealed partial class DockingSystem : EntitySystem
|
||||
public sealed partial class DockingSystem : SharedDockingSystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly DoorSystem _doorSystem = default!;
|
||||
[Dependency] private readonly FixtureSystem _fixtureSystem = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly PathfindingSystem _pathfinding = default!;
|
||||
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||
[Dependency] private readonly SharedJointSystem _jointSystem = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
private const string DockingFixture = "docking";
|
||||
private const string DockingJoint = "docking";
|
||||
private const float DockingRadius = 0.20f;
|
||||
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
private readonly HashSet<Entity<DockingComponent>> _dockingSet = new();
|
||||
private readonly HashSet<Entity<DockingComponent, DoorBoltComponent>> _dockingBoltSet = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
SubscribeLocalEvent<DockingComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<DockingComponent, ComponentShutdown>(OnShutdown);
|
||||
@@ -48,15 +56,35 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
// Yes this isn't in shuttle console; it may be used by other systems technically.
|
||||
// in which case I would also add their subs here.
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, AutodockRequestMessage>(OnRequestAutodock);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, StopAutodockRequestMessage>(OnRequestStopAutodock);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, DockRequestMessage>(OnRequestDock);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, UndockRequestMessage>(OnRequestUndock);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
/// <summary>
|
||||
/// Sets the docks for the provided entity as enabled or disabled.
|
||||
/// </summary>
|
||||
public void SetDocks(EntityUid gridUid, bool enabled)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
UpdateAutodock();
|
||||
_dockingSet.Clear();
|
||||
_lookup.GetChildEntities(gridUid, _dockingSet);
|
||||
|
||||
foreach (var dock in _dockingSet)
|
||||
{
|
||||
Undock(dock);
|
||||
dock.Comp.Enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDockBolts(EntityUid gridUid, bool enabled)
|
||||
{
|
||||
_dockingBoltSet.Clear();
|
||||
_lookup.GetChildEntities(gridUid, _dockingBoltSet);
|
||||
|
||||
foreach (var entity in _dockingBoltSet)
|
||||
{
|
||||
_doorSystem.TryClose(entity);
|
||||
_doorSystem.SetBoltsDown((entity.Owner, entity.Comp2), enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAutoClose(EntityUid uid, DockingComponent component, BeforeDoorAutoCloseEvent args)
|
||||
@@ -66,79 +94,6 @@ namespace Content.Server.Shuttles.Systems
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private Entity<DockingComponent>? GetDockable(EntityUid uid, TransformComponent dockingXform)
|
||||
{
|
||||
// Did you know Saltern is the most dockable station?
|
||||
|
||||
// Assume the docking port itself (and its body) is valid
|
||||
|
||||
if (!HasComp<ShuttleComponent>(dockingXform.GridUid))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var transform = _physics.GetPhysicsTransform(uid, dockingXform);
|
||||
var dockingFixture = _fixtureSystem.GetFixtureOrNull(uid, DockingFixture);
|
||||
|
||||
if (dockingFixture == null)
|
||||
return null;
|
||||
|
||||
Box2? aabb = null;
|
||||
|
||||
for (var i = 0; i < dockingFixture.Shape.ChildCount; i++)
|
||||
{
|
||||
aabb = aabb?.Union(dockingFixture.Shape.ComputeAABB(transform, i)) ?? dockingFixture.Shape.ComputeAABB(transform, i);
|
||||
}
|
||||
|
||||
if (aabb == null)
|
||||
return null;
|
||||
|
||||
var enlargedAABB = aabb.Value.Enlarged(DockingRadius * 1.5f);
|
||||
|
||||
// Get any docking ports in range on other grids.
|
||||
var grids = new List<Entity<MapGridComponent>>();
|
||||
_mapManager.FindGridsIntersecting(dockingXform.MapID, enlargedAABB, ref grids);
|
||||
foreach (var otherGrid in grids)
|
||||
{
|
||||
if (otherGrid.Owner == dockingXform.GridUid)
|
||||
continue;
|
||||
|
||||
foreach (var ent in otherGrid.Comp.GetAnchoredEntities(enlargedAABB))
|
||||
{
|
||||
if (!TryComp(ent, out DockingComponent? otherDocking) ||
|
||||
!otherDocking.Enabled ||
|
||||
!TryComp(ent, out FixturesComponent? otherBody))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var otherTransform = _physics.GetPhysicsTransform(ent);
|
||||
var otherDockingFixture = _fixtureSystem.GetFixtureOrNull(ent, DockingFixture, manager: otherBody);
|
||||
|
||||
if (otherDockingFixture == null)
|
||||
{
|
||||
DebugTools.Assert(false);
|
||||
Log.Error($"Found null docking fixture on {ent}");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var i = 0; i < otherDockingFixture.Shape.ChildCount; i++)
|
||||
{
|
||||
var otherAABB = otherDockingFixture.Shape.ComputeAABB(otherTransform, i);
|
||||
|
||||
if (!aabb.Value.Intersects(otherAABB))
|
||||
continue;
|
||||
|
||||
// TODO: Need CollisionManager's GJK for accurate bounds
|
||||
// Realistically I want 2 fixtures anyway but I'll deal with that later.
|
||||
return (ent, otherDocking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, DockingComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (component.DockedWith == null ||
|
||||
@@ -147,6 +102,13 @@ namespace Content.Server.Shuttles.Systems
|
||||
return;
|
||||
}
|
||||
|
||||
var gridUid = Transform(uid).GridUid;
|
||||
|
||||
if (gridUid != null && !Terminating(gridUid.Value))
|
||||
{
|
||||
_console.RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
Cleanup(uid, component);
|
||||
}
|
||||
|
||||
@@ -166,12 +128,6 @@ namespace Content.Server.Shuttles.Systems
|
||||
Log.Error($"Tried to cleanup {dockAUid} but not docked?");
|
||||
|
||||
dockA.DockedWith = null;
|
||||
if (dockA.DockJoint != null)
|
||||
{
|
||||
// We'll still cleanup the dock joint on release at least
|
||||
_jointSystem.RemoveJoint(dockA.DockJoint);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -200,12 +156,16 @@ namespace Content.Server.Shuttles.Systems
|
||||
RaiseLocalEvent(msg);
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, DockingComponent component, ComponentStartup args)
|
||||
private void OnStartup(Entity<DockingComponent> entity, ref ComponentStartup args)
|
||||
{
|
||||
// Use startup so transform already initialized
|
||||
if (!EntityManager.GetComponent<TransformComponent>(uid).Anchored) return;
|
||||
var uid = entity.Owner;
|
||||
var component = entity.Comp;
|
||||
|
||||
EnableDocking(uid, component);
|
||||
// Use startup so transform already initialized
|
||||
if (!EntityManager.GetComponent<TransformComponent>(uid).Anchored)
|
||||
return;
|
||||
|
||||
SetDockingEnabled((uid, component), true);
|
||||
|
||||
// This little gem is for docking deserialization
|
||||
if (component.DockedWith != null)
|
||||
@@ -217,75 +177,62 @@ namespace Content.Server.Shuttles.Systems
|
||||
var otherDock = EntityManager.GetComponent<DockingComponent>(component.DockedWith.Value);
|
||||
DebugTools.Assert(otherDock.DockedWith != null);
|
||||
|
||||
Dock(uid, component, component.DockedWith.Value, otherDock);
|
||||
Dock((uid, component), (component.DockedWith.Value, otherDock));
|
||||
DebugTools.Assert(component.Docked && otherDock.Docked);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAnchorChange(EntityUid uid, DockingComponent component, ref AnchorStateChangedEvent args)
|
||||
private void OnAnchorChange(Entity<DockingComponent> entity, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
if (args.Anchored)
|
||||
{
|
||||
EnableDocking(uid, component);
|
||||
SetDockingEnabled(entity, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableDocking(uid, component);
|
||||
SetDockingEnabled(entity, false);
|
||||
}
|
||||
|
||||
_console.RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void OnDockingReAnchor(EntityUid uid, DockingComponent component, ref ReAnchorEvent args)
|
||||
private void OnDockingReAnchor(Entity<DockingComponent> entity, ref ReAnchorEvent args)
|
||||
{
|
||||
var uid = entity.Owner;
|
||||
var component = entity.Comp;
|
||||
|
||||
if (!component.Docked)
|
||||
return;
|
||||
|
||||
var otherDock = component.DockedWith;
|
||||
var other = Comp<DockingComponent>(otherDock!.Value);
|
||||
|
||||
Undock(uid, component);
|
||||
Dock(uid, component, otherDock.Value, other);
|
||||
Undock(entity);
|
||||
Dock((uid, component), (otherDock.Value, other));
|
||||
_console.RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void DisableDocking(EntityUid uid, DockingComponent component)
|
||||
public void SetDockingEnabled(Entity<DockingComponent> entity, bool value)
|
||||
{
|
||||
if (!component.Enabled)
|
||||
if (entity.Comp.Enabled == value)
|
||||
return;
|
||||
|
||||
component.Enabled = false;
|
||||
entity.Comp.Enabled = value;
|
||||
|
||||
if (component.DockedWith != null)
|
||||
if (!entity.Comp.Enabled && entity.Comp.DockedWith != null)
|
||||
{
|
||||
Undock(uid, component);
|
||||
Undock(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableDocking(EntityUid uid, DockingComponent component)
|
||||
{
|
||||
if (component.Enabled)
|
||||
return;
|
||||
|
||||
if (!TryComp(uid, out PhysicsComponent? physicsComponent))
|
||||
return;
|
||||
|
||||
component.Enabled = true;
|
||||
|
||||
var shape = new PhysShapeCircle(DockingRadius, new Vector2(0f, -0.5f));
|
||||
|
||||
// Listen it makes intersection tests easier; you can probably dump this but it requires a bunch more boilerplate
|
||||
// TODO: I want this to ideally be 2 fixtures to force them to have some level of alignment buuuttt
|
||||
// I also need collisionmanager for that yet again so they get dis.
|
||||
// TODO: CollisionManager is fine so get to work sloth chop chop.
|
||||
_fixtureSystem.TryCreateFixture(uid, shape, DockingFixture, hard: false, body: physicsComponent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Docks 2 ports together and assumes it is valid.
|
||||
/// </summary>
|
||||
public void Dock(EntityUid dockAUid, DockingComponent dockA, EntityUid dockBUid, DockingComponent dockB)
|
||||
public void Dock(Entity<DockingComponent> dockA, Entity<DockingComponent> dockB)
|
||||
{
|
||||
var dockAUid = dockA.Owner;
|
||||
var dockBUid = dockB.Owner;
|
||||
|
||||
if (dockBUid.GetHashCode() < dockAUid.GetHashCode())
|
||||
{
|
||||
(dockA, dockB) = (dockB, dockA);
|
||||
@@ -322,10 +269,10 @@ namespace Content.Server.Shuttles.Systems
|
||||
WeldJoint joint;
|
||||
|
||||
// Pre-existing joint so use that.
|
||||
if (dockA.DockJointId != null)
|
||||
if (dockA.Comp.DockJointId != null)
|
||||
{
|
||||
DebugTools.Assert(dockB.DockJointId == dockA.DockJointId);
|
||||
joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, dockA.DockJointId);
|
||||
DebugTools.Assert(dockB.Comp.DockJointId == dockA.Comp.DockJointId);
|
||||
joint = _jointSystem.GetOrCreateWeldJoint(gridA, gridB, dockA.Comp.DockJointId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -345,15 +292,15 @@ namespace Content.Server.Shuttles.Systems
|
||||
joint.Stiffness = stiffness;
|
||||
joint.Damping = damping;
|
||||
|
||||
dockA.DockJoint = joint;
|
||||
dockA.DockJointId = joint.ID;
|
||||
dockA.Comp.DockJoint = joint;
|
||||
dockA.Comp.DockJointId = joint.ID;
|
||||
|
||||
dockB.DockJoint = joint;
|
||||
dockB.DockJointId = joint.ID;
|
||||
dockB.Comp.DockJoint = joint;
|
||||
dockB.Comp.DockJointId = joint.ID;
|
||||
}
|
||||
|
||||
dockA.DockedWith = dockBUid;
|
||||
dockB.DockedWith = dockAUid;
|
||||
dockA.Comp.DockedWith = dockBUid;
|
||||
dockB.Comp.DockedWith = dockAUid;
|
||||
|
||||
if (TryComp(dockAUid, out DoorComponent? doorA))
|
||||
{
|
||||
@@ -381,8 +328,8 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
if (_pathfinding.TryCreatePortal(dockAXform.Coordinates, dockBXform.Coordinates, out var handle))
|
||||
{
|
||||
dockA.PathfindHandle = handle;
|
||||
dockB.PathfindHandle = handle;
|
||||
dockA.Comp.PathfindHandle = handle;
|
||||
dockB.Comp.PathfindHandle = handle;
|
||||
}
|
||||
|
||||
var msg = new DockEvent
|
||||
@@ -393,77 +340,35 @@ namespace Content.Server.Shuttles.Systems
|
||||
GridBUid = gridB,
|
||||
};
|
||||
|
||||
_console.RefreshShuttleConsoles();
|
||||
RaiseLocalEvent(dockAUid, msg);
|
||||
RaiseLocalEvent(dockBUid, msg);
|
||||
RaiseLocalEvent(msg);
|
||||
}
|
||||
|
||||
private bool CanDock(EntityUid dockAUid, EntityUid dockBUid, DockingComponent dockA, DockingComponent dockB)
|
||||
{
|
||||
if (!dockA.Enabled ||
|
||||
!dockB.Enabled ||
|
||||
dockA.DockedWith != null ||
|
||||
dockB.DockedWith != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fixtureA = _fixtureSystem.GetFixtureOrNull(dockAUid, DockingFixture);
|
||||
var fixtureB = _fixtureSystem.GetFixtureOrNull(dockBUid, DockingFixture);
|
||||
|
||||
if (fixtureA == null || fixtureB == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var transformA = _physics.GetPhysicsTransform(dockAUid);
|
||||
var transformB = _physics.GetPhysicsTransform(dockBUid);
|
||||
var intersect = false;
|
||||
|
||||
for (var i = 0; i < fixtureA.Shape.ChildCount; i++)
|
||||
{
|
||||
var aabb = fixtureA.Shape.ComputeAABB(transformA, i);
|
||||
|
||||
for (var j = 0; j < fixtureB.Shape.ChildCount; j++)
|
||||
{
|
||||
var otherAABB = fixtureB.Shape.ComputeAABB(transformB, j);
|
||||
if (!aabb.Intersects(otherAABB))
|
||||
continue;
|
||||
|
||||
// TODO: Need collisionmanager's GJK for accurate checks don't @ me son
|
||||
intersect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (intersect)
|
||||
break;
|
||||
}
|
||||
|
||||
return intersect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to dock 2 ports together and will return early if it's not possible.
|
||||
/// </summary>
|
||||
private void TryDock(EntityUid dockAUid, DockingComponent dockA, Entity<DockingComponent> dockB)
|
||||
private void TryDock(Entity<DockingComponent> dockA, Entity<DockingComponent> dockB)
|
||||
{
|
||||
if (!CanDock(dockAUid, dockB, dockA, dockB))
|
||||
if (!CanDock(dockA, dockB))
|
||||
return;
|
||||
|
||||
Dock(dockAUid, dockA, dockB, dockB);
|
||||
Dock(dockA, dockB);
|
||||
}
|
||||
|
||||
public void Undock(EntityUid dockUid, DockingComponent dock)
|
||||
public void Undock(Entity<DockingComponent> dock)
|
||||
{
|
||||
if (dock.DockedWith == null)
|
||||
if (dock.Comp.DockedWith == null)
|
||||
return;
|
||||
|
||||
OnUndock(dockUid, dock.DockedWith.Value);
|
||||
OnUndock(dock.DockedWith.Value, dockUid);
|
||||
Cleanup(dockUid, dock);
|
||||
OnUndock(dock.Owner);
|
||||
OnUndock(dock.Comp.DockedWith.Value);
|
||||
Cleanup(dock.Owner, dock);
|
||||
_console.RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void OnUndock(EntityUid dockUid, EntityUid other)
|
||||
private void OnUndock(EntityUid dockUid)
|
||||
{
|
||||
if (TerminatingOrDeleted(dockUid))
|
||||
return;
|
||||
@@ -473,9 +378,97 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
if (TryComp(dockUid, out DoorComponent? door) && _doorSystem.TryClose(dockUid, door))
|
||||
door.ChangeAirtight = true;
|
||||
}
|
||||
|
||||
var recentlyDocked = EnsureComp<RecentlyDockedComponent>(dockUid);
|
||||
recentlyDocked.LastDocked = other;
|
||||
private void OnRequestUndock(EntityUid uid, ShuttleConsoleComponent component, UndockRequestMessage args)
|
||||
{
|
||||
if (!TryGetEntity(args.DockEntity, out var dockEnt) ||
|
||||
!TryComp(dockEnt, out DockingComponent? dockComp))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-undock-fail"));
|
||||
return;
|
||||
}
|
||||
|
||||
var dock = (dockEnt.Value, dockComp);
|
||||
|
||||
if (!CanUndock(dock))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-undock-fail"));
|
||||
return;
|
||||
}
|
||||
|
||||
Undock(dock);
|
||||
}
|
||||
|
||||
private void OnRequestDock(EntityUid uid, ShuttleConsoleComponent component, DockRequestMessage args)
|
||||
{
|
||||
var shuttleUid = Transform(uid).GridUid;
|
||||
|
||||
if (!CanShuttleDock(shuttleUid))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-dock-fail"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryGetEntity(args.DockEntity, out var ourDock) ||
|
||||
!TryGetEntity(args.TargetDockEntity, out var targetDock) ||
|
||||
!TryComp(ourDock, out DockingComponent? ourDockComp) ||
|
||||
!TryComp(targetDock, out DockingComponent? targetDockComp))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-dock-fail"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Cheating?
|
||||
if (!TryComp(ourDock, out TransformComponent? xformA) ||
|
||||
xformA.GridUid != shuttleUid)
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-dock-fail"));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Move the CanDock stuff to the port state and also validate that stuff
|
||||
// Also need to check preventpilot + enabled / dockedwith
|
||||
if (!CanDock((ourDock.Value, ourDockComp), (targetDock.Value, targetDockComp)))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-dock-fail"));
|
||||
return;
|
||||
}
|
||||
|
||||
Dock((ourDock.Value, ourDockComp), (targetDock.Value, targetDockComp));
|
||||
}
|
||||
|
||||
public bool CanUndock(Entity<DockingComponent?> dock)
|
||||
{
|
||||
if (!Resolve(dock, ref dock.Comp) ||
|
||||
!dock.Comp.Docked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if both docks can connect. Does not consider whether the shuttle allows it.
|
||||
/// </summary>
|
||||
public bool CanDock(Entity<DockingComponent> dockA, Entity<DockingComponent> dockB)
|
||||
{
|
||||
if (!dockA.Comp.Enabled ||
|
||||
!dockB.Comp.Enabled ||
|
||||
dockA.Comp.DockedWith != null ||
|
||||
dockB.Comp.DockedWith != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var xformA = Transform(dockA);
|
||||
var xformB = Transform(dockB);
|
||||
var (worldPosA, worldRotA) = XformSystem.GetWorldPositionRotation(xformA);
|
||||
var (worldPosB, worldRotB) = XformSystem.GetWorldPositionRotation(xformB);
|
||||
|
||||
return CanDock(new MapCoordinates(worldPosA, xformA.MapID), worldRotA,
|
||||
new MapCoordinates(worldPosB, xformB.MapID), worldRotB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,15 +163,15 @@ public sealed partial class EmergencyShuttleSystem
|
||||
|
||||
if (!Deleted(centcomm.Entity))
|
||||
{
|
||||
_shuttle.FTLTravel(comp.EmergencyShuttle.Value, shuttle,
|
||||
centcomm.Entity.Value, _consoleAccumulator, TransitTime, true);
|
||||
_shuttle.FTLToDock(comp.EmergencyShuttle.Value, shuttle,
|
||||
centcomm.Entity.Value, _consoleAccumulator, TransitTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Deleted(centcomm.MapEntity))
|
||||
{
|
||||
// TODO: Need to get non-overlapping positions.
|
||||
_shuttle.FTLTravel(comp.EmergencyShuttle.Value, shuttle,
|
||||
_shuttle.FTLToCoordinates(comp.EmergencyShuttle.Value, shuttle,
|
||||
new EntityCoordinates(centcomm.MapEntity.Value,
|
||||
_random.NextVector2(1000f)), _consoleAccumulator, TransitTime);
|
||||
}
|
||||
@@ -201,7 +201,7 @@ public sealed partial class EmergencyShuttleSystem
|
||||
}
|
||||
|
||||
// Don't dock them. If you do end up doing this then stagger launch.
|
||||
_shuttle.FTLTravel(uid, shuttle, centcomm.Entity.Value, hyperspaceTime: TransitTime);
|
||||
_shuttle.FTLToDock(uid, shuttle, centcomm.Entity.Value, hyperspaceTime: TransitTime);
|
||||
RemCompDeferred<EscapePodComponent>(uid);
|
||||
}
|
||||
|
||||
@@ -217,15 +217,18 @@ public sealed partial class EmergencyShuttleSystem
|
||||
// All the others.
|
||||
if (_consoleAccumulator < minTime)
|
||||
{
|
||||
var query = AllEntityQuery<StationCentcommComponent>();
|
||||
var query = AllEntityQuery<StationCentcommComponent, TransformComponent>();
|
||||
|
||||
// Guarantees that emergency shuttle arrives first before anyone else can FTL.
|
||||
while (query.MoveNext(out var comp))
|
||||
while (query.MoveNext(out var comp, out var centcommXform))
|
||||
{
|
||||
if (Deleted(comp.Entity))
|
||||
continue;
|
||||
|
||||
_shuttle.AddFTLDestination(comp.Entity.Value, true);
|
||||
if (_shuttle.TryAddFTLDestination(centcommXform.MapID, true, out var ftlComp))
|
||||
{
|
||||
_shuttle.SetFTLWhitelist((centcommXform.MapUid!.Value, ftlComp), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +445,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
||||
|
||||
component.MapEntity = map;
|
||||
component.Entity = grid;
|
||||
_shuttle.AddFTLDestination(grid.Value, false);
|
||||
_shuttle.TryAddFTLDestination(mapId, false, out _);
|
||||
}
|
||||
|
||||
public HashSet<EntityUid> GetCentcommMaps()
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed class RadarConsoleSystem : SharedRadarConsoleSystem
|
||||
{
|
||||
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -39,11 +40,20 @@ public sealed class RadarConsoleSystem : SharedRadarConsoleSystem
|
||||
}
|
||||
|
||||
if (_uiSystem.TryGetUi(uid, RadarConsoleUiKey.Key, out var bui))
|
||||
_uiSystem.SetUiState(bui, new RadarConsoleBoundInterfaceState(
|
||||
component.MaxRange,
|
||||
GetNetCoordinates(coordinates),
|
||||
angle,
|
||||
new List<DockingInterfaceState>()
|
||||
));
|
||||
{
|
||||
NavInterfaceState state;
|
||||
var docks = _console.GetAllDocks();
|
||||
|
||||
if (coordinates != null && angle != null)
|
||||
{
|
||||
state = _console.GetNavState(uid, docks, coordinates.Value, angle.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = _console.GetNavState(uid, docks);
|
||||
}
|
||||
|
||||
_uiSystem.SetUiState(bui, new NavBoundUserInterfaceState(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,20 @@ namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class ShuttleConsoleSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the drone console target if applicable otherwise returns itself.
|
||||
/// </summary>
|
||||
private EntityUid? GetDroneConsole(EntityUid consoleUid)
|
||||
{
|
||||
var getShuttleEv = new ConsoleShuttleEvent
|
||||
{
|
||||
Console = consoleUid,
|
||||
};
|
||||
|
||||
RaiseLocalEvent(consoleUid, ref getShuttleEv);
|
||||
return getShuttleEv.Console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes all drone console entities.
|
||||
/// </summary>
|
||||
|
||||
160
Content.Server/Shuttles/Systems/ShuttleConsoleSystem.FTL.cs
Normal file
160
Content.Server/Shuttles/Systems/ShuttleConsoleSystem.FTL.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Shuttles.UI.MapObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class ShuttleConsoleSystem
|
||||
{
|
||||
private void InitializeFTL()
|
||||
{
|
||||
SubscribeLocalEvent<FTLBeaconComponent, ComponentStartup>(OnBeaconStartup);
|
||||
SubscribeLocalEvent<FTLBeaconComponent, AnchorStateChangedEvent>(OnBeaconAnchorChanged);
|
||||
|
||||
SubscribeLocalEvent<FTLExclusionComponent, ComponentStartup>(OnExclusionStartup);
|
||||
}
|
||||
|
||||
private void OnExclusionStartup(Entity<FTLExclusionComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void OnBeaconStartup(Entity<FTLBeaconComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void OnBeaconAnchorChanged(Entity<FTLBeaconComponent> ent, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void OnBeaconFTLMessage(Entity<ShuttleConsoleComponent> ent, ref ShuttleConsoleFTLBeaconMessage args)
|
||||
{
|
||||
var beaconEnt = GetEntity(args.Beacon);
|
||||
if (!_xformQuery.TryGetComponent(beaconEnt, out var targetXform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var nCoordinates = new NetCoordinates(GetNetEntity(targetXform.ParentUid), targetXform.LocalPosition);
|
||||
|
||||
// Check target exists
|
||||
if (!_shuttle.CanFTLBeacon(nCoordinates))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var angle = args.Angle.Reduced();
|
||||
var targetCoordinates = new EntityCoordinates(targetXform.MapUid!.Value, _transform.GetWorldPosition(targetXform));
|
||||
|
||||
ConsoleFTL(ent, true, targetCoordinates, angle, targetXform.MapID);
|
||||
}
|
||||
|
||||
private void OnPositionFTLMessage(Entity<ShuttleConsoleComponent> entity, ref ShuttleConsoleFTLPositionMessage args)
|
||||
{
|
||||
var mapUid = _mapManager.GetMapEntityId(args.Coordinates.MapId);
|
||||
|
||||
// If it's beacons only block all position messages.
|
||||
if (!Exists(mapUid) || _shuttle.IsBeaconMap(mapUid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var targetCoordinates = new EntityCoordinates(mapUid, args.Coordinates.Position);
|
||||
var angle = args.Angle.Reduced();
|
||||
ConsoleFTL(entity, false, targetCoordinates, angle, args.Coordinates.MapId);
|
||||
}
|
||||
|
||||
private void GetBeacons(ref List<ShuttleBeaconObject>? beacons)
|
||||
{
|
||||
var beaconQuery = AllEntityQuery<FTLBeaconComponent>();
|
||||
|
||||
while (beaconQuery.MoveNext(out var destUid, out _))
|
||||
{
|
||||
var meta = _metaQuery.GetComponent(destUid);
|
||||
var name = meta.EntityName;
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = Loc.GetString("shuttle-console-unknown");
|
||||
|
||||
// Can't travel to same map (yet)
|
||||
var destXform = _xformQuery.GetComponent(destUid);
|
||||
beacons ??= new List<ShuttleBeaconObject>();
|
||||
beacons.Add(new ShuttleBeaconObject(GetNetEntity(destUid), GetNetCoordinates(destXform.Coordinates), name));
|
||||
}
|
||||
}
|
||||
|
||||
private void GetExclusions(ref List<ShuttleExclusionObject>? exclusions)
|
||||
{
|
||||
var query = AllEntityQuery<FTLExclusionComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp, out var xform))
|
||||
{
|
||||
if (!comp.Enabled)
|
||||
continue;
|
||||
|
||||
exclusions ??= new List<ShuttleExclusionObject>();
|
||||
exclusions.Add(new ShuttleExclusionObject(GetNetCoordinates(xform.Coordinates), comp.Range, Loc.GetString("shuttle-console-exclusion")));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles shuttle console FTLs.
|
||||
/// </summary>
|
||||
private void ConsoleFTL(Entity<ShuttleConsoleComponent> ent, bool beacon, EntityCoordinates targetCoordinates, Angle targetAngle, MapId targetMap)
|
||||
{
|
||||
var consoleUid = GetDroneConsole(ent.Owner);
|
||||
|
||||
if (consoleUid == null)
|
||||
return;
|
||||
|
||||
var shuttleUid = _xformQuery.GetComponent(consoleUid.Value).GridUid;
|
||||
|
||||
if (!TryComp(shuttleUid, out ShuttleComponent? shuttleComp))
|
||||
return;
|
||||
|
||||
// Check shuttle can even FTL
|
||||
if (!_shuttle.CanFTL(shuttleUid.Value, out var reason))
|
||||
{
|
||||
// TODO: Session popup
|
||||
return;
|
||||
}
|
||||
|
||||
// Check shuttle can FTL to this target.
|
||||
if (!_shuttle.CanFTLTo(shuttleUid.Value, targetMap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<ShuttleExclusionObject>? exclusions = null;
|
||||
GetExclusions(ref exclusions);
|
||||
|
||||
if (!beacon && !_shuttle.FTLFree(shuttleUid.Value, targetCoordinates, targetAngle, exclusions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp(shuttleUid.Value, out PhysicsComponent? shuttlePhysics))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Client sends the "adjusted" coordinates and we adjust it back to get the actual transform coordinates.
|
||||
var adjustedCoordinates = targetCoordinates.Offset(targetAngle.RotateVec(-shuttlePhysics.LocalCenter));
|
||||
|
||||
var tagEv = new FTLTagEvent();
|
||||
RaiseLocalEvent(shuttleUid.Value, ref tagEv);
|
||||
|
||||
var ev = new ShuttleConsoleFTLTravelStartEvent(ent.Owner);
|
||||
RaiseLocalEvent(ref ev);
|
||||
|
||||
_shuttle.FTLToCoordinates(shuttleUid.Value, shuttleComp, adjustedCoordinates, targetAngle);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Popups;
|
||||
@@ -13,12 +12,11 @@ using Content.Shared.Shuttles.Events;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Shuttles.UI.MapObjects;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.UserInterface;
|
||||
|
||||
@@ -26,27 +24,38 @@ namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly TagSystem _tags = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
[Dependency] private readonly SharedContentEyeSystem _eyeSystem = default!;
|
||||
|
||||
private EntityQuery<MetaDataComponent> _metaQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
private readonly HashSet<Entity<ShuttleConsoleComponent>> _consoles = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_metaQuery = GetEntityQuery<MetaDataComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, ComponentShutdown>(OnConsoleShutdown);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, PowerChangedEvent>(OnConsolePowerChange);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, AnchorStateChangedEvent>(OnConsoleAnchorChange);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnConsoleUIOpenAttempt);
|
||||
Subs.BuiEvents<ShuttleConsoleComponent>(ShuttleConsoleUiKey.Key, subs =>
|
||||
{
|
||||
subs.Event<ShuttleConsoleFTLRequestMessage>(OnDestinationMessage);
|
||||
subs.Event<ShuttleConsoleFTLBeaconMessage>(OnBeaconFTLMessage);
|
||||
subs.Event<ShuttleConsoleFTLPositionMessage>(OnPositionFTLMessage);
|
||||
subs.Event<BoundUIClosedEvent>(OnConsoleUIClose);
|
||||
});
|
||||
|
||||
@@ -60,11 +69,12 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
SubscribeLocalEvent<DockEvent>(OnDock);
|
||||
SubscribeLocalEvent<UndockEvent>(OnUndock);
|
||||
|
||||
SubscribeLocalEvent<PilotComponent, MoveEvent>(HandlePilotMove);
|
||||
SubscribeLocalEvent<PilotComponent, ComponentGetState>(OnGetState);
|
||||
|
||||
SubscribeLocalEvent<FTLDestinationComponent, ComponentStartup>(OnFtlDestStartup);
|
||||
SubscribeLocalEvent<FTLDestinationComponent, ComponentShutdown>(OnFtlDestShutdown);
|
||||
|
||||
InitializeFTL();
|
||||
}
|
||||
|
||||
private void OnFtlDestStartup(EntityUid uid, FTLDestinationComponent component, ComponentStartup args)
|
||||
@@ -77,65 +87,6 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
private void OnDestinationMessage(EntityUid uid, ShuttleConsoleComponent component,
|
||||
ShuttleConsoleFTLRequestMessage args)
|
||||
{
|
||||
var destination = GetEntity(args.Destination);
|
||||
|
||||
if (!TryComp<FTLDestinationComponent>(destination, out var dest))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dest.Enabled)
|
||||
return;
|
||||
|
||||
EntityUid? entity = uid;
|
||||
|
||||
var getShuttleEv = new ConsoleShuttleEvent
|
||||
{
|
||||
Console = uid,
|
||||
};
|
||||
|
||||
RaiseLocalEvent(entity.Value, ref getShuttleEv);
|
||||
entity = getShuttleEv.Console;
|
||||
|
||||
if (!TryComp<TransformComponent>(entity, out var xform) ||
|
||||
!TryComp<ShuttleComponent>(xform.GridUid, out var shuttle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (dest.Whitelist?.IsValid(entity.Value, EntityManager) == false &&
|
||||
dest.Whitelist?.IsValid(xform.GridUid.Value, EntityManager) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var shuttleUid = xform.GridUid.Value;
|
||||
|
||||
if (HasComp<FTLComponent>(shuttleUid))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("shuttle-console-in-ftl"), args.Session);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_shuttle.CanFTL(xform.GridUid, out var reason))
|
||||
{
|
||||
_popup.PopupCursor(reason, args.Session);
|
||||
return;
|
||||
}
|
||||
|
||||
var dock = HasComp<MapComponent>(destination) && HasComp<MapGridComponent>(destination);
|
||||
var tagEv = new FTLTagEvent();
|
||||
RaiseLocalEvent(xform.GridUid.Value, ref tagEv);
|
||||
|
||||
var ev = new ShuttleConsoleFTLTravelStartEvent(uid);
|
||||
RaiseLocalEvent(ref ev);
|
||||
|
||||
_shuttle.FTLTravel(xform.GridUid.Value, shuttle, destination, dock: dock, priorityTag: tagEv.Tag);
|
||||
}
|
||||
|
||||
private void OnDock(DockEvent ev)
|
||||
{
|
||||
RefreshShuttleConsoles();
|
||||
@@ -146,10 +97,21 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
RefreshShuttleConsoles();
|
||||
}
|
||||
|
||||
public void RefreshShuttleConsoles(EntityUid _)
|
||||
/// <summary>
|
||||
/// Refreshes all the shuttle console data for a particular grid.
|
||||
/// </summary>
|
||||
public void RefreshShuttleConsoles(EntityUid gridUid)
|
||||
{
|
||||
// TODO: Should really call this per shuttle in some instances.
|
||||
RefreshShuttleConsoles();
|
||||
var exclusions = new List<ShuttleExclusionObject>();
|
||||
GetExclusions(ref exclusions);
|
||||
_consoles.Clear();
|
||||
_lookup.GetChildEntities(gridUid, _consoles);
|
||||
DockingInterfaceState? dockState = null;
|
||||
|
||||
foreach (var entity in _consoles)
|
||||
{
|
||||
UpdateState(entity, ref dockState);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -157,12 +119,14 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
/// </summary>
|
||||
public void RefreshShuttleConsoles()
|
||||
{
|
||||
var docks = GetAllDocks();
|
||||
var exclusions = new List<ShuttleExclusionObject>();
|
||||
GetExclusions(ref exclusions);
|
||||
var query = AllEntityQuery<ShuttleConsoleComponent>();
|
||||
DockingInterfaceState? dockState = null;
|
||||
|
||||
while (query.MoveNext(out var uid, out var _))
|
||||
while (query.MoveNext(out var uid, out _))
|
||||
{
|
||||
UpdateState(uid, docks);
|
||||
UpdateState(uid,ref dockState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,12 +141,6 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
return;
|
||||
}
|
||||
|
||||
// In case they D/C should still clean them up.
|
||||
foreach (var comp in EntityQuery<AutoDockComponent>(true))
|
||||
{
|
||||
comp.Requesters.Remove(user);
|
||||
}
|
||||
|
||||
RemovePilot(user);
|
||||
}
|
||||
|
||||
@@ -196,12 +154,14 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
private void OnConsoleAnchorChange(EntityUid uid, ShuttleConsoleComponent component,
|
||||
ref AnchorStateChangedEvent args)
|
||||
{
|
||||
UpdateState(uid);
|
||||
DockingInterfaceState? dockState = null;
|
||||
UpdateState(uid, ref dockState);
|
||||
}
|
||||
|
||||
private void OnConsolePowerChange(EntityUid uid, ShuttleConsoleComponent component, ref PowerChangedEvent args)
|
||||
{
|
||||
UpdateState(uid);
|
||||
DockingInterfaceState? dockState = null;
|
||||
UpdateState(uid, ref dockState);
|
||||
}
|
||||
|
||||
private bool TryPilot(EntityUid user, EntityUid uid)
|
||||
@@ -239,33 +199,38 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
/// <summary>
|
||||
/// Returns the position and angle of all dockingcomponents.
|
||||
/// </summary>
|
||||
private List<DockingInterfaceState> GetAllDocks()
|
||||
public Dictionary<NetEntity, List<DockingPortState>> GetAllDocks()
|
||||
{
|
||||
// TODO: NEED TO MAKE SURE THIS UPDATES ON ANCHORING CHANGES!
|
||||
var result = new List<DockingInterfaceState>();
|
||||
var query = AllEntityQuery<DockingComponent, TransformComponent>();
|
||||
var result = new Dictionary<NetEntity, List<DockingPortState>>();
|
||||
var query = AllEntityQuery<DockingComponent, TransformComponent, MetaDataComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp, out var xform))
|
||||
while (query.MoveNext(out var uid, out var comp, out var xform, out var metadata))
|
||||
{
|
||||
if (xform.ParentUid != xform.GridUid)
|
||||
continue;
|
||||
|
||||
var state = new DockingInterfaceState()
|
||||
var gridDocks = result.GetOrNew(GetNetEntity(xform.GridUid.Value));
|
||||
|
||||
var state = new DockingPortState()
|
||||
{
|
||||
Name = metadata.EntityName,
|
||||
Coordinates = GetNetCoordinates(xform.Coordinates),
|
||||
Angle = xform.LocalRotation,
|
||||
Entity = GetNetEntity(uid),
|
||||
Connected = comp.Docked,
|
||||
Color = comp.RadarColor,
|
||||
HighlightedColor = comp.HighlightedRadarColor,
|
||||
GridDockedWith =
|
||||
_xformQuery.TryGetComponent(comp.DockedWith, out var otherDockXform) ?
|
||||
GetNetEntity(otherDockXform.GridUid) :
|
||||
null,
|
||||
};
|
||||
result.Add(state);
|
||||
|
||||
gridDocks.Add(state);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void UpdateState(EntityUid consoleUid, List<DockingInterfaceState>? docks = null)
|
||||
private void UpdateState(EntityUid consoleUid, ref DockingInterfaceState? dockState)
|
||||
{
|
||||
EntityUid? entity = consoleUid;
|
||||
|
||||
@@ -278,77 +243,26 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
entity = getShuttleEv.Console;
|
||||
|
||||
TryComp<TransformComponent>(entity, out var consoleXform);
|
||||
TryComp<RadarConsoleComponent>(entity, out var radar);
|
||||
var range = radar?.MaxRange ?? SharedRadarConsoleSystem.DefaultMaxRange;
|
||||
|
||||
var shuttleGridUid = consoleXform?.GridUid;
|
||||
|
||||
var destinations = new List<(NetEntity, string, bool)>();
|
||||
var ftlState = FTLState.Available;
|
||||
var ftlTime = TimeSpan.Zero;
|
||||
NavInterfaceState navState;
|
||||
ShuttleMapInterfaceState mapState;
|
||||
dockState ??= GetDockState();
|
||||
|
||||
if (TryComp<FTLComponent>(shuttleGridUid, out var shuttleFtl))
|
||||
if (shuttleGridUid != null && entity != null)
|
||||
{
|
||||
ftlState = shuttleFtl.State;
|
||||
ftlTime = _timing.CurTime + TimeSpan.FromSeconds(shuttleFtl.Accumulator);
|
||||
navState = GetNavState(entity.Value, dockState.Docks);
|
||||
mapState = GetMapState(shuttleGridUid.Value);
|
||||
}
|
||||
|
||||
// Mass too large
|
||||
if (entity != null && shuttleGridUid != null &&
|
||||
(!TryComp<PhysicsComponent>(shuttleGridUid, out var shuttleBody) || shuttleBody.Mass < 1000f))
|
||||
else
|
||||
{
|
||||
var metaQuery = GetEntityQuery<MetaDataComponent>();
|
||||
|
||||
// Can't go anywhere when in FTL.
|
||||
var locked = shuttleFtl != null || Paused(shuttleGridUid.Value);
|
||||
|
||||
// Can't cache it because it may have a whitelist for the particular console.
|
||||
// Include paused as we still want to show CentCom.
|
||||
var destQuery = AllEntityQuery<FTLDestinationComponent>();
|
||||
|
||||
while (destQuery.MoveNext(out var destUid, out var comp))
|
||||
{
|
||||
// Can't warp to itself or if it's not on the whitelist (console or shuttle).
|
||||
if (destUid == shuttleGridUid ||
|
||||
comp.Whitelist?.IsValid(entity.Value) == false &&
|
||||
(shuttleGridUid == null || comp.Whitelist?.IsValid(shuttleGridUid.Value, EntityManager) == false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var meta = metaQuery.GetComponent(destUid);
|
||||
var name = meta.EntityName;
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = Loc.GetString("shuttle-console-unknown");
|
||||
|
||||
var canTravel = !locked &&
|
||||
comp.Enabled &&
|
||||
(!TryComp<FTLComponent>(destUid, out var ftl) || ftl.State == FTLState.Cooldown);
|
||||
|
||||
// Can't travel to same map (yet)
|
||||
if (canTravel && consoleXform?.MapUid == Transform(destUid).MapUid)
|
||||
{
|
||||
canTravel = false;
|
||||
}
|
||||
|
||||
destinations.Add((GetNetEntity(destUid), name, canTravel));
|
||||
}
|
||||
navState = new NavInterfaceState(0f, null, null, new Dictionary<NetEntity, List<DockingPortState>>());
|
||||
mapState = new ShuttleMapInterfaceState(FTLState.Invalid, 0f, new List<ShuttleBeaconObject>(), new List<ShuttleExclusionObject>());
|
||||
}
|
||||
|
||||
docks ??= GetAllDocks();
|
||||
|
||||
if (_ui.TryGetUi(consoleUid, ShuttleConsoleUiKey.Key, out var bui))
|
||||
{
|
||||
_ui.SetUiState(bui, new ShuttleConsoleBoundInterfaceState(
|
||||
ftlState,
|
||||
ftlTime,
|
||||
destinations,
|
||||
range,
|
||||
GetNetCoordinates(consoleXform?.Coordinates),
|
||||
consoleXform?.LocalRotation,
|
||||
docks
|
||||
));
|
||||
_ui.SetUiState(bui, new ShuttleBoundUserInterfaceState(navState, mapState, dockState));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,27 +290,6 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If pilot is moved then we'll stop them from piloting.
|
||||
/// </summary>
|
||||
private void HandlePilotMove(EntityUid uid, PilotComponent component, ref MoveEvent args)
|
||||
{
|
||||
if (component.Console == null || component.Position == null)
|
||||
{
|
||||
DebugTools.Assert(component.Position == null && component.Console == null);
|
||||
EntityManager.RemoveComponent<PilotComponent>(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.NewPosition.TryDistance(EntityManager, component.Position.Value, out var distance) &&
|
||||
distance < PilotComponent.BreakDistance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RemovePilot(uid, component);
|
||||
}
|
||||
|
||||
protected override void HandlePilotShutdown(EntityUid uid, PilotComponent component, ComponentShutdown args)
|
||||
{
|
||||
base.HandlePilotShutdown(uid, component, args);
|
||||
@@ -467,4 +360,70 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||
RemovePilot(pilot, pilotComponent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific for a particular shuttle.
|
||||
/// </summary>
|
||||
public NavInterfaceState GetNavState(Entity<RadarConsoleComponent?, TransformComponent?> entity, Dictionary<NetEntity, List<DockingPortState>> docks)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp1, ref entity.Comp2))
|
||||
return new NavInterfaceState(SharedRadarConsoleSystem.DefaultMaxRange, null, null, docks);
|
||||
|
||||
return GetNavState(
|
||||
entity,
|
||||
docks,
|
||||
entity.Comp2.Coordinates,
|
||||
entity.Comp2.LocalRotation);
|
||||
}
|
||||
|
||||
public NavInterfaceState GetNavState(
|
||||
Entity<RadarConsoleComponent?, TransformComponent?> entity,
|
||||
Dictionary<NetEntity, List<DockingPortState>> docks,
|
||||
EntityCoordinates coordinates,
|
||||
Angle angle)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp1, ref entity.Comp2))
|
||||
return new NavInterfaceState(SharedRadarConsoleSystem.DefaultMaxRange, GetNetCoordinates(coordinates), angle, docks);
|
||||
|
||||
return new NavInterfaceState(
|
||||
entity.Comp1.MaxRange,
|
||||
GetNetCoordinates(coordinates),
|
||||
angle,
|
||||
docks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Global for all shuttles.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DockingInterfaceState GetDockState()
|
||||
{
|
||||
var docks = GetAllDocks();
|
||||
return new DockingInterfaceState(docks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific to a particular shuttle.
|
||||
/// </summary>
|
||||
public ShuttleMapInterfaceState GetMapState(Entity<FTLComponent?> shuttle)
|
||||
{
|
||||
FTLState ftlState = FTLState.Available;
|
||||
float stateDuration = 0f;
|
||||
|
||||
if (Resolve(shuttle, ref shuttle.Comp, false) && shuttle.Comp.LifeStage < ComponentLifeStage.Stopped)
|
||||
{
|
||||
ftlState = shuttle.Comp.State;
|
||||
stateDuration = _shuttle.GetStateDuration(shuttle.Comp);
|
||||
}
|
||||
|
||||
List<ShuttleBeaconObject>? beacons = null;
|
||||
List<ShuttleExclusionObject>? exclusions = null;
|
||||
GetBeacons(ref beacons);
|
||||
GetExclusions(ref exclusions);
|
||||
|
||||
return new ShuttleMapInterfaceState(
|
||||
ftlState, stateDuration,
|
||||
beacons ?? new List<ShuttleBeaconObject>(),
|
||||
exclusions ?? new List<ShuttleExclusionObject>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Station.Events;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Parallax;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Whitelist;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Components;
|
||||
@@ -21,8 +21,8 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
using FTLMapComponent = Content.Shared.Shuttles.Components.FTLMapComponent;
|
||||
|
||||
namespace Content.Server.Shuttles.Systems;
|
||||
|
||||
@@ -32,18 +32,11 @@ public sealed partial class ShuttleSystem
|
||||
* This is a way to move a shuttle from one location to another, via an intermediate map for fanciness.
|
||||
*/
|
||||
|
||||
private MapId? _hyperSpaceMap;
|
||||
|
||||
public const float DefaultStartupTime = 5.5f;
|
||||
public const float DefaultTravelTime = 20f;
|
||||
public const float DefaultArrivalTime = 5f;
|
||||
private const float FTLCooldown = 10f;
|
||||
private const float ShuttleFTLRange = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum mass a grid needs to be to block a shuttle recall.
|
||||
/// </summary>
|
||||
public const float ShuttleFTLMassThreshold = 300f;
|
||||
public const float FTLMassLimit = 100000f;
|
||||
|
||||
// I'm too lazy to make CVars.
|
||||
|
||||
@@ -51,7 +44,7 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
Params = AudioParams.Default.WithVolume(-5f),
|
||||
};
|
||||
// private SoundSpecifier _travelSound = new SoundPathSpecifier();
|
||||
|
||||
private readonly SoundSpecifier _arrivalSound = new SoundPathSpecifier("/Audio/Effects/Shuttle/hyperspace_end.ogg")
|
||||
{
|
||||
Params = AudioParams.Default.WithVolume(-5f),
|
||||
@@ -59,7 +52,9 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
private readonly TimeSpan _hyperspaceKnockdownTime = TimeSpan.FromSeconds(5);
|
||||
|
||||
/// <summary>
|
||||
/// Left-side of the station we're allowed to use
|
||||
/// </summary>
|
||||
private float _index;
|
||||
|
||||
/// <summary>
|
||||
@@ -72,12 +67,7 @@ public sealed partial class ShuttleSystem
|
||||
/// </summary>
|
||||
private const int FTLProximityIterations = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum mass for an FTL destination
|
||||
/// </summary>
|
||||
public const float FTLDestinationMass = 500f;
|
||||
|
||||
private HashSet<EntityUid> _lookupEnts = new();
|
||||
private readonly HashSet<EntityUid> _lookupEnts = new();
|
||||
|
||||
private EntityQuery<BodyComponent> _bodyQuery;
|
||||
private EntityQuery<BuckleComponent> _buckleQuery;
|
||||
@@ -88,68 +78,112 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
private void InitializeFTL()
|
||||
{
|
||||
SubscribeLocalEvent<StationPostInitEvent>(OnStationPostInit);
|
||||
_bodyQuery = GetEntityQuery<BodyComponent>();
|
||||
_buckleQuery = GetEntityQuery<BuckleComponent>();
|
||||
_ghostQuery = GetEntityQuery<GhostComponent>();
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
_statusQuery = GetEntityQuery<StatusEffectsComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
SubscribeLocalEvent<StationGridAddedEvent>(OnStationGridAdd);
|
||||
}
|
||||
|
||||
private void OnStationGridAdd(StationGridAddedEvent ev)
|
||||
private void OnStationPostInit(ref StationPostInitEvent ev)
|
||||
{
|
||||
if (HasComp<MapComponent>(ev.GridId) ||
|
||||
TryComp<PhysicsComponent>(ev.GridId, out var body) &&
|
||||
body.Mass > FTLDestinationMass)
|
||||
// Add all grid maps as ftl destinations that anyone can FTL to.
|
||||
foreach (var gridUid in ev.Station.Comp.Grids)
|
||||
{
|
||||
AddFTLDestination(ev.GridId, true);
|
||||
}
|
||||
}
|
||||
var gridXform = _xformQuery.GetComponent(gridUid);
|
||||
|
||||
public bool CanFTL(EntityUid? uid, [NotNullWhen(false)] out string? reason)
|
||||
{
|
||||
if (HasComp<PreventPilotComponent>(uid))
|
||||
{
|
||||
reason = Loc.GetString("shuttle-console-prevent");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uid != null)
|
||||
{
|
||||
var ev = new ConsoleFTLAttemptEvent(uid.Value, false, string.Empty);
|
||||
RaiseLocalEvent(uid.Value, ref ev, true);
|
||||
|
||||
if (ev.Cancelled)
|
||||
if (gridXform.MapUid == null)
|
||||
{
|
||||
reason = ev.Reason;
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
reason = null;
|
||||
return true;
|
||||
TryAddFTLDestination(gridXform.MapID, true, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a target for hyperspace to every shuttle console.
|
||||
/// Ensures the FTL map exists and returns it.
|
||||
/// </summary>
|
||||
public FTLDestinationComponent AddFTLDestination(EntityUid uid, bool enabled)
|
||||
private EntityUid EnsureFTLMap()
|
||||
{
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var destination) && destination.Enabled == enabled)
|
||||
return destination;
|
||||
var query = AllEntityQuery<FTLMapComponent>();
|
||||
|
||||
destination = EnsureComp<FTLDestinationComponent>(uid);
|
||||
|
||||
if (HasComp<FTLComponent>(uid))
|
||||
while (query.MoveNext(out var uid, out _))
|
||||
{
|
||||
enabled = false;
|
||||
return uid;
|
||||
}
|
||||
|
||||
destination.Enabled = enabled;
|
||||
var mapId = _mapManager.CreateMap();
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
var ftlMap = AddComp<FTLMapComponent>(mapUid);
|
||||
|
||||
_metadata.SetEntityName(mapUid, "FTL");
|
||||
Log.Debug($"Setup hyperspace map at {mapUid}");
|
||||
DebugTools.Assert(!_mapManager.IsMapPaused(mapId));
|
||||
var parallax = EnsureComp<ParallaxComponent>(mapUid);
|
||||
parallax.Parallax = ftlMap.Parallax;
|
||||
|
||||
return mapUid;
|
||||
}
|
||||
|
||||
public float GetStateDuration(FTLComponent component)
|
||||
{
|
||||
var state = component.State;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case FTLState.Starting:
|
||||
case FTLState.Travelling:
|
||||
case FTLState.Arriving:
|
||||
case FTLState.Cooldown:
|
||||
return component.Accumulator;
|
||||
case FTLState.Available:
|
||||
return 0f;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the whitelist for this FTL destination.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="whitelist"></param>
|
||||
public void SetFTLWhitelist(Entity<FTLDestinationComponent?> entity, EntityWhitelist? whitelist)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return;
|
||||
|
||||
if (entity.Comp.Whitelist == whitelist)
|
||||
return;
|
||||
|
||||
entity.Comp.Whitelist = whitelist;
|
||||
_console.RefreshShuttleConsoles();
|
||||
return destination;
|
||||
Dirty(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the target map as available for FTL.
|
||||
/// </summary>
|
||||
public bool TryAddFTLDestination(MapId mapId, bool enabled, [NotNullWhen(true)] out FTLDestinationComponent? component)
|
||||
{
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
component = null;
|
||||
|
||||
if (!Exists(mapUid))
|
||||
return false;
|
||||
|
||||
component = EnsureComp<FTLDestinationComponent>(mapUid);
|
||||
|
||||
if (component.Enabled == enabled)
|
||||
return true;
|
||||
|
||||
component.Enabled = enabled;
|
||||
_console.RefreshShuttleConsoles();
|
||||
Dirty(mapUid, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
@@ -162,40 +196,51 @@ public sealed partial class ShuttleSystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves a shuttle from its current position to the target one. Goes through the hyperspace map while the timer is running.
|
||||
/// Returns true if the grid can FTL. Used to block protected shuttles like the emergency shuttle.
|
||||
/// </summary>
|
||||
public void FTLTravel(
|
||||
EntityUid shuttleUid,
|
||||
ShuttleComponent component,
|
||||
EntityCoordinates coordinates,
|
||||
float startupTime = DefaultStartupTime,
|
||||
float hyperspaceTime = DefaultTravelTime,
|
||||
string? priorityTag = null)
|
||||
public bool CanFTL(EntityUid shuttleUid, [NotNullWhen(false)] out string? reason)
|
||||
{
|
||||
if (!TrySetupFTL(shuttleUid, component, out var hyperspace))
|
||||
return;
|
||||
if (HasComp<FTLComponent>(shuttleUid))
|
||||
{
|
||||
reason = Loc.GetString("shuttle-console-in-ftl");
|
||||
return false;
|
||||
}
|
||||
|
||||
hyperspace.StartupTime = startupTime;
|
||||
hyperspace.TravelTime = hyperspaceTime;
|
||||
hyperspace.Accumulator = hyperspace.StartupTime;
|
||||
hyperspace.TargetCoordinates = coordinates;
|
||||
hyperspace.Dock = false;
|
||||
hyperspace.PriorityTag = priorityTag;
|
||||
_console.RefreshShuttleConsoles();
|
||||
var ev = new FTLRequestEvent(_mapManager.GetMapEntityId(coordinates.ToMap(EntityManager, _transform).MapId));
|
||||
if (TryComp(shuttleUid, out PhysicsComponent? shuttlePhysics) && shuttlePhysics.Mass > 300f)
|
||||
{
|
||||
reason = Loc.GetString("shuttle-console-mass");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasComp<PreventPilotComponent>(shuttleUid))
|
||||
{
|
||||
reason = Loc.GetString("shuttle-console-prevent");
|
||||
return false;
|
||||
}
|
||||
|
||||
var ev = new ConsoleFTLAttemptEvent(shuttleUid, false, string.Empty);
|
||||
RaiseLocalEvent(shuttleUid, ref ev, true);
|
||||
|
||||
if (ev.Cancelled)
|
||||
{
|
||||
reason = ev.Reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
reason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves a shuttle from its current position to docked on the target one. Goes through the hyperspace map while the timer is running.
|
||||
/// Moves a shuttle from its current position to the target one without any checks. Goes through the hyperspace map while the timer is running.
|
||||
/// </summary>
|
||||
public void FTLTravel(
|
||||
public void FTLToCoordinates(
|
||||
EntityUid shuttleUid,
|
||||
ShuttleComponent component,
|
||||
EntityUid target,
|
||||
EntityCoordinates coordinates,
|
||||
Angle angle,
|
||||
float startupTime = DefaultStartupTime,
|
||||
float hyperspaceTime = DefaultTravelTime,
|
||||
bool dock = false,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
if (!TrySetupFTL(shuttleUid, component, out var hyperspace))
|
||||
@@ -204,10 +249,58 @@ public sealed partial class ShuttleSystem
|
||||
hyperspace.StartupTime = startupTime;
|
||||
hyperspace.TravelTime = hyperspaceTime;
|
||||
hyperspace.Accumulator = hyperspace.StartupTime;
|
||||
hyperspace.TargetUid = target;
|
||||
hyperspace.Dock = dock;
|
||||
hyperspace.TargetCoordinates = coordinates;
|
||||
hyperspace.TargetAngle = angle;
|
||||
hyperspace.PriorityTag = priorityTag;
|
||||
_console.RefreshShuttleConsoles();
|
||||
|
||||
_console.RefreshShuttleConsoles(shuttleUid);
|
||||
|
||||
var mapId = coordinates.GetMapId(EntityManager);
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
var ev = new FTLRequestEvent(mapUid);
|
||||
RaiseLocalEvent(shuttleUid, ref ev, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves a shuttle from its current position to docked on the target one.
|
||||
/// If no docks are free when FTLing it will arrive in proximity
|
||||
/// </summary>
|
||||
public void FTLToDock(
|
||||
EntityUid shuttleUid,
|
||||
ShuttleComponent component,
|
||||
EntityUid target,
|
||||
float startupTime = DefaultStartupTime,
|
||||
float hyperspaceTime = DefaultTravelTime,
|
||||
string? priorityTag = null)
|
||||
{
|
||||
if (!TrySetupFTL(shuttleUid, component, out var hyperspace))
|
||||
return;
|
||||
|
||||
var config = _dockSystem.GetDockingConfig(shuttleUid, target, priorityTag);
|
||||
hyperspace.StartupTime = startupTime;
|
||||
hyperspace.TravelTime = hyperspaceTime;
|
||||
hyperspace.Accumulator = hyperspace.StartupTime;
|
||||
hyperspace.PriorityTag = priorityTag;
|
||||
|
||||
_console.RefreshShuttleConsoles(shuttleUid);
|
||||
|
||||
// Valid dock for now time so just use that as the target.
|
||||
if (config != null)
|
||||
{
|
||||
hyperspace.TargetCoordinates = config.Coordinates;
|
||||
hyperspace.TargetAngle = config.Angle;
|
||||
}
|
||||
else if (TryGetFTLProximity(shuttleUid, target, out var coords, out var targAngle))
|
||||
{
|
||||
hyperspace.TargetCoordinates = coords;
|
||||
hyperspace.TargetAngle = targAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FTL back to its own position.
|
||||
hyperspace.TargetCoordinates = Transform(shuttleUid).Coordinates;
|
||||
Log.Error($"Unable to FTL grid {ToPrettyString(shuttleUid)} to target properly?");
|
||||
}
|
||||
}
|
||||
|
||||
private bool TrySetupFTL(EntityUid uid, ShuttleComponent shuttle, [NotNullWhen(true)] out FTLComponent? component)
|
||||
@@ -216,20 +309,14 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
if (HasComp<FTLComponent>(uid))
|
||||
{
|
||||
Log.Warning($"Tried queuing {ToPrettyString(uid)} which already has HyperspaceComponent?");
|
||||
Log.Warning($"Tried queuing {ToPrettyString(uid)} which already has {nameof(FTLComponent)}?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var dest))
|
||||
{
|
||||
dest.Enabled = false;
|
||||
}
|
||||
|
||||
_thruster.DisableLinearThrusters(shuttle);
|
||||
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.North);
|
||||
_thruster.SetAngularThrust(shuttle, false);
|
||||
// TODO: Maybe move this to docking instead?
|
||||
SetDocks(uid, false);
|
||||
_dockSystem.SetDocks(uid, false);
|
||||
|
||||
component = AddComp<FTLComponent>(uid);
|
||||
component.State = FTLState.Starting;
|
||||
@@ -241,228 +328,226 @@ public sealed partial class ShuttleSystem
|
||||
_transform.SetLocalPosition(audio.Value.Entity, gridPhysics.LocalCenter);
|
||||
}
|
||||
|
||||
// TODO: Play previs here for docking arrival.
|
||||
|
||||
// Make sure the map is setup before we leave to avoid pop-in (e.g. parallax).
|
||||
SetupHyperspace();
|
||||
EnsureFTLMap();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transitions shuttle to FTL map.
|
||||
/// </summary>
|
||||
private void UpdateFTLStarting(Entity<FTLComponent, ShuttleComponent> entity)
|
||||
{
|
||||
var uid = entity.Owner;
|
||||
var comp = entity.Comp1;
|
||||
var xform = _xformQuery.GetComponent(entity);
|
||||
DoTheDinosaur(xform);
|
||||
|
||||
comp.State = FTLState.Travelling;
|
||||
var fromMapUid = xform.MapUid;
|
||||
var fromMatrix = _transform.GetWorldMatrix(xform);
|
||||
var fromRotation = _transform.GetWorldRotation(xform);
|
||||
|
||||
var width = Comp<MapGridComponent>(uid).LocalAABB.Width;
|
||||
var ftlMap = EnsureFTLMap();
|
||||
var body = _physicsQuery.GetComponent(entity);
|
||||
var shuttleCenter = body.LocalCenter;
|
||||
|
||||
// Offset the start by buffer range just to avoid overlap.
|
||||
var ftlStart = new EntityCoordinates(ftlMap, new Vector2(_index + width / 2f, 0f) - shuttleCenter);
|
||||
|
||||
_transform.SetCoordinates(entity.Owner, ftlStart);
|
||||
|
||||
// Reset rotation so they always face the same direction.
|
||||
xform.LocalRotation = Angle.Zero;
|
||||
_index += width + Buffer;
|
||||
comp.Accumulator += comp.TravelTime - DefaultArrivalTime;
|
||||
|
||||
Enable(uid, component: body);
|
||||
_physics.SetLinearVelocity(uid, new Vector2(0f, 20f), body: body);
|
||||
_physics.SetAngularVelocity(uid, 0f, body: body);
|
||||
_physics.SetLinearDamping(body, 0f);
|
||||
_physics.SetAngularDamping(body, 0f);
|
||||
|
||||
_dockSystem.SetDockBolts(uid, true);
|
||||
_console.RefreshShuttleConsoles(uid);
|
||||
|
||||
var ev = new FTLStartedEvent(uid, comp.TargetCoordinates, fromMapUid, fromMatrix, fromRotation);
|
||||
RaiseLocalEvent(uid, ref ev, true);
|
||||
|
||||
// Audio
|
||||
var wowdio = _audio.PlayPvs(comp.TravelSound, uid);
|
||||
comp.TravelStream = wowdio?.Entity;
|
||||
if (wowdio?.Component != null)
|
||||
{
|
||||
wowdio.Value.Component.Flags |= AudioFlags.GridAudio;
|
||||
|
||||
if (_physicsQuery.TryGetComponent(uid, out var gridPhysics))
|
||||
{
|
||||
_transform.SetLocalPosition(wowdio.Value.Entity, gridPhysics.LocalCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuttle arriving.
|
||||
/// </summary>
|
||||
private void UpdateFTLTravelling(Entity<FTLComponent, ShuttleComponent> entity)
|
||||
{
|
||||
var shuttle = entity.Comp2;
|
||||
var comp = entity.Comp1;
|
||||
comp.Accumulator += DefaultArrivalTime;
|
||||
comp.State = FTLState.Arriving;
|
||||
// TODO: Arrival effects
|
||||
// For now we'll just use the ss13 bubbles but we can do fancier.
|
||||
|
||||
_thruster.DisableLinearThrusters(shuttle);
|
||||
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South);
|
||||
|
||||
_console.RefreshShuttleConsoles(entity.Owner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuttle arrived.
|
||||
/// </summary>
|
||||
private void UpdateFTLArriving(Entity<FTLComponent, ShuttleComponent> entity)
|
||||
{
|
||||
var uid = entity.Owner;
|
||||
var xform = _xformQuery.GetComponent(uid);
|
||||
var body = _physicsQuery.GetComponent(uid);
|
||||
var comp = entity.Comp1;
|
||||
DoTheDinosaur(xform);
|
||||
_dockSystem.SetDockBolts(entity, false);
|
||||
_dockSystem.SetDocks(entity, true);
|
||||
|
||||
_physics.SetLinearVelocity(uid, Vector2.Zero, body: body);
|
||||
_physics.SetAngularVelocity(uid, 0f, body: body);
|
||||
_physics.SetLinearDamping(body, entity.Comp2.LinearDamping);
|
||||
_physics.SetAngularDamping(body, entity.Comp2.AngularDamping);
|
||||
|
||||
var target = entity.Comp1.TargetCoordinates;
|
||||
|
||||
MapId mapId;
|
||||
|
||||
if (!Exists(entity.Comp1.TargetCoordinates.EntityId))
|
||||
{
|
||||
// Uhh good luck
|
||||
// Pick earliest map?
|
||||
var maps = EntityQuery<MapComponent>().Select(o => o.MapId).ToList();
|
||||
var map = maps.Min(o => o.GetHashCode());
|
||||
|
||||
mapId = new MapId(map);
|
||||
TryFTLProximity(uid, _mapManager.GetMapEntityId(mapId));
|
||||
}
|
||||
// Docking FTL
|
||||
else if (HasComp<MapGridComponent>(target.EntityId) &&
|
||||
!HasComp<MapComponent>(target.EntityId))
|
||||
{
|
||||
var config = _dockSystem.GetDockingConfigAt(uid, target.EntityId, target, entity.Comp1.TargetAngle);
|
||||
|
||||
// Couldn't dock somehow so just fallback to regular position FTL.
|
||||
if (config == null)
|
||||
{
|
||||
_transform.SetCoordinates(uid, xform, target, rotation: entity.Comp1.TargetAngle);
|
||||
}
|
||||
|
||||
mapId = target.GetMapId(EntityManager);
|
||||
}
|
||||
// Position ftl
|
||||
else
|
||||
{
|
||||
mapId = target.GetMapId(EntityManager);
|
||||
_transform.SetCoordinates(uid, xform, target, rotation: entity.Comp1.TargetAngle);
|
||||
}
|
||||
|
||||
if (_physicsQuery.TryGetComponent(uid, out body))
|
||||
{
|
||||
_physics.SetLinearVelocity(uid, Vector2.Zero, body: body);
|
||||
_physics.SetAngularVelocity(uid, 0f, body: body);
|
||||
|
||||
// Disable shuttle if it's on a planet; unfortunately can't do this in parent change messages due
|
||||
// to event ordering and awake body shenanigans (at least for now).
|
||||
if (HasComp<MapGridComponent>(xform.MapUid))
|
||||
{
|
||||
Disable(uid, component: body);
|
||||
}
|
||||
|
||||
Enable(uid, component: body, shuttle: entity.Comp2);
|
||||
}
|
||||
|
||||
_thruster.DisableLinearThrusters(entity.Comp2);
|
||||
|
||||
comp.TravelStream = _audio.Stop(comp.TravelStream);
|
||||
var audio = _audio.PlayPvs(_arrivalSound, uid);
|
||||
audio.Value.Component.Flags |= AudioFlags.GridAudio;
|
||||
// TODO: Shitcode til engine fix
|
||||
|
||||
if (_physicsQuery.TryGetComponent(uid, out var gridPhysics))
|
||||
{
|
||||
_transform.SetLocalPosition(audio.Value.Entity, gridPhysics.LocalCenter);
|
||||
}
|
||||
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var dest))
|
||||
{
|
||||
dest.Enabled = true;
|
||||
}
|
||||
|
||||
comp.State = FTLState.Cooldown;
|
||||
comp.Accumulator += FTLCooldown;
|
||||
_console.RefreshShuttleConsoles(uid);
|
||||
_mapManager.SetMapPaused(mapId, false);
|
||||
Smimsh(uid, xform: xform);
|
||||
|
||||
var ftlEvent = new FTLCompletedEvent(uid, _mapManager.GetMapEntityId(mapId));
|
||||
RaiseLocalEvent(uid, ref ftlEvent, true);
|
||||
}
|
||||
|
||||
private void UpdateFTLCooldown(Entity<FTLComponent, ShuttleComponent> entity)
|
||||
{
|
||||
RemCompDeferred<FTLComponent>(entity);
|
||||
_console.RefreshShuttleConsoles(entity);
|
||||
}
|
||||
|
||||
private void UpdateHyperspace(float frameTime)
|
||||
{
|
||||
var query = EntityQueryEnumerator<FTLComponent>();
|
||||
var query = EntityQueryEnumerator<FTLComponent, ShuttleComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
while (query.MoveNext(out var uid, out var comp, out var shuttle))
|
||||
{
|
||||
comp.Accumulator -= frameTime;
|
||||
|
||||
if (comp.Accumulator > 0f)
|
||||
continue;
|
||||
|
||||
var xform = Transform(uid);
|
||||
PhysicsComponent? body;
|
||||
ShuttleComponent? shuttle;
|
||||
TryComp(uid, out shuttle);
|
||||
var entity = (uid, comp, shuttle);
|
||||
|
||||
switch (comp.State)
|
||||
{
|
||||
// Startup time has elapsed and in hyperspace.
|
||||
case FTLState.Starting:
|
||||
{
|
||||
DoTheDinosaur(xform);
|
||||
|
||||
comp.State = FTLState.Travelling;
|
||||
var fromMapUid = xform.MapUid;
|
||||
var fromMatrix = _transform.GetWorldMatrix(xform);
|
||||
var fromRotation = _transform.GetWorldRotation(xform);
|
||||
|
||||
var width = Comp<MapGridComponent>(uid).LocalAABB.Width;
|
||||
xform.Coordinates = new EntityCoordinates(_mapManager.GetMapEntityId(_hyperSpaceMap!.Value),
|
||||
new Vector2(_index + width / 2f, 0f));
|
||||
xform.LocalRotation = Angle.Zero;
|
||||
_index += width + Buffer;
|
||||
comp.Accumulator += comp.TravelTime - DefaultArrivalTime;
|
||||
|
||||
if (TryComp(uid, out body))
|
||||
{
|
||||
if (shuttle != null)
|
||||
Enable(uid, component: body, shuttle: shuttle);
|
||||
_physics.SetLinearVelocity(uid, new Vector2(0f, 20f), body: body);
|
||||
_physics.SetAngularVelocity(uid, 0f, body: body);
|
||||
_physics.SetLinearDamping(body, 0f);
|
||||
_physics.SetAngularDamping(body, 0f);
|
||||
}
|
||||
|
||||
SetDockBolts(uid, true);
|
||||
_console.RefreshShuttleConsoles(uid);
|
||||
var target = comp.TargetUid != null
|
||||
? new EntityCoordinates(comp.TargetUid.Value, Vector2.Zero)
|
||||
: comp.TargetCoordinates;
|
||||
|
||||
var ev = new FTLStartedEvent(uid, target, fromMapUid, fromMatrix, fromRotation);
|
||||
RaiseLocalEvent(uid, ref ev, true);
|
||||
|
||||
var wowdio = _audio.PlayPvs(comp.TravelSound, uid);
|
||||
comp.TravelStream = wowdio?.Entity;
|
||||
if (wowdio?.Component != null)
|
||||
{
|
||||
wowdio.Value.Component.Flags |= AudioFlags.GridAudio;
|
||||
|
||||
if (_physicsQuery.TryGetComponent(uid, out var gridPhysics))
|
||||
{
|
||||
_transform.SetLocalPosition(wowdio.Value.Entity, gridPhysics.LocalCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateFTLStarting(entity);
|
||||
break;
|
||||
// Arriving, play effects
|
||||
case FTLState.Travelling:
|
||||
comp.Accumulator += DefaultArrivalTime;
|
||||
comp.State = FTLState.Arriving;
|
||||
// TODO: Arrival effects
|
||||
// For now we'll just use the ss13 bubbles but we can do fancier.
|
||||
|
||||
if (shuttle != null)
|
||||
{
|
||||
_thruster.DisableLinearThrusters(shuttle);
|
||||
_thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South);
|
||||
}
|
||||
|
||||
_console.RefreshShuttleConsoles(uid);
|
||||
UpdateFTLTravelling(entity);
|
||||
break;
|
||||
// Arrived
|
||||
case FTLState.Arriving:
|
||||
{
|
||||
DoTheDinosaur(xform);
|
||||
SetDockBolts(uid, false);
|
||||
SetDocks(uid, true);
|
||||
|
||||
if (TryComp(uid, out body))
|
||||
{
|
||||
_physics.SetLinearVelocity(uid, Vector2.Zero, body: body);
|
||||
_physics.SetAngularVelocity(uid, 0f, body: body);
|
||||
if (shuttle != null)
|
||||
{
|
||||
_physics.SetLinearDamping(body, shuttle.LinearDamping);
|
||||
_physics.SetAngularDamping(body, shuttle.AngularDamping);
|
||||
}
|
||||
}
|
||||
|
||||
MapId mapId;
|
||||
|
||||
if (comp.TargetUid != null && shuttle != null)
|
||||
{
|
||||
if (!Deleted(comp.TargetUid))
|
||||
{
|
||||
if (comp.Dock)
|
||||
TryFTLDock(uid, shuttle, comp.TargetUid.Value, comp.PriorityTag);
|
||||
else
|
||||
TryFTLProximity(uid, shuttle, comp.TargetUid.Value);
|
||||
|
||||
mapId = Transform(comp.TargetUid.Value).MapID;
|
||||
}
|
||||
// oh boy, fallback time
|
||||
else
|
||||
{
|
||||
// Pick earliest map?
|
||||
var maps = EntityQuery<MapComponent>().Select(o => o.MapId).ToList();
|
||||
var map = maps.Min(o => o.GetHashCode());
|
||||
|
||||
mapId = new MapId(map);
|
||||
TryFTLProximity(uid, shuttle, _mapManager.GetMapEntityId(mapId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xform.Coordinates = comp.TargetCoordinates;
|
||||
mapId = comp.TargetCoordinates.GetMapId(EntityManager);
|
||||
}
|
||||
|
||||
if (TryComp(uid, out body))
|
||||
{
|
||||
_physics.SetLinearVelocity(uid, Vector2.Zero, body: body);
|
||||
_physics.SetAngularVelocity(uid, 0f, body: body);
|
||||
|
||||
// Disable shuttle if it's on a planet; unfortunately can't do this in parent change messages due
|
||||
// to event ordering and awake body shenanigans (at least for now).
|
||||
if (HasComp<MapGridComponent>(xform.MapUid))
|
||||
{
|
||||
Disable(uid, component: body);
|
||||
}
|
||||
else if (shuttle != null)
|
||||
{
|
||||
Enable(uid, component: body, shuttle: shuttle);
|
||||
}
|
||||
}
|
||||
|
||||
if (shuttle != null)
|
||||
{
|
||||
_thruster.DisableLinearThrusters(shuttle);
|
||||
}
|
||||
|
||||
comp.TravelStream = _audio.Stop(comp.TravelStream);
|
||||
var audio = _audio.PlayPvs(_arrivalSound, uid);
|
||||
audio.Value.Component.Flags |= AudioFlags.GridAudio;
|
||||
// TODO: Shitcode til engine fix
|
||||
|
||||
if (_physicsQuery.TryGetComponent(uid, out var gridPhysics))
|
||||
{
|
||||
_transform.SetLocalPosition(audio.Value.Entity, gridPhysics.LocalCenter);
|
||||
}
|
||||
|
||||
if (TryComp<FTLDestinationComponent>(uid, out var dest))
|
||||
{
|
||||
dest.Enabled = true;
|
||||
}
|
||||
|
||||
comp.State = FTLState.Cooldown;
|
||||
comp.Accumulator += FTLCooldown;
|
||||
_console.RefreshShuttleConsoles(uid);
|
||||
_mapManager.SetMapPaused(mapId, false);
|
||||
Smimsh(uid, xform: xform);
|
||||
|
||||
var ftlEvent = new FTLCompletedEvent(uid, _mapManager.GetMapEntityId(mapId));
|
||||
RaiseLocalEvent(uid, ref ftlEvent, true);
|
||||
}
|
||||
UpdateFTLArriving(entity);
|
||||
break;
|
||||
case FTLState.Cooldown:
|
||||
RemComp<FTLComponent>(uid);
|
||||
_console.RefreshShuttleConsoles(uid);
|
||||
UpdateFTLCooldown(entity);
|
||||
break;
|
||||
default:
|
||||
Log.Error($"Found invalid FTL state {comp.State} for {uid}");
|
||||
RemComp<FTLComponent>(uid);
|
||||
RemCompDeferred<FTLComponent>(uid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDocks(EntityUid uid, bool enabled)
|
||||
{
|
||||
var query = AllEntityQuery<DockingComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var dockUid, out var dock, out var xform))
|
||||
{
|
||||
if (xform.ParentUid != uid || dock.Enabled == enabled)
|
||||
continue;
|
||||
|
||||
_dockSystem.Undock(dockUid, dock);
|
||||
dock.Enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDockBolts(EntityUid uid, bool enabled)
|
||||
{
|
||||
var query = AllEntityQuery<DockingComponent, DoorBoltComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var doorUid, out _, out var door, out var xform))
|
||||
{
|
||||
if (xform.ParentUid != uid)
|
||||
continue;
|
||||
|
||||
_doors.TryClose(doorUid);
|
||||
_doors.SetBoltsDown((doorUid, door), enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetSoundRange(EntityUid uid)
|
||||
{
|
||||
if (!_mapManager.TryGetGrid(uid, out var grid))
|
||||
@@ -471,31 +556,6 @@ public sealed partial class ShuttleSystem
|
||||
return MathF.Max(grid.LocalAABB.Width, grid.LocalAABB.Height) + 12.5f;
|
||||
}
|
||||
|
||||
private void SetupHyperspace()
|
||||
{
|
||||
if (_hyperSpaceMap != null)
|
||||
return;
|
||||
|
||||
_hyperSpaceMap = _mapManager.CreateMap();
|
||||
_metadata.SetEntityName(_mapManager.GetMapEntityId(_hyperSpaceMap.Value), "FTL");
|
||||
Log.Debug($"Setup hyperspace map at {_hyperSpaceMap.Value}");
|
||||
DebugTools.Assert(!_mapManager.IsMapPaused(_hyperSpaceMap.Value));
|
||||
var parallax = EnsureComp<ParallaxComponent>(_mapManager.GetMapEntityId(_hyperSpaceMap.Value));
|
||||
parallax.Parallax = "FastSpace";
|
||||
}
|
||||
|
||||
private void CleanupHyperspace()
|
||||
{
|
||||
_index = 0f;
|
||||
if (_hyperSpaceMap == null || !_mapManager.MapExists(_hyperSpaceMap.Value))
|
||||
{
|
||||
_hyperSpaceMap = null;
|
||||
return;
|
||||
}
|
||||
_mapManager.DeleteMap(_hyperSpaceMap.Value);
|
||||
_hyperSpaceMap = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts everyone unbuckled on the floor, paralyzed.
|
||||
/// </summary>
|
||||
@@ -559,11 +619,12 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
/// <summary>
|
||||
/// Tries to dock with the target grid, otherwise falls back to proximity.
|
||||
/// This bypasses FTL travel time.
|
||||
/// </summary>
|
||||
public bool TryFTLDock(EntityUid shuttleUid, ShuttleComponent component, EntityUid targetUid, string? priorityTag = null)
|
||||
{
|
||||
if (!TryComp<TransformComponent>(shuttleUid, out var shuttleXform) ||
|
||||
!TryComp<TransformComponent>(targetUid, out var targetXform) ||
|
||||
if (!_xformQuery.TryGetComponent(shuttleUid, out var shuttleXform) ||
|
||||
!_xformQuery.TryGetComponent(targetUid, out var targetXform) ||
|
||||
targetXform.MapUid == null ||
|
||||
!targetXform.MapUid.Value.IsValid())
|
||||
{
|
||||
@@ -574,35 +635,41 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
FTLDock(config, shuttleXform);
|
||||
FTLDock((shuttleUid, shuttleXform), config);
|
||||
return true;
|
||||
}
|
||||
|
||||
TryFTLProximity(shuttleUid, component, targetUid, shuttleXform, targetXform);
|
||||
TryFTLProximity(shuttleUid, targetUid, shuttleXform, targetXform);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces an FTL dock.
|
||||
/// </summary>
|
||||
public void FTLDock(DockingConfig config, TransformComponent shuttleXform)
|
||||
public void FTLDock(Entity<TransformComponent> shuttle, DockingConfig config)
|
||||
{
|
||||
// Set position
|
||||
shuttleXform.Coordinates = config.Coordinates;
|
||||
_transform.SetWorldRotation(shuttleXform, config.Angle);
|
||||
var mapCoordinates = _transform.ToMapCoordinates(config.Coordinates);
|
||||
var mapUid = _mapManager.GetMapEntityId(mapCoordinates.MapId);
|
||||
_transform.SetCoordinates(shuttle.Owner, shuttle.Comp, new EntityCoordinates(mapUid, mapCoordinates.Position), rotation: config.Angle);
|
||||
|
||||
// Connect everything
|
||||
foreach (var (dockAUid, dockBUid, dockA, dockB) in config.Docks)
|
||||
{
|
||||
_dockSystem.Dock(dockAUid, dockA, dockBUid, dockB);
|
||||
_dockSystem.Dock((dockAUid, dockA), (dockBUid, dockB));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to arrive nearby without overlapping with other grids.
|
||||
/// Tries to get the target position to FTL near to another grid.
|
||||
/// </summary>
|
||||
public bool TryFTLProximity(EntityUid shuttleUid, ShuttleComponent component, EntityUid targetUid, TransformComponent? xform = null, TransformComponent? targetXform = null)
|
||||
private bool TryGetFTLProximity(EntityUid shuttleUid, EntityUid targetUid,
|
||||
out EntityCoordinates coordinates, out Angle angle,
|
||||
TransformComponent? xform = null, TransformComponent? targetXform = null)
|
||||
{
|
||||
coordinates = EntityCoordinates.Invalid;
|
||||
angle = Angle.Zero;
|
||||
|
||||
if (!Resolve(targetUid, ref targetXform) ||
|
||||
targetXform.MapUid == null ||
|
||||
!targetXform.MapUid.Value.IsValid() ||
|
||||
@@ -611,6 +678,7 @@ public sealed partial class ShuttleSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var shuttleAABB = Comp<MapGridComponent>(shuttleUid).LocalAABB;
|
||||
Box2 targetLocalAABB;
|
||||
@@ -702,17 +770,36 @@ public sealed partial class ShuttleSystem
|
||||
spawnPos = _transform.GetWorldPosition(targetXform, xformQuery);
|
||||
}
|
||||
|
||||
xform.Coordinates = new EntityCoordinates(targetXform.MapUid.Value, spawnPos);
|
||||
|
||||
if (!HasComp<MapComponent>(targetXform.GridUid))
|
||||
{
|
||||
_transform.SetLocalRotation(xform, _random.NextAngle());
|
||||
angle = _random.NextAngle();
|
||||
}
|
||||
else
|
||||
{
|
||||
_transform.SetLocalRotation(xform, Angle.Zero);
|
||||
angle = Angle.Zero;
|
||||
}
|
||||
|
||||
coordinates = new EntityCoordinates(targetXform.MapUid.Value, spawnPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to arrive nearby without overlapping with other grids.
|
||||
/// </summary>
|
||||
public bool TryFTLProximity(EntityUid shuttleUid, EntityUid targetUid, TransformComponent? xform = null, TransformComponent? targetXform = null)
|
||||
{
|
||||
if (!Resolve(targetUid, ref targetXform) ||
|
||||
targetXform.MapUid == null ||
|
||||
!targetXform.MapUid.Value.IsValid() ||
|
||||
!Resolve(shuttleUid, ref xform))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryGetFTLProximity(shuttleUid, targetUid, out var coords, out var angle, xform, targetXform))
|
||||
return false;
|
||||
|
||||
_transform.SetCoordinates(shuttleUid, xform, coords, rotation: angle);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -768,6 +855,9 @@ public sealed partial class ShuttleSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HasComp<FTLBeaconComponent>(ent))
|
||||
continue;
|
||||
|
||||
QueueDel(ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
if (TryComp<ShuttleComponent>(ent[0], out var shuttle))
|
||||
{
|
||||
TryFTLProximity(ent[0], shuttle, targetGrid.Value);
|
||||
TryFTLProximity(ent[0], targetGrid.Value);
|
||||
}
|
||||
|
||||
_station.AddGridToStation(uid, ent[0]);
|
||||
@@ -127,7 +127,7 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
if (TryComp<ShuttleComponent>(ent[0], out var shuttle))
|
||||
{
|
||||
TryFTLProximity(ent[0], shuttle, targetGrid.Value);
|
||||
TryFTLProximity(ent[0], targetGrid.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -206,7 +206,7 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
FTLDock(config, shuttleXform);
|
||||
FTLDock((ent[0], shuttleXform), config);
|
||||
|
||||
if (TryComp<StationMemberComponent>(xform.GridUid, out var stationMember))
|
||||
{
|
||||
|
||||
@@ -33,7 +33,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
[Dependency] private readonly BiomeSystem _biomes = default!;
|
||||
[Dependency] private readonly BodySystem _bobby = default!;
|
||||
[Dependency] private readonly DockingSystem _dockSystem = default!;
|
||||
[Dependency] private readonly DoorSystem _doors = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _loader = default!;
|
||||
@@ -62,8 +61,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
SubscribeLocalEvent<ShuttleComponent, ComponentStartup>(OnShuttleStartup);
|
||||
SubscribeLocalEvent<ShuttleComponent, ComponentShutdown>(OnShuttleShutdown);
|
||||
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
|
||||
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInit);
|
||||
SubscribeLocalEvent<FixturesComponent, GridFixtureChangeEvent>(OnGridFixtureChange);
|
||||
}
|
||||
@@ -74,11 +71,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
UpdateHyperspace(frameTime);
|
||||
}
|
||||
|
||||
private void OnRoundRestart(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
CleanupHyperspace();
|
||||
}
|
||||
|
||||
private void OnGridFixtureChange(EntityUid uid, FixturesComponent manager, GridFixtureChangeEvent args)
|
||||
{
|
||||
foreach (var fixture in args.NewFixtures)
|
||||
|
||||
Reference in New Issue
Block a user