Add typed verse settings shell and command bridge
This commit is contained in:
parent
cff88b79e4
commit
fea05967f8
14 changed files with 765 additions and 5 deletions
|
|
@ -53,6 +53,7 @@ var eveStatus = new AetheriaEveCommandDrainStatus
|
|||
AppliedCatalogRefreshes = eveReport.AppliedCatalogRefreshes,
|
||||
AppliedOperationsRefreshes = eveReport.AppliedOperationsRefreshes,
|
||||
AppliedPlayerSettingsCommands = eveReport.AppliedPlayerSettingsCommands,
|
||||
AppliedVerseHostCommands = eveReport.AppliedVerseHostCommands,
|
||||
LastRejectedCommand = eveReport.LastRejectedCommand,
|
||||
LastRejectedReason = eveReport.LastRejectedReason,
|
||||
Status = eveReport.RejectedCommands > 0 ? "rejected" : "ok"
|
||||
|
|
@ -89,6 +90,7 @@ Console.WriteLine($"Eve commands rejected: {eveReport.RejectedCommands}");
|
|||
Console.WriteLine($"Eve catalog refreshes: {eveReport.AppliedCatalogRefreshes}");
|
||||
Console.WriteLine($"Eve operations refreshes: {eveReport.AppliedOperationsRefreshes}");
|
||||
Console.WriteLine($"Eve player settings commands: {eveReport.AppliedPlayerSettingsCommands}");
|
||||
Console.WriteLine($"Eve verse host commands: {eveReport.AppliedVerseHostCommands}");
|
||||
if (!deleteApplied)
|
||||
Console.WriteLine("Applied command files were kept because --keep was supplied.");
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
<Compile Include="..\..\Eve\packages\org.gamecult.eve.surface\Runtime\EveSurfaceDocument.cs" Link="EveSurfaceDocument.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeCatalogSnapshot.cs" Link="AetheriaRuntimeCatalogSnapshot.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeCatalogStore.cs" Link="AetheriaRuntimeCatalogStore.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeClientTargetCommands.cs" Link="AetheriaRuntimeClientTargetCommands.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeClientTargetSurfaceBuilder.cs" Link="AetheriaRuntimeClientTargetSurfaceBuilder.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeClientTargetStore.cs" Link="AetheriaRuntimeClientTargetStore.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeStateBoundary.cs" Link="AetheriaRuntimeStateBoundary.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeStateBoot.cs" Link="AetheriaRuntimeStateBoot.cs" />
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ RequireNoDeadPopupShells(root);
|
|||
RequirePlayerSettingsEveSurface(root);
|
||||
RequireVerseHostSettingsAuthority(root);
|
||||
RequireClientTargetBootAuthority(root);
|
||||
RequireVerseSettingsShellAndBridge(root);
|
||||
RequireMainMenuVerseHostProjection(root);
|
||||
RequireMainMenuContinueRunState(root);
|
||||
RequireDeadPropertiesPanelShellDeleted(root);
|
||||
|
|
@ -538,6 +539,7 @@ Console.WriteLine("NameTools editor shell: the remaining name helper window lowe
|
|||
Console.WriteLine("Runtime state reader authority: Unity gameplay/UI read typed state through a shared runtime reader instead of direct store spelunking");
|
||||
Console.WriteLine("Verse host authority: daemon-owned typed verse host settings now drive provider advertisement and operations telemetry");
|
||||
Console.WriteLine("Client target boot authority: Unity boot resolves the active Verse through a typed client target instead of local path folklore");
|
||||
Console.WriteLine("Verse settings shell: client target edits and Verse-host visibility commands lower through typed Eve surfaces");
|
||||
Console.WriteLine("Main-menu Verse projection: the Unity Eve shell lowers daemon-owned verse identity instead of ad-libbing local menu copy");
|
||||
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");
|
||||
|
|
@ -2464,11 +2466,14 @@ static void RequireMainMenuSettingsShellUsesEveSurface(string root)
|
|||
{
|
||||
"RenderMenuSurface(",
|
||||
"BuildSettingsSurfaceDefinition()",
|
||||
"BuildVerseSettingsSurfaceDefinition()",
|
||||
"BuildInputSettingsSurfaceDefinition(",
|
||||
"HandleSettingsSurfaceCommand(",
|
||||
"HandleVerseSettingsSurfaceCommand(",
|
||||
"HandleInputSettingsSurfaceCommand(",
|
||||
"WithBackAction(",
|
||||
"ShowPlayerSettingsCommand",
|
||||
"ShowVerseSettingsCommand",
|
||||
"ShowInputSettingsCommand",
|
||||
"BackToMainCommand",
|
||||
"BackToSettingsCommand"
|
||||
|
|
@ -2488,6 +2493,7 @@ static void RequireMainMenuSettingsShellUsesEveSurface(string root)
|
|||
var forbiddenSymbols = new[]
|
||||
{
|
||||
"_nextMenu.panel.AddButton(\"Player Settings\"",
|
||||
"_nextMenu.panel.AddButton(\"Verse\"",
|
||||
"_nextMenu.panel.AddButton(\"Input\"",
|
||||
"_nextMenu.panel.AddButton(\"Audio\"",
|
||||
"BuildAudioSettingsSurfaceDefinition(",
|
||||
|
|
@ -4035,6 +4041,225 @@ static void RequireClientTargetBootAuthority(string root)
|
|||
}
|
||||
}
|
||||
|
||||
static void RequireVerseSettingsShellAndBridge(string root)
|
||||
{
|
||||
var unityFacadeProjectPath = Path.Combine(root, "Aetheria.State.Unity", "Aetheria.State.Unity.csproj");
|
||||
var stateProjectPath = Path.Combine(root, "Aetheria.State", "Aetheria.State.csproj");
|
||||
var clientTargetCommandsPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeClientTargetCommands.cs");
|
||||
var clientTargetSurfaceBuilderPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeClientTargetSurfaceBuilder.cs");
|
||||
var verseHostCommandsPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeVerseHostCommands.cs");
|
||||
var clientTargetStorePath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeClientTargetStore.cs");
|
||||
var mainMenuPath = Path.Combine(root, "Assets", "Scripts", "UI", "MainMenu.cs");
|
||||
var commandBridgePath = Path.Combine(root, "Aetheria.State", "AetheriaEveCommandBridge.cs");
|
||||
var drainStatusPath = Path.Combine(root, "Aetheria.State", "Documents", "AetheriaEveCommandDrainStatus.cs");
|
||||
var operationsProjectorPath = Path.Combine(root, "Aetheria.State", "AetheriaOperationsSurfaceProjector.cs");
|
||||
var applyPendingPath = Path.Combine(root, "Aetheria.State.ApplyPending", "Program.cs");
|
||||
var economyServerPath = Path.Combine(root, "Economy.Server", "Program.cs");
|
||||
|
||||
var requiredFiles = new[]
|
||||
{
|
||||
unityFacadeProjectPath,
|
||||
stateProjectPath,
|
||||
clientTargetCommandsPath,
|
||||
clientTargetSurfaceBuilderPath,
|
||||
verseHostCommandsPath,
|
||||
clientTargetStorePath,
|
||||
mainMenuPath,
|
||||
commandBridgePath,
|
||||
drainStatusPath,
|
||||
operationsProjectorPath,
|
||||
applyPendingPath,
|
||||
economyServerPath
|
||||
};
|
||||
|
||||
var missingFiles = requiredFiles
|
||||
.Where(path => !File.Exists(path))
|
||||
.Select(path => Path.GetRelativePath(root, path))
|
||||
.ToArray();
|
||||
if (missingFiles.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Verse settings shell/bridge cannot be verified because required files are missing: " +
|
||||
string.Join(", ", missingFiles));
|
||||
}
|
||||
|
||||
var unityFacadeProject = File.ReadAllText(unityFacadeProjectPath);
|
||||
var stateProject = File.ReadAllText(stateProjectPath);
|
||||
var clientTargetCommands = File.ReadAllText(clientTargetCommandsPath);
|
||||
var clientTargetSurfaceBuilder = File.ReadAllText(clientTargetSurfaceBuilderPath);
|
||||
var verseHostCommands = File.ReadAllText(verseHostCommandsPath);
|
||||
var clientTargetStore = File.ReadAllText(clientTargetStorePath);
|
||||
var mainMenu = File.ReadAllText(mainMenuPath);
|
||||
var commandBridge = File.ReadAllText(commandBridgePath);
|
||||
var drainStatus = File.ReadAllText(drainStatusPath);
|
||||
var operationsProjector = File.ReadAllText(operationsProjectorPath);
|
||||
var applyPending = File.ReadAllText(applyPendingPath);
|
||||
var economyServer = File.ReadAllText(economyServerPath);
|
||||
|
||||
var requiredUnityFacadeSymbols = new[]
|
||||
{
|
||||
"AetheriaRuntimeClientTargetCommands.cs",
|
||||
"AetheriaRuntimeClientTargetSurfaceBuilder.cs"
|
||||
};
|
||||
var missingUnityFacadeSymbols = requiredUnityFacadeSymbols
|
||||
.Where(symbol => !unityFacadeProject.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingUnityFacadeSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Aetheria.State.Unity.csproj does not compile the Verse settings shell files: " +
|
||||
string.Join(", ", missingUnityFacadeSymbols));
|
||||
}
|
||||
|
||||
if (!stateProject.Contains("AetheriaRuntimeVerseHostCommands.cs", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Aetheria.State.csproj does not compile the Verse-host Eve command contract.");
|
||||
}
|
||||
|
||||
var requiredClientTargetCommandSymbols = new[]
|
||||
{
|
||||
"SurfaceId = \"aetheria.client_target\"",
|
||||
"CycleTargetKind",
|
||||
"SetTitle",
|
||||
"SetVerseId",
|
||||
"SetCultMeshAddress",
|
||||
"SetStateFilePath",
|
||||
"IsKnown"
|
||||
};
|
||||
var missingClientTargetCommandSymbols = requiredClientTargetCommandSymbols
|
||||
.Where(symbol => !clientTargetCommands.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingClientTargetCommandSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Client-target command contract is incomplete: " +
|
||||
string.Join(", ", missingClientTargetCommandSymbols));
|
||||
}
|
||||
|
||||
var requiredVerseHostCommandSymbols = new[]
|
||||
{
|
||||
"SurfaceId = \"aetheria.verse_host_settings\"",
|
||||
"CycleVisibility",
|
||||
"Refresh",
|
||||
"IsKnown"
|
||||
};
|
||||
var missingVerseHostCommandSymbols = requiredVerseHostCommandSymbols
|
||||
.Where(symbol => !verseHostCommands.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingVerseHostCommandSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Verse-host command contract is incomplete: " +
|
||||
string.Join(", ", missingVerseHostCommandSymbols));
|
||||
}
|
||||
|
||||
var requiredSurfaceBuilderSymbols = new[]
|
||||
{
|
||||
"public sealed class AetheriaRuntimeClientTargetSurfaceState",
|
||||
"\"Client Target\"",
|
||||
"\"Target Fields\"",
|
||||
"\"Daemon Verse Host\"",
|
||||
"AetheriaRuntimeClientTargetCommands.SetStateFilePath",
|
||||
"AetheriaRuntimeVerseHostCommands.CycleVisibility",
|
||||
"AetheriaRuntimeVerseHostCommands.Refresh"
|
||||
};
|
||||
var missingSurfaceBuilderSymbols = requiredSurfaceBuilderSymbols
|
||||
.Where(symbol => !clientTargetSurfaceBuilder.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingSurfaceBuilderSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Client-target Eve surface builder is incomplete: " +
|
||||
string.Join(", ", missingSurfaceBuilderSymbols));
|
||||
}
|
||||
|
||||
if (!clientTargetStore.Contains("Update(", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Client-target store no longer exposes typed update ownership for local target edits.");
|
||||
}
|
||||
|
||||
var requiredMainMenuSymbols = new[]
|
||||
{
|
||||
"VerseSettingsShellSurfaceId",
|
||||
"ShowVerseSettingsCommand",
|
||||
"ShowVerseSettingsSurface()",
|
||||
"HandleVerseSettingsSurfaceCommand(EveSurfaceCommandRequest request)",
|
||||
"BuildVerseSettingsSurfaceDefinition()",
|
||||
"AetheriaRuntimeClientTargetSurfaceBuilder.Build(",
|
||||
"TryCommitClientTargetCommand(",
|
||||
"TryQueueVerseHostCommand(",
|
||||
"AetheriaRuntimeClientTargetStore.Update(",
|
||||
"new EveSurfaceCommandRequest(",
|
||||
"AetheriaRuntimeVerseHostCommands.SurfaceId"
|
||||
};
|
||||
var missingMainMenuSymbols = requiredMainMenuSymbols
|
||||
.Where(symbol => !mainMenu.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingMainMenuSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"MainMenu no longer owns the typed Verse settings shell handoff: " +
|
||||
string.Join(", ", missingMainMenuSymbols));
|
||||
}
|
||||
|
||||
var requiredBridgeSymbols = new[]
|
||||
{
|
||||
"AppliedVerseHostCommands",
|
||||
"AetheriaRuntimeVerseHostCommands.Refresh",
|
||||
"AetheriaRuntimeVerseHostCommands.CycleVisibility",
|
||||
"ApplyVerseHostCommandAsync",
|
||||
"PutVerseHostSettingsAsync",
|
||||
"PutProviderAdvertisementAsync",
|
||||
"AetheriaOperationsSurfaceProjector.Build(",
|
||||
"AetheriaRuntimeVerseHostCommands.IsKnown(command)"
|
||||
};
|
||||
var missingBridgeSymbols = requiredBridgeSymbols
|
||||
.Where(symbol => !commandBridge.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingBridgeSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Aetheria Eve command bridge no longer routes Verse-host commands through the provider owner: " +
|
||||
string.Join(", ", missingBridgeSymbols));
|
||||
}
|
||||
|
||||
var requiredDrainSymbols = new[]
|
||||
{
|
||||
"AppliedVerseHostCommands"
|
||||
};
|
||||
var missingDrainSymbols = requiredDrainSymbols
|
||||
.Where(symbol => !drainStatus.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingDrainSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Aetheria Eve command drain status no longer records Verse-host command counts.");
|
||||
}
|
||||
|
||||
if (!operationsProjector.Contains("Verse Host Commands", StringComparison.Ordinal) ||
|
||||
!operationsProjector.Contains("AppliedVerseHostCommands", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Operations surface no longer projects Verse-host Eve command counts.");
|
||||
}
|
||||
|
||||
if (!applyPending.Contains("AppliedVerseHostCommands = eveReport.AppliedVerseHostCommands", StringComparison.Ordinal) ||
|
||||
!applyPending.Contains("Eve verse host commands: {eveReport.AppliedVerseHostCommands}", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Aetheria.State.ApplyPending no longer publishes Verse-host Eve command totals.");
|
||||
}
|
||||
|
||||
if (!economyServer.Contains("AppliedVerseHostCommands = report.AppliedVerseHostCommands", StringComparison.Ordinal) ||
|
||||
!economyServer.Contains("verseHost={report.AppliedVerseHostCommands}", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Economy.Server no longer publishes Verse-host Eve command totals.");
|
||||
}
|
||||
}
|
||||
|
||||
static void RequireMainMenuVerseHostProjection(string root)
|
||||
{
|
||||
var packageSnapshotPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeCatalogSnapshot.cs");
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeStateCommitDocument.cs" Link="AetheriaRuntimeStateCommitDocument.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeEveCommandDocument.cs" Link="AetheriaRuntimeEveCommandDocument.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimePendingCultCacheStore.cs" Link="AetheriaRuntimePendingCultCacheStore.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeVerseHostCommands.cs" Link="AetheriaRuntimeVerseHostCommands.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimePlayerSettingsSurfaceBuilder.cs" Link="AetheriaRuntimePlayerSettingsSurfaceBuilder.cs" />
|
||||
<Compile Include="..\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimePlayerSettingsCommands.cs" Link="AetheriaRuntimePlayerSettingsCommands.cs" />
|
||||
<ProjectReference Include="..\..\CultLib\src\GameCult.Caching\GameCult.Caching.csproj" />
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ public sealed class AetheriaEveCommandApplyReport
|
|||
public int AppliedCatalogRefreshes { get; set; }
|
||||
public int AppliedOperationsRefreshes { get; set; }
|
||||
public int AppliedPlayerSettingsCommands { get; set; }
|
||||
public int AppliedVerseHostCommands { get; set; }
|
||||
public int RejectedCommands { get; set; }
|
||||
public string[] AcceptedPaths { get; set; } = [];
|
||||
public string[] RejectedPaths { get; set; } = [];
|
||||
|
|
@ -85,6 +86,11 @@ public static class AetheriaEveCommandBridge
|
|||
await ApplyPlayerSettingsCommandAsync(node, command).ConfigureAwait(false);
|
||||
report.AppliedPlayerSettingsCommands++;
|
||||
break;
|
||||
case GameCult.Aetheria.State.Unity.AetheriaRuntimeVerseHostCommands.Refresh:
|
||||
case GameCult.Aetheria.State.Unity.AetheriaRuntimeVerseHostCommands.CycleVisibility:
|
||||
await ApplyVerseHostCommandAsync(node, command).ConfigureAwait(false);
|
||||
report.AppliedVerseHostCommands++;
|
||||
break;
|
||||
}
|
||||
|
||||
accepted.Add(path);
|
||||
|
|
@ -122,7 +128,9 @@ public static class AetheriaEveCommandBridge
|
|||
(string.Equals(surfaceId, AetheriaOperationsSurfaceProjector.SurfaceId, StringComparison.Ordinal) &&
|
||||
string.Equals(command, "aetheria.operations.refresh", StringComparison.Ordinal)) ||
|
||||
(string.Equals(surfaceId, AetheriaPlayerSettingsSurfaceProjector.SurfaceId, StringComparison.Ordinal) &&
|
||||
GameCult.Aetheria.State.Unity.AetheriaRuntimePlayerSettingsCommands.IsKnown(command));
|
||||
GameCult.Aetheria.State.Unity.AetheriaRuntimePlayerSettingsCommands.IsKnown(command)) ||
|
||||
(string.Equals(surfaceId, GameCult.Aetheria.State.Unity.AetheriaRuntimeVerseHostCommands.SurfaceId, StringComparison.Ordinal) &&
|
||||
GameCult.Aetheria.State.Unity.AetheriaRuntimeVerseHostCommands.IsKnown(command));
|
||||
}
|
||||
|
||||
private static async Task ApplyPlayerSettingsCommandAsync(
|
||||
|
|
@ -185,6 +193,46 @@ public static class AetheriaEveCommandBridge
|
|||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task ApplyVerseHostCommandAsync(
|
||||
AetheriaStateNode node,
|
||||
AetheriaRuntimeEveCommandDocument command)
|
||||
{
|
||||
var settings = await node.GetVerseHostSettingsAsync().ConfigureAwait(false) ?? new AetheriaVerseHostSettings();
|
||||
var normalized = AetheriaVerseHostSettingsNormalizer.Normalize(settings);
|
||||
var persistSettings = false;
|
||||
|
||||
switch (command.Command)
|
||||
{
|
||||
case GameCult.Aetheria.State.Unity.AetheriaRuntimeVerseHostCommands.CycleVisibility:
|
||||
normalized.Visibility = Cycle(normalized.Visibility, "private", "public");
|
||||
persistSettings = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (persistSettings)
|
||||
{
|
||||
normalized.LastUpdatedAtUtc = command.IssuedAtUtc;
|
||||
await node.PutVerseHostSettingsAsync(normalized).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var commitStatus = await node.GetRuntimeCommitDrainStatusAsync().ConfigureAwait(false) ??
|
||||
EmptyCommitDrainStatus(node.StatePath, command.IssuedAtUtc);
|
||||
var eveStatus = await node.GetEveCommandDrainStatusAsync().ConfigureAwait(false) ??
|
||||
EmptyEveCommandDrainStatus(node.StatePath, command.IssuedAtUtc);
|
||||
var runtimeSession = string.IsNullOrWhiteSpace(commitStatus.RuntimeId)
|
||||
? null
|
||||
: await node.GetRuntimeSessionAsync(commitStatus.RuntimeId).ConfigureAwait(false);
|
||||
|
||||
await node.PutOperationsSurfaceAsync(
|
||||
AetheriaOperationsSurfaceProjector.Build(
|
||||
commitStatus,
|
||||
eveStatus,
|
||||
normalized,
|
||||
runtimeSession)).ConfigureAwait(false);
|
||||
await node.PutProviderAdvertisementAsync(
|
||||
AetheriaProviderAdvertisementProjector.Build(normalized, node.StatePath, command.IssuedAtUtc)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string Cycle(string current, params string[] values)
|
||||
{
|
||||
if (values.Length == 0)
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ public static class AetheriaOperationsSurfaceProjector
|
|||
Metric("eveCommandDrain.catalogRefreshes", "Catalog Refreshes", (eveCommandStatus?.AppliedCatalogRefreshes ?? 0).ToString()),
|
||||
Metric("eveCommandDrain.operationsRefreshes", "Operations Refreshes", (eveCommandStatus?.AppliedOperationsRefreshes ?? 0).ToString()),
|
||||
Metric("eveCommandDrain.playerSettings", "Player Settings Commands", (eveCommandStatus?.AppliedPlayerSettingsCommands ?? 0).ToString()),
|
||||
Metric("eveCommandDrain.verseHost", "Verse Host Commands", (eveCommandStatus?.AppliedVerseHostCommands ?? 0).ToString()),
|
||||
Metric("eveCommandDrain.failures", "Consecutive Failures", (eveCommandStatus?.ConsecutiveFailures ?? 0).ToString()),
|
||||
Row(
|
||||
"eveCommandDrain.last",
|
||||
|
|
|
|||
|
|
@ -57,4 +57,7 @@ public sealed class AetheriaEveCommandDrainStatus
|
|||
|
||||
[Key(15)]
|
||||
public int AppliedPlayerSettingsCommands { get; set; }
|
||||
|
||||
[Key(16)]
|
||||
public int AppliedVerseHostCommands { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,9 @@ Unity Eve surfaces also emit typed `gamecult.eve.command.v1` documents under
|
|||
provider-owned acceptance organ for those commands: it validates the provider,
|
||||
surface, and command template before running the narrow refresh handlers for
|
||||
the catalog and operations surfaces plus the typed player-settings mutation
|
||||
handlers for gameplay/graphics Eve controls. Renderer callbacks do not accept
|
||||
commands or mutate game state locally.
|
||||
handlers for gameplay/graphics Eve controls and typed Verse-host visibility
|
||||
commands. Renderer callbacks do not accept commands or mutate game state
|
||||
locally.
|
||||
`AetheriaEveRuntimeBootstrap` mounts the `aetheria.operations` surface through a
|
||||
runtime-created `UIDocument` after scene load, with environment and command-line
|
||||
switches for diagnostics. UI Toolkit is now a live runtime lowering path, not
|
||||
|
|
@ -316,6 +317,10 @@ can read typed player settings for Unity boot, and can read the published Eve
|
|||
catalog surface. It does not deserialize legacy runtime projection objects and
|
||||
does not write daemon-owned Verse state. Unity can use this as the first
|
||||
package boundary once CultLib/Eve runtime packaging is available.
|
||||
Unity `MainMenu` now lowers a typed Verse settings shell over that split:
|
||||
client-target edits persist locally in `aetheria-client.cc`, while Verse-host
|
||||
visibility changes queue provider-owned Eve commands against the selected local
|
||||
Verse state file.
|
||||
`Galaxy` now consumes this package-owned runtime catalog for faction selection
|
||||
and name generation, so generated sectors use typed corporation v2 and
|
||||
`aetheria.name_file.v2` records instead of legacy `Faction`/`NameFile`
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@ public class MainMenu : MonoBehaviour
|
|||
private const string SettingsSurfaceId = "aetheria.main_menu.settings";
|
||||
private const string InputSettingsSurfaceId = "aetheria.main_menu.input_settings";
|
||||
private const string PlayerSettingsShellSurfaceId = "aetheria.main_menu.player_settings";
|
||||
private const string VerseSettingsShellSurfaceId = "aetheria.main_menu.verse_settings";
|
||||
private const string ContinueRunCommand = "aetheria.main_menu.root.continue";
|
||||
private const string NewGameCommand = "aetheria.main_menu.root.new_game";
|
||||
private const string ShowSettingsCommand = "aetheria.main_menu.root.show_settings";
|
||||
private const string QuitCommand = "aetheria.main_menu.root.quit";
|
||||
private const string OpenRuntimeInputScreenCommand = "aetheria.main_menu.input_settings.open_runtime_screen";
|
||||
private const string ShowPlayerSettingsCommand = "aetheria.main_menu.settings.show_player_settings";
|
||||
private const string ShowVerseSettingsCommand = "aetheria.main_menu.settings.show_verse_settings";
|
||||
private const string ShowInputSettingsCommand = "aetheria.main_menu.settings.show_input_settings";
|
||||
private const string BackToMainCommand = "aetheria.main_menu.settings.back_to_main";
|
||||
private const string BackToSettingsCommand = "aetheria.main_menu.settings.back_to_settings";
|
||||
|
|
@ -275,6 +277,17 @@ public class MainMenu : MonoBehaviour
|
|||
HandlePlayerSettingsSurfaceCommand);
|
||||
}
|
||||
|
||||
private void ShowVerseSettingsSurface()
|
||||
{
|
||||
RenderMenuSurface(
|
||||
WithBackAction(
|
||||
ToEveSurfaceDocument(BuildVerseSettingsSurfaceDefinition()),
|
||||
VerseSettingsShellSurfaceId,
|
||||
BackToSettingsCommand,
|
||||
"Back"),
|
||||
HandleVerseSettingsSurfaceCommand);
|
||||
}
|
||||
|
||||
private void RenderMenuSurface(
|
||||
EveSurfaceDocument document,
|
||||
Action<EveSurfaceCommandRequest> commandHandler)
|
||||
|
|
@ -315,6 +328,9 @@ public class MainMenu : MonoBehaviour
|
|||
case ShowPlayerSettingsCommand:
|
||||
ShowPlayerSettingsSurface();
|
||||
return;
|
||||
case ShowVerseSettingsCommand:
|
||||
ShowVerseSettingsSurface();
|
||||
return;
|
||||
case ShowInputSettingsCommand:
|
||||
ShowInputSettings();
|
||||
return;
|
||||
|
|
@ -366,6 +382,29 @@ public class MainMenu : MonoBehaviour
|
|||
ShowPlayerSettingsSurface();
|
||||
}
|
||||
|
||||
private void HandleVerseSettingsSurfaceCommand(EveSurfaceCommandRequest request)
|
||||
{
|
||||
if (string.Equals(request.Command, BackToSettingsCommand, StringComparison.Ordinal))
|
||||
{
|
||||
ShowSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryCommitClientTargetCommand(request.Command, request.Payload))
|
||||
{
|
||||
ShowVerseSettingsSurface();
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryQueueVerseHostCommand(request.Command, request.Payload))
|
||||
{
|
||||
ShowVerseSettingsSurface();
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Unknown verse-settings command: {request.Command}");
|
||||
}
|
||||
|
||||
private void HideMenuSurface()
|
||||
{
|
||||
if (_menuSurfaceDocument == null)
|
||||
|
|
@ -403,6 +442,27 @@ public class MainMenu : MonoBehaviour
|
|||
DateTime.UtcNow.ToString("O")));
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceDocument BuildVerseSettingsSurfaceDefinition()
|
||||
{
|
||||
var stateBoot = CurrentStateBoot();
|
||||
var verseHost = LatestVerseHostSettings(stateBoot);
|
||||
return AetheriaRuntimeClientTargetSurfaceBuilder.Build(
|
||||
new AetheriaRuntimeClientTargetSurfaceState(
|
||||
stateBoot.TargetKind,
|
||||
stateBoot.Title,
|
||||
stateBoot.VerseId,
|
||||
stateBoot.CultMeshAddress,
|
||||
stateBoot.StateFilePath,
|
||||
stateBoot.TargetSource,
|
||||
stateBoot.SupportsLocalStateFileRead,
|
||||
stateBoot.FailureMessage,
|
||||
verseHost?.Title ?? stateBoot.Title,
|
||||
verseHost?.VerseId ?? stateBoot.VerseId,
|
||||
verseHost?.Visibility ?? "unknown",
|
||||
verseHost?.CultMeshAddress ?? stateBoot.CultMeshAddress,
|
||||
DateTime.UtcNow.ToString("O")));
|
||||
}
|
||||
|
||||
private static EveSurfaceDocument BuildMainSurfaceDefinition(
|
||||
AetheriaRuntimeStateBootReport stateBoot,
|
||||
AetheriaRuntimeRunStateSnapshot continueRun,
|
||||
|
|
@ -505,6 +565,7 @@ public class MainMenu : MonoBehaviour
|
|||
new[]
|
||||
{
|
||||
new EveCommandTemplate(ShowPlayerSettingsCommand, "Player Settings", "unity-uitoolkit"),
|
||||
new EveCommandTemplate(ShowVerseSettingsCommand, "Verse", "unity-uitoolkit"),
|
||||
new EveCommandTemplate(ShowInputSettingsCommand, "Input", "unity-uitoolkit"),
|
||||
new EveCommandTemplate(BackToMainCommand, "Back", "unity-uitoolkit")
|
||||
},
|
||||
|
|
@ -513,10 +574,11 @@ public class MainMenu : MonoBehaviour
|
|||
"Settings",
|
||||
Text(
|
||||
"aetheria.mainMenu.settings.note",
|
||||
"Typed Verse settings already lower through Eve. Input rebinding now opens the runtime Eve input screen, and audio still has no typed surface."),
|
||||
"Player settings, client target selection, and input rebinding all lower through typed Eve surfaces. Audio still has no typed owner."),
|
||||
ButtonRow(
|
||||
"aetheria.mainMenu.settings.actions",
|
||||
Button("aetheria.mainMenu.settings.playerSettings", "Player Settings", ShowPlayerSettingsCommand),
|
||||
Button("aetheria.mainMenu.settings.verse", "Verse", ShowVerseSettingsCommand),
|
||||
Button("aetheria.mainMenu.settings.input", "Input", ShowInputSettingsCommand),
|
||||
Button("aetheria.mainMenu.settings.back", "Back", BackToMainCommand))));
|
||||
}
|
||||
|
|
@ -540,6 +602,101 @@ public class MainMenu : MonoBehaviour
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool TryCommitClientTargetCommand(string command, IReadOnlyDictionary<string, string> payload)
|
||||
{
|
||||
if (!AetheriaRuntimeClientTargetCommands.IsKnown(command))
|
||||
return false;
|
||||
|
||||
if (string.Equals(command, AetheriaRuntimeClientTargetCommands.Refresh, StringComparison.Ordinal))
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
var gameDataDirectory = ActionGameManager.GameDataDirectory;
|
||||
var clientTargetPath = AetheriaRuntimeStateBoundary.GetClientTargetPath(gameDataDirectory);
|
||||
var defaultStateFilePath = AetheriaRuntimeStateBoundary.GetStateFilePath(gameDataDirectory);
|
||||
AetheriaRuntimeClientTargetStore.Update(
|
||||
clientTargetPath,
|
||||
defaultStateFilePath,
|
||||
document =>
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case var _ when string.Equals(command, AetheriaRuntimeClientTargetCommands.CycleTargetKind, StringComparison.Ordinal):
|
||||
document.TargetKind = string.Equals(document.TargetKind, AetheriaRuntimeClientTargetKinds.CultMeshVerse, StringComparison.Ordinal)
|
||||
? AetheriaRuntimeClientTargetKinds.StateFile
|
||||
: AetheriaRuntimeClientTargetKinds.CultMeshVerse;
|
||||
break;
|
||||
case var _ when string.Equals(command, AetheriaRuntimeClientTargetCommands.SetTitle, StringComparison.Ordinal):
|
||||
document.Title = ReadPayloadValue(payload, "value");
|
||||
break;
|
||||
case var _ when string.Equals(command, AetheriaRuntimeClientTargetCommands.SetVerseId, StringComparison.Ordinal):
|
||||
document.VerseId = ReadPayloadValue(payload, "value");
|
||||
break;
|
||||
case var _ when string.Equals(command, AetheriaRuntimeClientTargetCommands.SetCultMeshAddress, StringComparison.Ordinal):
|
||||
document.CultMeshAddress = ReadPayloadValue(payload, "value");
|
||||
break;
|
||||
case var _ when string.Equals(command, AetheriaRuntimeClientTargetCommands.SetStateFilePath, StringComparison.Ordinal):
|
||||
document.StateFilePath = ReadPayloadValue(payload, "value");
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(document.TargetKind))
|
||||
document.TargetKind = AetheriaRuntimeClientTargetKinds.StateFile;
|
||||
if (string.IsNullOrWhiteSpace(document.StateFilePath))
|
||||
document.StateFilePath = defaultStateFilePath;
|
||||
document.UpdatedAtUtc = DateTime.UtcNow.ToString("O");
|
||||
});
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to update typed Aetheria client target: {ex}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryQueueVerseHostCommand(string command, IReadOnlyDictionary<string, string> payload)
|
||||
{
|
||||
if (!AetheriaRuntimeVerseHostCommands.IsKnown(command))
|
||||
return false;
|
||||
|
||||
var stateBoot = CurrentStateBoot();
|
||||
if (!stateBoot.SupportsLocalStateFileRead || !stateBoot.StateFileExists)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"Cannot queue Verse-host command '{command}' because the active target is not a readable local Verse state file.");
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var request = new EveSurfaceCommandRequest(
|
||||
"aetheria",
|
||||
AetheriaRuntimeVerseHostCommands.SurfaceId,
|
||||
command,
|
||||
payload?.ToDictionary(entry => entry.Key, entry => entry.Value ?? "", StringComparer.Ordinal)
|
||||
?? new Dictionary<string, string>(StringComparer.Ordinal),
|
||||
DateTimeOffset.UtcNow,
|
||||
"unity-main-menu");
|
||||
var envelope = AetheriaRuntimeEveCommandLog.QueueCommand(stateBoot.StateFilePath, request);
|
||||
Debug.Log($"Queued Aetheria Verse-host Eve command: {envelope.Path}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to queue typed Aetheria Verse-host Eve command: {ex}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReadPayloadValue(IReadOnlyDictionary<string, string> payload, string key)
|
||||
{
|
||||
return payload != null && payload.TryGetValue(key, out var value)
|
||||
? value ?? ""
|
||||
: "";
|
||||
}
|
||||
|
||||
private static EveSurfaceDocument BuildInputSettingsSurfaceDefinition(bool canOpenRuntimeInputScreen, bool inGame)
|
||||
{
|
||||
var commands = new List<EveCommandTemplate>
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ internal static class Program
|
|||
AppliedCatalogRefreshes = report.AppliedCatalogRefreshes,
|
||||
AppliedOperationsRefreshes = report.AppliedOperationsRefreshes,
|
||||
AppliedPlayerSettingsCommands = report.AppliedPlayerSettingsCommands,
|
||||
AppliedVerseHostCommands = report.AppliedVerseHostCommands,
|
||||
LastRejectedCommand = report.LastRejectedCommand,
|
||||
LastRejectedReason = report.LastRejectedReason,
|
||||
ConsecutiveFailures = 0,
|
||||
|
|
@ -178,7 +179,8 @@ internal static class Program
|
|||
$"rejected={report.RejectedCommands}, " +
|
||||
$"catalogRefreshes={report.AppliedCatalogRefreshes}, " +
|
||||
$"operationsRefreshes={report.AppliedOperationsRefreshes}, " +
|
||||
$"playerSettings={report.AppliedPlayerSettingsCommands}");
|
||||
$"playerSettings={report.AppliedPlayerSettingsCommands}, " +
|
||||
$"verseHost={report.AppliedVerseHostCommands}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
namespace GameCult.Aetheria.State.Unity
|
||||
{
|
||||
public static class AetheriaRuntimeClientTargetCommands
|
||||
{
|
||||
public const string SurfaceId = "aetheria.client_target";
|
||||
public const string Refresh = "aetheria.client_target.refresh";
|
||||
public const string CycleTargetKind = "aetheria.client_target.kind.cycle";
|
||||
public const string SetTitle = "aetheria.client_target.title.set";
|
||||
public const string SetVerseId = "aetheria.client_target.verse_id.set";
|
||||
public const string SetCultMeshAddress = "aetheria.client_target.cultmesh_address.set";
|
||||
public const string SetStateFilePath = "aetheria.client_target.state_file_path.set";
|
||||
|
||||
public static bool IsKnown(string command)
|
||||
{
|
||||
return command == Refresh ||
|
||||
command == CycleTargetKind ||
|
||||
command == SetTitle ||
|
||||
command == SetVerseId ||
|
||||
command == SetCultMeshAddress ||
|
||||
command == SetStateFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +83,19 @@ namespace GameCult.Aetheria.State.Unity
|
|||
MessagePackSerializer.Serialize(document));
|
||||
}
|
||||
|
||||
public static AetheriaRuntimeClientTargetDocument Update(
|
||||
string clientTargetPath,
|
||||
string defaultStateFilePath,
|
||||
Action<AetheriaRuntimeClientTargetDocument> mutate)
|
||||
{
|
||||
if (mutate == null) throw new ArgumentNullException(nameof(mutate));
|
||||
|
||||
var document = ReadOrInitialize(clientTargetPath, defaultStateFilePath);
|
||||
mutate(document);
|
||||
Write(clientTargetPath, document);
|
||||
return document;
|
||||
}
|
||||
|
||||
public static AetheriaRuntimeClientTargetDocument Read(string clientTargetPath)
|
||||
{
|
||||
return MessagePackSerializer.Deserialize<AetheriaRuntimeClientTargetDocument>(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,263 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameCult.Aetheria.State.Unity
|
||||
{
|
||||
public sealed class AetheriaRuntimeClientTargetSurfaceState
|
||||
{
|
||||
public AetheriaRuntimeClientTargetSurfaceState(
|
||||
string targetKind,
|
||||
string targetTitle,
|
||||
string targetVerseId,
|
||||
string targetCultMeshAddress,
|
||||
string targetStateFilePath,
|
||||
string targetSource,
|
||||
bool supportsLocalStateFileRead,
|
||||
string bootFailureMessage,
|
||||
string hostTitle,
|
||||
string hostVerseId,
|
||||
string hostVisibility,
|
||||
string hostCultMeshAddress,
|
||||
string updatedAtUtc)
|
||||
{
|
||||
TargetKind = targetKind ?? "";
|
||||
TargetTitle = targetTitle ?? "";
|
||||
TargetVerseId = targetVerseId ?? "";
|
||||
TargetCultMeshAddress = targetCultMeshAddress ?? "";
|
||||
TargetStateFilePath = targetStateFilePath ?? "";
|
||||
TargetSource = targetSource ?? "";
|
||||
SupportsLocalStateFileRead = supportsLocalStateFileRead;
|
||||
BootFailureMessage = bootFailureMessage ?? "";
|
||||
HostTitle = hostTitle ?? "";
|
||||
HostVerseId = hostVerseId ?? "";
|
||||
HostVisibility = hostVisibility ?? "";
|
||||
HostCultMeshAddress = hostCultMeshAddress ?? "";
|
||||
UpdatedAtUtc = updatedAtUtc ?? "";
|
||||
}
|
||||
|
||||
public string TargetKind { get; }
|
||||
public string TargetTitle { get; }
|
||||
public string TargetVerseId { get; }
|
||||
public string TargetCultMeshAddress { get; }
|
||||
public string TargetStateFilePath { get; }
|
||||
public string TargetSource { get; }
|
||||
public bool SupportsLocalStateFileRead { get; }
|
||||
public string BootFailureMessage { get; }
|
||||
public string HostTitle { get; }
|
||||
public string HostVerseId { get; }
|
||||
public string HostVisibility { get; }
|
||||
public string HostCultMeshAddress { get; }
|
||||
public string UpdatedAtUtc { get; }
|
||||
|
||||
public string TargetLabel =>
|
||||
string.IsNullOrWhiteSpace(TargetTitle)
|
||||
? (string.IsNullOrWhiteSpace(TargetVerseId) ? "Unknown Verse" : TargetVerseId)
|
||||
: (string.IsNullOrWhiteSpace(TargetVerseId) || string.Equals(TargetTitle, TargetVerseId, StringComparison.Ordinal)
|
||||
? TargetTitle
|
||||
: $"{TargetTitle} ({TargetVerseId})");
|
||||
|
||||
public string HostLabel =>
|
||||
string.IsNullOrWhiteSpace(HostTitle)
|
||||
? (string.IsNullOrWhiteSpace(HostVerseId) ? "Unknown Verse" : HostVerseId)
|
||||
: (string.IsNullOrWhiteSpace(HostVerseId) || string.Equals(HostTitle, HostVerseId, StringComparison.Ordinal)
|
||||
? HostTitle
|
||||
: $"{HostTitle} ({HostVerseId})");
|
||||
}
|
||||
|
||||
public static class AetheriaRuntimeClientTargetSurfaceBuilder
|
||||
{
|
||||
public static AetheriaRuntimeSurfaceDocument Build(
|
||||
AetheriaRuntimeClientTargetSurfaceState state,
|
||||
long version = 1)
|
||||
{
|
||||
state ??= new AetheriaRuntimeClientTargetSurfaceState(
|
||||
AetheriaRuntimeClientTargetKinds.StateFile,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
supportsLocalStateFileRead: true,
|
||||
bootFailureMessage: "",
|
||||
hostTitle: "",
|
||||
hostVerseId: "",
|
||||
hostVisibility: "",
|
||||
hostCultMeshAddress: "",
|
||||
updatedAtUtc: "");
|
||||
|
||||
var targetKindLabel = string.Equals(state.TargetKind, AetheriaRuntimeClientTargetKinds.CultMeshVerse, StringComparison.Ordinal)
|
||||
? "CultMesh Verse"
|
||||
: "Local State File";
|
||||
var visibilityLabel = string.IsNullOrWhiteSpace(state.HostVisibility) ? "unknown" : state.HostVisibility;
|
||||
var visibilityActionLabel = string.Equals(visibilityLabel, "public", StringComparison.OrdinalIgnoreCase)
|
||||
? "Make Private"
|
||||
: "Make Public";
|
||||
var summaryNote = !state.SupportsLocalStateFileRead && !string.IsNullOrWhiteSpace(state.BootFailureMessage)
|
||||
? state.BootFailureMessage
|
||||
: string.Equals(state.TargetSource, "state-path-override", StringComparison.Ordinal)
|
||||
? "AETHERIA_STATE_PATH is overriding the persisted client target. Update the environment if you want boot to follow the saved target again."
|
||||
: "Client target edits persist in aetheria-client.cc. Verse visibility changes queue typed Eve commands for the provider bridge.";
|
||||
|
||||
return new AetheriaRuntimeSurfaceDocument(
|
||||
providerId: "aetheria",
|
||||
providerKind: "game.menu",
|
||||
title: "Aetheria Verse Settings",
|
||||
version: version,
|
||||
updatedAtUtc: state.UpdatedAtUtc,
|
||||
surface: new AetheriaRuntimeSurfaceTree(
|
||||
AetheriaRuntimeClientTargetCommands.SurfaceId,
|
||||
Node(
|
||||
"aetheria.clientTarget.root",
|
||||
"surface",
|
||||
Array.Empty<(string Key, string Value)>(),
|
||||
Node(
|
||||
"aetheria.clientTarget.summary",
|
||||
"card",
|
||||
new[] { ("title", "Client Target") },
|
||||
Metric("aetheria.clientTarget.summary.target", "Target", state.TargetLabel),
|
||||
Metric("aetheria.clientTarget.summary.transport", "Transport", targetKindLabel),
|
||||
Metric("aetheria.clientTarget.summary.source", "Target Source", state.TargetSource),
|
||||
Text("aetheria.clientTarget.summary.note", summaryNote)),
|
||||
Node(
|
||||
"aetheria.clientTarget.target",
|
||||
"card",
|
||||
new[] { ("title", "Target Fields") },
|
||||
TextInput(
|
||||
"aetheria.clientTarget.target.title",
|
||||
"Title",
|
||||
state.TargetTitle,
|
||||
AetheriaRuntimeClientTargetCommands.SetTitle),
|
||||
TextInput(
|
||||
"aetheria.clientTarget.target.verseId",
|
||||
"Verse Id",
|
||||
state.TargetVerseId,
|
||||
AetheriaRuntimeClientTargetCommands.SetVerseId),
|
||||
TextInput(
|
||||
"aetheria.clientTarget.target.cultMeshAddress",
|
||||
"CultMesh Address",
|
||||
state.TargetCultMeshAddress,
|
||||
AetheriaRuntimeClientTargetCommands.SetCultMeshAddress),
|
||||
TextInput(
|
||||
"aetheria.clientTarget.target.stateFilePath",
|
||||
"State File Path",
|
||||
state.TargetStateFilePath,
|
||||
AetheriaRuntimeClientTargetCommands.SetStateFilePath),
|
||||
ButtonRow(
|
||||
"aetheria.clientTarget.target.actions",
|
||||
Button(
|
||||
"aetheria.clientTarget.target.cycleTransport",
|
||||
string.Equals(state.TargetKind, AetheriaRuntimeClientTargetKinds.CultMeshVerse, StringComparison.Ordinal)
|
||||
? "Use Local State File"
|
||||
: "Use CultMesh Verse",
|
||||
AetheriaRuntimeClientTargetCommands.CycleTargetKind),
|
||||
Button(
|
||||
"aetheria.clientTarget.target.refresh",
|
||||
"Refresh",
|
||||
AetheriaRuntimeClientTargetCommands.Refresh))),
|
||||
Node(
|
||||
"aetheria.clientTarget.host",
|
||||
"card",
|
||||
new[] { ("title", "Daemon Verse Host") },
|
||||
Metric("aetheria.clientTarget.host.verse", "Verse", state.HostLabel),
|
||||
Metric("aetheria.clientTarget.host.visibility", "Visibility", visibilityLabel),
|
||||
Metric("aetheria.clientTarget.host.cultMesh", "CultMesh", state.HostCultMeshAddress),
|
||||
ButtonRow(
|
||||
"aetheria.clientTarget.host.actions",
|
||||
Button(
|
||||
"aetheria.clientTarget.host.toggleVisibility",
|
||||
visibilityActionLabel,
|
||||
AetheriaRuntimeVerseHostCommands.CycleVisibility),
|
||||
Button(
|
||||
"aetheria.clientTarget.host.refresh",
|
||||
"Refresh Host",
|
||||
AetheriaRuntimeVerseHostCommands.Refresh))),
|
||||
Node(
|
||||
"aetheria.clientTarget.host.noteCard",
|
||||
"card",
|
||||
new[] { ("title", "Ownership") },
|
||||
Text(
|
||||
"aetheria.clientTarget.host.note",
|
||||
"Client target edits are local. Visibility changes queue provider-owned Eve commands against the selected local Verse state file."))),
|
||||
Array.Empty<AetheriaRuntimeSurfaceStyleToken>()),
|
||||
commands: new[]
|
||||
{
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeClientTargetCommands.Refresh,
|
||||
"Refresh",
|
||||
"unity-uitoolkit"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeClientTargetCommands.CycleTargetKind,
|
||||
"Cycle Transport",
|
||||
"unity-uitoolkit"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeClientTargetCommands.SetTitle,
|
||||
"Set Title",
|
||||
"unity-uitoolkit"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeClientTargetCommands.SetVerseId,
|
||||
"Set Verse Id",
|
||||
"unity-uitoolkit"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeClientTargetCommands.SetCultMeshAddress,
|
||||
"Set CultMesh Address",
|
||||
"unity-uitoolkit"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeClientTargetCommands.SetStateFilePath,
|
||||
"Set State File Path",
|
||||
"unity-uitoolkit"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeVerseHostCommands.CycleVisibility,
|
||||
"Toggle Visibility",
|
||||
"cultmesh"),
|
||||
new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeVerseHostCommands.Refresh,
|
||||
"Refresh Host",
|
||||
"cultmesh")
|
||||
});
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent Metric(string id, string label, string value)
|
||||
{
|
||||
return Node(id, "metric", new[] { ("label", label), ("value", value ?? "") });
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent Text(string id, string value)
|
||||
{
|
||||
return Node(id, "text", new[] { ("value", value ?? "") });
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent Button(string id, string label, string command)
|
||||
{
|
||||
return Node(id, "control.button", new[] { ("label", label ?? ""), ("command", command ?? "") });
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent TextInput(string id, string label, string value, string command)
|
||||
{
|
||||
return Node(
|
||||
id,
|
||||
"control.text",
|
||||
new[] { ("label", label ?? ""), ("value", value ?? ""), ("command", command ?? "") });
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent ButtonRow(
|
||||
string id,
|
||||
params AetheriaRuntimeSurfaceComponent[] children)
|
||||
{
|
||||
return Node(id, "row", Array.Empty<(string Key, string Value)>(), children);
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent Node(
|
||||
string id,
|
||||
string kind,
|
||||
IEnumerable<(string Key, string Value)> props,
|
||||
params AetheriaRuntimeSurfaceComponent[] children)
|
||||
{
|
||||
return new AetheriaRuntimeSurfaceComponent(
|
||||
id,
|
||||
kind,
|
||||
props.ToDictionary(prop => prop.Key, prop => prop.Value, StringComparer.Ordinal),
|
||||
children ?? Array.Empty<AetheriaRuntimeSurfaceComponent>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
namespace GameCult.Aetheria.State.Unity
|
||||
{
|
||||
public static class AetheriaRuntimeVerseHostCommands
|
||||
{
|
||||
public const string SurfaceId = "aetheria.verse_host_settings";
|
||||
public const string Refresh = "aetheria.verse_host_settings.refresh";
|
||||
public const string CycleVisibility = "aetheria.verse_host_settings.visibility.cycle";
|
||||
|
||||
public static bool IsKnown(string command)
|
||||
{
|
||||
return command == Refresh ||
|
||||
command == CycleVisibility;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue