Cargo shuttle changes (#14363)

This commit is contained in:
metalgearsloth
2023-03-23 16:10:49 +11:00
committed by GitHub
parent 7f4bb7fe8a
commit 569f30b721
26 changed files with 523 additions and 628 deletions

View File

@@ -1,4 +1,3 @@
using Content.Server.Doors.Components;
using Content.Server.Doors.Systems;
using Content.Server.Shuttles.Components;
using Content.Server.Station.Systems;
@@ -12,10 +11,12 @@ using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Utility;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Shuttles.Events;
using Content.Shared.Buckle.Components;
using Content.Shared.Doors.Components;
using Content.Shared.Shuttles.Components;
using JetBrains.Annotations;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
@@ -46,7 +47,7 @@ public sealed partial class ShuttleSystem
/// <summary>
/// Minimum mass a grid needs to be to block a shuttle recall.
/// </summary>
private const float ShuttleFTLMassThreshold = 300f;
public const float ShuttleFTLMassThreshold = 300f;
// I'm too lazy to make CVars.
@@ -69,6 +70,11 @@ 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 void InitializeFTL()
{
SubscribeLocalEvent<StationGridAddedEvent>(OnStationGridAdd);
@@ -76,7 +82,9 @@ public sealed partial class ShuttleSystem
private void OnStationGridAdd(StationGridAddedEvent ev)
{
if (TryComp<PhysicsComponent>(ev.GridId, out var body) && body.Mass > 500f)
if (HasComp<MapComponent>(ev.GridId) ||
TryComp<PhysicsComponent>(ev.GridId, out var body) &&
body.Mass > FTLDestinationMass)
{
AddFTLDestination(ev.GridId, true);
}
@@ -133,9 +141,11 @@ public sealed partial class ShuttleSystem
return destination;
}
[PublicAPI]
public void RemoveFTLDestination(EntityUid uid)
{
if (!RemComp<FTLDestinationComponent>(uid)) return;
if (!RemComp<FTLDestinationComponent>(uid))
return;
_console.RefreshShuttleConsoles();
}
@@ -145,7 +155,8 @@ public sealed partial class ShuttleSystem
public void FTLTravel(ShuttleComponent component,
EntityCoordinates coordinates,
float startupTime = DefaultStartupTime,
float hyperspaceTime = DefaultTravelTime)
float hyperspaceTime = DefaultTravelTime,
string? priorityTag = null)
{
if (!TrySetupFTL(component, out var hyperspace))
return;
@@ -155,6 +166,7 @@ public sealed partial class ShuttleSystem
hyperspace.Accumulator = hyperspace.StartupTime;
hyperspace.TargetCoordinates = coordinates;
hyperspace.Dock = false;
hyperspace.PriorityTag = priorityTag;
_console.RefreshShuttleConsoles();
}
@@ -165,7 +177,8 @@ public sealed partial class ShuttleSystem
EntityUid target,
float startupTime = DefaultStartupTime,
float hyperspaceTime = DefaultTravelTime,
bool dock = false)
bool dock = false,
string? priorityTag = null)
{
if (!TrySetupFTL(component, out var hyperspace))
return;
@@ -175,6 +188,7 @@ public sealed partial class ShuttleSystem
hyperspace.Accumulator = hyperspace.StartupTime;
hyperspace.TargetUid = target;
hyperspace.Dock = dock;
hyperspace.PriorityTag = priorityTag;
_console.RefreshShuttleConsoles();
}
@@ -206,18 +220,23 @@ public sealed partial class ShuttleSystem
SoundSystem.Play(_startupSound.GetSound(), Filter.Empty().AddInRange(Transform(uid).MapPosition, GetSoundRange(component.Owner)), _startupSound.Params);
// Make sure the map is setup before we leave to avoid pop-in (e.g. parallax).
SetupHyperspace();
var ev = new FTLStartedEvent();
RaiseLocalEvent(uid, ref ev);
return true;
}
private void UpdateHyperspace(float frameTime)
{
foreach (var comp in EntityQuery<FTLComponent>())
var query = EntityQueryEnumerator<FTLComponent>();
while (query.MoveNext(out var uid, out var comp))
{
comp.Accumulator -= frameTime;
if (comp.Accumulator > 0f) continue;
if (comp.Accumulator > 0f)
continue;
var uid = comp.Owner;
var xform = Transform(uid);
PhysicsComponent? body;
ShuttleComponent? shuttle;
@@ -280,13 +299,21 @@ public sealed partial class ShuttleSystem
SetDockBolts(uid, false);
SetDocks(uid, true);
if (TryComp(uid, out body))
{
_physics.SetLinearVelocity(uid, Vector2.Zero, body: body);
_physics.SetAngularVelocity(uid, 0f, body: body);
_physics.SetLinearDamping(body, ShuttleLinearDamping);
_physics.SetAngularDamping(body, ShuttleAngularDamping);
}
TryComp(uid, out shuttle);
MapId mapId;
if (comp.TargetUid != null && shuttle != null)
{
if (comp.Dock)
TryFTLDock(shuttle, comp.TargetUid.Value);
TryFTLDock(shuttle, comp.TargetUid.Value, comp.PriorityTag);
else
TryFTLProximity(shuttle, comp.TargetUid.Value);
@@ -439,7 +466,8 @@ public sealed partial class ShuttleSystem
/// <summary>
/// Tries to dock with the target grid, otherwise falls back to proximity.
/// </summary>
public bool TryFTLDock(ShuttleComponent component, EntityUid targetUid)
/// <param name="priorityTag">Priority docking tag to prefer, e.g. for emergency shuttle</param>
public bool TryFTLDock(ShuttleComponent component, EntityUid targetUid, string? priorityTag = null)
{
if (!TryComp<TransformComponent>(component.Owner, out var xform) ||
!TryComp<TransformComponent>(targetUid, out var targetXform) ||
@@ -449,7 +477,7 @@ public sealed partial class ShuttleSystem
return false;
}
var config = GetDockingConfig(component, targetUid);
var config = GetDockingConfig(component, targetUid, priorityTag);
if (config != null)
{
@@ -460,7 +488,7 @@ public sealed partial class ShuttleSystem
// Connect everything
foreach (var (dockA, dockB) in config.Docks)
{
_dockSystem.Dock(dockA, dockB);
_dockSystem.Dock(dockA.Owner, dockA, dockB.Owner, dockB);
}
return true;
@@ -476,7 +504,6 @@ public sealed partial class ShuttleSystem
public bool TryFTLProximity(ShuttleComponent component, EntityUid targetUid, TransformComponent? xform = null, TransformComponent? targetXform = null)
{
if (!Resolve(targetUid, ref targetXform) ||
targetXform.GridUid == null ||
targetXform.MapUid == null ||
!targetXform.MapUid.Value.IsValid() ||
!Resolve(component.Owner, ref xform))
@@ -502,9 +529,9 @@ public sealed partial class ShuttleSystem
var targetAABB = _transform.GetWorldMatrix(targetXform, xformQuery)
.TransformBox(targetLocalAABB).Enlarged(shuttleAABB.Size.Length);
var nearbyGrids = new HashSet<EntityUid>(1) { targetXform.GridUid.Value };
var nearbyGrids = new HashSet<EntityUid>();
var iteration = 0;
var lastCount = 1;
var lastCount = nearbyGrids.Count;
var mapId = targetXform.MapID;
while (iteration < FTLProximityIterations)
@@ -552,7 +579,7 @@ public sealed partial class ShuttleSystem
}
// TODO: This is pretty crude for multiple landings.
if (nearbyGrids.Count > 1 || !HasComp<MapComponent>(targetXform.GridUid.Value))
if (nearbyGrids.Count > 1 || !HasComp<MapComponent>(targetXform.GridUid))
{
var minRadius = (MathF.Max(targetAABB.Width, targetAABB.Height) + MathF.Max(shuttleAABB.Width, shuttleAABB.Height)) / 2f;
spawnPos = targetAABB.Center + _random.NextVector2(minRadius, minRadius + 64f);
@@ -570,7 +597,7 @@ public sealed partial class ShuttleSystem
xform.Coordinates = new EntityCoordinates(targetXform.MapUid.Value, spawnPos);
if (!HasComp<MapComponent>(targetXform.GridUid.Value))
if (!HasComp<MapComponent>(targetXform.GridUid))
{
_transform.SetLocalRotation(xform, _random.NextAngle());
}
@@ -581,4 +608,138 @@ public sealed partial class ShuttleSystem
return true;
}
/// <summary>
/// Checks whether the emergency shuttle can warp to the specified position.
/// </summary>
private bool ValidSpawn(EntityUid gridUid, MapGridComponent grid, Box2 area)
{
// If the target is a map then any tile is valid.
// TODO: We already need the entities-under check
if (HasComp<MapComponent>(gridUid))
return true;
return !grid.GetLocalTilesIntersecting(area).Any();
}
/// <summary>
/// Tries to get a valid docking configuration for the shuttle to the target grid.
/// </summary>
/// <param name="priorityTag">Priority docking tag to prefer, e.g. for emergency shuttle</param>
private DockingConfig? GetDockingConfig(ShuttleComponent component, EntityUid targetGrid, string? priorityTag = null)
{
var gridDocks = GetDocks(targetGrid);
if (gridDocks.Count <= 0)
return null;
var xformQuery = GetEntityQuery<TransformComponent>();
var targetGridGrid = Comp<MapGridComponent>(targetGrid);
var targetGridXform = xformQuery.GetComponent(targetGrid);
var targetGridAngle = targetGridXform.WorldRotation.Reduced();
var shuttleDocks = GetDocks(component.Owner);
var shuttleAABB = Comp<MapGridComponent>(component.Owner).LocalAABB;
var validDockConfigs = new List<DockingConfig>();
if (shuttleDocks.Count > 0)
{
// We'll try all combinations of shuttle docks and see which one is most suitable
foreach (var shuttleDock in shuttleDocks)
{
var shuttleDockXform = xformQuery.GetComponent(shuttleDock.Owner);
foreach (var gridDock in gridDocks)
{
var gridXform = xformQuery.GetComponent(gridDock.Owner);
if (!CanDock(
shuttleDock, shuttleDockXform,
gridDock, gridXform,
targetGridAngle,
shuttleAABB,
targetGrid,
targetGridGrid,
out var dockedAABB,
out var matty,
out var targetAngle)) continue;
// 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));
var dockedBounds = new Box2Rotated(shuttleAABB.Translated(spawnPosition.Position), targetGridAngle, spawnPosition.Position);
// Check if there's no intersecting grids (AKA oh god it's docking at cargo).
if (_mapManager.FindGridsIntersecting(targetGridXform.MapID,
dockedBounds).Any(o => o.Owner != targetGrid))
{
continue;
}
// Alright well the spawn is valid now to check how many we can connect
// Get the matrix for each shuttle dock and test it against the grid docks to see
// if the connected position / direction matches.
var dockedPorts = new List<(DockingComponent DockA, DockingComponent DockB)>()
{
(shuttleDock, gridDock),
};
foreach (var other in shuttleDocks)
{
if (other == shuttleDock) continue;
foreach (var otherGrid in gridDocks)
{
if (otherGrid == gridDock) continue;
if (!CanDock(
other,
xformQuery.GetComponent(other.Owner),
otherGrid,
xformQuery.GetComponent(otherGrid.Owner),
targetGridAngle,
shuttleAABB,
targetGrid,
targetGridGrid,
out var otherDockedAABB,
out _,
out var otherTargetAngle) ||
!otherDockedAABB.Equals(dockedAABB) ||
!targetAngle.Equals(otherTargetAngle)) continue;
dockedPorts.Add((other, otherGrid));
}
}
validDockConfigs.Add(new DockingConfig()
{
Docks = dockedPorts,
Area = dockedAABB.Value,
Coordinates = spawnPosition,
Angle = targetAngle,
});
}
}
}
if (validDockConfigs.Count <= 0)
return null;
// Prioritise by priority docks, then by maximum connected ports, then by most similar angle.
validDockConfigs = validDockConfigs
.OrderByDescending(x => x.Docks.Any(docks =>
TryComp<PriorityDockComponent>(docks.DockB.Owner, out var priority) &&
priority.Tag?.Equals(priorityTag) == true))
.ThenByDescending(x => x.Docks.Count)
.ThenBy(x => Math.Abs(Angle.ShortestDistance(x.Angle.Reduced(), targetGridAngle).Theta)).ToList();
var location = validDockConfigs.First();
location.TargetGrid = targetGrid;
// TODO: Ideally do a hyperspace warpin, just have it run on like a 10 second timer.
return location;
}
}