Persist entity simulation grids in checkpoints

This commit is contained in:
Meta Vens 2026-06-14 13:03:57 +01:00
commit f276f9bcb3
7 changed files with 140 additions and 14 deletions

Binary file not shown.

View file

@ -273,7 +273,24 @@ try
}
}
},
WeaponGroups = new[] { new[] { 0 } }
WeaponGroups = new[] { new[] { 0 } },
StatGrids = new[]
{
new AetheriaRuntimeEntityStatGridCommit
{
Name = "temperature",
Width = 2,
Height = 1,
Values = new[] { 280.0, 281.0 }
},
new AetheriaRuntimeEntityStatGridCommit
{
Name = "hull_conductivity_x",
Width = 2,
Height = 1,
Values = new[] { 1.0, 0.0 }
}
}
}
}
}
@ -325,6 +342,9 @@ try
zone.Bodies[0].Asteroids.Length == 1 &&
entity?.Equipment.Length == 1 &&
entity.WeaponGroups.Length == 1 &&
entity.StatGrids.Length == 2 &&
entity.StatGrids.Any(grid => grid.Name == "temperature" && grid.Values.Length == 2 && grid.Values[1] == 281.0) &&
entity.StatGrids.Any(grid => grid.Name == "hull_conductivity_x" && grid.Values.Length == 2 && grid.Values[0] == 1.0) &&
AetheriaRuntimeStateCommitLog.ReadPending(commitSmokeStatePath).Count == 0;
}

View file

@ -424,10 +424,25 @@ public static class AetheriaRuntimeCommitLogApplier
.ToArray(),
WeaponGroups = ToIntArrayArray(entity.WeaponGroups)
.Select(group => new AetheriaWeaponGroupSnapshot { EquipmentIndices = group })
.ToArray()
.ToArray(),
StatGrids = ToEntityStatGrids(entity.StatGrids)
};
}
private static AetheriaEntityStatGrid[] ToEntityStatGrids(
IReadOnlyList<AetheriaRuntimeEntityStatGridCommit>? grids)
{
return (grids ?? Array.Empty<AetheriaRuntimeEntityStatGridCommit>())
.Select(grid => new AetheriaEntityStatGrid
{
Name = grid.Name ?? "",
Width = grid.Width,
Height = grid.Height,
Values = (grid.Values ?? Array.Empty<double>()).ToArray()
})
.ToArray();
}
private static int[] ToIntArray(IReadOnlyList<int>? values)
{
return (values ?? Array.Empty<int>()).ToArray();

View file

@ -21,7 +21,8 @@ typed corporation references plus relationship tokens and numeric standings.
Zone checkpoints include typed orbit and body rows for generated celestial
state: orbit IDs, parent IDs, distance, phase, fixed positions, body kind,
resources, gravity/body multipliers, asteroid entries, and gas/sun visual
parameters.
parameters. Entity checkpoints include typed simulation stat grids for
temperature, thermal mass, armor, max armor, and hull-conductivity axes.
Player settings include player name, tutorial flag,
story-file hash cursors, gameplay formatting, graphics preferences, input
binding overrides, and action-bar inputs. Do not preserve `SavedGame`, Unity
@ -120,9 +121,12 @@ needs actual allegiance weights, not only display counts. Runtime checkpoints
now persist session faction relationships into typed run state, and runtime
sessions publish typed state-host liveness. Zone checkpoints persist generated
orbit/body rows into `AetheriaZoneState`, so `RuntimeZoneBlueprint` is no
longer the only surface carrying celestial graph facts. Broader runtime object
graphs, typed behavior factory construction, and simulation state remain legacy
until dedicated typed runtime documents exist.
longer the only surface carrying celestial graph facts. Entity checkpoints
persist hull simulation grids into `AetheriaEntitySnapshot`, so
`RuntimeEntityBlueprint` is no longer the only surface carrying those live
values. Broader runtime object graphs, typed behavior factory construction, and
behavior-private simulation state remain legacy until dedicated typed runtime
documents exist.
Typed name-file documents are `aetheria.name_file.v2` records. They carry the
legacy ID, display name, count, compact sample names for surfaces, and the full
name array needed to move `Galaxy`/Markov name generation off legacy
@ -170,8 +174,8 @@ an entity snapshot. It also writes and reopens `AetheriaRuntimeSession` and
checks that the Eve provider advertises the runtime-session schema. The run
smoke proves a typed run can reference a typed zone, the zone can preserve
orbit/body rows and reference typed entity snapshots, and entity snapshots can
preserve equipment slots, weapon groups, and stat grids without reviving
`PlayerSettings.msgpack`, `.loadout`, or `.zone` serialization.
preserve equipment slots, weapon groups, and simulation stat grids without
reviving `PlayerSettings.msgpack`, `.loadout`, or `.zone` serialization.
`Aetheria.State.Verify` opens a materialized state file and checks that the
typed migration ledger matches the actual item, corporation, and name-file

View file

@ -655,7 +655,67 @@ public class ActionGameManager : MonoBehaviour
.ToArray() ?? Array.Empty<int>(),
WeaponGroups = entity.WeaponGroups?
.Select(group => (IReadOnlyList<int>)group.items.Select(item => entity.Equipment.IndexOf(item)).Where(index => index >= 0).ToArray())
.ToArray() ?? Array.Empty<IReadOnlyList<int>>()
.ToArray() ?? Array.Empty<IReadOnlyList<int>>(),
StatGrids = ProjectEntityStatGrids(entity)
};
}
private static AetheriaRuntimeEntityStatGridCommit[] ProjectEntityStatGrids(Entity entity)
{
return new[]
{
ProjectFloatGrid("temperature", entity.Temperature),
ProjectFloatGrid("thermal_mass", entity.ThermalMass),
ProjectFloatGrid("armor", entity.Armor),
ProjectFloatGrid("max_armor", entity.MaxArmor),
ProjectBool2Grid("hull_conductivity_x", entity.HullConductivity, axis: 0),
ProjectBool2Grid("hull_conductivity_y", entity.HullConductivity, axis: 1)
}
.Where(grid => grid != null)
.ToArray();
}
private static AetheriaRuntimeEntityStatGridCommit ProjectFloatGrid(string name, float[,] values)
{
if (values == null)
return null;
var width = values.GetLength(0);
var height = values.GetLength(1);
var flattened = new double[width * height];
var index = 0;
for (var y = 0; y < height; y++)
for (var x = 0; x < width; x++)
flattened[index++] = values[x, y];
return new AetheriaRuntimeEntityStatGridCommit
{
Name = name,
Width = width,
Height = height,
Values = flattened
};
}
private static AetheriaRuntimeEntityStatGridCommit ProjectBool2Grid(string name, bool2[,] values, int axis)
{
if (values == null)
return null;
var width = values.GetLength(0);
var height = values.GetLength(1);
var flattened = new double[width * height];
var index = 0;
for (var y = 0; y < height; y++)
for (var x = 0; x < width; x++)
flattened[index++] = (axis == 0 ? values[x, y].x : values[x, y].y) ? 1.0 : 0.0;
return new AetheriaRuntimeEntityStatGridCommit
{
Name = name,
Width = width,
Height = height,
Values = flattened
};
}

