Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion apps/mapgen-studio/src/app/hooks/useSetupDataQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export function useSetupDataQueries(): {
return {
status: "ok",
directory: body.directory ?? "",
// The contract deliberately types `configurations` as opaque records:
// the saved-config file shape is owned by @civ7/direct-control
// (listCiv7SavedGameConfigurations), and re-declaring it in the oRPC
// contract would just drift. The cast states that trust explicitly.
configurations: body.configurations as unknown as ReadonlyArray<Civ7SavedSetupConfigFile>,
updatedAt: body.observedAt ?? new Date().toISOString(),
};
Expand All @@ -84,11 +88,13 @@ export function useSetupDataQueries(): {
if (!body) {
return { status: "idle" };
}
// Same deliberate-opacity trust as `configurations` above: the catalog
// shape is owned by the server's civ7Resources catalog builder.
const catalog = body.catalog as unknown as Civ7SetupCatalog;
return {
status: "ok",
catalog,
updatedAt: catalog.observedAt,
updatedAt: catalog.observedAt ?? new Date().toISOString(),
};
}, [setupCatalogQuery.data, setupCatalogQuery.error, setupCatalogQuery.isError]);

Expand Down
9 changes: 9 additions & 0 deletions apps/mapgen-studio/src/features/civ7Setup/setupConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ export type Civ7StudioSavedConfigRef = Readonly<{
path: string;
}>;

/**
* The authored game-setup state behind the header's Game bar — the single
* source for what launches in Civ7. At launch the engine loads
* `savedConfig` (if any) into Civ7 first and then re-applies EVERY key in
* `gameOptions`/`playerOptions` on top, so these maps must contain only
* values the user (or an exact saved-config application) authored: any
* extra key silently overrides the loaded file (see
* `studioSetupConfigFromSavedConfigFile` / `studioSetupDriftsFromSavedConfig`).
*/
export type Civ7StudioSetupConfig = Readonly<{
savedConfig?: Civ7StudioSavedConfigRef;
mapScript?: string;
Expand Down
22 changes: 22 additions & 0 deletions apps/mapgen-studio/src/server/studio/engines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,17 @@ export interface AutoplayEngineResult {
type SaveDeployOperationStore = ReturnType<typeof createMapConfigSaveDeployOperationStore>;
export type SaveDeployEngineResult = ReturnType<SaveDeployOperationStore["create"]>;

/**
* The studio's stateful server engines — the one place long-running Civ7
* operations (run-in-game, save/deploy, autoplay) execute and are tracked.
*
* Contract: engines serialize through a process-wide operation queue (one
* Civ7-mutating operation at a time), record progress in TTL-bounded
* operation stores keyed by request id, and throw `RunInGameHttpError`
* (legacy HTTP status + structured `details`) for every client-visible
* failure — transports map it 1:1, so error codes stay stable across the
* Vite middleware and Bun daemon mounts.
*/
export interface StudioEngines {
/** Process-lifetime identity — clients reconcile run-in-game state against it. */
readonly serverInstanceId: string;
Expand Down Expand Up @@ -504,6 +515,17 @@ export function createStudioEngines(options: Readonly<{ repoRoot: string }>): St
};
}

/**
* The Run-in-Game orchestrator: validate the request, materialize the map
* config + generated script, build-and-deploy the swooper mod, prove the
* deployed script carries this run's materialization markers (request id /
* config hash / envelope hash / native river markers — the correctness
* boundary: a launch must never run a stale script), restart or exit Civ7
* to shell as needed, start the prepared single-player game, and wait for
* the in-game mapgen log proof. Progress is recorded phase-by-phase in the
* operation store under the request id; duplicate requests return the
* already-tracked operation instead of double-launching.
*/
async function runRunInGameStartEngine(
body: RunInGameStartEngineBody,
): Promise<RunInGameStartResult> {
Expand Down
4 changes: 2 additions & 2 deletions apps/mapgen-studio/src/ui/components/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export interface AppHeaderProps {
onHeaderHeightChange?: (height: number) => void;
/**
* The live-game command cluster (Pass-5 zoning v2: top = Game, bottom =
* World/Map). Composed INLINE into the Game bar row, between the
* saved-config selector and the trailing setup disclosure.
* World/Map). Composed INLINE into the Game bar row, after the Config
* cluster (selector + setup gear, Z-wave Game bar v3).
*/
gameConsole?: React.ReactNode;
}
Expand Down