Eight factions pointed at one boss hull GUID that no longer resolves, shared wreckage from the database loss. PlaceFactionsMain gives a boss zone to every faction carrying a BossHull, so each dangling link claimed a chokepoint that could never spawn a boss. AetherDb.Open no longer registers the name file store. CultCache subscribes Add to a store EntryAdded, MultiFileBackingStore.PullAll re-emits what it loads, and Add pushes to that type store, whose Push writes a file: opening the cache rewrote all twelve name files, 4.4 MB, on every command. They were byte identical, and it only surfaced as an error because Unity had one of them memory mapped. Name files now load only on request, and the scope doc records the underlying smell. Adds commands: factions, clear-boss-hulls, save, loadout (runs the real LoadoutGenerator against every hull), hardpoint-fit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46 lines
2.3 KiB
C#
46 lines
2.3 KiB
C#
using System;
|
|
using System.IO;
|
|
|
|
// Opens GameData/AetherDB.msgpack through the game's own CultCache and data types, for inspection and editing.
|
|
// Close the editor's Database Tools before saving, or its next Save will overwrite what was written here.
|
|
//
|
|
// Reads do not write. That needs saying because CultCache makes it easy to get wrong: AddBackingStore subscribes
|
|
// Add to a store's EntryAdded, MultiFileBackingStore.PullAll re-emits every entry it loads, and Add pushes to the
|
|
// store registered for that type, whose Push writes a file. So registering a second store makes merely opening the
|
|
// cache rewrite its files. Name files are therefore loaded only when a command asks for them.
|
|
public sealed class AetherDb
|
|
{
|
|
public string Root { get; }
|
|
public CultCache Cache { get; }
|
|
private readonly SingleFileMessagePackBackingStore _store;
|
|
|
|
private AetherDb(string root, bool withNameFiles)
|
|
{
|
|
Root = root;
|
|
RegisterResolver.Register();
|
|
var gameData = Path.Combine(root, "GameData");
|
|
_store = new SingleFileMessagePackBackingStore(Path.Combine(gameData, "AetherDB.msgpack"));
|
|
Cache = new CultCache();
|
|
Cache.AddBackingStore(_store);
|
|
if (withNameFiles) Cache.AddBackingStore(new MultiFileMessagePackBackingStore(gameData), typeof(NameFile));
|
|
Cache.PullAllBackingStores();
|
|
}
|
|
|
|
// With no root given, walks up from the working directory to the repository
|
|
public static AetherDb Open(string root = null) => new AetherDb(root ?? FindRoot(), false);
|
|
|
|
// Galaxy generation needs the name files; loading them rewrites them, so only ask when they are needed,
|
|
// and not while the editor holds them open.
|
|
public static AetherDb OpenWithNameFiles(string root = null) => new AetherDb(root ?? FindRoot(), true);
|
|
|
|
// Writes every entry back to AetherDB.msgpack, as the editor's Save button does
|
|
public void Save() => _store.PushAll();
|
|
|
|
private static string FindRoot()
|
|
{
|
|
for (var dir = new DirectoryInfo(Environment.CurrentDirectory); dir != null; dir = dir.Parent)
|
|
if (File.Exists(Path.Combine(dir.FullName, "GameData", "AetherDB.msgpack")))
|
|
return dir.FullName;
|
|
throw new DirectoryNotFoundException("Run from inside the Aetheria repository.");
|
|
}
|
|
}
|