Persist mining tool state in typed snapshots

This commit is contained in:
Meta Vens 2026-06-14 16:07:33 +01:00
commit a67a228c6b
10 changed files with 89 additions and 8 deletions

Binary file not shown.

View file

@ -284,6 +284,16 @@ await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-s
ResourceScannerRange = 500.0,
ResourceScannerMinimumDensity = 0.2,
ResourceScannerScanDuration = 3.5
},
new AetheriaBehaviorStateSnapshot
{
OwnerKind = "equipment",
OwnerIndex = 0,
BehaviorIndex = 2,
BehaviorKind = "MiningTool",
MiningToolAsteroidBeltId = "smoke:body",
MiningToolAsteroidIndex = 3,
MiningToolRange = 275.0
}
],
StatGrids =
@ -547,7 +557,7 @@ await using (var reopened = await AetheriaStateNode.OpenAsync(statePath, "aether
entitySnapshot.WeaponStates[0].BehaviorKind != "LockWeapon" ||
entitySnapshot.WeaponStates[0].LockProgress != 0.65 ||
entitySnapshot.WeaponStates[0].LockTargetEntityKey != entityKey.ToString() ||
entitySnapshot.BehaviorStates.Length != 2 ||
entitySnapshot.BehaviorStates.Length != 3 ||
entitySnapshot.BehaviorStates[0].BehaviorKind != "AetherDrive" ||
entitySnapshot.BehaviorStates[0].AetherDriveAxisX != 0.5 ||
entitySnapshot.BehaviorStates[0].AetherDriveRpmY != 900.0 ||
@ -557,6 +567,10 @@ await using (var reopened = await AetheriaStateNode.OpenAsync(statePath, "aether
entitySnapshot.BehaviorStates[1].ResourceScannerAsteroidIndex != 2 ||
entitySnapshot.BehaviorStates[1].ResourceScannerScanTime != 1.25 ||
entitySnapshot.BehaviorStates[1].ResourceScannerScanDuration != 3.5 ||
entitySnapshot.BehaviorStates[2].BehaviorKind != "MiningTool" ||
entitySnapshot.BehaviorStates[2].MiningToolAsteroidBeltId != "smoke:body" ||
entitySnapshot.BehaviorStates[2].MiningToolAsteroidIndex != 3 ||
entitySnapshot.BehaviorStates[2].MiningToolRange != 275.0 ||
entitySnapshot.StatGrids.Length != 1 ||
entitySnapshot.StatGrids[0].Values.Length != 4)
{

View file

@ -513,6 +513,16 @@ try
ResourceScannerRange = 500.0,
ResourceScannerMinimumDensity = 0.2,
ResourceScannerScanDuration = 3.5
},
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = "equipment",
OwnerIndex = 6,
BehaviorIndex = 0,
BehaviorKind = "MiningTool",
MiningToolAsteroidBeltId = "smoke:body",
MiningToolAsteroidIndex = 3,
MiningToolRange = 275.0
}
},
StatGrids = new[]
@ -633,7 +643,7 @@ try
entity.WeaponStates[3].BehaviorKind == "LockWeapon" &&
entity.WeaponStates[3].LockProgress == 0.65 &&
entity.WeaponStates[3].LockTargetEntityKey == "global:aetheria.run_state.smoke-run.zone.0.entity.0.v1" &&
entity.BehaviorStates.Length == 6 &&
entity.BehaviorStates.Length == 7 &&
entity.BehaviorStates[0].BehaviorKind == "Sensor" &&
entity.BehaviorStates[0].Pinging &&
entity.BehaviorStates[0].PingRadius == 1200.0 &&
@ -655,6 +665,10 @@ try
entity.BehaviorStates[5].ResourceScannerAsteroidIndex == 2 &&
entity.BehaviorStates[5].ResourceScannerScanTime == 1.25 &&
entity.BehaviorStates[5].ResourceScannerScanDuration == 3.5 &&
entity.BehaviorStates[6].BehaviorKind == "MiningTool" &&
entity.BehaviorStates[6].MiningToolAsteroidBeltId == "smoke:body" &&
entity.BehaviorStates[6].MiningToolAsteroidIndex == 3 &&
entity.BehaviorStates[6].MiningToolRange == 275.0 &&
entity.WeaponGroups.Length == 1 &&
entity.StatGrids.Length == 2 &&
entity.StatGrids.Any(grid => grid.Name == "temperature" && grid.Values.Length == 2 && grid.Values[1] == 281.0) &&
@ -710,12 +724,14 @@ try
packageEntities[0].WeaponStates[2].AmmoIntervalProgress != 0.6 ||
packageEntities[0].WeaponStates[3].LockProgress != 0.65 ||
packageEntities[0].WeaponStates[3].LockTargetEntityKey != "global:aetheria.run_state.smoke-run.zone.0.entity.0.v1" ||
packageEntities[0].BehaviorStates.Count != 6 ||
packageEntities[0].BehaviorStates.Count != 7 ||
packageEntities[0].BehaviorStates[3].CapacitorCharge != 7.5 ||
packageEntities[0].BehaviorStates[4].AetherDriveRpmY != 900.0 ||
packageEntities[0].BehaviorStates[4].AetherDriveMaximumRpm != 2400.0 ||
packageEntities[0].BehaviorStates[5].ResourceScannerTargetBodyId != "smoke:body" ||
packageEntities[0].BehaviorStates[5].ResourceScannerScanDuration != 3.5 ||
packageEntities[0].BehaviorStates[6].MiningToolAsteroidBeltId != "smoke:body" ||
packageEntities[0].BehaviorStates[6].MiningToolRange != 275.0 ||
packageEntities[0].StatGrids.Count != 2 ||
packageEntities[0].StatGrids.All(grid => grid.Name != "temperature" || grid.Values.Count != 2 || grid.Values[1] != 281.0))
{

View file

@ -504,7 +504,10 @@ public static class AetheriaRuntimeCommitLogApplier
ResourceScannerScanTime = state.ResourceScannerScanTime,
ResourceScannerRange = state.ResourceScannerRange,
ResourceScannerMinimumDensity = state.ResourceScannerMinimumDensity,
ResourceScannerScanDuration = state.ResourceScannerScanDuration
ResourceScannerScanDuration = state.ResourceScannerScanDuration,
MiningToolAsteroidBeltId = state.MiningToolAsteroidBeltId ?? "",
MiningToolAsteroidIndex = state.MiningToolAsteroidIndex,
MiningToolRange = state.MiningToolRange
})
.ToArray();
}

