Persist behavior runtime state in checkpoints
This commit is contained in:
parent
f98f650ab5
commit
16a92b0173
8 changed files with 311 additions and 6 deletions
Binary file not shown.
|
|
@ -406,6 +406,52 @@ try
|
|||
AmmoIntervalProgress = 0.6
|
||||
}
|
||||
},
|
||||
BehaviorStates = new[]
|
||||
{
|
||||
new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
OwnerKind = "equipment",
|
||||
OwnerIndex = 0,
|
||||
BehaviorIndex = 2,
|
||||
BehaviorKind = "Sensor",
|
||||
Pinging = true,
|
||||
PingCooldown = 0.25,
|
||||
PingLerp = 0.5,
|
||||
PingRadius = 1200.0,
|
||||
PingedEntityCount = 3
|
||||
},
|
||||
new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
OwnerKind = "equipment",
|
||||
OwnerIndex = 1,
|
||||
BehaviorIndex = 0,
|
||||
BehaviorKind = "Radiator",
|
||||
RadiatorTemperature = 450.0,
|
||||
Emissivity = 0.8,
|
||||
PumpedHeat = 12.0,
|
||||
WasteHeat = 1.5,
|
||||
EnergyUsage = 2.25
|
||||
},
|
||||
new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
OwnerKind = "equipment",
|
||||
OwnerIndex = 2,
|
||||
BehaviorIndex = 0,
|
||||
BehaviorKind = "Reactor",
|
||||
ReactorDraw = 4.5,
|
||||
ReactorLoadRatio = 1.25
|
||||
},
|
||||
new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
OwnerKind = "equipment",
|
||||
OwnerIndex = 3,
|
||||
BehaviorIndex = 0,
|
||||
BehaviorKind = "Capacitor",
|
||||
CapacitorCharge = 7.5,
|
||||
CapacitorCapacity = 10.0,
|
||||
CapacitorEfficiency = 0.95
|
||||
}
|
||||
},
|
||||
StatGrids = new[]
|
||||
{
|
||||
new AetheriaRuntimeEntityStatGridCommit
|
||||
|
|
@ -513,6 +559,18 @@ try
|
|||
entity.WeaponStates[2].BehaviorKind == "ConstantWeapon" &&
|
||||
entity.WeaponStates[2].Reloading &&
|
||||
entity.WeaponStates[2].AmmoIntervalProgress == 0.6 &&
|
||||
entity.BehaviorStates.Length == 4 &&
|
||||
entity.BehaviorStates[0].BehaviorKind == "Sensor" &&
|
||||
entity.BehaviorStates[0].Pinging &&
|
||||
entity.BehaviorStates[0].PingRadius == 1200.0 &&
|
||||
entity.BehaviorStates[1].BehaviorKind == "Radiator" &&
|
||||
entity.BehaviorStates[1].RadiatorTemperature == 450.0 &&
|
||||
entity.BehaviorStates[1].PumpedHeat == 12.0 &&
|
||||
entity.BehaviorStates[2].BehaviorKind == "Reactor" &&
|
||||
entity.BehaviorStates[2].ReactorLoadRatio == 1.25 &&
|
||||
entity.BehaviorStates[3].BehaviorKind == "Capacitor" &&
|
||||
entity.BehaviorStates[3].CapacitorCharge == 7.5 &&
|
||||
entity.BehaviorStates[3].CapacitorEfficiency == 0.95 &&
|
||||
entity.WeaponGroups.Length == 1 &&
|
||||
entity.StatGrids.Length == 2 &&
|
||||
entity.StatGrids.Any(grid => grid.Name == "temperature" && grid.Values.Length == 2 && grid.Values[1] == 281.0) &&
|
||||
|
|
|
|||
|
|
@ -442,10 +442,40 @@ public static class AetheriaRuntimeCommitLogApplier
|
|||
StatGrids = ToEntityStatGrids(entity.StatGrids),
|
||||
ActiveConsumables = ToActiveConsumables(entity.ActiveConsumables),
|
||||
BehaviorProgress = ToBehaviorProgress(entity.BehaviorProgress),
|
||||
WeaponStates = ToWeaponStates(entity.WeaponStates)
|
||||
WeaponStates = ToWeaponStates(entity.WeaponStates),
|
||||
BehaviorStates = ToBehaviorStates(entity.BehaviorStates)
|
||||
};
|
||||
}
|
||||
|
||||
private static AetheriaBehaviorStateSnapshot[] ToBehaviorStates(
|
||||
IReadOnlyList<AetheriaRuntimeBehaviorStateCommit>? states)
|
||||
{
|
||||
return (states ?? Array.Empty<AetheriaRuntimeBehaviorStateCommit>())
|
||||
.Select(state => new AetheriaBehaviorStateSnapshot
|
||||
{
|
||||
OwnerKind = state.OwnerKind ?? "",
|
||||
OwnerIndex = state.OwnerIndex,
|
||||
BehaviorIndex = state.BehaviorIndex,
|
||||
BehaviorKind = state.BehaviorKind ?? "",
|
||||
Pinging = state.Pinging,
|
||||
PingCooldown = state.PingCooldown,
|
||||
PingLerp = state.PingLerp,
|
||||
PingRadius = state.PingRadius,
|
||||
PingedEntityCount = state.PingedEntityCount,
|
||||
RadiatorTemperature = state.RadiatorTemperature,
|
||||
Emissivity = state.Emissivity,
|
||||
PumpedHeat = state.PumpedHeat,
|
||||
WasteHeat = state.WasteHeat,
|
||||
EnergyUsage = state.EnergyUsage,
|
||||
ReactorDraw = state.ReactorDraw,
|
||||
ReactorLoadRatio = state.ReactorLoadRatio,
|
||||
CapacitorCharge = state.CapacitorCharge,
|
||||
CapacitorCapacity = state.CapacitorCapacity,
|
||||
CapacitorEfficiency = state.CapacitorEfficiency
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static AetheriaWeaponStateSnapshot[] ToWeaponStates(
|
||||
IReadOnlyList<AetheriaRuntimeWeaponStateCommit>? states)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -488,6 +488,9 @@ public sealed class AetheriaEntitySnapshot
|
|||
|
||||
[Key(22)]
|
||||
public AetheriaWeaponStateSnapshot[] WeaponStates { get; set; } = [];
|
||||
|
||||
[Key(23)]
|
||||
public AetheriaBehaviorStateSnapshot[] BehaviorStates { get; set; } = [];
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
|
|
@ -614,6 +617,67 @@ public sealed class AetheriaWeaponStateSnapshot
|
|||
public double AmmoIntervalProgress { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaBehaviorStateSnapshot
|
||||
{
|
||||
[Key(0)]
|
||||
public string OwnerKind { get; set; } = "";
|
||||
|
||||
[Key(1)]
|
||||
public int OwnerIndex { get; set; } = -1;
|
||||
|
||||
[Key(2)]
|
||||
public int BehaviorIndex { get; set; } = -1;
|
||||
|
||||
[Key(3)]
|
||||
public string BehaviorKind { get; set; } = "";
|
||||
|
||||
[Key(4)]
|
||||
public bool Pinging { get; set; }
|
||||
|
||||
[Key(5)]
|
||||
public double PingCooldown { get; set; }
|
||||
|
||||
[Key(6)]
|
||||
public double PingLerp { get; set; }
|
||||
|
||||
[Key(7)]
|
||||
public double PingRadius { get; set; }
|
||||
|
||||
[Key(8)]
|
||||
public int PingedEntityCount { get; set; }
|
||||
|
||||
[Key(9)]
|
||||
public double RadiatorTemperature { get; set; }
|
||||
|
||||
[Key(10)]
|
||||
public double Emissivity { get; set; }
|
||||
|
||||
[Key(11)]
|
||||
public double PumpedHeat { get; set; }
|
||||
|
||||
[Key(12)]
|
||||
public double WasteHeat { get; set; }
|
||||
|
||||
[Key(13)]
|
||||
public double EnergyUsage { get; set; }
|
||||
|
||||
[Key(14)]
|
||||
public double ReactorDraw { get; set; }
|
||||
|
||||
[Key(15)]
|
||||
public double ReactorLoadRatio { get; set; }
|
||||
|
||||
[Key(16)]
|
||||
public double CapacitorCharge { get; set; }
|
||||
|
||||
[Key(17)]
|
||||
public double CapacitorCapacity { get; set; }
|
||||
|
||||
[Key(18)]
|
||||
public double CapacitorEfficiency { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaActionBarBinding
|
||||
{
|
||||
|
|
|
|||
|
|
@ -789,10 +789,89 @@ public class ActionGameManager : MonoBehaviour
|
|||
StatGrids = ProjectEntityStatGrids(entity),
|
||||
ActiveConsumables = ProjectActiveConsumables(entity),
|
||||
BehaviorProgress = ProjectBehaviorProgress(entity),
|
||||
WeaponStates = ProjectWeaponStates(entity)
|
||||
WeaponStates = ProjectWeaponStates(entity),
|
||||
BehaviorStates = ProjectBehaviorStates(entity)
|
||||
};
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeBehaviorStateCommit[] ProjectBehaviorStates(Entity entity)
|
||||
{
|
||||
var states = new List<AetheriaRuntimeBehaviorStateCommit>();
|
||||
|
||||
for (var ownerIndex = 0; ownerIndex < entity.Equipment.Count; ownerIndex++)
|
||||
states.AddRange(ProjectBehaviorStates("equipment", ownerIndex, entity.Equipment[ownerIndex].Behaviors));
|
||||
|
||||
var activeConsumables = entity.ActiveConsumables;
|
||||
for (var ownerIndex = 0; ownerIndex < activeConsumables.Count; ownerIndex++)
|
||||
states.AddRange(ProjectBehaviorStates("active_consumable", ownerIndex, activeConsumables[ownerIndex].Behaviors));
|
||||
|
||||
return states.ToArray();
|
||||
}
|
||||
|
||||
private static IEnumerable<AetheriaRuntimeBehaviorStateCommit> ProjectBehaviorStates(
|
||||
string ownerKind,
|
||||
int ownerIndex,
|
||||
IReadOnlyList<Behavior> behaviors)
|
||||
{
|
||||
if (behaviors == null)
|
||||
yield break;
|
||||
|
||||
for (var behaviorIndex = 0; behaviorIndex < behaviors.Count; behaviorIndex++)
|
||||
{
|
||||
var behavior = behaviors[behaviorIndex];
|
||||
AetheriaRuntimeBehaviorStateCommit state = null;
|
||||
|
||||
if (behavior is Sensor sensor)
|
||||
{
|
||||
state = new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
Pinging = sensor.Pinging,
|
||||
PingCooldown = sensor.Cooldown,
|
||||
PingLerp = sensor.PingLerp,
|
||||
PingRadius = sensor.PingRadius,
|
||||
PingedEntityCount = sensor.PingedEntityCount
|
||||
};
|
||||
}
|
||||
else if (behavior is Radiator radiator)
|
||||
{
|
||||
state = new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
RadiatorTemperature = radiator.RadiatorTemperature,
|
||||
Emissivity = radiator.Emissivity,
|
||||
PumpedHeat = radiator.PumpedHeat,
|
||||
WasteHeat = radiator.WasteHeat,
|
||||
EnergyUsage = radiator.EnergyUsage
|
||||
};
|
||||
}
|
||||
else if (behavior is Reactor reactor)
|
||||
{
|
||||
state = new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
ReactorDraw = reactor.Draw,
|
||||
ReactorLoadRatio = reactor.CurrentLoadRatio
|
||||
};
|
||||
}
|
||||
else if (behavior is Capacitor capacitor)
|
||||
{
|
||||
state = new AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
CapacitorCharge = capacitor.Charge,
|
||||
CapacitorCapacity = capacitor.Capacity,
|
||||
CapacitorEfficiency = capacitor.Efficiency
|
||||
};
|
||||
}
|
||||
|
||||
if (state == null)
|
||||
continue;
|
||||
|
||||
state.OwnerKind = ownerKind;
|
||||
state.OwnerIndex = ownerIndex;
|
||||
state.BehaviorIndex = behaviorIndex;
|
||||
state.BehaviorKind = behavior.Data?.Kind ?? "";
|
||||
yield return state;
|
||||
}
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeWeaponStateCommit[] ProjectWeaponStates(Entity entity)
|
||||
{
|
||||
var states = new List<AetheriaRuntimeWeaponStateCommit>();
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ public class Sensor : Behavior, IEventBehavior
|
|||
{
|
||||
get => _pingRadius;
|
||||
}
|
||||
public float PingLerp => _pingLerp;
|
||||
public bool Pinging => _pinging;
|
||||
public int PingedEntityCount => _pingedEntities.Count;
|
||||
|
||||
public float PingBrightness => pow(1 - _pingLerp, _data.PingRadiusExponent);
|
||||
|
||||
|
|
@ -153,4 +156,4 @@ public class Sensor : Behavior, IEventBehavior
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,6 +564,9 @@ namespace GameCult.Aetheria.State.Unity
|
|||
|
||||
[Key(27)]
|
||||
public IReadOnlyList<AetheriaRuntimeWeaponStateCommit> WeaponStates { get; set; } = Array.Empty<AetheriaRuntimeWeaponStateCommit>();
|
||||
|
||||
[Key(28)]
|
||||
public IReadOnlyList<AetheriaRuntimeBehaviorStateCommit> BehaviorStates { get; set; } = Array.Empty<AetheriaRuntimeBehaviorStateCommit>();
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
|
|
@ -671,4 +674,65 @@ namespace GameCult.Aetheria.State.Unity
|
|||
[Key(16)]
|
||||
public double AmmoIntervalProgress { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaRuntimeBehaviorStateCommit
|
||||
{
|
||||
[Key(0)]
|
||||
public string OwnerKind { get; set; } = "";
|
||||
|
||||
[Key(1)]
|
||||
public int OwnerIndex { get; set; } = -1;
|
||||
|
||||
[Key(2)]
|
||||
public int BehaviorIndex { get; set; } = -1;
|
||||
|
||||
[Key(3)]
|
||||
public string BehaviorKind { get; set; } = "";
|
||||
|
||||
[Key(4)]
|
||||
public bool Pinging { get; set; }
|
||||
|
||||
[Key(5)]
|
||||
public double PingCooldown { get; set; }
|
||||
|
||||
[Key(6)]
|
||||
public double PingLerp { get; set; }
|
||||
|
||||
[Key(7)]
|
||||
public double PingRadius { get; set; }
|
||||
|
||||
[Key(8)]
|
||||
public int PingedEntityCount { get; set; }
|
||||
|
||||
[Key(9)]
|
||||
public double RadiatorTemperature { get; set; }
|
||||
|
||||
[Key(10)]
|
||||
public double Emissivity { get; set; }
|
||||
|
||||
[Key(11)]
|
||||
public double PumpedHeat { get; set; }
|
||||
|
||||
[Key(12)]
|
||||
public double WasteHeat { get; set; }
|
||||
|
||||
[Key(13)]
|
||||
public double EnergyUsage { get; set; }
|
||||
|
||||
[Key(14)]
|
||||
public double ReactorDraw { get; set; }
|
||||
|
||||
[Key(15)]
|
||||
public double ReactorLoadRatio { get; set; }
|
||||
|
||||
[Key(16)]
|
||||
public double CapacitorCharge { get; set; }
|
||||
|
||||
[Key(17)]
|
||||
public double CapacitorCapacity { get; set; }
|
||||
|
||||
[Key(18)]
|
||||
public double CapacitorEfficiency { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
|
|||
Weapon behaviors now also publish typed runtime rows for firing state, ammo,
|
||||
burst timing, cooldown progress, charged-weapon charging/charge state, and
|
||||
constant-weapon reload/ammo-interval state.
|
||||
Sensor, radiator, reactor, and capacitor behaviors publish typed state rows
|
||||
for ping state, radiator temperature/throughput, reactor draw/load, and
|
||||
capacitor charge/capacity/efficiency.
|
||||
`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.
|
||||
|
|
@ -773,12 +776,15 @@ First Aetheria surfaces to publish:
|
|||
- Done: extend run checkpoint commits and smoke coverage to carry typed
|
||||
weapon behavior state rows for instant, charged, and constant weapon
|
||||
runtime internals.
|
||||
- Done: extend run checkpoint commits and smoke coverage to carry typed
|
||||
behavior state rows for sensor ping state plus radiator, reactor, and
|
||||
capacitor runtime internals.
|
||||
- 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.
|
||||
- Remaining: add typed documents/mappers for runtime object graphs,
|
||||
typed behavior factory construction, behavior-private simulation state
|
||||
such as sensor ping state, radiator/reactor/capacitor runtime internals,
|
||||
typed behavior factory construction, remaining behavior-private state not
|
||||
covered by progress, weapon, sensor, radiator, reactor, or capacitor rows,
|
||||
and any catalog fields not covered by the stable scalar/fingerprint/
|
||||
payload pass.
|
||||
|
||||
|
|
@ -1173,7 +1179,8 @@ First Aetheria surfaces to publish:
|
|||
includes orbit/body rows for generated celestial state, and the entity smoke
|
||||
includes typed simulation stat grids, public entity session scalars, and
|
||||
active consumable timer rows, plus typed behavior progress rows for
|
||||
`IProgressBehavior` surfaces and typed weapon runtime rows. The Unity runtime smoke also proves
|
||||
`IProgressBehavior` surfaces, typed weapon runtime rows, and typed
|
||||
sensor/radiator/reactor/capacitor behavior state rows. The Unity runtime smoke also proves
|
||||
package-owned readback of typed loadout templates from `.cc` records. It also
|
||||
proves `aetheria.runtime_session.v1` is advertised and survives reopen as the
|
||||
typed daemon-session signal.
|
||||
|
|
|
|||
Loading…
Reference in a new issue