feat(starbridge): publish commander and pilot surfaces
This commit is contained in:
parent
2b276a95b4
commit
fdcff0f2d6
7 changed files with 142 additions and 17 deletions
|
|
@ -75,7 +75,7 @@ app.whenReady().then(async () => {
|
|||
},
|
||||
renderer: rendererIndex,
|
||||
runtimeId: "eve-electron-aetheria",
|
||||
surfaceId: process.env.EVE_SURFACE_ID || "aetheria.game",
|
||||
surfaceId: process.env.EVE_SURFACE_ID || "aetheria.starbridge.commander",
|
||||
window: {
|
||||
show: !electronSmoke,
|
||||
backgroundColor: "#0b1016",
|
||||
|
|
@ -87,10 +87,10 @@ app.whenReady().then(async () => {
|
|||
if (electronSmoke) {
|
||||
await withTimeout(mainWindow.webContents.executeJavaScript("window.eveProvider.providerAdvertisement()"), 10000, "provider advertisement smoke");
|
||||
writeElectronSmokeResult({ ok: false, stage: "provider-advertisement-readable" });
|
||||
await withTimeout(mainWindow.webContents.executeJavaScript("window.eveProvider.surface({ surfaceId: 'aetheria.game' })"), 10000, "surface smoke");
|
||||
await withTimeout(mainWindow.webContents.executeJavaScript("window.eveProvider.surface({ surfaceId: 'aetheria.starbridge.commander' })"), 10000, "surface smoke");
|
||||
writeElectronSmokeResult({ ok: false, stage: "provider-surface-readable" });
|
||||
await withTimeout(mainWindow.webContents.executeJavaScript(`window.eveProvider.submitCommand({
|
||||
providerId: 'aetheria.daemon', surfaceId: 'aetheria.game', command: 'aetheria.daemon.commands.SensorPing',
|
||||
providerId: 'aetheria.daemon', surfaceId: 'aetheria.starbridge.commander', command: 'aetheria.daemon.commands.SensorPing',
|
||||
clientId: 'aetheria-electron-smoke-preflight', payload: {}
|
||||
})`), 10000, "command receipt smoke");
|
||||
writeElectronSmokeResult({ ok: false, stage: "provider-command-receipt-readable" });
|
||||
|
|
@ -160,7 +160,7 @@ async function runElectronSmoke(window: BrowserWindow): Promise<Record<string, u
|
|||
});
|
||||
const eveReceipt = eveProvider ? await eveProvider.submitCommand({
|
||||
providerId: "aetheria.daemon",
|
||||
surfaceId: "aetheria.game",
|
||||
surfaceId: "aetheria.starbridge.commander",
|
||||
command: "aetheria.daemon.commands.SensorPing",
|
||||
clientId: "aetheria-electron-smoke",
|
||||
payload: {},
|
||||
|
|
@ -214,10 +214,10 @@ function isElectronSmokeReady(result: Record<string, unknown>): boolean {
|
|||
result.worldSceneReady === true &&
|
||||
Number(result.worldEntityCount) > 0 &&
|
||||
Number(result.controlledWorldEntityCount) === 1 &&
|
||||
eveHostText.includes("Daemon Frame") &&
|
||||
eveHostText.includes("Typed Command Boundary") &&
|
||||
arrayValue(providerAdvertisement?.surfaces).some(surface => objectValue(surface)?.surfaceId === "aetheria.game") &&
|
||||
objectValue(eveSurface?.surface)?.id === "aetheria.game" &&
|
||||
eveHostText.includes("Station Stock") &&
|
||||
eveHostText.includes("Wave Forecast") &&
|
||||
arrayValue(providerAdvertisement?.surfaces).some(surface => objectValue(surface)?.surfaceId === "aetheria.starbridge.commander") &&
|
||||
objectValue(eveSurface?.surface)?.id === "aetheria.starbridge.commander" &&
|
||||
stringValue(renderSplatsResolved?.documentId).length > 0 &&
|
||||
stringValue(gravityResolved?.documentId).length > 0 &&
|
||||
stringValue(objectsResolved?.documentId).length > 0 &&
|
||||
|
|
|
|||
|
|
@ -1348,6 +1348,14 @@ static async Task PublishDaemonApiDocumentsAsync(
|
|||
await node.MutableDocument<EveSurfaceDocument>(AetheriaRuntimeVerseRecordKeys.DaemonGameSurface)
|
||||
.ReplaceAsync(AetheriaRuntimeSurfaceDocuments.ToPortableSurface(gameSurface))
|
||||
.ConfigureAwait(false);
|
||||
var commanderSurface = AetheriaRuntimeDaemonGameSurfaceBuilder.BuildCommander(
|
||||
result.Frame,
|
||||
result.Health ?? new AetheriaRuntimeDaemonHealthDocument(),
|
||||
result.CommandBoundary ?? AetheriaRuntimeDaemonCommandBoundaryDocument.Create(options.DaemonId),
|
||||
result.StarbridgeSessionSummary);
|
||||
await node.MutableDocument<EveSurfaceDocument>(AetheriaRuntimeVerseRecordKeys.StarbridgeCommanderSurface)
|
||||
.ReplaceAsync(AetheriaRuntimeSurfaceDocuments.ToPortableSurface(commanderSurface))
|
||||
.ConfigureAwait(false);
|
||||
if (result.GameTuiSurface != null)
|
||||
await node.MutableDocument<EveSurfaceDocument>(AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface)
|
||||
.ReplaceAsync(AetheriaRuntimeSurfaceDocuments.ToPortableSurface(result.GameTuiSurface))
|
||||
|
|
@ -1398,12 +1406,20 @@ static EveProviderAdvertisementDocument BuildCoreProviderAdvertisement(
|
|||
new[]
|
||||
{
|
||||
new EveAdvertisedSurface(
|
||||
AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId,
|
||||
AetheriaRuntimeDaemonGameSurfaceBuilder.PilotSurfaceId,
|
||||
EveSurfaceDocument.SchemaId,
|
||||
AetheriaRuntimeVerseRecordKeys.DaemonGameSurface.ToString(),
|
||||
"cultmesh-record",
|
||||
"active",
|
||||
"interactive-world",
|
||||
interaction),
|
||||
new EveAdvertisedSurface(
|
||||
AetheriaRuntimeDaemonGameSurfaceBuilder.CommanderSurfaceId,
|
||||
EveSurfaceDocument.SchemaId,
|
||||
AetheriaRuntimeVerseRecordKeys.StarbridgeCommanderSurface.ToString(),
|
||||
"cultmesh-record",
|
||||
"active",
|
||||
"interactive-world",
|
||||
interaction)
|
||||
},
|
||||
Array.Empty<EveAdvertisedCommand>());
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ namespace GameCult.Aetheria.State.Verse
|
|||
{
|
||||
public static class AetheriaRuntimeDaemonGameSurfaceBuilder
|
||||
{
|
||||
public const string SurfaceId = "aetheria.game";
|
||||
public const string TuiSurfaceId = "aetheria.game.tui";
|
||||
public const string PilotSurfaceId = "aetheria.starbridge.pilot";
|
||||
public const string CommanderSurfaceId = "aetheria.starbridge.commander";
|
||||
public const string SurfaceId = PilotSurfaceId;
|
||||
public const string TuiSurfaceId = "aetheria.starbridge.pilot.tui";
|
||||
|
||||
public static AetheriaRuntimeSurfaceDocument Build(
|
||||
AetheriaRuntimeDaemonFrameDocument frame,
|
||||
|
|
@ -126,6 +128,75 @@ namespace GameCult.Aetheria.State.Verse
|
|||
.ToArray());
|
||||
}
|
||||
|
||||
public static AetheriaRuntimeSurfaceDocument BuildCommander(
|
||||
AetheriaRuntimeDaemonFrameDocument frame,
|
||||
AetheriaRuntimeDaemonHealthDocument health,
|
||||
AetheriaRuntimeDaemonCommandBoundaryDocument commandBoundary,
|
||||
AetheriaRuntimeStarbridgeSessionSummaryDocument? starbridge = null)
|
||||
{
|
||||
frame ??= new AetheriaRuntimeDaemonFrameDocument();
|
||||
health ??= new AetheriaRuntimeDaemonHealthDocument();
|
||||
commandBoundary ??= AetheriaRuntimeDaemonCommandBoundaryDocument.Create(frame.DaemonId);
|
||||
starbridge ??= AetheriaRuntimeStarbridgeDocuments.SessionSummary(frame);
|
||||
var run = frame.Run ?? new AetheriaRuntimeRunCheckpointCommit();
|
||||
var zone = FindCurrentZone(run);
|
||||
|
||||
var root = SurfaceRoot(
|
||||
"aetheria.starbridge.commander.root",
|
||||
StrategicWorldSurface("aetheria.starbridge.commander.world", run, zone),
|
||||
BuildStarbridgeStationStockCard(starbridge),
|
||||
BuildStarbridgeWaveForecastCard(starbridge),
|
||||
BuildStarbridgeRuntimeRolesCard(starbridge));
|
||||
|
||||
return new AetheriaRuntimeSurfaceDocument(
|
||||
"aetheria.daemon",
|
||||
"game.daemon",
|
||||
"Starbridge Commander",
|
||||
frame.FrameId,
|
||||
frame.PublishedAtUtc,
|
||||
new AetheriaRuntimeSurfaceTree(
|
||||
CommanderSurfaceId,
|
||||
root,
|
||||
Array.Empty<AetheriaRuntimeSurfaceStyleToken>()),
|
||||
commandBoundary.Commands
|
||||
.Where(entry => AetheriaRuntimeDaemonSurfaceCommandCatalog.IsArgumentlessCommand(entry.Kind))
|
||||
.Select(entry => new AetheriaRuntimeSurfaceCommandTemplate(
|
||||
AetheriaRuntimeDaemonSurfaceCommandCatalog.CommandName(entry.Kind),
|
||||
AetheriaRuntimeDaemonSurfaceCommandCatalog.Label(entry.Kind),
|
||||
"cultmesh"))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent StrategicWorldSurface(
|
||||
string id,
|
||||
AetheriaRuntimeRunCheckpointCommit run,
|
||||
AetheriaRuntimeZoneSnapshotCommit zone)
|
||||
{
|
||||
var props = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["label"] = string.IsNullOrWhiteSpace(zone.Name) ? "Starbridge" : zone.Name,
|
||||
["statePointerId"] = AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest.ToString(),
|
||||
["assetManifest"] = AetheriaRuntimeVerseRecordKeys.EveAssetCatalog.ToString(),
|
||||
["inputProfile"] = "rts.pointer-keyboard.v1",
|
||||
["cameraRig"] = "rts.top-down.v1",
|
||||
["zoneIndex"] = zone.ZoneIndex.ToString(CultureInfo.InvariantCulture),
|
||||
["runId"] = run.RunId ?? ""
|
||||
};
|
||||
var entities = (zone.Entities ?? Array.Empty<AetheriaRuntimeEntitySnapshotCommit>())
|
||||
.Where(entity => entity != null && entity.IsActive)
|
||||
.Select(entity => PlayableWorldEntity(entity, run, zone, run.CurrentEntityKey))
|
||||
.ToArray();
|
||||
return new AetheriaRuntimeSurfaceComponent(
|
||||
id,
|
||||
"world.scene2d",
|
||||
props,
|
||||
entities,
|
||||
AetheriaRuntimeSurfaceStateBindings.FromProps(props),
|
||||
Array.Empty<AetheriaRuntimeEmbeddedDocumentSlot>(),
|
||||
Layout(("position", "absolute"), ("inset", "0"), ("width", "100%"), ("height", "100%")),
|
||||
new Dictionary<string, string> { ["background"] = "transparent" });
|
||||
}
|
||||
|
||||
private static AetheriaRuntimeSurfaceComponent BuildStarbridgeStationStockCard(
|
||||
AetheriaRuntimeStarbridgeSessionSummaryDocument summary)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -110,7 +110,8 @@ namespace GameCult.Aetheria.State.Verse
|
|||
AetheriaRuntimePlayerSettingsCommands.IncrementSignificantDigits,
|
||||
AetheriaRuntimePlayerSettingsCommands.CycleNebulaQuality,
|
||||
AetheriaRuntimePlayerSettingsCommands.ToggleShowAsteroidsInMinimap),
|
||||
Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, "Aetheria Daemon", AetheriaRuntimeVerseRecordKeys.DaemonGameSurface.ToString(), "player", "Authoritative daemon game surface.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface"), requiresPlugins: FieldPluginRequirements()),
|
||||
Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.PilotSurfaceId, "Starbridge Pilot", AetheriaRuntimeVerseRecordKeys.DaemonGameSurface.ToString(), "pilot", "Embodied Starbridge pilot projection.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface"), requiresPlugins: FieldPluginRequirements()),
|
||||
Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.CommanderSurfaceId, "Starbridge Commander", AetheriaRuntimeVerseRecordKeys.StarbridgeCommanderSurface.ToString(), "commander", "Strategic Starbridge commander projection.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface"), requiresPlugins: FieldPluginRequirements()),
|
||||
Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, "Aetheria Daemon TUI", AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface.ToString(), "agent", "Compact daemon game surface for dense inspection.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface")),
|
||||
Surface(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, "Aetheria Daemon Editor", AetheriaRuntimeVerseRecordKeys.DaemonEditorSurface.ToString(), "operator", "Daemon editor and surface inventory.", providerId: "aetheria.daemon", providerKind: "editor.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world-editor", worldInteraction: WorldInteraction("provider-authored-world-editor-surface")),
|
||||
Surface(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, "Aetheria Daemon Editor TUI", AetheriaRuntimeVerseRecordKeys.DaemonEditorTuiSurface.ToString(), "agent", "Compact daemon editor and surface inventory.", providerId: "aetheria.daemon", providerKind: "editor.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world-editor", worldInteraction: WorldInteraction("provider-authored-world-editor-surface")),
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ namespace GameCult.Aetheria.State.Verse
|
|||
public static CultRecordKey DaemonGameSurface { get; } =
|
||||
new CultRecordKey("eve:surface:aetheria.daemon.game");
|
||||
|
||||
public static CultRecordKey StarbridgeCommanderSurface { get; } =
|
||||
new CultRecordKey("eve:surface:aetheria.starbridge.commander");
|
||||
|
||||
public static CultRecordKey DaemonGameTuiSurface { get; } =
|
||||
new CultRecordKey("eve:surface:aetheria.daemon.game.tui");
|
||||
|
||||
|
|
|
|||
|
|
@ -95,11 +95,11 @@
|
|||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.daemon.game",
|
||||
"surfaceId": "aetheria.starbridge.pilot",
|
||||
"key": "AetheriaRuntimeVerseRecordKeys.DaemonGameSurface",
|
||||
"transport": "cultmesh-record",
|
||||
"status": "available",
|
||||
"audience": "player",
|
||||
"audience": "pilot",
|
||||
"mode": "interactive",
|
||||
"surfaceKind": "interactive-world",
|
||||
"interactionModel": "provider-command-receipts",
|
||||
|
|
@ -115,11 +115,35 @@
|
|||
"loweringTargets": ["web-reference", "unity-uitoolkit", "unity-scene", "electron-shell", "tui"],
|
||||
"ownership": "provider-owns-world-state-assets-command-acceptance-and-receipts"
|
||||
},
|
||||
"summary": "Authoritative daemon game surface consumed by Unity, Electron, and web lowerers."
|
||||
"summary": "Embodied Starbridge pilot surface lowered by generic Eve runtimes."
|
||||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.daemon.game.tui",
|
||||
"surfaceId": "aetheria.starbridge.commander",
|
||||
"key": "AetheriaRuntimeVerseRecordKeys.StarbridgeCommanderSurface",
|
||||
"transport": "cultmesh-record",
|
||||
"status": "available",
|
||||
"audience": "commander",
|
||||
"mode": "interactive",
|
||||
"surfaceKind": "interactive-world",
|
||||
"interactionModel": "provider-command-receipts",
|
||||
"worldInteraction": {
|
||||
"projectionKind": "provider-authored-world-surface",
|
||||
"stateSchemas": [
|
||||
"aetheria.world_state.v1",
|
||||
"aetheria.runtime.daemon.frame.v1",
|
||||
"aetheria.runtime.daemon.soa_view.v1"
|
||||
],
|
||||
"commandBoundary": "aetheria.daemon.commands",
|
||||
"receiptSchema": "aetheria.eve_command_acceptance_status.v1",
|
||||
"loweringTargets": ["web-reference", "unity-uitoolkit", "unity-scene", "electron-shell", "tui"],
|
||||
"ownership": "provider-owns-world-state-assets-command-acceptance-and-receipts"
|
||||
},
|
||||
"summary": "Strategic Starbridge surface lowered full-screen by Electron or embedded by Unity."
|
||||
},
|
||||
{
|
||||
"schema": "gamecult.eve.surface.v1",
|
||||
"surfaceId": "aetheria.starbridge.pilot.tui",
|
||||
"key": "AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface",
|
||||
"transport": "cultmesh-record",
|
||||
"status": "available",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,17 @@ assert.equal(pack.ownerRepo, "Aetheria");
|
|||
|
||||
const advertisement = read(pack.advertisementPath);
|
||||
assert.equal(advertisement.providerId, pack.providerId);
|
||||
assert.ok(advertisement.surfaces.some((surface) => surface.surfaceId === "aetheria.daemon.game" && surface.worldInteraction?.projectionKind === "provider-authored-world-surface"));
|
||||
const starbridgeSurfaces = advertisement.surfaces.filter((surface) =>
|
||||
surface.surfaceId === "aetheria.starbridge.commander" ||
|
||||
surface.surfaceId === "aetheria.starbridge.pilot");
|
||||
assert.equal(starbridgeSurfaces.length, 2);
|
||||
assert.deepEqual(new Set(starbridgeSurfaces.map((surface) => surface.audience)), new Set(["commander", "pilot"]));
|
||||
for (const surface of starbridgeSurfaces) {
|
||||
assert.equal(surface.worldInteraction?.projectionKind, "provider-authored-world-surface");
|
||||
assert.equal(surface.worldInteraction?.commandBoundary, "aetheria.daemon.commands");
|
||||
assert.ok(surface.worldInteraction?.loweringTargets.includes("electron-shell"));
|
||||
assert.ok(surface.worldInteraction?.loweringTargets.includes("unity-scene"));
|
||||
}
|
||||
assert.ok(advertisement.surfaces.some((surface) => surface.surfaceId === "aetheria.daemon.editor" && surface.worldInteraction?.projectionKind === "provider-authored-world-editor-surface"));
|
||||
|
||||
for (const fixture of pack.fixtures) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue