Shuttle drone improvements (#16931)

This commit is contained in:
metalgearsloth
2023-05-31 11:13:02 +10:00
committed by GitHub
parent 53d4e408aa
commit 57858f802f
35 changed files with 335 additions and 278 deletions

View File

@@ -53,7 +53,7 @@ public static class PoolManager
(CCVars.NPCMaxUpdates.Name, "999999"), (CCVars.NPCMaxUpdates.Name, "999999"),
(CVars.ThreadParallelCount.Name, "1"), (CVars.ThreadParallelCount.Name, "1"),
(CCVars.GameRoleTimers.Name, "false"), (CCVars.GameRoleTimers.Name, "false"),
(CCVars.CargoShuttles.Name, "false"), (CCVars.GridFill.Name, "false"),
(CCVars.ArrivalsShuttles.Name, "false"), (CCVars.ArrivalsShuttles.Name, "false"),
(CCVars.EmergencyShuttleEnabled.Name, "false"), (CCVars.EmergencyShuttleEnabled.Name, "false"),
(CCVars.ProcgenPreload.Name, "false"), (CCVars.ProcgenPreload.Name, "false"),

View File

@@ -63,8 +63,6 @@ public sealed class CargoTest
var entManager = server.ResolveDependency<IEntityManager>(); var entManager = server.ResolveDependency<IEntityManager>();
var mapManager = server.ResolveDependency<IMapManager>(); var mapManager = server.ResolveDependency<IMapManager>();
var protoManager = server.ResolveDependency<IPrototypeManager>(); var protoManager = server.ResolveDependency<IPrototypeManager>();
var cfg = server.ResolveDependency<IConfigurationManager>();
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, true));
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
@@ -106,7 +104,6 @@ public sealed class CargoTest
mapManager.DeleteMap(mapId); mapManager.DeleteMap(mapId);
}); });
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, false));
await pairTracker.CleanReturnAsync(); await pairTracker.CleanReturnAsync();
} }

View File

@@ -27,15 +27,12 @@ namespace Content.IntegrationTests.Tests
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Destructive = true}); await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Destructive = true});
var server = pairTracker.Pair.Server; var server = pairTracker.Pair.Server;
IEntityManager entityMan = null; var entityMan = server.ResolveDependency<IEntityManager>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var mapManager = server.ResolveDependency<IMapManager>();
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, true)); var prototypeMan = server.ResolveDependency<IPrototypeManager>();
await server.WaitPost(() => await server.WaitPost(() =>
{ {
entityMan = IoCManager.Resolve<IEntityManager>();
var mapManager = IoCManager.Resolve<IMapManager>();
var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
var protoIds = prototypeMan var protoIds = prototypeMan
.EnumeratePrototypes<EntityPrototype>() .EnumeratePrototypes<EntityPrototype>()
.Where(p=>!p.Abstract) .Where(p=>!p.Abstract)
@@ -65,7 +62,6 @@ namespace Content.IntegrationTests.Tests
Assert.That(entityMan.EntityCount, Is.Zero); Assert.That(entityMan.EntityCount, Is.Zero);
}); });
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, false));
await pairTracker.CleanReturnAsync(); await pairTracker.CleanReturnAsync();
} }
@@ -75,16 +71,13 @@ namespace Content.IntegrationTests.Tests
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Destructive = true}); await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Destructive = true});
var server = pairTracker.Pair.Server; var server = pairTracker.Pair.Server;
var map = await PoolManager.CreateTestMap(pairTracker); var map = await PoolManager.CreateTestMap(pairTracker);
IEntityManager entityMan = null;
var cfg = server.ResolveDependency<IConfigurationManager>(); var entityMan = server.ResolveDependency<IEntityManager>();
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, true)); var prototypeMan = server.ResolveDependency<IPrototypeManager>();
await server.WaitPost(() => await server.WaitPost(() =>
{ {
entityMan = IoCManager.Resolve<IEntityManager>();
var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
var protoIds = prototypeMan var protoIds = prototypeMan
.EnumeratePrototypes<EntityPrototype>() .EnumeratePrototypes<EntityPrototype>()
.Where(p=>!p.Abstract) .Where(p=>!p.Abstract)
@@ -109,7 +102,6 @@ namespace Content.IntegrationTests.Tests
Assert.That(entityMan.EntityCount, Is.Zero); Assert.That(entityMan.EntityCount, Is.Zero);
}); });
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, false));
await pairTracker.CleanReturnAsync(); await pairTracker.CleanReturnAsync();
} }
@@ -129,7 +121,6 @@ namespace Content.IntegrationTests.Tests
var mapManager = server.ResolveDependency<IMapManager>(); var mapManager = server.ResolveDependency<IMapManager>();
var sEntMan = server.ResolveDependency<IEntityManager>(); var sEntMan = server.ResolveDependency<IEntityManager>();
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, true));
Assert.That(cfg.GetCVar(CVars.NetPVS), Is.False); Assert.That(cfg.GetCVar(CVars.NetPVS), Is.False);
var protoIds = prototypeMan var protoIds = prototypeMan
@@ -178,7 +169,6 @@ namespace Content.IntegrationTests.Tests
Assert.That(sEntMan.EntityCount, Is.Zero); Assert.That(sEntMan.EntityCount, Is.Zero);
}); });
await server.WaitPost(() => cfg.SetCVar(CCVars.DisableGridFill, false));
await pairTracker.CleanReturnAsync(); await pairTracker.CleanReturnAsync();
} }

