From 01fc810eb4ad8045c2f26876c5e01826706e548b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 16 Jun 2026 09:01:05 +0100 Subject: [PATCH] Restore behavior runtime state from typed Continue --- .voidbot/state/aetheria.cc | Bin 148330 -> 151460 bytes Aetheria.State.Verify/Program.cs | 5 + Aetheria.State/README.md | 8 +- Assets/Scripts/Gameplay/ActionGameManager.cs | 179 ++++++++++++++++++ .../ServerShared/Behaviors/AetherDrive.cs | 14 ++ .../ServerShared/Behaviors/Capacitor.cs | 7 + .../ServerShared/Behaviors/ChargedWeapon.cs | 26 ++- .../ServerShared/Behaviors/ConstantWeapon.cs | 14 ++ .../ServerShared/Behaviors/InstantWeapon.cs | 18 ++ .../ServerShared/Behaviors/LockWeapon.cs | 25 ++- .../ServerShared/Behaviors/MiningTool.cs | 7 + .../ServerShared/Behaviors/Radiator.cs | 14 ++ .../Scripts/ServerShared/Behaviors/Reactor.cs | 6 + .../ServerShared/Behaviors/ResourceScanner.cs | 16 ++ .../Scripts/ServerShared/Behaviors/Sensor.cs | 13 ++ .../Scripts/ServerShared/Behaviors/Shield.cs | 6 + .../ServerShared/Behaviors/StatModifier.cs | 11 ++ .../ServerShared/Behaviors/Thruster.cs | 6 + .../Scripts/ServerShared/Behaviors/Trigger.cs | 5 + .../Behaviors/TurretController.cs | 6 + .../ServerShared/Behaviors/VelocityLimit.cs | 5 + .../Scripts/ServerShared/Behaviors/Weapon.cs | 5 + docs/aetheria-perfect-machine-map.md | 23 ++- 23 files changed, 406 insertions(+), 13 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 065ffb53a0262943df078148ed56a49c88a99027..05efe6c7e289cf870b9a6eaf5a3a415fba21d8ac 100644 GIT binary patch delta 2817 zcmd6p&u<$=6vtUN1%i+&l$J&a$fO6LBD-~x#&*J?3QY=?K%g|@ke+6D$M%rjoz2Xw zjeA+42!uo{Q4C#iDnI%oDO5z_kV~b~1HGp=OZ){$9Js&{-pqP8mh%G@A;Hahv!3_f z_r3Rd^UH^W*RBq3+$cOTRhpTqSf$C6OP7r!?Vk!CXO@#iZD9v4C<}~rQD~KWF!ek4GlwsV zK9?xOvW^1QL>_B`J}6WoK^87*5*)Gs;lRzEARa;bK0%x{1+uZToCe|120q*($0=GJ-^#j4wmh4cds|vMfN`i%7^pp%dV|N^6j3%VXHh^8?qY%J_CbskCDd z4nfRQIg5}j6C^O?h9d}oQ`rJf;585^3S7bwMvg~t0Ka@JjOAo>)fkF9cV=C;tFsnL z`H2DtipEuix*9_MkeZTLORpUJxfof+p{%`C?F#VPF~KVWFomN_oj6C<6;l zsQg(ZQLc?Z5SUQi?a>R6gY7X}Sht`okn94ficeR+;iTG`YH#u3WMjZM*8b?Fq4VeZ zx^qY8WWndDY87<5>Q2ee^CqxTN0xT<<#FTb_Oau`^YgD}Lzb$rTWjb(ha^B)sCPq2 znh9K`#B)V*`HFGGFxwaJm{%?t2iw0sGj#BcMJRInt3RF{%R}i-7Tz%+dFicWHZ~3) zDlHbvGbxIS6Xm7ksY>DSTYbiB64%6MYZ(N-P1&Ifz6K@H1o=L5-6crMA44JW|abg^M2OnJ_Q$w4u}fmMB0U>*khgF z&j1~&$<_m7I37bdN16z52pdwSOF*%$MuLb2#B1$KIfzVeCY?YA{XWUlX;x~17J6#* z67w#o~Gty87c}>__9tc(2d? z350Laz=>=<5TE33_KzufyIgoadv}(~>Lr?7Di`i%rgHieWd|NjRw@OSn=AUuKP!dz TGgDkKF!n$7qS2eiA~ODu7U{}8AF6PSmb4m zbz9dKCugMQCWfUJ6=&w>F|I7m$S*1hNiE8q(d@#q-GzlwypU%_Zfb6RQD$oK9R~63 zzpEJcALLn;nU`Felvo1PGhuqL4U@{`i_8)*E6mJ5R$PT~Eul8%GqX)!?ZT7~6}L2m dh)=h4Wom?p8AHUj-*ja<$jJrqn5CI%6aa+zN)`YB diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index f3c6d3553..bc1a9d79a 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -854,6 +854,11 @@ static void RequireMainMenuContinueRunState(string root) "string.Equals(entitySnapshot.RecordKey, currentEntityKey", "BindToEntity(currentEntity)", "RestoreActiveConsumablesFromTypedEntitySnapshot(entity, entitySnapshot)", + "RestoreRuntimeBehaviorStateFromTypedSnapshot(entity, entitySnapshot, restoredEntities)", + "ResolveRuntimeBehavior(entity, weaponState.OwnerKind, weaponState.OwnerIndex, weaponState.BehaviorIndex)", + "lockWeapon.RestoreRuntimeState(", + "drive.RestoreRuntimeState(", + "resourceScanner.RestoreRuntimeState(", "entity.RestoreStatGrids(entitySnapshot.StatGrids)", "RestoreThermalExposure((float)entitySnapshot.Heatstroke, (float)entitySnapshot.Hypothermia)", "entity.HeatsinksEnabled = entitySnapshot.HeatsinksEnabled", diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index a539445e9..5f6fac41c 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -182,8 +182,12 @@ docked children, into exact typed entity snapshot records. Continue restore lowers the current zone entity graph from those records, including position, velocity, target/contact state, child/docking relationships, shutdown/heatsink state, thermal exposure, active consumable timers, and typed -stat grids for temperature, thermal mass, armor, max armor, and hull conductivity. Broader runtime object graphs -such as behavior-private simulation state remain legacy until dedicated typed runtime documents exist. Live behavior +stat grids for temperature, thermal mass, armor, max armor, and hull +conductivity. Continue also lowers typed weapon and behavior runtime rows back +into live equipped-item and active-consumable behavior instances through +behavior-owned restore methods; construction/loadout blueprints do not own +behavior replay. Broader runtime object graphs without typed rows remain legacy +until dedicated typed runtime documents exist. Live behavior instances expose typed behavior kind and group through `Behavior.Kind` and `Behavior.Group`; behavior construction now reads typed payload fields through `RuntimeBehaviorDefinition` instead of projecting through config DTOs. Stat diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index b25f29b2a..fad046b5b 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -2612,6 +2612,7 @@ public class ActionGameManager : MonoBehaviour entity.RestoreStatGrids(entitySnapshot.StatGrids); entity.RestoreThermalExposure((float)entitySnapshot.Heatstroke, (float)entitySnapshot.Hypothermia); RestoreActiveConsumablesFromTypedEntitySnapshot(entity, entitySnapshot); + RestoreRuntimeBehaviorStateFromTypedSnapshot(entity, entitySnapshot, restoredEntities); RestoreEntityContactsFromTypedSnapshot(entity, entitySnapshot, restoredEntities); if (restoredEntities.TryGetValue(entitySnapshot.TargetEntityKey, out var target)) entity.Target.Value = target; @@ -2738,6 +2739,184 @@ public class ActionGameManager : MonoBehaviour } } + private void RestoreRuntimeBehaviorStateFromTypedSnapshot( + Entity entity, + AetheriaRuntimeEntitySnapshot snapshot, + IReadOnlyDictionary restoredEntities) + { + foreach (var weaponState in snapshot.WeaponStates) + { + if (!(ResolveRuntimeBehavior(entity, weaponState.OwnerKind, weaponState.OwnerIndex, weaponState.BehaviorIndex) is Weapon weapon)) + continue; + + if (weapon is LockWeapon lockWeapon) + { + restoredEntities.TryGetValue(weaponState.LockTargetEntityKey, out var lockTarget); + lockWeapon.RestoreRuntimeState( + weaponState.Firing, + weaponState.Ammo, + weaponState.BurstRemaining, + (float)weaponState.BurstTimer, + (float)weaponState.BurstInterval, + (float)weaponState.CooldownProgress, + weaponState.CoolingDown, + (float)weaponState.LockProgress, + lockTarget); + } + else if (weapon is ChargedWeapon chargedWeapon) + { + chargedWeapon.RestoreRuntimeState( + weaponState.Firing, + weaponState.Ammo, + weaponState.BurstRemaining, + (float)weaponState.BurstTimer, + (float)weaponState.BurstInterval, + (float)weaponState.CooldownProgress, + weaponState.CoolingDown, + weaponState.Charging, + weaponState.Charged, + (float)weaponState.Charge); + } + else if (weapon is ConstantWeapon constantWeapon) + { + constantWeapon.RestoreRuntimeState( + weaponState.Firing, + weaponState.Ammo, + (float)weaponState.AmmoIntervalProgress, + (float)weaponState.ReloadProgress, + weaponState.Reloading); + } + else if (weapon is InstantWeapon instantWeapon) + { + instantWeapon.RestoreRuntimeState( + weaponState.Firing, + weaponState.Ammo, + weaponState.BurstRemaining, + (float)weaponState.BurstTimer, + (float)weaponState.BurstInterval, + (float)weaponState.CooldownProgress, + weaponState.CoolingDown); + } + else + { + weapon.RestoreRuntimeState(weaponState.Firing); + } + } + + foreach (var behaviorState in snapshot.BehaviorStates) + { + var behavior = ResolveRuntimeBehavior(entity, behaviorState.OwnerKind, behaviorState.OwnerIndex, behaviorState.BehaviorIndex); + switch (behavior) + { + case Sensor sensor: + sensor.RestoreRuntimeState( + behaviorState.Pinging, + (float)behaviorState.PingCooldown, + (float)behaviorState.PingLerp, + (float)behaviorState.PingRadius); + break; + case Radiator radiator: + radiator.RestoreRuntimeState( + (float)behaviorState.RadiatorTemperature, + (float)behaviorState.Emissivity, + (float)behaviorState.PumpedHeat, + (float)behaviorState.WasteHeat, + (float)behaviorState.EnergyUsage); + break; + case Reactor reactor: + reactor.RestoreRuntimeState( + (float)behaviorState.ReactorDraw, + (float)behaviorState.ReactorLoadRatio); + break; + case Capacitor capacitor: + capacitor.RestoreRuntimeState( + (float)behaviorState.CapacitorCharge, + (float)behaviorState.CapacitorCapacity, + (float)behaviorState.CapacitorEfficiency); + break; + case AetherDrive drive: + drive.RestoreRuntimeState( + new float3((float)behaviorState.AetherDriveAxisX, (float)behaviorState.AetherDriveAxisY, (float)behaviorState.AetherDriveAxisZ), + new float3((float)behaviorState.AetherDriveThrustX, (float)behaviorState.AetherDriveThrustY, (float)behaviorState.AetherDriveThrustZ), + new float3((float)behaviorState.AetherDriveRpmX, (float)behaviorState.AetherDriveRpmY, (float)behaviorState.AetherDriveRpmZ), + (float)behaviorState.AetherDriveMaximumRpm, + new float2((float)behaviorState.AetherDriveThrustDirectionX, (float)behaviorState.AetherDriveThrustDirectionY)); + break; + case ResourceScanner resourceScanner: + resourceScanner.RestoreRuntimeState( + ParseLegacyGuidFromReferenceKey(behaviorState.ResourceScannerTargetBodyId, "aetheria.body"), + behaviorState.ResourceScannerAsteroidIndex, + (float)behaviorState.ResourceScannerScanTime, + (float)behaviorState.ResourceScannerRange, + (float)behaviorState.ResourceScannerMinimumDensity, + (float)behaviorState.ResourceScannerScanDuration); + break; + case MiningTool miningTool: + miningTool.RestoreRuntimeState( + ParseLegacyGuidFromReferenceKey(behaviorState.MiningToolAsteroidBeltId, "aetheria.body"), + behaviorState.MiningToolAsteroidIndex, + (float)behaviorState.MiningToolRange); + break; + case Thruster thruster: + thruster.RestoreRuntimeState( + (float)behaviorState.ThrusterAxis, + (float)behaviorState.ThrusterThrust); + break; + case Shield shield: + shield.RestoreRuntimeState( + (float)behaviorState.ShieldEfficiency, + (float)behaviorState.ShieldEnergyUsage); + break; + case VelocityLimit velocityLimit: + velocityLimit.RestoreRuntimeState((float)behaviorState.VelocityLimit); + break; + case Thermotoggle thermotoggle: + thermotoggle.TargetTemperature = (float)behaviorState.ThermotoggleTargetTemperature; + break; + case Switch switchBehavior: + switchBehavior.Activated = behaviorState.SwitchActivated; + break; + case Trigger trigger: + trigger.RestoreRuntimeState(behaviorState.TriggerPulled); + break; + case StatModifier statModifier: + statModifier.RestoreRuntimeState( + behaviorState.StatModifierApplied, + behaviorState.StatModifierExecuted); + break; + case TurretController turretController: + turretController.RestoreRuntimeState( + (float)behaviorState.TurretControllerShotSpeed, + behaviorState.TurretControllerPredictShots); + break; + } + } + } + + private static Behavior ResolveRuntimeBehavior(Entity entity, string ownerKind, int ownerIndex, int behaviorIndex) + { + var behaviors = ResolveRuntimeBehaviorList(entity, ownerKind, ownerIndex); + return behaviors != null && behaviorIndex >= 0 && behaviorIndex < behaviors.Count + ? behaviors[behaviorIndex] + : null; + } + + private static IReadOnlyList ResolveRuntimeBehaviorList(Entity entity, string ownerKind, int ownerIndex) + { + if (entity == null || ownerIndex < 0) + return null; + + switch (ownerKind) + { + case "equipment": + return ownerIndex < entity.Equipment.Count ? entity.Equipment[ownerIndex].Behaviors : null; + case "active_consumable": + return ownerIndex < entity.ActiveConsumables.Count ? entity.ActiveConsumables[ownerIndex].Behaviors : null; + default: + return null; + } + } + private static GalaxyZone ResolveStartZone(AetheriaRuntimeRunStateSnapshot run) { if (CurrentGalaxy?.Zones == null || CurrentGalaxy.Zones.Length == 0) diff --git a/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs b/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs index 032f8c543..2fd63cae5 100644 --- a/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs +++ b/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs @@ -135,4 +135,18 @@ public class AetherDrive : Behavior return false; } + + public void RestoreRuntimeState( + float3 axis, + float3 thrust, + float3 rpm, + float maximumRpm, + float2 thrustDirection) + { + Axis = axis; + Thrust = thrust; + Rpm = rpm; + MaximumRpm = maximumRpm; + ThrustDirection = thrustDirection; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Capacitor.cs b/Assets/Scripts/ServerShared/Behaviors/Capacitor.cs index 002234f17..f4bda3fb7 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Capacitor.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Capacitor.cs @@ -43,4 +43,11 @@ public class Capacitor : Behavior Efficiency = Evaluate(_efficiency); return true; } + + public void RestoreRuntimeState(float charge, float capacity, float efficiency) + { + Charge = clamp(charge, 0, capacity); + Capacity = capacity; + Efficiency = efficiency; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/ChargedWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/ChargedWeapon.cs index a79351924..5104e6a50 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ChargedWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ChargedWeapon.cs @@ -168,5 +168,29 @@ public class ChargedWeapon : InstantWeapon _charging = false; } } -} + public void RestoreRuntimeState( + bool firing, + int ammo, + int burstRemaining, + float burstTimer, + float burstInterval, + float cooldownProgress, + bool coolingDown, + bool charging, + bool charged, + float charge) + { + base.RestoreRuntimeState( + firing, + ammo, + burstRemaining, + burstTimer, + burstInterval, + cooldownProgress, + coolingDown); + _charging = charging; + _charged = charged; + _charge = charge; + } +} diff --git a/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs index 1dc8aad70..135449c0a 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs @@ -134,4 +134,18 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior OnStopFiring?.Invoke(); } } + + public void RestoreRuntimeState( + bool firing, + int ammo, + float ammoIntervalProgress, + float reloadProgress, + bool reloading) + { + base.RestoreRuntimeState(firing); + _ammo = ammo; + _ammoInterval = ammoIntervalProgress; + _reload = reloadProgress; + _reloading = reloading; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs index 6530e019a..68a24bd22 100644 --- a/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs @@ -194,4 +194,22 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior Trigger(); base.Activate(); } + + public void RestoreRuntimeState( + bool firing, + int ammo, + int burstRemaining, + float burstTimer, + float burstInterval, + float cooldownProgress, + bool coolingDown) + { + base.RestoreRuntimeState(firing); + _ammo = ammo; + _burstRemaining = burstRemaining; + _burstTimer = burstTimer; + _burstInterval = burstInterval; + _cooldown = cooldownProgress; + _coolingDown = coolingDown; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs index 4e1f6cda8..d5d564f8e 100644 --- a/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs @@ -93,5 +93,28 @@ public class LockWeapon : InstantWeapon return base.Execute(dt); } -} + public void RestoreRuntimeState( + bool firing, + int ammo, + int burstRemaining, + float burstTimer, + float burstInterval, + float cooldownProgress, + bool coolingDown, + float lockProgress, + Entity lockTarget) + { + base.RestoreRuntimeState( + firing, + ammo, + burstRemaining, + burstTimer, + burstInterval, + cooldownProgress, + coolingDown); + _lock = lockProgress; + _target = lockTarget; + _locking = lockTarget != null; + } +} diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs index 0fd00c456..aefced964 100644 --- a/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs +++ b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs @@ -62,4 +62,11 @@ public class MiningTool : Behavior return false; } + + public void RestoreRuntimeState(Guid asteroidBelt, int asteroid, float range) + { + AsteroidBelt = asteroidBelt; + Asteroid = asteroid; + Range = range; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Radiator.cs b/Assets/Scripts/ServerShared/Behaviors/Radiator.cs index 4ee732dec..8fff88746 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Radiator.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Radiator.cs @@ -90,4 +90,18 @@ public class Radiator : Behavior, IAlwaysUpdatedBehavior, IInitializableBehavior { RadiatorTemperature = Temperature; } + + public void RestoreRuntimeState( + float radiatorTemperature, + float emissivity, + float pumpedHeat, + float wasteHeat, + float energyUsage) + { + RadiatorTemperature = radiatorTemperature; + Emissivity = emissivity; + PumpedHeat = pumpedHeat; + WasteHeat = wasteHeat; + EnergyUsage = energyUsage; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Reactor.cs b/Assets/Scripts/ServerShared/Behaviors/Reactor.cs index b182b41dd..c9dbc6649 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Reactor.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Reactor.cs @@ -141,4 +141,10 @@ public class Reactor : Behavior, IOrderedBehavior, IDisposable foreach(var sub in _subscriptions) sub.Dispose(); } + + public void RestoreRuntimeState(float draw, float currentLoadRatio) + { + Draw = draw; + CurrentLoadRatio = currentLoadRatio; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs index ab9ac6151..b48c2ccf3 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs @@ -93,4 +93,20 @@ public class ResourceScanner : Behavior, IAlwaysUpdatedBehavior MinimumDensity = Evaluate(_minimumDensity); ScanDuration = Evaluate(_scanDuration); } + + public void RestoreRuntimeState( + Guid scanTarget, + int asteroid, + float scanTime, + float range, + float minimumDensity, + float scanDuration) + { + _scanTarget = scanTarget; + Asteroid = asteroid; + _scanTime = scanTime; + Range = range; + MinimumDensity = minimumDensity; + ScanDuration = scanDuration; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Sensor.cs b/Assets/Scripts/ServerShared/Behaviors/Sensor.cs index a7913b080..1ff077bb5 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Sensor.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Sensor.cs @@ -151,4 +151,17 @@ public class Sensor : Behavior, IEventBehavior } return true; } + + public void RestoreRuntimeState( + bool pinging, + float pingCooldown, + float pingLerp, + float pingRadius) + { + _pinging = pinging; + _pingCooldown = pingCooldown; + _pingLerp = pingLerp; + _pingRadius = pingRadius; + _pingedEntities.Clear(); + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Shield.cs b/Assets/Scripts/ServerShared/Behaviors/Shield.cs index 963649c79..6bf7e2cac 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Shield.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Shield.cs @@ -48,4 +48,10 @@ public class Shield : Behavior, IProgressBehavior } public virtual float Progress => Item.ThermalPerformance; + + public void RestoreRuntimeState(float efficiency, float energyUsage) + { + Efficiency = efficiency; + EnergyUsage = energyUsage; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs index 6e9308a81..91f2e2720 100644 --- a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs +++ b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs @@ -125,6 +125,17 @@ public class StatModifier : Behavior, IInitializableBehavior, IDisposable, IAlwa RemoveModifier(); _executed = false; } + + public void RestoreRuntimeState(bool applied, bool executed) + { + if (_stats == null) + Initialize(); + if (applied && !_applied) + ApplyModifier(); + if (!applied && _applied) + RemoveModifier(); + _executed = executed; + } } public enum StatModifierType diff --git a/Assets/Scripts/ServerShared/Behaviors/Thruster.cs b/Assets/Scripts/ServerShared/Behaviors/Thruster.cs index 176069902..12ddf2414 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Thruster.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Thruster.cs @@ -76,4 +76,10 @@ public class Thruster : Behavior, IAnalogBehavior } return false; } + + public void RestoreRuntimeState(float axis, float thrust) + { + Axis = axis; + Thrust = thrust; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Trigger.cs b/Assets/Scripts/ServerShared/Behaviors/Trigger.cs index 1080fb15f..5c9f92cff 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Trigger.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Trigger.cs @@ -31,4 +31,9 @@ public class Trigger : Behavior, IActivatedBehavior public void Deactivate() { } + + public void RestoreRuntimeState(bool pulled) + { + _pulled = pulled; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/TurretController.cs b/Assets/Scripts/ServerShared/Behaviors/TurretController.cs index 718212ed3..b42655d2c 100644 --- a/Assets/Scripts/ServerShared/Behaviors/TurretController.cs +++ b/Assets/Scripts/ServerShared/Behaviors/TurretController.cs @@ -84,4 +84,10 @@ public class TurretController : Behavior, IInitializableBehavior } return true; } + + public void RestoreRuntimeState(float shotSpeed, bool predictShots) + { + _shotSpeed = shotSpeed; + _predictShots = predictShots; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs b/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs index d9424bad6..a95e3ee51 100644 --- a/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs +++ b/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs @@ -33,4 +33,9 @@ public class VelocityLimit : Behavior Entity.Velocity = normalize(Entity.Velocity) * Limit; return true; } + + public void RestoreRuntimeState(float limit) + { + Limit = limit; + } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs index 8157dbe3d..10a220029 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs @@ -172,6 +172,11 @@ public abstract class Weapon : Behavior, IActivatedBehavior _firing = false; } + public virtual void RestoreRuntimeState(bool firing) + { + _firing = firing; + } + public float EvaluateRange() { return Evaluate(_range); diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 6773381d5..fb986ddbc 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -194,7 +194,11 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. publish their active target temperature. Switches publish activated state, triggers publish pending pulled state, and stat modifiers publish applied/executed flags plus target-stat count. Turret controllers publish - initialized weapon count, shot speed, and predictive-aim flag. + initialized weapon count, shot speed, and predictive-aim flag. Continue + restore lowers those typed weapon and behavior rows back into the live + equipped-item and active-consumable behavior instances through narrow + behavior-owned restore methods; construction/loadout blueprints do not own + behavior replay. `EntityConstructionBlueprint` 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. @@ -980,18 +984,19 @@ First Aetheria surfaces to publish: typed stat grids for temperature, thermal mass, armor, max armor, and hull-conductivity axes, then reconnects target/contact rows among restored entities, restores child/docking relationships from typed child keys and - docking-bay assignments, and binds the saved current entity as the player - ship or docked current ship. + docking-bay assignments, restores typed weapon and behavior runtime rows + into live behavior instances, and binds the saved current entity as the + player ship or docked current ship. - Done: project run checkpoint entity snapshots from the flattened live entity graph, not only `Zone.Entities`, so docked child ships can receive typed entity records and stable child/docking references instead of disappearing from the `.zone` replacement graph. - - Remaining: add typed documents/mappers for runtime object graphs, - complete full Continue/run entity graph reconstruction from typed state - for restored active-consumable behavior runtime internals, - behavior-private state not covered by progress, weapon, sensor, radiator, - reactor, or capacitor rows, typed behavior factory construction, and any - catalog fields not covered by the stable scalar/fingerprint/payload pass. + - Remaining: add typed documents/mappers for runtime object graphs not + covered by progress, weapon, sensor, radiator, reactor, capacitor, drive, + scanner, mining, thruster, shield, limiter, thermotoggle, switch, trigger, + stat-modifier, or turret rows; complete typed behavior factory + construction 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