View file

@ -757,6 +757,15 @@ public sealed class AetheriaBehaviorStateSnapshot
[Key(36)]
public double ResourceScannerScanDuration { get; set; }
[Key(37)]
public string MiningToolAsteroidBeltId { get; set; } = "";
[Key(38)]
public int MiningToolAsteroidIndex { get; set; } = -1;
[Key(39)]
public double MiningToolRange { get; set; }
}
[MessagePackObject]

View file

@ -916,6 +916,17 @@ public class ActionGameManager : MonoBehaviour
ResourceScannerScanDuration = resourceScanner.ScanDuration
};
}
else if (behavior is MiningTool miningTool)
{
state = new AetheriaRuntimeBehaviorStateCommit
{
MiningToolAsteroidBeltId = miningTool.AsteroidBelt == Guid.Empty
? ""
: miningTool.AsteroidBelt.ToString("D"),
MiningToolAsteroidIndex = miningTool.Asteroid,
MiningToolRange = miningTool.Range
};
}
if (state == null)
continue;

View file

@ -1104,7 +1104,10 @@ namespace GameCult.Aetheria.State.Unity
double resourceScannerScanTime,
double resourceScannerRange,
double resourceScannerMinimumDensity,
double resourceScannerScanDuration)
double resourceScannerScanDuration,
string miningToolAsteroidBeltId,
int miningToolAsteroidIndex,
double miningToolRange)
{
OwnerKind = ownerKind;
OwnerIndex = ownerIndex;
@ -1143,6 +1146,9 @@ namespace GameCult.Aetheria.State.Unity
ResourceScannerRange = resourceScannerRange;
ResourceScannerMinimumDensity = resourceScannerMinimumDensity;
ResourceScannerScanDuration = resourceScannerScanDuration;
MiningToolAsteroidBeltId = miningToolAsteroidBeltId;
MiningToolAsteroidIndex = miningToolAsteroidIndex;
MiningToolRange = miningToolRange;
}
public string OwnerKind { get; }
@ -1182,5 +1188,8 @@ namespace GameCult.Aetheria.State.Unity
public double ResourceScannerRange { get; }
public double ResourceScannerMinimumDensity { get; }
public double ResourceScannerScanDuration { get; }
public string MiningToolAsteroidBeltId { get; }
public int MiningToolAsteroidIndex { get; }
public double MiningToolRange { get; }
}
}

