From 02058a3cdf7ca823cb0f5dab6103ee1bafa7968e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 11 Sep 2026 23:23:20 +0200 Subject: [PATCH] Build ServerShared without Unity and add AetherDb scripts Aetheria.Shared.csproj compiles ServerShared with MessagePack, UniRx core, Ink and Unity.Mathematics from source against .NET Standard 2.1 (Unity's API level) with no Unity defines; a clean build checks that the simulation stays engine-independent. tools/AetherDb opens AetherDB.msgpack through the game's own CultCache for file-based C# scripts; station-fit checks every station hull can take a docking bay. Co-Authored-By: Claude Opus 5 --- .gitignore | 6 +++++ Aetheria.Shared/Aetheria.Shared.csproj | 35 ++++++++++++++++++++++++ docs/three-gates-scope.md | 15 ++++++++--- tools/AetherDb/AetherDb.cs | 37 ++++++++++++++++++++++++++ tools/AetherDb/Directory.Build.props | 14 ++++++++++ tools/AetherDb/scripts/station-fit.cs | 22 +++++++++++++++ 6 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 Aetheria.Shared/Aetheria.Shared.csproj create mode 100644 tools/AetherDb/AetherDb.cs create mode 100644 tools/AetherDb/Directory.Build.props create mode 100644 tools/AetherDb/scripts/station-fit.cs diff --git a/.gitignore b/.gitignore index e82f6272d..50e57f2ed 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,12 @@ ExportedObj/ # Per-user editor state /[Uu]ser[Ss]ettings/ +# .NET build output outside Unity +/Aetheria.Shared/bin/ +/Aetheria.Shared/obj/ +/tools/**/bin/ +/tools/**/obj/ + # Unity3D generated meta files *.pidb.meta *.pdb.meta diff --git a/Aetheria.Shared/Aetheria.Shared.csproj b/Aetheria.Shared/Aetheria.Shared.csproj new file mode 100644 index 000000000..b546290bd --- /dev/null +++ b/Aetheria.Shared/Aetheria.Shared.csproj @@ -0,0 +1,35 @@ + + + + + netstandard2.1 + 9.0 + disable + disable + true + false + + $(DefineConstants);UniRxLibrary + + $(NoWarn);CS0108;CS0114;CS0162;CS0168;CS0169;CS0219;CS0414;CS0618;CS0649;CS8321;CS8981;SYSLIB0021 + $(MSBuildThisFileDirectory)..\Assets\ + + $(MSBuildThisFileDirectory)..\Library\PackageCache\com.unity.mathematics@*\Unity.Mathematics\ + + + + + + + + + + + + + + + + diff --git a/docs/three-gates-scope.md b/docs/three-gates-scope.md index e9e5452ed..a99c86073 100644 --- a/docs/three-gates-scope.md +++ b/docs/three-gates-scope.md @@ -59,9 +59,12 @@ AI share it, so AI accuracy is no longer superhuman by construction. pickup (`ShieldManager`), `TractorBeam`, `Mine`. Not blockers. **Invariant: game simulation runs independently of Unity.** `ServerShared` -enforces this at compile time (`Aetheria.Shared.Unity.asmdef` sets -`noEngineReferences`), but Unity-owned hit resolution breaks it behaviorally: -the simulation compiles without Unity yet cannot resolve combat without it. +cannot reference UnityEngine (`Aetheria.Shared.Unity.asmdef` sets +`noEngineReferences`), and `Aetheria.Shared/Aetheria.Shared.csproj` builds it +from source with the plain .NET SDK, so a clean headless build is the check. +Tools (`tools/AetherDb`) and future test harnesses reference that project. +Unity-owned hit resolution still breaks the invariant behaviorally: the +simulation builds without Unity yet cannot resolve combat without it. That was a velocity compromise. Moving hit authority into fire control restores the invariant, and lets the planner and a balance harness simulate combat. @@ -95,3 +98,9 @@ Economy simulation, hauling, mining yield, crafting/blueprints, reputation changes, story placement, multiplayer and `Economy.Server`, a headless server deployment, and the CultMesh/daemon rebuild (parked in `F:\Projects\AetheriaEve`). + +Post-ship direction for items: generic item classes (docking bays, cargo +bays) become faction-neutral blueprints that branded manufacturing runs +reference, so no faction's absence from a galaxy can remove a required item +class. Until then, database variety has to guarantee it; `LoadoutGenerator` +logs whenever a required item falls back to an unavailable manufacturer. diff --git a/tools/AetherDb/AetherDb.cs b/tools/AetherDb/AetherDb.cs new file mode 100644 index 000000000..c31fcf6ee --- /dev/null +++ b/tools/AetherDb/AetherDb.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; + +// Opens GameData/AetherDB.msgpack through the game's own CultCache and data types, for inspection and editing scripts. +// Close the editor's Database Tools before saving from a script, or its next Save will overwrite the script's changes. +public sealed class AetherDb +{ + public string Root { get; } + public CultCache Cache { get; } + private readonly SingleFileMessagePackBackingStore _store; + + private AetherDb(string root) + { + Root = root; + RegisterResolver.Register(); + var gameData = Path.Combine(root, "GameData"); + _store = new SingleFileMessagePackBackingStore(Path.Combine(gameData, "AetherDB.msgpack")); + Cache = new CultCache(); + Cache.AddBackingStore(_store); + 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()); + + // 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."); + } +} diff --git a/tools/AetherDb/Directory.Build.props b/tools/AetherDb/Directory.Build.props new file mode 100644 index 000000000..1a7b942e9 --- /dev/null +++ b/tools/AetherDb/Directory.Build.props @@ -0,0 +1,14 @@ + + + + disable + disable + + false + + + + + + diff --git a/tools/AetherDb/scripts/station-fit.cs b/tools/AetherDb/scripts/station-fit.cs new file mode 100644 index 000000000..fd1323daf --- /dev/null +++ b/tools/AetherDb/scripts/station-fit.cs @@ -0,0 +1,22 @@ +// Checks that some docking bay fits every station hull, which LoadoutGenerator.GenerateStationLoadout requires. +// Exits with the number of station hulls that cannot take any docking bay. +using System; +using System.Linq; + +var db = AetherDb.Open(); +var bays = db.Cache.GetAll().ToArray(); +var failures = 0; +foreach (var hull in db.Cache.GetAll().Where(h => h.HullType == HullType.Station)) +{ + // Hardpoint gear is equipped before the docking bay, so the worst case leaves only the non-hardpoint interior free + var worstCase = new Shape(hull.Shape.Width, hull.Shape.Height); + foreach (var v in hull.InteriorCells.Coordinates) worstCase[v] = true; + foreach (var hardpoint in hull.Hardpoints) + foreach (var v in hardpoint.Shape.Coordinates) + worstCase[hardpoint.Position + v] = false; + + var fitting = bays.Where(b => b.Shape.FitsWithin(worstCase, out _, out _)).Select(b => b.Name).ToArray(); + if (fitting.Length == 0) failures++; + Console.WriteLine($"{hull.Name}: {(fitting.Length == 0 ? "NO docking bay fits" : string.Join(", ", fitting))}"); +} +return failures;