View File

@@ -27,7 +27,7 @@ public sealed class StartEndGameRulesTest
await server.WaitIdleAsync(); await server.WaitIdleAsync();
var gameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>(); var gameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {

View File

@@ -58,7 +58,7 @@ namespace Content.IntegrationTests.Tests
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>(); var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
var mapManager = server.ResolveDependency<IMapManager>(); var mapManager = server.ResolveDependency<IMapManager>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
await server.WaitPost(() => await server.WaitPost(() =>
{ {
@@ -188,7 +188,7 @@ namespace Content.IntegrationTests.Tests
var shuttleSystem = entManager.EntitySysManager.GetEntitySystem<ShuttleSystem>(); var shuttleSystem = entManager.EntitySysManager.GetEntitySystem<ShuttleSystem>();
var xformQuery = entManager.GetEntityQuery<TransformComponent>(); var xformQuery = entManager.GetEntityQuery<TransformComponent>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
await server.WaitPost(() => await server.WaitPost(() =>
{ {
@@ -352,7 +352,7 @@ namespace Content.IntegrationTests.Tests
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>(); var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
var mapManager = server.ResolveDependency<IMapManager>(); var mapManager = server.ResolveDependency<IMapManager>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
await server.WaitPost(() => await server.WaitPost(() =>
{ {

View File

@@ -29,7 +29,7 @@ namespace Content.IntegrationTests.Tests
var xformSystem = sEntities.EntitySysManager.GetEntitySystem<SharedTransformSystem>(); var xformSystem = sEntities.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
var resManager = server.ResolveDependency<IResourceManager>(); var resManager = server.ResolveDependency<IResourceManager>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {

View File

@@ -28,7 +28,7 @@ namespace Content.IntegrationTests.Tests
var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>(); var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
var mapManager = server.ResolveDependency<IMapManager>(); var mapManager = server.ResolveDependency<IMapManager>();
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
await server.WaitPost(() => await server.WaitPost(() =>
{ {
@@ -97,7 +97,7 @@ namespace Content.IntegrationTests.Tests
MapId mapId = default; MapId mapId = default;
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
// Load bagel.yml as uninitialized map, and save it to ensure it's up to date. // Load bagel.yml as uninitialized map, and save it to ensure it's up to date.
server.Post(() => server.Post(() =>
@@ -178,7 +178,7 @@ namespace Content.IntegrationTests.Tests
var mapManager = server.ResolveDependency<IMapManager>(); var mapManager = server.ResolveDependency<IMapManager>();
var userData = server.ResolveDependency<IResourceManager>().UserData; var userData = server.ResolveDependency<IResourceManager>().UserData;
var cfg = server.ResolveDependency<IConfigurationManager>(); var cfg = server.ResolveDependency<IConfigurationManager>();
Assert.That(cfg.GetCVar(CCVars.DisableGridFill), Is.False); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
MapId mapId = default; MapId mapId = default;
const string fileA = "/load tick load a.yml"; const string fileA = "/load tick load a.yml";

View File

@@ -1,15 +0,0 @@
using Content.Server.Shuttles.Components;
namespace Content.Server.Cargo.Components;
/// <summary>
/// Lets you remotely control the cargo shuttle.
/// </summary>
[RegisterComponent]
public sealed class CargoPilotConsoleComponent : Component
{
/// <summary>
/// <see cref="ShuttleConsoleComponent"/> that we're proxied into.
/// </summary>
public EntityUid? Entity;
}

View File

@@ -24,9 +24,7 @@ public sealed class StationCargoOrderDatabaseComponent : Component
/// </summary> /// </summary>
public int NumOrdersCreated; public int NumOrdersCreated;
[DataField("cargoShuttleProto", customTypeSerializer:typeof(PrototypeIdSerializer<CargoShuttlePrototype>))] // TODO: Can probably dump this
public string? CargoShuttleProto = "CargoShuttle";
/// <summary> /// <summary>
/// The cargo shuttle assigned to this station. /// The cargo shuttle assigned to this station.
/// </summary> /// </summary>

View File

@@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using Content.Server.Cargo.Components; using Content.Server.Cargo.Components;
using Content.Server.Shuttle.Components;
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events; using Content.Server.Shuttles.Events;
using Content.Server.UserInterface; using Content.Server.UserInterface;
@@ -30,35 +31,21 @@ namespace Content.Server.Cargo.Systems;
public sealed partial class CargoSystem public sealed partial class CargoSystem
{ {
/* /*
* Handles cargo shuttle mechanics, including cargo shuttle consoles. * Handles cargo shuttle mechanics.
*/ */
[Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly MapLoaderSystem _map = default!;
[Dependency] private readonly PricingSystem _pricing = default!; [Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ShuttleConsoleSystem _console = default!; [Dependency] private readonly ShuttleConsoleSystem _console = default!;
[Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly StackSystem _stack = default!;
public MapId? CargoMap { get; private set; } public MapId? CargoMap { get; private set; }
private int _index;
/// <summary>
/// Whether cargo shuttles are enabled at all. Mainly used to disable cargo shuttle loading for performance reasons locally.
/// </summary>
private bool _enabled;
private void InitializeShuttle() private void InitializeShuttle()
{ {
_enabled = _configManager.GetCVar(CCVars.CargoShuttles);
// Don't want to immediately call this as shuttles will get setup in the natural course of things.
_configManager.OnValueChanged(CCVars.CargoShuttles, SetCargoShuttleEnabled);
SubscribeLocalEvent<CargoShuttleComponent, FTLStartedEvent>(OnCargoFTLStarted); SubscribeLocalEvent<CargoShuttleComponent, FTLStartedEvent>(OnCargoFTLStarted);
SubscribeLocalEvent<CargoShuttleComponent, FTLCompletedEvent>(OnCargoFTLCompleted); SubscribeLocalEvent<CargoShuttleComponent, FTLCompletedEvent>(OnCargoFTLCompleted);
SubscribeLocalEvent<CargoShuttleComponent, FTLTagEvent>(OnCargoFTLTag); SubscribeLocalEvent<CargoShuttleComponent, FTLTagEvent>(OnCargoFTLTag);
@@ -69,12 +56,6 @@ public sealed partial class CargoSystem
SubscribeLocalEvent<CargoPalletConsoleComponent, CargoPalletAppraiseMessage>(OnPalletAppraise); SubscribeLocalEvent<CargoPalletConsoleComponent, CargoPalletAppraiseMessage>(OnPalletAppraise);
SubscribeLocalEvent<CargoPalletConsoleComponent, BoundUIOpenedEvent>(OnPalletUIOpen); SubscribeLocalEvent<CargoPalletConsoleComponent, BoundUIOpenedEvent>(OnPalletUIOpen);
SubscribeLocalEvent<CargoPilotConsoleComponent, ConsoleShuttleEvent>(OnCargoGetConsole);
SubscribeLocalEvent<CargoPilotConsoleComponent, AfterActivatableUIOpenEvent>(OnCargoPilotConsoleOpen);
SubscribeLocalEvent<CargoPilotConsoleComponent, BoundUIClosedEvent>(OnCargoPilotConsoleClose);
SubscribeLocalEvent<StationCargoOrderDatabaseComponent, ComponentStartup>(OnCargoOrderStartup);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart); SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
} }
@@ -88,90 +69,20 @@ public sealed partial class CargoSystem
args.Tag = "DockCargo"; args.Tag = "DockCargo";
} }
private void ShutdownShuttle()
{
_configManager.UnsubValueChanged(CCVars.CargoShuttles, SetCargoShuttleEnabled);
}
private void SetCargoShuttleEnabled(bool value)
{
if (_enabled == value)
return;
_enabled = value;
if (value)
{
Setup();
var query = AllEntityQuery<StationCargoOrderDatabaseComponent>();
while (query.MoveNext(out var stationUid, out var station))
{
AddShuttle(stationUid, station);
}
}
else
{
CleanupShuttle();
}
}
#region Cargo Pilot Console
private void OnCargoPilotConsoleOpen(EntityUid uid, CargoPilotConsoleComponent component, AfterActivatableUIOpenEvent args)
{
component.Entity = GetShuttleConsole(uid);
}
private void OnCargoPilotConsoleClose(EntityUid uid, CargoPilotConsoleComponent component, BoundUIClosedEvent args)
{
component.Entity = null;
}
private void OnCargoGetConsole(EntityUid uid, CargoPilotConsoleComponent component, ref ConsoleShuttleEvent args)
{
args.Console = GetShuttleConsole(uid);
}
private EntityUid? GetShuttleConsole(EntityUid uid)
{
var stationUid = _station.GetOwningStation(uid);
if (!TryComp<StationCargoOrderDatabaseComponent>(stationUid, out var orderDatabase) ||
!TryComp<CargoShuttleComponent>(orderDatabase.Shuttle, out var shuttle))
{
return null;
}
return GetShuttleConsole(orderDatabase.Shuttle.Value, shuttle);
}
#endregion
#region Console #region Console
private void UpdateCargoShuttleConsoles(CargoShuttleComponent component) private void UpdateCargoShuttleConsoles(EntityUid shuttleUid, CargoShuttleComponent component)
{ {
// Update pilot consoles that are already open. // Update pilot consoles that are already open.
var pilotConsoleQuery = AllEntityQuery<CargoPilotConsoleComponent>(); _console.RefreshDroneConsoles();
while (pilotConsoleQuery.MoveNext(out var uid, out var console))
{
var stationUid = _station.GetOwningStation(uid);
if (stationUid == null || stationUid != component.Station)
continue;
console.Entity = GetShuttleConsole(stationUid.Value);
}
// Update order consoles. // Update order consoles.
var shuttleConsoleQuery = AllEntityQuery<CargoShuttleConsoleComponent>(); var shuttleConsoleQuery = AllEntityQuery<CargoShuttleConsoleComponent>();
while (shuttleConsoleQuery.MoveNext(out var uid, out var console)) while (shuttleConsoleQuery.MoveNext(out var uid, out _))
{ {
var stationUid = _station.GetOwningStation(uid); var stationUid = _station.GetOwningStation(uid);
if (stationUid != component.Station) if (stationUid != shuttleUid)
continue; continue;
UpdateShuttleState(uid, stationUid); UpdateShuttleState(uid, stationUid);
@@ -245,21 +156,6 @@ public sealed partial class CargoSystem
#region Shuttle #region Shuttle
public EntityUid? GetShuttleConsole(EntityUid uid, CargoShuttleComponent component)
{
var query = AllEntityQuery<ShuttleConsoleComponent, TransformComponent>();
while (query.MoveNext(out var cUid, out var comp, out var xform))
{
if (xform.ParentUid != uid)
continue;
return cUid;
}
return null;
}
/// <summary> /// <summary>
/// Returns the orders that can fit on the cargo shuttle. /// Returns the orders that can fit on the cargo shuttle.
/// </summary> /// </summary>
@@ -331,50 +227,6 @@ public sealed partial class CargoSystem
#region Station #region Station
private void OnCargoOrderStartup(EntityUid uid, StationCargoOrderDatabaseComponent component, ComponentStartup args)
{
if (!_enabled)
return;
// Stations get created first but if any are added at runtime then do this.
AddShuttle(uid, component);
}
private void AddShuttle(EntityUid stationUid, StationCargoOrderDatabaseComponent component)
{
Setup();
if (CargoMap == null ||
component.Shuttle != null ||
component.CargoShuttleProto == null)
{
return;
}
var prototype = _protoMan.Index<CargoShuttlePrototype>(component.CargoShuttleProto);
var possibleNames = _protoMan.Index<DatasetPrototype>(prototype.NameDataset).Values;
var name = _random.Pick(possibleNames);
if (!_map.TryLoad(CargoMap.Value, prototype.Path.ToString(), out var gridList))
{
_sawmill.Error($"Could not load the cargo shuttle!");
return;
}
var shuttleUid = gridList[0];
var xform = Transform(shuttleUid);
MetaData(shuttleUid).EntityName = name;
// TODO: Something better like a bounds check.
_transform.SetLocalPosition(xform, xform.LocalPosition + 100 * _index);
var comp = EnsureComp<CargoShuttleComponent>(shuttleUid);
comp.Station = stationUid;
component.Shuttle = shuttleUid;
UpdateCargoShuttleConsoles(comp);
_index++;
_sawmill.Info($"Added cargo shuttle to {ToPrettyString(shuttleUid)}");
}
private void SellPallets(EntityUid gridUid, out double amount) private void SellPallets(EntityUid gridUid, out double amount)
{ {
GetPalletGoods(gridUid, out var toSell, out amount); GetPalletGoods(gridUid, out var toSell, out amount);
@@ -480,7 +332,7 @@ public sealed partial class CargoSystem
private void OnCargoFTLStarted(EntityUid uid, CargoShuttleComponent component, ref FTLStartedEvent args) private void OnCargoFTLStarted(EntityUid uid, CargoShuttleComponent component, ref FTLStartedEvent args)
{ {
var stationUid = component.Station; var stationUid = _station.GetOwningStation(uid);
// Called // Called
if (CargoMap == null || if (CargoMap == null ||
@@ -492,7 +344,7 @@ public sealed partial class CargoSystem
AddCargoContents(uid, component, orderDatabase); AddCargoContents(uid, component, orderDatabase);
UpdateOrders(orderDatabase); UpdateOrders(orderDatabase);
UpdateCargoShuttleConsoles(component); UpdateCargoShuttleConsoles(uid, component);
} }
private void OnCargoFTLCompleted(EntityUid uid, CargoShuttleComponent component, ref FTLCompletedEvent args) private void OnCargoFTLCompleted(EntityUid uid, CargoShuttleComponent component, ref FTLCompletedEvent args)
@@ -502,7 +354,7 @@ public sealed partial class CargoSystem
if (xform.MapID != CargoMap) if (xform.MapID != CargoMap)
return; return;
var stationUid = component.Station; var stationUid = _station.GetOwningStation(uid);
if (TryComp<StationBankAccountComponent>(stationUid, out var bank)) if (TryComp<StationBankAccountComponent>(stationUid, out var bank))
{ {
@@ -515,10 +367,11 @@ public sealed partial class CargoSystem
private void OnRoundRestart(RoundRestartCleanupEvent ev) private void OnRoundRestart(RoundRestartCleanupEvent ev)
{ {
CleanupShuttle(); CleanupCargoShuttle();
SetupCargoShuttle();
} }
private void CleanupShuttle() private void CleanupCargoShuttle()
{ {
if (CargoMap == null || !_mapManager.MapExists(CargoMap.Value)) if (CargoMap == null || !_mapManager.MapExists(CargoMap.Value))
{ {
@@ -535,7 +388,9 @@ public sealed partial class CargoSystem
while (query.MoveNext(out var uid, out var comp)) while (query.MoveNext(out var uid, out var comp))
{ {
if (TryComp<StationCargoOrderDatabaseComponent>(comp.Station, out var station)) var stationUid = _station.GetOwningStation(uid);
if (TryComp<StationCargoOrderDatabaseComponent>(uid, out var station))
{ {
station.Shuttle = null; station.Shuttle = null;
} }
@@ -543,9 +398,9 @@ public sealed partial class CargoSystem
} }
} }
private void Setup() private void SetupCargoShuttle()
{ {
if (!_enabled || CargoMap != null && _mapManager.MapExists(CargoMap.Value)) if (CargoMap != null && _mapManager.MapExists(CargoMap.Value))
{ {
return; return;
} }
@@ -564,13 +419,6 @@ public sealed partial class CargoSystem
MetaData(mapUid).EntityName = $"Trading post {_random.Next(1000):000}"; MetaData(mapUid).EntityName = $"Trading post {_random.Next(1000):000}";
var query = AllEntityQuery<StationCargoOrderDatabaseComponent>();
while (query.MoveNext(out var uid, out var comp))
{
AddShuttle(uid, comp);
}
_console.RefreshShuttleConsoles(); _console.RefreshShuttleConsoles();
} }
} }

View File

@@ -27,8 +27,7 @@ public sealed partial class CargoSystem : SharedCargoSystem
public override void Shutdown() public override void Shutdown()
{ {
base.Shutdown(); base.Shutdown();
ShutdownShuttle(); CleanupCargoShuttle();
CleanupShuttle();
} }
public override void Update(float frameTime) public override void Update(float frameTime)
@@ -39,19 +38,21 @@ public sealed partial class CargoSystem : SharedCargoSystem
} }
[PublicAPI] [PublicAPI]
public void UpdateBankAccount(StationBankAccountComponent component, int balanceAdded) public void UpdateBankAccount(EntityUid uid, StationBankAccountComponent component, int balanceAdded)
{ {
component.Balance += balanceAdded; component.Balance += balanceAdded;
// TODO: Code bad var query = EntityQueryEnumerator<CargoOrderConsoleComponent>();
foreach (var comp in EntityQuery<CargoOrderConsoleComponent>())
{
if (!_uiSystem.IsUiOpen(comp.Owner, CargoConsoleUiKey.Orders)) continue;
var station = _station.GetOwningStation(comp.Owner); while (query.MoveNext(out var oUid, out var oComp))
if (station != component.Owner) {
if (!_uiSystem.IsUiOpen(oUid, CargoConsoleUiKey.Orders))
continue; continue;
UpdateOrderState(comp, station); var station = _station.GetOwningStation(oUid);
if (station != uid)
continue;
UpdateOrderState(oComp, station);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.Cargo.Components; using Content.Server.Cargo.Components;
using Content.Server.Shuttle.Components;
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Systems; using Content.Server.Shuttles.Systems;
using Content.Shared.Movement.Components; using Content.Shared.Movement.Components;
@@ -254,7 +255,7 @@ namespace Content.Server.Physics.Controllers
var consoleEnt = pilot.Console?.Owner; var consoleEnt = pilot.Console?.Owner;
// TODO: This is terrible. Just make a new mover and also make it remote piloting + device networks // TODO: This is terrible. Just make a new mover and also make it remote piloting + device networks
if (TryComp<CargoPilotConsoleComponent>(consoleEnt, out var cargoConsole)) if (TryComp<DroneConsoleComponent>(consoleEnt, out var cargoConsole))
{ {
consoleEnt = cargoConsole.Entity; consoleEnt = cargoConsole.Entity;
} }

View File

@@ -0,0 +1,10 @@
namespace Content.Server.Salvage.Expeditions;
/// <summary>
/// Added to salvage shuttle. Used for drone control.
/// </summary>
[RegisterComponent]
public sealed class SalvageShuttleComponent : Component
{
}

View File

@@ -0,0 +1,21 @@
using Content.Server.Shuttles.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Shuttle.Components;
// Primo shitcode
/// <summary>
/// Lets you remotely control a shuttle.
/// </summary>
[RegisterComponent]
public sealed class DroneConsoleComponent : Component
{
[DataField("components", required: true)]
public ComponentRegistry Components = default!;
/// <summary>
/// <see cref="ShuttleConsoleComponent"/> that we're proxied into.
/// </summary>
[DataField("entity")]
public EntityUid? Entity;
}

View File

@@ -0,0 +1,13 @@
using Content.Server.Shuttles.Systems;
using Robust.Shared.Utility;
namespace Content.Server.Shuttles.Components;
/// <summary>
/// Similar to <see cref="GridFillComponent"/> except spawns the grid near to the station.
/// </summary>
[RegisterComponent, Access(typeof(ShuttleSystem))]
public sealed class GridSpawnComponent : Component
{
[DataField("paths", required: true)] public List<ResPath> Paths = new();
}

View File

@@ -8,5 +8,8 @@ namespace Content.Server.Shuttles.Events;
[ByRefEvent] [ByRefEvent]
public struct ConsoleShuttleEvent public struct ConsoleShuttleEvent
{ {
/// <summary>
/// Console that we proxy into.
/// </summary>
public EntityUid? Console; public EntityUid? Console;
} }

View File

@@ -0,0 +1,75 @@
using Content.Server.Shuttle.Components;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Station.Components;
using Content.Server.UserInterface;
namespace Content.Server.Shuttles.Systems;
public sealed partial class ShuttleConsoleSystem
{
/// <summary>
/// Refreshes all drone console entities.
/// </summary>
public void RefreshDroneConsoles()
{
var query = AllEntityQuery<DroneConsoleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
comp.Entity = GetShuttleConsole(uid, comp);
}
}
private void OnDronePilotConsoleOpen(EntityUid uid, DroneConsoleComponent component, AfterActivatableUIOpenEvent args)
{
component.Entity = GetShuttleConsole(uid);
}
private void OnDronePilotConsoleClose(EntityUid uid, DroneConsoleComponent component, BoundUIClosedEvent args)
{
component.Entity = null;
}
private void OnCargoGetConsole(EntityUid uid, DroneConsoleComponent component, ref ConsoleShuttleEvent args)
{
args.Console = GetShuttleConsole(uid, component);
}
/// <summary>
/// Gets the relevant shuttle console to proxy from the drone console.
/// </summary>
private EntityUid? GetShuttleConsole(EntityUid uid, DroneConsoleComponent? component = null)
{
if (!Resolve(uid, ref component))
return null;
var stationUid = _station.GetOwningStation(uid);
if (stationUid == null)
return null;
// I know this sucks but needs device linking or something idunno
var query = AllEntityQuery<ShuttleConsoleComponent, TransformComponent>();
while (query.MoveNext(out var cUid, out _, out var xform))
{
if (xform.GridUid == null ||
!TryComp<StationMemberComponent>(xform.GridUid, out var member) ||
member.Station != stationUid)
{
continue;
}
foreach (var compType in component.Components.Values)
{
if (!HasComp(xform.GridUid, compType.Component.GetType()))
continue;
return cUid;
}
}
return null;
}
}

View File

@@ -1,7 +1,9 @@
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Server.Shuttle.Components;
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events; using Content.Server.Shuttles.Events;
using Content.Server.Station.Systems;
using Content.Server.UserInterface; using Content.Server.UserInterface;
using Content.Shared.ActionBlocker; using Content.Shared.ActionBlocker;
using Content.Shared.Alert; using Content.Shared.Alert;
@@ -21,13 +23,14 @@ using Robust.Shared.Utility;
namespace Content.Server.Shuttles.Systems; namespace Content.Server.Shuttles.Systems;
public sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
{ {
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ActionBlockerSystem _blocker = default!; [Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly AlertsSystem _alertsSystem = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly ShuttleSystem _shuttle = default!; [Dependency] private readonly ShuttleSystem _shuttle = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly TagSystem _tags = default!; [Dependency] private readonly TagSystem _tags = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!;
@@ -42,6 +45,10 @@ public sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleConsoleFTLRequestMessage>(OnDestinationMessage); SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleConsoleFTLRequestMessage>(OnDestinationMessage);
SubscribeLocalEvent<ShuttleConsoleComponent, BoundUIClosedEvent>(OnConsoleUIClose); SubscribeLocalEvent<ShuttleConsoleComponent, BoundUIClosedEvent>(OnConsoleUIClose);
SubscribeLocalEvent<DroneConsoleComponent, ConsoleShuttleEvent>(OnCargoGetConsole);
SubscribeLocalEvent<DroneConsoleComponent, AfterActivatableUIOpenEvent>(OnDronePilotConsoleOpen);
SubscribeLocalEvent<DroneConsoleComponent, BoundUIClosedEvent>(OnDronePilotConsoleClose);
SubscribeLocalEvent<DockEvent>(OnDock); SubscribeLocalEvent<DockEvent>(OnDock);
SubscribeLocalEvent<UndockEvent>(OnUndock); SubscribeLocalEvent<UndockEvent>(OnUndock);

View File

@@ -1,5 +1,7 @@
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Server.Station.Components; using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Shared.Cargo.Components;
using Content.Shared.CCVar; using Content.Shared.CCVar;
namespace Content.Server.Shuttles.Systems; namespace Content.Server.Shuttles.Systems;
@@ -8,11 +10,88 @@ public sealed partial class ShuttleSystem
{ {
private void InitializeGridFills() private void InitializeGridFills()
{ {
SubscribeLocalEvent<GridSpawnComponent, StationPostInitEvent>(OnGridSpawnPostInit);
SubscribeLocalEvent<GridFillComponent, MapInitEvent>(OnGridFillMapInit); SubscribeLocalEvent<GridFillComponent, MapInitEvent>(OnGridFillMapInit);
_cfg.OnValueChanged(CCVars.GridFill, OnGridFillChange);
}
private void ShutdownGridFills()
{
_cfg.UnsubValueChanged(CCVars.GridFill, OnGridFillChange);
}
private void OnGridFillChange(bool obj)
{
// If you're doing this on live then god help you,
if (obj)
{
var query = AllEntityQuery<GridSpawnComponent>();
while (query.MoveNext(out var uid, out var comp))
{
GridSpawns(uid, comp);
}
}
}
private void OnGridSpawnPostInit(EntityUid uid, GridSpawnComponent component, ref StationPostInitEvent args)
{
GridSpawns(uid, component);
}
private void GridSpawns(EntityUid uid, GridSpawnComponent component)
{
if (!_cfg.GetCVar(CCVars.GridFill))
return;
if (!TryComp<StationDataComponent>(uid, out var data))
{
return;
}
var targetGrid = _station.GetLargestGrid(data);
if (targetGrid == null)
return;
// Spawn on a dummy map and try to FTL if possible, otherwise dump it.
var mapId = _mapManager.CreateMap();
var valid = true;
foreach (var path in component.Paths)
{
if (_loader.TryLoad(mapId, path.ToString(), out var ent) && ent.Count == 1)
{
if (TryComp<ShuttleComponent>(ent[0], out var shuttle))
{
TryFTLProximity(ent[0], shuttle, targetGrid.Value);
_station.AddGridToStation(uid, ent[0]);
}
else
{
valid = false;
}
}
else
{
valid = false;
}
if (!valid)
{
_sawmill.Error($"Error loading gridspawn for {ToPrettyString(uid)} / {path}");
}
}
_mapManager.DeleteMap(mapId);
} }
private void OnGridFillMapInit(EntityUid uid, GridFillComponent component, MapInitEvent args) private void OnGridFillMapInit(EntityUid uid, GridFillComponent component, MapInitEvent args)
{ {
if (!_cfg.GetCVar(CCVars.GridFill))
return;
if (!TryComp<DockingComponent>(uid, out var dock) || if (!TryComp<DockingComponent>(uid, out var dock) ||
!TryComp<TransformComponent>(uid, out var xform) || !TryComp<TransformComponent>(uid, out var xform) ||
xform.GridUid == null) xform.GridUid == null)
@@ -20,9 +99,6 @@ public sealed partial class ShuttleSystem
return; return;
} }
if (_cfg.GetCVar(CCVars.DisableGridFill))
return;
// Spawn on a dummy map and try to dock if possible, otherwise dump it. // Spawn on a dummy map and try to dock if possible, otherwise dump it.
var mapId = _mapManager.CreateMap(); var mapId = _mapManager.CreateMap();
var valid = false; var valid = false;

View File

@@ -67,6 +67,13 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
SubscribeLocalEvent<FixturesComponent, GridFixtureChangeEvent>(OnGridFixtureChange); SubscribeLocalEvent<FixturesComponent, GridFixtureChangeEvent>(OnGridFixtureChange);
} }
public override void Shutdown()
{
base.Shutdown();
ShutdownGridFills();
}
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Station.Events;
/// <summary>
/// Raised directed on a station after it has been initialized.
/// </summary>
[ByRefEvent]
public readonly record struct StationPostInitEvent;

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Server.Chat.Systems; using Content.Server.Chat.Systems;
using Content.Server.GameTicking; using Content.Server.GameTicking;
using Content.Server.Station.Components; using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Station; using Content.Shared.Station;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -304,6 +305,9 @@ public sealed class StationSystem : EntitySystem
AddGridToStation(station, grid, null, data, name); AddGridToStation(station, grid, null, data, name);
} }
var ev = new StationPostInitEvent();
RaiseLocalEvent(station, ref ev);
return station; return station;
} }

View File

@@ -1096,17 +1096,11 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> ArrivalsReturns = public static readonly CVarDef<bool> ArrivalsReturns =
CVarDef.Create("shuttle.arrivals_returns", false, CVar.SERVERONLY); CVarDef.Create("shuttle.arrivals_returns", false, CVar.SERVERONLY);
/// <summary>
/// Whether cargo shuttles are enabled.
/// </summary>
public static readonly CVarDef<bool> CargoShuttles =
CVarDef.Create("shuttle.cargo", true, CVar.SERVERONLY);
/// <summary> /// <summary>
/// Whether to automatically spawn escape shuttles. /// Whether to automatically spawn escape shuttles.
/// </summary> /// </summary>
public static readonly CVarDef<bool> DisableGridFill = public static readonly CVarDef<bool> GridFill =
CVarDef.Create("shuttle.disable_grid_fill", false, CVar.SERVERONLY); CVarDef.Create("shuttle.grid_fill", true, CVar.SERVERONLY);
/* /*
* Emergency * Emergency

View File

@@ -1,4 +1,4 @@
using Robust.Shared.Map; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -7,15 +7,9 @@ namespace Content.Shared.Cargo.Components;
/// <summary> /// <summary>
/// Present on cargo shuttles to provide metadata such as preventing spam calling. /// Present on cargo shuttles to provide metadata such as preventing spam calling.
/// </summary> /// </summary>
[RegisterComponent, Access(typeof(SharedCargoSystem))] [RegisterComponent, NetworkedComponent, Access(typeof(SharedCargoSystem))]
public sealed class CargoShuttleComponent : Component public sealed class CargoShuttleComponent : Component
{ {
/// <summary>
/// The assigned station for this cargo shuttle.
/// </summary>
[DataField("station")]
public EntityUid? Station;
/// <summary> /// <summary>
/// The paper-type prototype to spawn with the order information. /// The paper-type prototype to spawn with the order information.
/// </summary> /// </summary>

View File

@@ -1,20 +0,0 @@
using Content.Shared.Dataset;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Utility;
namespace Content.Shared.Cargo.Prototypes;
[Prototype("cargoShuttle")]
public sealed class CargoShuttlePrototype : IPrototype
{
[ViewVariables]
[IdDataField]
public string ID { get; } = default!;
[DataField("path")]
public ResPath Path = default!;
[DataField("nameDataset", customTypeSerializer:typeof(PrototypeIdSerializer<DatasetPrototype>))]
public string NameDataset = "CargoShuttleNames";
}

View File

@@ -17,8 +17,7 @@ expedition_cooldown = 30.0
expedition_failed_cooldown = 30.0 expedition_failed_cooldown = 30.0
[shuttle] [shuttle]
# Wastes startup time grid_fill = false
auto_call_time = 0 auto_call_time = 0
cargo = false
emergency = false emergency = false
arrivals = false arrivals = false

View File

@@ -14,6 +14,7 @@ entities:
- uid: 173 - uid: 173
components: components:
- type: MetaData - type: MetaData
name: Cargo shuttle
- pos: 2.2710133,-2.4148211 - pos: 2.2710133,-2.4148211
parent: invalid parent: invalid
type: Transform type: Transform
@@ -37,10 +38,10 @@ entities:
fixedRotation: False fixedRotation: False
bodyType: Dynamic bodyType: Dynamic
type: Physics type: Physics
- gravityShakeSound: !type:SoundPathSpecifier - gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg path: /Audio/Effects/alert.ogg
type: Gravity type: Gravity
- type: CargoShuttle
- chunkCollection: - chunkCollection:
version: 2 version: 2
nodes: nodes:

View File

@@ -37,7 +37,7 @@ entities:
fixedRotation: False fixedRotation: False
bodyType: Dynamic bodyType: Dynamic
type: Physics type: Physics
- type: SalvageShuttle
- gravityShakeSound: !type:SoundPathSpecifier - gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg path: /Audio/Effects/alert.ogg
type: Gravity type: Gravity

View File

@@ -19,6 +19,7 @@
- id: CargoRequestComputerCircuitboard - id: CargoRequestComputerCircuitboard
- id: CargoShuttleComputerCircuitboard - id: CargoShuttleComputerCircuitboard
- id: CargoShuttleConsoleCircuitboard - id: CargoShuttleConsoleCircuitboard
- id: SalvageShuttleConsoleCircuitboard
- id: CigPackGreen - id: CigPackGreen
prob: 0.50 prob: 0.50
- id: DoorRemoteCargo - id: DoorRemoteCargo

View File

@@ -1,5 +1,5 @@
- type: dataset - type: dataset
id: CargoShuttleNames id: ShuttleNames
values: values:
- A Shuttle Will Not Occur - A Shuttle Will Not Occur
- Big Money Shuttle - Big Money Shuttle

View File

@@ -103,12 +103,21 @@
- type: entity - type: entity
parent: BaseComputerCircuitboard parent: BaseComputerCircuitboard
id: CargoShuttleConsoleCircuitboard id: CargoShuttleConsoleCircuitboard
name: supply shuttle console board name: cargo shuttle console board
description: A computer printed circuit board for a cargo shuttle console. description: A computer printed circuit board for a cargo shuttle console.
components: components:
- type: ComputerBoard - type: ComputerBoard
prototype: ComputerShuttleCargo prototype: ComputerShuttleCargo
- type: entity
parent: BaseComputerCircuitboard
id: SalvageShuttleConsoleCircuitboard
name: salvage shuttle console board
description: A computer printed circuit board for a salvage shuttle console.
components:
- type: ComputerBoard
prototype: ComputerShuttleSalvage
- type: entity - type: entity
parent: BaseComputerCircuitboard parent: BaseComputerCircuitboard
id: SurveillanceCameraMonitorCircuitboard id: SurveillanceCameraMonitorCircuitboard

View File

@@ -31,6 +31,15 @@
components: components:
- type: StationArrivals - type: StationArrivals
- type: entity
id: BaseStationShuttles
abstract: true
components:
- type: GridSpawn
paths:
- /Maps/Shuttles/cargo.yml
- /Maps/Shuttles/mining.yml
- type: entity - type: entity
id: BaseStationCentcomm id: BaseStationCentcomm
abstract: true abstract: true

View File

@@ -14,6 +14,7 @@
- BaseStationJobsSpawning - BaseStationJobsSpawning
- BaseStationRecords - BaseStationRecords
- BaseStationArrivals - BaseStationArrivals
- BaseStationShuttles
- BaseStationCentcomm - BaseStationCentcomm
- BaseStationEvacuation - BaseStationEvacuation
- BaseStationAlertLevels - BaseStationAlertLevels

View File

@@ -129,7 +129,9 @@
state: shuttle state: shuttle
- map: ["computerLayerKeys"] - map: ["computerLayerKeys"]
state: generic_keys state: generic_keys
- type: CargoPilotConsole - type: DroneConsole
components:
- type: CargoShuttle
- type: RadarConsole - type: RadarConsole
maxRange: 256 maxRange: 256
- type: PointLight - type: PointLight
@@ -139,6 +141,34 @@
- type: Computer - type: Computer
board: CargoShuttleConsoleCircuitboard board: CargoShuttleConsoleCircuitboard
- type: entity
parent: BaseComputerShuttle
id: ComputerShuttleSalvage
name: salvage shuttle console
description: Used to pilot the salvage shuttle.
components:
- type: Sprite
layers:
- map: ["computerLayerBody"]
state: computer
- map: ["computerLayerKeyboard"]
state: generic_keyboard
- map: ["computerLayerScreen"]
state: shuttle
- map: ["computerLayerKeys"]
state: generic_keys
- type: DroneConsole
components:
- type: SalvageShuttle
- type: RadarConsole
maxRange: 256
- type: PointLight
radius: 1.5
energy: 1.6
color: "#c94242"
- type: Computer
board: SalvageShuttleConsoleCircuitboard
- type: entity - type: entity
parent: BaseComputer parent: BaseComputer
id: ComputerIFF id: ComputerIFF

View File

@@ -1,4 +0,0 @@
# Cargo
- type: cargoShuttle
id: CargoShuttle
path: /Maps/Shuttles/cargo.yml