View file

@ -525,5 +525,24 @@ namespace GameCult.Aetheria.State.Unity
[Key(14)]
public IReadOnlyList<IReadOnlyList<int>> WeaponGroups { get; set; } = Array.Empty<IReadOnlyList<int>>();
[Key(15)]
public IReadOnlyList<AetheriaRuntimeEntityStatGridCommit> StatGrids { get; set; } = Array.Empty<AetheriaRuntimeEntityStatGridCommit>();
}
[MessagePackObject]
public sealed class AetheriaRuntimeEntityStatGridCommit
{
[Key(0)]
public string Name { get; set; } = "";
[Key(1)]
public int Width { get; set; }
[Key(2)]
public int Height { get; set; }
[Key(3)]
public IReadOnlyList<double> Values { get; set; } = Array.Empty<double>();
}
}

View file

@ -135,6 +135,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
visual parameters now survive through the typed pending commit lane into
`AetheriaZoneState`. `RuntimeZoneBlueprint` feeds this projector, but it is
no longer the only place generated celestial graph facts can live.
- Run checkpoint entity snapshots include typed simulation stat grids for
temperature, thermal mass, armor, max armor, and hull-conductivity axes.
`RuntimeEntityBlueprint` still exists for construction/loadout projection,
but those live hull grids no longer survive only as blueprint fields.
- `Aetheria.State` now defines `AetheriaLoadoutTemplate` as the typed Verse
replacement for bespoke `.loadout` files. It stores structured hull,
equipment, cargo bay, docking bay, child-entity, assignment, and weapon-group
@ -738,9 +742,13 @@ First Aetheria surfaces to publish:
- Done: extend run checkpoint commits and smoke coverage to carry typed
zone orbit/body rows into `AetheriaZoneState`, so generated celestial
graph facts no longer live only inside `RuntimeZoneBlueprint`.
- Done: extend run checkpoint commits and smoke coverage to carry typed
entity simulation stat grids into `AetheriaEntitySnapshot`, so
temperature/armor/conductivity no longer live only in runtime blueprints.
- Remaining: add typed documents/mappers for runtime object graphs,
typed behavior factory construction, simulation state, and any catalog
fields not covered by the stable scalar/fingerprint/payload pass.
typed behavior factory construction, behavior-private simulation state,
and any catalog fields not covered by the stable scalar/fingerprint/
payload pass.
4. Runtime cutover
- Done: add a Unity-facing typed catalog read facade and smoke proving it can
@ -1130,9 +1138,9 @@ First Aetheria surfaces to publish:
resolution, including full player settings as the `PlayerSettings.msgpack`
replacement, loadout templates as the `.loadout` replacement, and a run ->
zone -> entity snapshot graph as the `.zone` replacement. The zone smoke
includes orbit/body rows for generated celestial state. It also proves
`aetheria.runtime_session.v1` is advertised and survives reopen as the typed
daemon-session signal.
includes orbit/body rows for generated celestial state, and the entity smoke
includes typed simulation stat grids. It also proves `aetheria.runtime_session.v1`
is advertised and survives reopen as the typed daemon-session signal.
- CultMesh smoke proves node start, typed put/get, subscription, flush, and
reopen.
- Eve surface smoke proves provider-owned surface documents are generated from