diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index a71310eb6..fe58beeda 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 4276dd340..3bee98f0e 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -713,25 +713,62 @@ static void RequireMainMenuSettingsCommit(string root) } var source = File.ReadAllText(mainMenuPath); - if (!source.Contains("private void CommitRuntimeSettingsAndReturn()", StringComparison.Ordinal) || - !source.Contains("ActionGameManager.QueueRuntimePlayerSettingsCommit();", StringComparison.Ordinal)) + var actionGameManagerPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs"); + var actionGameManager = File.Exists(actionGameManagerPath) + ? File.ReadAllText(actionGameManagerPath) + : throw new InvalidOperationException("Cannot verify main-menu settings authority; ActionGameManager.cs is missing."); + + var requiredCommits = new[] + { + "CommitRuntimePlayerName", + "CommitRuntimeTemperatureUnit", + "CommitRuntimeSignificantDigits", + "CommitRuntimeNebulaQuality", + "CommitRuntimeShowAsteroidsInMinimap" + }; + + var missingCommits = requiredCommits + .Where(symbol => !actionGameManager.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (missingCommits.Length > 0) { throw new InvalidOperationException( - "MainMenu no longer exposes a shared typed player-settings commit return path."); + "ActionGameManager no longer owns complete runtime player-settings commit primitives: " + + string.Join(", ", missingCommits)); } - var graphicsSettings = ExtractMethodBody(source, "ShowGraphicsSettings"); - if (!graphicsSettings.Contains("CommitRuntimeSettingsAndReturn", StringComparison.Ordinal)) + var forbiddenSymbols = new[] + { + "ActionGameManager.RuntimePlayerSettings.Name =", + "ActionGameManager.RuntimePlayerSettings.GameplaySettings.TemperatureUnit =", + "ActionGameManager.RuntimePlayerSettings.GameplaySettings.SignificantDigits =", + "ActionGameManager.RuntimePlayerSettings.GraphicsSettings.NebulaQuality =", + "ActionGameManager.RuntimePlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap =" + }; + + var hits = File.ReadLines(mainMenuPath) + .Select((line, index) => new { LineNumber = index + 1, Line = line }) + .Where(line => forbiddenSymbols.Any(symbol => line.Line.Contains(symbol, StringComparison.Ordinal))) + .Select(line => $"{Path.GetRelativePath(root, mainMenuPath)}:{line.LineNumber}: {line.Line.Trim()}") + .ToArray(); + + if (hits.Length > 0) { throw new InvalidOperationException( - "MainMenu graphics settings can return without queuing the typed player-settings commit."); + "MainMenu still owns direct RuntimePlayerSettings mutation: " + + string.Join("; ", hits)); } - var gameplaySettings = ExtractMethodBody(source, "ShowGameplaySettings"); - if (!gameplaySettings.Contains("CommitRuntimeSettingsAndReturn", StringComparison.Ordinal)) + var missingUiCalls = requiredCommits + .Where(symbol => !source.Contains("ActionGameManager." + symbol, StringComparison.Ordinal)) + .ToArray(); + + if (missingUiCalls.Length > 0) { throw new InvalidOperationException( - "MainMenu gameplay settings can return without queuing the typed player-settings commit."); + "MainMenu no longer routes settings changes through ActionGameManager: " + + string.Join(", ", missingUiCalls)); } } @@ -1178,33 +1215,6 @@ static void RequireDockedCurrentShipCommitAuthority(string root) } } -static string ExtractMethodBody(string source, string methodName) -{ - var signature = "private void " + methodName + "()"; - var signatureIndex = source.IndexOf(signature, StringComparison.Ordinal); - if (signatureIndex < 0) - throw new InvalidOperationException($"Cannot find MainMenu.{methodName} for settings authority verification."); - - var braceIndex = source.IndexOf('{', signatureIndex); - if (braceIndex < 0) - throw new InvalidOperationException($"Cannot find MainMenu.{methodName} body for settings authority verification."); - - var depth = 0; - for (var index = braceIndex; index < source.Length; index++) - { - if (source[index] == '{') - depth++; - else if (source[index] == '}') - { - depth--; - if (depth == 0) - return source.Substring(braceIndex, index - braceIndex + 1); - } - } - - throw new InvalidOperationException($"MainMenu.{methodName} body is not balanced."); -} - static bool ContainsBehaviorValueKind(AetheriaBehaviorValue value, string kind) { return string.Equals(value.Kind, kind, StringComparison.OrdinalIgnoreCase) || diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index 93c00996b..c065e065f 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -85,6 +85,36 @@ public class ActionGameManager : MonoBehaviour QueueRuntimePlayerSettingsCommit(); } + public static void CommitRuntimePlayerName(string name) + { + RuntimePlayerSettings.Name = name ?? ""; + QueueRuntimePlayerSettingsCommit(); + } + + public static void CommitRuntimeTemperatureUnit(TemperatureUnit unit) + { + RuntimePlayerSettings.GameplaySettings.TemperatureUnit = unit; + QueueRuntimePlayerSettingsCommit(); + } + + public static void CommitRuntimeSignificantDigits(int significantDigits) + { + RuntimePlayerSettings.GameplaySettings.SignificantDigits = significantDigits; + QueueRuntimePlayerSettingsCommit(); + } + + public static void CommitRuntimeNebulaQuality(Quality quality) + { + RuntimePlayerSettings.GraphicsSettings.NebulaQuality = quality; + QueueRuntimePlayerSettingsCommit(); + } + + public static void CommitRuntimeShowAsteroidsInMinimap(bool show) + { + RuntimePlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap = show; + QueueRuntimePlayerSettingsCommit(); + } + private static RuntimePlayerSettings CreateDefaultRuntimePlayerSettings() { var settings = new RuntimePlayerSettings(); diff --git a/Assets/Scripts/UI/MainMenu.cs b/Assets/Scripts/UI/MainMenu.cs index 9c624146c..0e4bf36f2 100644 --- a/Assets/Scripts/UI/MainMenu.cs +++ b/Assets/Scripts/UI/MainMenu.cs @@ -213,14 +213,14 @@ public class MainMenu : MonoBehaviour _nextMenu.panel.Title.text = TitleSubtitle("gameplay", "settings"); _nextMenu.panel.AddField("Name", () => ActionGameManager.RuntimePlayerSettings.Name, - s => ActionGameManager.RuntimePlayerSettings.Name = s); + ActionGameManager.CommitRuntimePlayerName); _nextMenu.panel.AddField("Temperature Unit", () => (int) ActionGameManager.RuntimePlayerSettings.GameplaySettings.TemperatureUnit, - i => ActionGameManager.RuntimePlayerSettings.GameplaySettings.TemperatureUnit = (TemperatureUnit) i, + i => ActionGameManager.CommitRuntimeTemperatureUnit((TemperatureUnit) i), Enum.GetNames(typeof(TemperatureUnit))); _nextMenu.panel.AddField("Significant Digits", () => ActionGameManager.RuntimePlayerSettings.GameplaySettings.SignificantDigits, - i => ActionGameManager.RuntimePlayerSettings.GameplaySettings.SignificantDigits = i); + ActionGameManager.CommitRuntimeSignificantDigits); _nextMenu.panel.AddButton("Back", CommitRuntimeSettingsAndReturn); } @@ -233,13 +233,13 @@ public class MainMenu : MonoBehaviour () => (int)ActionGameManager.RuntimePlayerSettings.GraphicsSettings.NebulaQuality, i => { - ActionGameManager.RuntimePlayerSettings.GraphicsSettings.NebulaQuality = (Quality)i; + ActionGameManager.CommitRuntimeNebulaQuality((Quality)i); CloudRenderer.quality = ActionGameManager.RuntimePlayerSettings.GraphicsSettings.NebulaQuality; }, Enum.GetNames(typeof(Quality))); _nextMenu.panel.AddField("Show Asteroids in Minimap", () => ActionGameManager.RuntimePlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap, - b => ActionGameManager.RuntimePlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap = b); + ActionGameManager.CommitRuntimeShowAsteroidsInMinimap); _nextMenu.panel.AddButton("Back", CommitRuntimeSettingsAndReturn); } @@ -270,7 +270,6 @@ public class MainMenu : MonoBehaviour private void CommitRuntimeSettingsAndReturn() { - ActionGameManager.QueueRuntimePlayerSettingsCommit(); ShowSettings(); Fade(false); } diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 8d67c313f..551c58a34 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -86,10 +86,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. pointer into the typed Verse replacement for `PlayerSettings.msgpack`: player name, tutorial flag, story-file hash cursors, gameplay formatting, graphics preferences, input binding overrides, and action-bar inputs. Unity's menu and - input screens mutate `RuntimePlayerSettings` in memory and queue typed Verse - commits through shared player-settings commit primitives. Gameplay and - graphics settings now return through the same main-menu commit primitive; the - in-memory projection is not portable state authority. Aetheria has its own + input screens route edits through named player-settings commit primitives that + mutate the session `RuntimePlayerSettings` projection and queue typed Verse + commits. The in-memory projection is not portable state authority. Aetheria has its own remapping UI that calls Unity's InputSystem at the binding/action layer; Unity's generated `AetheriaInput` class is the edge consumer of typed binding overrides, not @@ -1600,6 +1599,10 @@ First Aetheria surfaces to publish: - Done: route main-menu graphics settings returns through the same typed player-settings commit primitive as gameplay settings, so graphics edits no longer survive only as session-local `RuntimePlayerSettings`. + - Done: route main-menu player name, gameplay formatting, and graphics + preference edits through named `ActionGameManager` commit methods. MainMenu + reads the `RuntimePlayerSettings` projection for display, but no longer + assigns its player/gameplay/graphics fields directly. - Remaining: delete or quarantine old cache abstractions that no longer protect an invariant once catalog migration has a typed reader.