From 7bb896f41ee4eb83af6de618765ddf5c1cd5504e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 16 Jun 2026 19:55:50 +0100 Subject: [PATCH] Complete typed behavior metadata coverage --- Aetheria.State.Verify/Program.cs | 67 +++++++++++++++++++ Assets/Scripts/UI/Menu/TradeMenu.cs | 9 +++ .../UI/Properties Panel/PropertiesPanel.cs | 5 ++ .../AetheriaRuntimeBehaviorMetadata.cs | 15 ++++- docs/aetheria-perfect-machine-map.md | 5 ++ 5 files changed, 99 insertions(+), 2 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index bcf3de70a..659fcc3ea 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -32,6 +32,7 @@ RequireMainMenuSettingsCommit(root); RequirePlayerSettingsEveSurface(root); RequireMainMenuContinueRunState(root); RequirePropertiesPanelReadOnlyInspector(root); +RequireTypedBehaviorMetadataCoverage(root); RequireNoDeadRuntimeProjectionCaches(root); RequireNoDeadInspectorMetadata(root); RequireRuntimeSimulationTuningCommits(root); @@ -489,6 +490,7 @@ Console.WriteLine("Renderer-local debug panels: obsolete uGUI field tester autho Console.WriteLine("Main-menu settings authority: player name, gameplay, and graphics settings return through typed player-settings commits"); Console.WriteLine("Main-menu Continue authority: Continue selects typed run state instead of a null button"); Console.WriteLine("PropertiesPanel inspector authority: dead generic reflection inspector path is deleted"); +Console.WriteLine("Typed behavior metadata authority: live heat/mining/thermotoggle payload kinds stay owned by package metadata"); Console.WriteLine("Runtime simulation tuning authority: UI writes flow through gameplay checkpoint commits"); Console.WriteLine("Hull conductivity authority: inventory UI toggles flow through gameplay checkpoint commits"); Console.WriteLine("Inventory entity rename authority: UI rename flows through gameplay checkpoint commits"); @@ -2419,6 +2421,71 @@ static void RequirePropertiesPanelReadOnlyInspector(string root) } } +static void RequireTypedBehaviorMetadataCoverage(string root) +{ + var metadataPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeBehaviorMetadata.cs"); + var propertiesPanelPath = Path.Combine(root, "Assets", "Scripts", "UI", "Properties Panel", "PropertiesPanel.cs"); + var tradeMenuPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "TradeMenu.cs"); + + var metadata = File.Exists(metadataPath) + ? File.ReadAllText(metadataPath) + : throw new InvalidOperationException("Cannot verify typed behavior metadata coverage; AetheriaRuntimeBehaviorMetadata.cs is missing."); + var propertiesPanel = File.Exists(propertiesPanelPath) + ? File.ReadAllText(propertiesPanelPath) + : throw new InvalidOperationException("Cannot verify typed behavior metadata coverage; PropertiesPanel.cs is missing."); + var tradeMenu = File.Exists(tradeMenuPath) + ? File.ReadAllText(tradeMenuPath) + : throw new InvalidOperationException("Cannot verify typed behavior metadata coverage; TradeMenu.cs is missing."); + + var requiredMetadataSymbols = new[] + { + "AetheriaRuntimeBehaviorFieldValueKind.Temperature", + "Behavior(\"Heat\", \"\", Stat(\"Heat\", 1))", + "Behavior(\"MiningTool\", \"\", Stat(\"DamagePerSecond\", 1), Stat(\"Efficiency\", 2), Stat(\"Penetration\", 3), Stat(\"Range\", 4))", + "Behavior(\"Switch\", \"\")", + "Behavior(\"Thermotoggle\", \"\", Temperature(\"TargetTemperature\", 1))", + "Behavior(\"Trigger\", \"\")", + "Temperature(\"TemperatureFloor\", 3)" + }; + + var missingMetadataSymbols = requiredMetadataSymbols + .Where(symbol => !metadata.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (missingMetadataSymbols.Length > 0) + { + throw new InvalidOperationException( + "Typed behavior metadata no longer covers live heat/mining/thermotoggle payloads and switch/trigger shells: " + + string.Join(", ", missingMetadataSymbols)); + } + + var requiredUiSymbols = new[] + { + "AetheriaRuntimeBehaviorFieldValueKind.Temperature", + "FormatTemperature" + }; + + var missingPropertiesSymbols = requiredUiSymbols + .Where(symbol => !propertiesPanel.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingPropertiesSymbols.Length > 0) + { + throw new InvalidOperationException( + "PropertiesPanel no longer renders typed temperature-bearing behavior metadata: " + + string.Join(", ", missingPropertiesSymbols)); + } + + var missingTradeSymbols = requiredUiSymbols + .Where(symbol => !tradeMenu.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (missingTradeSymbols.Length > 0) + { + throw new InvalidOperationException( + "TradeMenu no longer renders typed temperature-bearing behavior metadata: " + + string.Join(", ", missingTradeSymbols)); + } +} + static void RequireRuntimeSimulationTuningCommits(string root) { var requiredActionGameManagerPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs"); diff --git a/Assets/Scripts/UI/Menu/TradeMenu.cs b/Assets/Scripts/UI/Menu/TradeMenu.cs index 4da0c7fb3..4803295d7 100644 --- a/Assets/Scripts/UI/Menu/TradeMenu.cs +++ b/Assets/Scripts/UI/Menu/TradeMenu.cs @@ -263,6 +263,15 @@ public class TradeMenu : MonoBehaviour var value = GetTypedBehaviorNumber(x, behaviorFilter, field); return () => ActionGameManager.RuntimePlayerSettings.Format((float)value); }, x => + { + return (float)GetTypedBehaviorNumber(x, behaviorFilter, field); + })); + else if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.Temperature) + columns.Add((field.Name, 1, x => + { + var value = GetTypedBehaviorNumber(x, behaviorFilter, field); + return () => ActionGameManager.RuntimePlayerSettings.FormatTemperature((float)value); + }, x => { return (float)GetTypedBehaviorNumber(x, behaviorFilter, field); })); diff --git a/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs b/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs index 52787c37d..69fbf29a5 100644 --- a/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs +++ b/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs @@ -455,6 +455,11 @@ public class PropertiesPanel : MonoBehaviour var value = (float)(payloadField?.Value.NumberValue ?? 0); sheet.AddStat(field.Name.SplitCamelCase(), () => $"{ActionGameManager.RuntimePlayerSettings.Format(value)}"); } + else if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.Temperature) + { + var value = (float)(payloadField?.Value.NumberValue ?? 0); + sheet.AddStat(field.Name.SplitCamelCase(), () => $"{ActionGameManager.RuntimePlayerSettings.FormatTemperature(value)}"); + } else if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.Integer) { var value = (int)(payloadField?.Value.NumberValue ?? 0); diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeBehaviorMetadata.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeBehaviorMetadata.cs index e7feb2536..207198f86 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeBehaviorMetadata.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeBehaviorMetadata.cs @@ -8,7 +8,8 @@ namespace GameCult.Aetheria.State.Unity { Number, Integer, - PerformanceStat + PerformanceStat, + Temperature } public sealed class AetheriaRuntimeBehaviorFieldMetadata @@ -74,15 +75,20 @@ namespace GameCult.Aetheria.State.Unity Behavior(AetheriaRuntimeBehaviorKinds.AutoWeapon, AetheriaRuntimeBehaviorKinds.InstantWeapon, InstantWeaponFields), Behavior("Cooldown", "", Stat("Cooldown", 1)), Behavior("EnergyDraw", "", Stat("EnergyDraw", 1)), + Behavior("Heat", "", Stat("Heat", 1)), Behavior("HeatStorage", ""), Behavior("ItemUsage", ""), - Behavior("Radiator", "", Stat("Emissivity", 1), Stat("PumpedHeat", 2), Number("TemperatureFloor", 3), Stat("WasteHeat", 4), Stat("EnergyUsage", 5), Stat("ThermalMass", 6)), + Behavior("MiningTool", "", Stat("DamagePerSecond", 1), Stat("Efficiency", 2), Stat("Penetration", 3), Stat("Range", 4)), + Behavior("Radiator", "", Stat("Emissivity", 1), Stat("PumpedHeat", 2), Temperature("TemperatureFloor", 3), Stat("WasteHeat", 4), Stat("EnergyUsage", 5), Stat("ThermalMass", 6)), Behavior("Reactor", "", Stat("Charge", 1), Stat("Efficiency", 2), Stat("OverloadEfficiency", 3), Stat("ThrottlingFactor", 4)), Behavior("Reflector", "", Stat("CrossSection", 1)), Behavior("ResourceScanner", "", Stat("Range", 1), Stat("MinimumDensity", 2), Stat("ScanDuration", 3)), Behavior("Sensor", "", Stat("Sensitivity", 3), Stat("PingBoost", 5), Stat("PingEnergy", 6), Stat("PingVisibility", 7), Stat("PingRange", 8), Stat("PingCooldown", 9)), Behavior("Shield", "", Stat("Efficiency", 1), Stat("EnergyUsage", 2)), + Behavior("Switch", ""), + Behavior("Thermotoggle", "", Temperature("TargetTemperature", 1)), Behavior("Thruster", "", Stat("Thrust", 1), Stat("Visibility", 2), Stat("Heat", 3), Stat("EnergyUsage", 4)), + Behavior("Trigger", ""), Behavior("TurretController", ""), Behavior("VelocityConversion", "", Stat("Lambda", 1)), Behavior("VelocityLimit", "", Stat("TopSpeed", 1)), @@ -142,6 +148,11 @@ namespace GameCult.Aetheria.State.Unity return new AetheriaRuntimeBehaviorFieldMetadata(name, key, AetheriaRuntimeBehaviorFieldValueKind.Number); } + private static AetheriaRuntimeBehaviorFieldMetadata Temperature(string name, int key) + { + return new AetheriaRuntimeBehaviorFieldMetadata(name, key, AetheriaRuntimeBehaviorFieldValueKind.Temperature); + } + private static AetheriaRuntimeBehaviorFieldMetadata[] With( AetheriaRuntimeBehaviorFieldMetadata[] baseFields, params AetheriaRuntimeBehaviorFieldMetadata[] extraFields) diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 512014d7e..d211c78bc 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -1117,6 +1117,11 @@ First Aetheria surfaces to publish: - Done: move PropertiesPanel generic behavior stat display off `BehaviorData` reflection and onto package-owned typed behavior display metadata keyed by behavior kind and payload field key. + - Done: complete package-owned typed behavior metadata coverage for live + `Heat`, `MiningTool`, and `Thermotoggle` payload fields plus `Switch` and + `Trigger` shell kinds. `PropertiesPanel` and `TradeMenu` no longer + silently drop those typed behavior families, and temperature-bearing + payload values format through the runtime temperature unit. - Done: move TradeMenu behavior filter options, behavior family matching, and dynamic behavior columns off `BehaviorData` reflection and onto package-owned typed behavior metadata.