From cd009fa9a9a4a6a82c53365685241382c4f0b8f6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 14 Jun 2026 16:34:40 +0100 Subject: [PATCH] Persist stat modifier state in typed snapshots --- .voidbot/state/aetheria.cc | Bin 85584 -> 86086 bytes Aetheria.State.Smoke/Program.cs | 16 +++++++++++++- Aetheria.State.Unity.Smoke/Program.cs | 20 ++++++++++++++++-- .../AetheriaRuntimeCommitLogApplier.cs | 5 ++++- .../AetheriaRuntimeStateDocuments.cs | 9 ++++++++ Assets/Scripts/Gameplay/ActionGameManager.cs | 9 ++++++++ .../ServerShared/Behaviors/StatModifier.cs | 4 ++++ .../Runtime/AetheriaRuntimeCatalogSnapshot.cs | 11 +++++++++- .../Runtime/AetheriaRuntimeCatalogStore.cs | 10 +++++++-- .../AetheriaRuntimeStateCommitDocument.cs | 9 ++++++++ docs/aetheria-perfect-machine-map.md | 5 ++++- 11 files changed, 90 insertions(+), 8 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index aff784580125c1a6541d323d57af665c54d1d67d..c6e4ca17a19f6fde2f9da3acedc9ca96e8e35678 100644 GIT binary patch delta 1429 zcma)6L2n#27?qPPO{oNmAWB6d>Pk_n(#|Gi12nV>O*TDH6|zYMl_~_d<8OCNXY8r% z-85V(h~UBjRYv&2p%PMQP^q|8>V@_ISGeW}fW!%U=ECQlnY2kbaGS9|zwf>0=kK>~ z_Wg2m-;cKjh8m66XXom#PP<2gqweQ{FP<(JUY@>mgN!&e`0@72On+slc6i{-fsJFe zd&g?z$EK- z4^1^>Ovvz+iXKEtrt8~oOc^jiN2xtniMAnbhYE{CtSTimyQyum7&#aI%%VY+5)P;} z90_t**Ct8}yWSUT>fbXNy2+Uw6`w0NAJ(LU)i&6^XkFc5{ApI{5k&S!aFi}RK&3K6jK{Btpy6) zL1kA*d}Jv%^#Xq0J$!r8J-84JztOCcOfkI(?#XHL+}M9277*_Ep>g-(#*jOu5BuX2 zWcYlu|0<$XbxMmh%~-yRPI0)fWc&3{Be5`1wj$OFy8V~4q(RR4yZDgKa=doFTU!a% z)+(cqGp37#lp3eGvJ%kauB7hj$_xHRL?-t~EzCJ^e}0Zc2VZ(z;y(C%WKYG>+Gec5 zA6X=0{`LZynEvW^HM}-sjCLHNeRrqPcfzBprkWpKB+dQhgmixo9`a_9{8SCdnYnUg kKIJbqiK>y=xRf6larYjD-k_ky!YILkQemycm-ZMKN~~v5+JxqK!;;=WfUB&5Sd%cb+K@ zv9yu}x6ncm;s=6SNJ_ELT1&OC@(&QK#W%Zqo5TZ~g?&5w-tYZB=F^iMpC9jdvpz5~ zIWJa8`(yYRaI$`xY0nQr1*cYRXU7%+231R+jERJK!!n(A20$;N8;-W#VJgv z>_;Wqx(rpq1!pb^fO5mk-VSI^r1pg!j8o&qd1tgsZ%d&m7~ekYj0T=ACZBavtWph9 zi53M{G@Hzn0@1LT1MF%!0U3lEJf^5?pc)3IN^m=vOuQB1c2|LEgw28gh>tZ8b*ST#P!))phZGdmMkqShPp=MDi?t9Ws+BJXk{G`T zE1>}uVv8o-qz8ctu8j(jX@rj~+}O4c&hAlJlFBNNx30~``l9r6y6<0zQcttQsi}|;GpREWA z7+3;3fLqvRsSSGiCKQ~^z%brzKwGGU=!{E?Ws?T<4O+!IzJL1$kwvtz0fJ2xLGz(b zc_=`mx$#3M5X39LL=JqRmT6r-xc5}i`qzRdTs;xL8FmWM+V`=YSFT8pnE3MO4N3T%9qiIq!S5sfw-L&tIp~Bi|RCyLoLUsco#Cb3Tmh L&aT)KmFs^2zA+3{ diff --git a/Aetheria.State.Smoke/Program.cs b/Aetheria.State.Smoke/Program.cs index 54be8c134..f9296294e 100644 --- a/Aetheria.State.Smoke/Program.cs +++ b/Aetheria.State.Smoke/Program.cs @@ -345,6 +345,16 @@ await using (var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-s BehaviorIndex = 8, BehaviorKind = "Trigger", TriggerPulled = true + }, + new AetheriaBehaviorStateSnapshot + { + OwnerKind = "equipment", + OwnerIndex = 0, + BehaviorIndex = 9, + BehaviorKind = "StatModifier", + StatModifierApplied = true, + StatModifierExecuted = true, + StatModifierTargetStatCount = 2 } ], StatGrids = @@ -608,7 +618,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 != 9 || + entitySnapshot.BehaviorStates.Length != 10 || entitySnapshot.BehaviorStates[0].BehaviorKind != "AetherDrive" || entitySnapshot.BehaviorStates[0].AetherDriveAxisX != 0.5 || entitySnapshot.BehaviorStates[0].AetherDriveRpmY != 900.0 || @@ -637,6 +647,10 @@ await using (var reopened = await AetheriaStateNode.OpenAsync(statePath, "aether !entitySnapshot.BehaviorStates[7].SwitchActivated || entitySnapshot.BehaviorStates[8].BehaviorKind != "Trigger" || !entitySnapshot.BehaviorStates[8].TriggerPulled || + entitySnapshot.BehaviorStates[9].BehaviorKind != "StatModifier" || + !entitySnapshot.BehaviorStates[9].StatModifierApplied || + !entitySnapshot.BehaviorStates[9].StatModifierExecuted || + entitySnapshot.BehaviorStates[9].StatModifierTargetStatCount != 2 || entitySnapshot.StatGrids.Length != 1 || entitySnapshot.StatGrids[0].Values.Length != 4) { diff --git a/Aetheria.State.Unity.Smoke/Program.cs b/Aetheria.State.Unity.Smoke/Program.cs index 3a9ec6561..2027a9215 100644 --- a/Aetheria.State.Unity.Smoke/Program.cs +++ b/Aetheria.State.Unity.Smoke/Program.cs @@ -574,6 +574,16 @@ try BehaviorIndex = 0, BehaviorKind = "Trigger", TriggerPulled = true + }, + new AetheriaRuntimeBehaviorStateCommit + { + OwnerKind = "equipment", + OwnerIndex = 13, + BehaviorIndex = 0, + BehaviorKind = "StatModifier", + StatModifierApplied = true, + StatModifierExecuted = true, + StatModifierTargetStatCount = 2 } }, StatGrids = new[] @@ -694,7 +704,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 == 13 && + entity.BehaviorStates.Length == 14 && entity.BehaviorStates[0].BehaviorKind == "Sensor" && entity.BehaviorStates[0].Pinging && entity.BehaviorStates[0].PingRadius == 1200.0 && @@ -735,6 +745,10 @@ try entity.BehaviorStates[11].SwitchActivated && entity.BehaviorStates[12].BehaviorKind == "Trigger" && entity.BehaviorStates[12].TriggerPulled && + entity.BehaviorStates[13].BehaviorKind == "StatModifier" && + entity.BehaviorStates[13].StatModifierApplied && + entity.BehaviorStates[13].StatModifierExecuted && + entity.BehaviorStates[13].StatModifierTargetStatCount == 2 && entity.WeaponGroups.Length == 1 && entity.StatGrids.Length == 2 && entity.StatGrids.Any(grid => grid.Name == "temperature" && grid.Values.Length == 2 && grid.Values[1] == 281.0) && @@ -790,7 +804,7 @@ 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 != 13 || + packageEntities[0].BehaviorStates.Count != 14 || packageEntities[0].BehaviorStates[3].CapacitorCharge != 7.5 || packageEntities[0].BehaviorStates[4].AetherDriveRpmY != 900.0 || packageEntities[0].BehaviorStates[4].AetherDriveMaximumRpm != 2400.0 || @@ -805,6 +819,8 @@ try packageEntities[0].BehaviorStates[10].ThermotoggleTargetTemperature != 315.5 || !packageEntities[0].BehaviorStates[11].SwitchActivated || !packageEntities[0].BehaviorStates[12].TriggerPulled || + !packageEntities[0].BehaviorStates[13].StatModifierApplied || + packageEntities[0].BehaviorStates[13].StatModifierTargetStatCount != 2 || packageEntities[0].StatGrids.Count != 2 || packageEntities[0].StatGrids.All(grid => grid.Name != "temperature" || grid.Values.Count != 2 || grid.Values[1] != 281.0)) { diff --git a/Aetheria.State/AetheriaRuntimeCommitLogApplier.cs b/Aetheria.State/AetheriaRuntimeCommitLogApplier.cs index aeb0d328e..ccbc231c6 100644 --- a/Aetheria.State/AetheriaRuntimeCommitLogApplier.cs +++ b/Aetheria.State/AetheriaRuntimeCommitLogApplier.cs @@ -516,7 +516,10 @@ public static class AetheriaRuntimeCommitLogApplier VelocityLimit = state.VelocityLimit, ThermotoggleTargetTemperature = state.ThermotoggleTargetTemperature, SwitchActivated = state.SwitchActivated, - TriggerPulled = state.TriggerPulled + TriggerPulled = state.TriggerPulled, + StatModifierApplied = state.StatModifierApplied, + StatModifierExecuted = state.StatModifierExecuted, + StatModifierTargetStatCount = state.StatModifierTargetStatCount }) .ToArray(); } diff --git a/Aetheria.State/Documents/AetheriaRuntimeStateDocuments.cs b/Aetheria.State/Documents/AetheriaRuntimeStateDocuments.cs index ba2725507..449070b8d 100644 --- a/Aetheria.State/Documents/AetheriaRuntimeStateDocuments.cs +++ b/Aetheria.State/Documents/AetheriaRuntimeStateDocuments.cs @@ -793,6 +793,15 @@ public sealed class AetheriaBehaviorStateSnapshot [Key(48)] public bool TriggerPulled { get; set; } + + [Key(49)] + public bool StatModifierApplied { get; set; } + + [Key(50)] + public bool StatModifierExecuted { get; set; } + + [Key(51)] + public int StatModifierTargetStatCount { get; set; } } [MessagePackObject] diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index ff4d5e452..f80427f0d 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -972,6 +972,15 @@ public class ActionGameManager : MonoBehaviour TriggerPulled = trigger.Pulled }; } + else if (behavior is StatModifier statModifier) + { + state = new AetheriaRuntimeBehaviorStateCommit + { + StatModifierApplied = statModifier.Applied, + StatModifierExecuted = statModifier.Executed, + StatModifierTargetStatCount = statModifier.TargetStatCount + }; + } if (state == null) continue; diff --git a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs index 394bcc1ca..af3904052 100644 --- a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs +++ b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs @@ -42,6 +42,10 @@ public class StatModifier : Behavior, IInitializableBehavior, IDisposable, IAlwa private bool _applied; private bool _executed; + public bool Applied => _applied; + public bool Executed => _executed; + public int TargetStatCount => _stats?.Length ?? 0; + public StatModifier(StatModifierData data, EquippedItem item) : base(data, item) { _data = data; diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs index 2ef42bef6..614bb842c 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs @@ -1116,7 +1116,10 @@ namespace GameCult.Aetheria.State.Unity double velocityLimit, double thermotoggleTargetTemperature, bool switchActivated, - bool triggerPulled) + bool triggerPulled, + bool statModifierApplied, + bool statModifierExecuted, + int statModifierTargetStatCount) { OwnerKind = ownerKind; OwnerIndex = ownerIndex; @@ -1167,6 +1170,9 @@ namespace GameCult.Aetheria.State.Unity ThermotoggleTargetTemperature = thermotoggleTargetTemperature; SwitchActivated = switchActivated; TriggerPulled = triggerPulled; + StatModifierApplied = statModifierApplied; + StatModifierExecuted = statModifierExecuted; + StatModifierTargetStatCount = statModifierTargetStatCount; } public string OwnerKind { get; } @@ -1218,5 +1224,8 @@ namespace GameCult.Aetheria.State.Unity public double ThermotoggleTargetTemperature { get; } public bool SwitchActivated { get; } public bool TriggerPulled { get; } + public bool StatModifierApplied { get; } + public bool StatModifierExecuted { get; } + public int StatModifierTargetStatCount { get; } } } diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs index 77607b31a..549847110 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs @@ -906,7 +906,10 @@ namespace GameCult.Aetheria.State.Unity var thermotoggleTargetTemperature = ReadFieldDouble(ref reader, behaviorFields, 46); var switchActivated = ReadFieldBool(ref reader, behaviorFields, 47); var triggerPulled = ReadFieldBool(ref reader, behaviorFields, 48); - SkipRemaining(ref reader, behaviorFields, 49); + var statModifierApplied = ReadFieldBool(ref reader, behaviorFields, 49); + var statModifierExecuted = ReadFieldBool(ref reader, behaviorFields, 50); + var statModifierTargetStatCount = ReadFieldInt32(ref reader, behaviorFields, 51); + SkipRemaining(ref reader, behaviorFields, 52); behaviorStates[behavior] = new AetheriaRuntimeBehaviorStateSnapshot( ownerKind, ownerIndex, @@ -956,7 +959,10 @@ namespace GameCult.Aetheria.State.Unity velocityLimit, thermotoggleTargetTemperature, switchActivated, - triggerPulled); + triggerPulled, + statModifierApplied, + statModifierExecuted, + statModifierTargetStatCount); } return behaviorStates; diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateCommitDocument.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateCommitDocument.cs index 8a2f54121..b0c7ecbaf 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateCommitDocument.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateCommitDocument.cs @@ -842,5 +842,14 @@ namespace GameCult.Aetheria.State.Unity [Key(48)] public bool TriggerPulled { get; set; } + + [Key(49)] + public bool StatModifierApplied { get; set; } + + [Key(50)] + public bool StatModifierExecuted { get; set; } + + [Key(51)] + public int StatModifierTargetStatCount { get; set; } } } diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 58e41faca..08bd75ebd 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -178,7 +178,8 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. evaluated thrust, and torque rows. Shields publish evaluated efficiency and energy usage, velocity limiters publish evaluated limit, and thermotoggles publish their active target temperature. Switches publish activated state, - and triggers publish pending pulled state. + triggers publish pending pulled state, and stat modifiers publish + applied/executed flags plus target-stat count. `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. @@ -825,6 +826,8 @@ First Aetheria surfaces to publish: VelocityLimit limit, and Thermotoggle target temperature. - Done: extend behavior state rows for Switch activation and Trigger pending pull state. + - Done: extend behavior state rows for StatModifier applied/executed flags + and target-stat count. - 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.