Make loadouts authored catalog presets with an editor capture command

Loadouts are ship presets (variants) for spawners, not a player feature.

- Route Loadout to the catalog; the player store no longer holds it.
- Materialize takes no credits: affordability, the charge and Loadouts.Price
  are deleted, since only the player menu priced loadouts. Availability,
  key-order product choice, all-or-nothing failures and the weapon-group
  rules stay.
- Delete the InventoryPanel Save Loadout and Restore Loadout entries and
  RestoreLoadout, which also removes its docking-bay overwrite.
- The editor opens the catalog writable in the one process cache, and the
  editor-only console command capturepreset "<name>" [replace] captures the
  piloted ship. Loadouts.Commit keys a preset by name, refuses a same-name
  replace unless asked, and commits conditionally on that key. The single-file
  store then lands only that record onto the file as it is on disk. An
  unconditional commit would re-serialize every live catalog instance,
  including any that play has mutated.
- Tests: capture -> commit -> fresh reopen round-trip, explicit replace with
  no duplicate, and a preset commit that does not persist a mutated live
  Faction. The money-only tests are removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-14 23:09:43 +02:00
commit db83cd290d
6 changed files with 124 additions and 166 deletions

View file

@ -50,10 +50,12 @@ public class ActionGameManager : MonoBehaviour
// All three stores attach once and stay attached until the process exits. The run lifecycle is record-level
// inside this cache; reopening would replace the catalog instances the galaxy and live entities hold.
// The editor opens the catalog writable so the capturepreset console command can author presets in play.
_cultCache = AetheriaStores.Open(
Path.Combine(GameDataDirectory.FullName, "Aetheria.cc"),
runPath: Path.Combine(GameDataDirectory.FullName, "run.cc"),
playerPath: Path.Combine(GameDataDirectory.FullName, "player.cc"));
playerPath: Path.Combine(GameDataDirectory.FullName, "player.cc"),
catalogWritable: Application.isEditor);
return _cultCache;
}
@ -543,6 +545,25 @@ public class ActionGameManager : MonoBehaviour
});
//Temporary, or not
ConsoleController.AddCommand("tow", _ => TowShip());
// Editor only: capturepreset "<name>" [replace] writes the piloted ship as a catalog preset.
if (Application.isEditor)
ConsoleController.AddCommand("capturepreset", args =>
{
var console = ConsoleController.Instance;
var name = args.Length > 0 ? args[0] : "";
if (string.IsNullOrWhiteSpace(name)) { console.AppendLogLine("usage: capturepreset \"<name>\" [replace]"); return; }
if (!(_currentEntity is Ship ship)) { console.AppendLogLine("capturepreset: pilot a ship first"); return; }
try
{
var written = Loadouts.Commit(CultCache, Loadouts.Capture(ItemManager, ship, name), args.Length > 1 && args[1] == "replace");
console.AppendLogLine(written ? $"Preset '{name}' written to the catalog" : $"Preset '{name}' changed on disk since load; nothing written");
}
catch (InvalidOperationException e)
{
console.AppendLogLine(e.Message);
}
});
}
public void BeginDrag(DragObject dragObject)