View file

@ -894,7 +894,10 @@ namespace GameCult.Aetheria.State.Unity
var resourceScannerRange = ReadFieldDouble(ref reader, behaviorFields, 34);
var resourceScannerMinimumDensity = ReadFieldDouble(ref reader, behaviorFields, 35);
var resourceScannerScanDuration = ReadFieldDouble(ref reader, behaviorFields, 36);
SkipRemaining(ref reader, behaviorFields, 37);
var miningToolAsteroidBeltId = ReadFieldString(ref reader, behaviorFields, 37);
var miningToolAsteroidIndex = ReadFieldInt32(ref reader, behaviorFields, 38);
var miningToolRange = ReadFieldDouble(ref reader, behaviorFields, 39);
SkipRemaining(ref reader, behaviorFields, 40);
behaviorStates[behavior] = new AetheriaRuntimeBehaviorStateSnapshot(
ownerKind,
ownerIndex,
@ -932,7 +935,10 @@ namespace GameCult.Aetheria.State.Unity
resourceScannerScanTime,
resourceScannerRange,
resourceScannerMinimumDensity,
resourceScannerScanDuration);
resourceScannerScanDuration,
miningToolAsteroidBeltId,
miningToolAsteroidIndex,
miningToolRange);
}
return behaviorStates;

View file

@ -806,5 +806,14 @@ namespace GameCult.Aetheria.State.Unity
[Key(36)]
public double ResourceScannerScanDuration { get; set; }
[Key(37)]
public string MiningToolAsteroidBeltId { get; set; } = "";
[Key(38)]
public int MiningToolAsteroidIndex { get; set; } = -1;
[Key(39)]
public double MiningToolRange { get; set; }
}
}

View file

@ -173,7 +173,8 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
thrust, RPM, maximum RPM, and thrust-direction rows, so rotor simulation
state is no longer trapped inside live behavior memory. Resource scanners
publish target body id, asteroid index, scan timer, range, minimum density,
and scan duration rows.
and scan duration rows. Mining tools publish asteroid belt id, asteroid
index, and evaluated range rows.
`RuntimeEntityBlueprint` still exists for construction/loadout projection,
but those live hull grids and session scalars are not blueprint fields and
cannot be restored by the old blueprint projector path.
@ -811,6 +812,9 @@ First Aetheria surfaces to publish:
- Done: extend behavior state rows for ResourceScanner target body,
asteroid index, scan timer, range, minimum density, and duration, so
scanner progress is typed state instead of live-only behavior memory.
- Done: extend behavior state rows for MiningTool asteroid belt id,
asteroid index, and range, so active mining target state is typed
snapshot/readback state.
- Done: cut live simulation grids out of `RuntimeEntityBlueprint`; loadout
and construction templates no longer capture or restore temperature,
armor, max-armor, or hull-conductivity state.