Route main menu settings through commits

This commit is contained in:
Meta Vens 2026-06-16 04:04:59 +01:00
commit eb2f1a3d2b
5 changed files with 88 additions and 46 deletions

Binary file not shown.

View file

@ -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) ||

View file

@ -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();

View file

@ -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);
}

View file

@ -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.