Consume generic EveElectron host
This commit is contained in:
parent
1218dbf655
commit
8975d7ebbb
7 changed files with 86 additions and 64 deletions
|
|
@ -14,6 +14,13 @@ export {};
|
|||
declare global {
|
||||
interface Window {
|
||||
aetheriaRts: AetheriaRtsApi;
|
||||
eveProvider: {
|
||||
providerAdvertisement: AetheriaRtsApi["eveProviderAdvertisement"];
|
||||
surface: AetheriaRtsApi["eveSurface"];
|
||||
document: AetheriaRtsApi["eveDocument"];
|
||||
submitCommand: AetheriaRtsApi["submitEveCommand"];
|
||||
windowControl: AetheriaRtsApi["windowControl"];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,8 +45,8 @@ async function showDaemonEveSurface(): Promise<void> {
|
|||
host.setAttribute("aria-label", "Aetheria daemon Eve surface");
|
||||
const requestedSurfaceId = new URLSearchParams(location.search).get("surface") || "";
|
||||
const providerHost = new EveBrowserProviderHost(host, {
|
||||
providerAdvertisement: () => window.aetheriaRts.eveProviderAdvertisement(),
|
||||
surface: surface => window.aetheriaRts.eveSurface(surfaceRequest(surface)),
|
||||
providerAdvertisement: () => window.eveProvider.providerAdvertisement(),
|
||||
surface: surface => window.eveProvider.surface(surfaceRequest(surface)),
|
||||
submitCommand: submitEveCommand,
|
||||
resolveDocument: resolveEveDocument,
|
||||
resolveAssetUrl: resolveAetheriaAssetUrl,
|
||||
|
|
@ -64,7 +71,7 @@ async function resolveEveDocument(
|
|||
request: EveEmbeddedDocumentRequest,
|
||||
component: EveSurfaceComponent,
|
||||
): ReturnType<AetheriaRtsApi["eveDocument"]> {
|
||||
return window.aetheriaRts.eveDocument({
|
||||
return window.eveProvider.document({
|
||||
...request,
|
||||
context: { viewport: viewportFromComponent(component) },
|
||||
});
|
||||
|
|
@ -103,7 +110,7 @@ function resolveAetheriaAssetUrl(uri: string): string {
|
|||
|
||||
async function submitEveCommand(intent: EveCommandIntent): Promise<void> {
|
||||
try {
|
||||
const receipt = await window.aetheriaRts.submitEveCommand({
|
||||
const receipt = await window.eveProvider.submitCommand({
|
||||
providerId: intent.providerId,
|
||||
surfaceId: intent.surfaceId,
|
||||
command: intent.command,
|
||||
|
|
@ -126,7 +133,7 @@ function wireWindowControls(): void {
|
|||
button.addEventListener("click", () => {
|
||||
const action = button.dataset.windowControl as "minimize" | "maximize" | "close" | undefined;
|
||||
if (action) {
|
||||
void window.aetheriaRts.windowControl(action);
|
||||
void window.eveProvider.windowControl(action);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
AetheriaCultMeshClient,
|
||||
} from "./aetheria-cultmesh.js";
|
||||
import { registerAetheriaRtsIpcHandlers } from "./aetheria-rts-generated-bindings.js";
|
||||
import { createEveElectronWindow, registerEveWindowControls } from "@gamecult/eve-electron";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const projectRoot = resolve(__dirname, "..");
|
||||
|
|
@ -116,29 +117,12 @@ app.on("before-quit", () => {
|
|||
});
|
||||
|
||||
function createWindow(): BrowserWindow {
|
||||
const window = new BrowserWindow({
|
||||
width: 1440,
|
||||
height: 900,
|
||||
minWidth: 1000,
|
||||
minHeight: 640,
|
||||
return createEveElectronWindow({
|
||||
show: !electronSmoke,
|
||||
backgroundColor: "#0b1016",
|
||||
title: "Aetheria Starbridge",
|
||||
frame: false,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
preload: resolve(__dirname, "preload.cjs"),
|
||||
},
|
||||
});
|
||||
|
||||
window.webContents.setWindowOpenHandler(({ url }) => {
|
||||
void shell.openExternal(url);
|
||||
return { action: "deny" };
|
||||
});
|
||||
|
||||
return window;
|
||||
preload: resolve(__dirname, "preload.cjs"),
|
||||
}, { BrowserWindow, shell });
|
||||
}
|
||||
|
||||
async function runElectronSmoke(window: BrowserWindow): Promise<Record<string, unknown>> {
|
||||
|
|
@ -149,14 +133,15 @@ async function runElectronSmoke(window: BrowserWindow): Promise<Record<string, u
|
|||
(async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
const api = window.aetheriaRts;
|
||||
const eveProvider = window.eveProvider;
|
||||
const status = document.querySelector("#status")?.textContent ?? "";
|
||||
const bodyMode = document.body.className;
|
||||
const eveHostText = document.querySelector("#eve-surface-host")?.textContent ?? "";
|
||||
const worldScene = document.querySelector(".cultui-world-scene");
|
||||
const worldEntityCount = worldScene?.querySelectorAll(".cultui-world-entity").length ?? 0;
|
||||
const controlledWorldEntityCount = worldScene?.querySelectorAll('.cultui-world-entity[data-controlled="true"]').length ?? 0;
|
||||
const providerAdvertisement = api ? await api.eveProviderAdvertisement() : null;
|
||||
const eveSurface = api ? await api.eveSurface({ recordKey: "eve:surface:aetheria.daemon.game" }) : null;
|
||||
const providerAdvertisement = eveProvider ? await eveProvider.providerAdvertisement() : null;
|
||||
const eveSurface = eveProvider ? await eveProvider.surface({ recordKey: "eve:surface:aetheria.daemon.game" }) : null;
|
||||
const health = api ? await api.daemonHealth() : null;
|
||||
const authority = api ? await api.authorityStatus() : null;
|
||||
const starbridge = api ? await api.starbridgeSession() : null;
|
||||
|
|
@ -177,7 +162,7 @@ async function runElectronSmoke(window: BrowserWindow): Promise<Record<string, u
|
|||
};
|
||||
const eveFieldSurface = findComponent(eveSurface?.surface?.root, component =>
|
||||
component.kind === "field.surface2d" || component.kind === "gravity.surface");
|
||||
const eveReceipt = api ? await api.submitEveCommand({
|
||||
const eveReceipt = eveProvider ? await eveProvider.submitCommand({
|
||||
providerId: "aetheria.daemon",
|
||||
surfaceId: "aetheria.game",
|
||||
command: "sensor_ping",
|
||||
|
|
@ -198,10 +183,11 @@ async function runElectronSmoke(window: BrowserWindow): Promise<Record<string, u
|
|||
typeof api.assetManifest === "function" &&
|
||||
typeof api.surfaceCatalog === "function" &&
|
||||
typeof api.surfaceCatalogIndex === "function" &&
|
||||
typeof api.eveProviderAdvertisement === "function" &&
|
||||
typeof api.eveDocument === "function" &&
|
||||
typeof api.eveSurface === "function" &&
|
||||
typeof api.submitEveCommand === "function",
|
||||
!!eveProvider &&
|
||||
typeof eveProvider.providerAdvertisement === "function" &&
|
||||
typeof eveProvider.document === "function" &&
|
||||
typeof eveProvider.surface === "function" &&
|
||||
typeof eveProvider.submitCommand === "function",
|
||||
status,
|
||||
bodyMode,
|
||||
eveHostText,
|
||||
|
|
@ -331,28 +317,7 @@ function registerIpc(): void {
|
|||
daemonRunning: daemonProcess != null && !daemonProcess.killed,
|
||||
daemonMode: launchLocalDaemon ? "local" : "remote",
|
||||
}));
|
||||
ipcMain.handle("aetheria-rts:window-control", (event, action: string) => {
|
||||
const window = BrowserWindow.fromWebContents(event.sender);
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
switch (action) {
|
||||
case "minimize":
|
||||
window.minimize();
|
||||
return;
|
||||
case "maximize":
|
||||
if (window.isMaximized())
|
||||
window.unmaximize();
|
||||
else
|
||||
window.maximize();
|
||||
return;
|
||||
case "close":
|
||||
window.close();
|
||||
return;
|
||||
default:
|
||||
throw new Error(`Unknown window control '${action}'.`);
|
||||
}
|
||||
});
|
||||
registerEveWindowControls(ipcMain, BrowserWindow, "aetheria-rts:window-control");
|
||||
}
|
||||
|
||||
function registerAssetProtocol(): void {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Generated by scripts/generate-rts-bindings.mjs from the RTS IPC surface contract.
|
||||
|
||||
const { contextBridge, ipcRenderer } = require("electron");
|
||||
const { installEveProviderBridge } = require("@gamecult/eve-electron/preload");
|
||||
|
||||
const channels = {
|
||||
mapViewport: "aetheria-rts:map-viewport",
|
||||
|
|
@ -58,10 +59,17 @@ contextBridge.exposeInMainWorld("aetheriaRts", {
|
|||
setTarget: request => ipcRenderer.invoke(channels.setTarget, request),
|
||||
surfaceCatalog: () => ipcRenderer.invoke(channels.surfaceCatalog),
|
||||
surfaceCatalogIndex: () => ipcRenderer.invoke(channels.surfaceCatalogIndex),
|
||||
eveSurface: request => ipcRenderer.invoke(channels.eveSurface, request),
|
||||
eveProviderAdvertisement: request => ipcRenderer.invoke(channels.eveProviderAdvertisement, request),
|
||||
eveDocument: request => ipcRenderer.invoke(channels.eveDocument, request),
|
||||
submitEveCommand: request => ipcRenderer.invoke(channels.submitEveCommand, request),
|
||||
windowControl: request => ipcRenderer.invoke(channels.windowControl, request),
|
||||
health: () => ipcRenderer.invoke(channels.health),
|
||||
});
|
||||
|
||||
installEveProviderBridge({
|
||||
contextBridge,
|
||||
ipcRenderer,
|
||||
channels: {
|
||||
providerAdvertisement: channels.eveProviderAdvertisement,
|
||||
surface: channels.eveSurface,
|
||||
document: channels.eveDocument,
|
||||
submitCommand: channels.submitEveCommand,
|
||||
windowControl: channels.windowControl,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
18
Aetheria.Rts.Web/package-lock.json
generated
18
Aetheria.Rts.Web/package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
|||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@gamecult/eve-browser-lowering": "file:../../Eve/packages/eve-browser-lowering",
|
||||
"@gamecult/eve-electron": "file:../../EveElectron",
|
||||
"@msgpack/msgpack": "^3.1.2",
|
||||
"cultcache-ts": "file:../../CultLib/packages/cultcache-ts",
|
||||
"cultmesh-ts": "file:../../CultLib/packages/cultmesh-ts",
|
||||
|
|
@ -68,6 +69,19 @@
|
|||
"typescript": "^5.6.3"
|
||||
}
|
||||
},
|
||||
"../../EveElectron": {
|
||||
"name": "@gamecult/eve-electron",
|
||||
"version": "0.1.0",
|
||||
"license": "MPL-2.0",
|
||||
"peerDependencies": {
|
||||
"electron": ">=30"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"electron": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@electron-internal/extract-zip": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.3.tgz",
|
||||
|
|
@ -103,6 +117,10 @@
|
|||
"resolved": "../../Eve/packages/eve-browser-lowering",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@gamecult/eve-electron": {
|
||||
"resolved": "../../EveElectron",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@msgpack/msgpack": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.3.tgz",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
"dependencies": {
|
||||
"@msgpack/msgpack": "^3.1.2",
|
||||
"@gamecult/eve-browser-lowering": "file:../../Eve/packages/eve-browser-lowering",
|
||||
"@gamecult/eve-electron": "file:../../EveElectron",
|
||||
"cultcache-ts": "file:../../CultLib/packages/cultcache-ts",
|
||||
"cultmesh-ts": "file:../../CultLib/packages/cultmesh-ts",
|
||||
"cultnet-ts": "file:../../CultLib/packages/cultnet-ts"
|
||||
|
|
|
|||
|
|
@ -1591,9 +1591,17 @@ function renderIpcChannelLines() {
|
|||
|
||||
function renderPreload() {
|
||||
const channelLines = renderIpcChannelLines();
|
||||
const eveProviderMethods = new Set([
|
||||
"eveSurface",
|
||||
"eveProviderAdvertisement",
|
||||
"eveDocument",
|
||||
"submitEveCommand",
|
||||
"windowControl",
|
||||
]);
|
||||
const apiLines = ipcChannels
|
||||
.filter(([name]) => name !== "viewportFeedUpdate" &&
|
||||
name !== "viewportFeedStop")
|
||||
name !== "viewportFeedStop" &&
|
||||
!eveProviderMethods.has(name))
|
||||
.map(([name]) => {
|
||||
if (name === "viewportFeed") {
|
||||
return ` watchViewportFeed: (request, callback) => {
|
||||
|
|
@ -1628,6 +1636,7 @@ function renderPreload() {
|
|||
// Generated by scripts/generate-rts-bindings.mjs from the RTS IPC surface contract.
|
||||
|
||||
const { contextBridge, ipcRenderer } = require("electron");
|
||||
const { installEveProviderBridge } = require("@gamecult/eve-electron/preload");
|
||||
|
||||
const channels = {
|
||||
${channelLines}
|
||||
|
|
@ -1636,5 +1645,17 @@ ${channelLines}
|
|||
contextBridge.exposeInMainWorld("aetheriaRts", {
|
||||
${apiLines}
|
||||
});
|
||||
|
||||
installEveProviderBridge({
|
||||
contextBridge,
|
||||
ipcRenderer,
|
||||
channels: {
|
||||
providerAdvertisement: channels.eveProviderAdvertisement,
|
||||
surface: channels.eveSurface,
|
||||
document: channels.eveDocument,
|
||||
submitCommand: channels.submitEveCommand,
|
||||
windowControl: channels.windowControl,
|
||||
},
|
||||
});
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ if (-not (Get-Content wwwroot\index.html -Raw).Contains('eve-surface-host')) {
|
|||
}
|
||||
|
||||
$appText = Get-Content wwwroot\app.js -Raw
|
||||
if (-not $appText.Contains('window.aetheriaRts.eveProviderAdvertisement') -or
|
||||
if (-not $appText.Contains('window.eveProvider.providerAdvertisement') -or
|
||||
-not $appText.Contains('EveBrowserProviderHost') -or
|
||||
-not $appText.Contains('window.aetheriaRts.eveDocument') -or
|
||||
-not $appText.Contains('window.eveProvider.document') -or
|
||||
$appText.Contains('window.aetheriaRts.eveProviderAdvertisement') -or
|
||||
$appText.Contains('window.aetheriaRts.eveDocument') -or
|
||||
$appText.Contains('eve:surface:aetheria.daemon.game') -or
|
||||
$appText.Contains('gamecult.aetheria.gravity_viewport.v1') -or
|
||||
$appText.Contains('gamecult.aetheria.render_splats_viewport.v1') -or
|
||||
|
|
@ -34,7 +36,7 @@ $mainText = Get-Content Electron\main.ts -Raw
|
|||
if (-not $mainText.Contains('await api.surfaceCatalog()') -or -not $mainText.Contains('await api.surfaceCatalogIndex()')) {
|
||||
Write-Error "Stage 7C Electron RTS verifier failed: Electron smoke does not call the preload CultMesh surface catalog APIs."
|
||||
}
|
||||
if (-not $mainText.Contains('await api.eveProviderAdvertisement()')) {
|
||||
if (-not $mainText.Contains('await eveProvider.providerAdvertisement()')) {
|
||||
Write-Error "Stage 7C Electron RTS verifier failed: Electron smoke does not verify provider advertisement discovery through preload."
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ if (-not $mainText.Contains('await api.renderSplatsViewport') -or
|
|||
Write-Error "Stage 7C Electron RTS verifier failed: Electron smoke does not verify daemon Eve field document lowering."
|
||||
}
|
||||
|
||||
if (-not $mainText.Contains('await api.submitEveCommand') -or
|
||||
if (-not $mainText.Contains('await eveProvider.submitCommand') -or
|
||||
-not $mainText.Contains('eveReceipt?.commandId') -or
|
||||
-not $mainText.Contains('eveReceipt?.accepted') -or
|
||||
-not $mainText.Contains('eveReceipt?.route')) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue