lili 1981a6be01
Some checks failed
contract-gates / contract-gates (push) Has been cancelled
docs-gate / docs-gate (push) Has been cancelled
feat(storage): 闭合 Agent 到 Runtime 的 OSS 游戏链路
增加不可变源码检出、两阶段 finalize/activate、Runtime 同源对象读取与 iframe 安全边界,并用 fail-closed CI 门固定契约。Git 仅提交平台实现、契约、迁移和 SoT,不包含具体游戏源码、素材、bundle 或验收证据。
2026-07-30 05:21:44 -07:00

92 lines
7.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* entry-generic.js — P3 generic bundle 入口壳模板·esbuild 锁参打成 iifeglobalName=__GameBundle
* ownerP3/W-G1 生成主线 L0 消费方studio host 引擎包分支DB-manifest 内嵌路,与 wanglanmei-ref/entry-bundle.js 同消费方)
*
* ════════════════════════════════════════════════════════════════════════════
* 【本入口是什么 · 与 wanglanmei-ref/entry-bundle.js 的关系】
* entry-bundle.js 是 wanglanmei 一款游戏的「studio-consumable」bundle 入口(工厂写死 import game-shop
* 本 entry-generic.js 把它泛化成「任意生成游戏」的通用入口壳:
* · 游戏工厂来源参数化 → `import createGame from './generated-factory.js'`L1 生成 worker 写入的产出靶);
* · 装配走 buildGenericHostConfig零wanglanmei专属标准能力插件集不再走 buildRefHostConfig。
* 这是 L1 生成 worker 的「套壳靶」worker 只需产出 generated-factory.js一个 GameHostFactory
* 套进本壳 esbuild 打成 __GameBundle bundle即得一个 studio 可消费的引擎包——避免 20 个 prompt 各造一遍
* 「7 插件 wiring + boot 入口」(见 execution §3.2 套壳分级框 / §7-S1
*
* 【契约(冻结·逐字对齐)】
* - iife 顶层全局名固定 **__GameBundle**(与 game-package.schema.json/contract.ts/inject.ts 逐字一致);
* studio iframe 注入本 bundle 文本 → 取 window.__GameBundle.bootGameHost 启动。
* - boot 入口调用形 **{canvas, seed}** 逐字对齐 game-studio/src/host/inject.ts:248
* `bundleNS.bootGameHost({ canvas: canvas, seed: seed })`)。
* - 本 bundle = 引擎(LittleJS) + 包装层(bootGameHost + generic 装配) + 生成游戏代码(generated-factory)。
*
* 【Q4 · Option C引擎 import 只落本入口,且经动态 import 延后求值】
* littlejsengine ESM 在模块装载期触 window/AudioContext顶层静态 import 会让 node 一 import 即抛 →
* 击穿 import-safe。修法与 entry-bundle 逐字同款):引擎 import 改「bootGameHost 内动态 import」
* · node import 本入口时不触引擎bootGameHost 未被调)→ import-safe
* · esbuildbundle+iife 无 splitting把动态 import 的引擎内联进单文件 → 引擎真入 bundle
* · 浏览器运行期 studio 调 __GameBundle.bootGameHost 时才求值引擎window/AudioContext 已存在)。
* ════════════════════════════════════════════════════════════════════════════
*/
'use strict';
// 通用宿主(引擎骨架参数化;本身零引擎 import引擎经 opts.engine 注入)。
import { bootGameHost as bootGameHostCore } from '../../src/host/boot-game-host.js';
// generic 装配配置(标准能力插件集 / 偏序 / 视口 / wiring零wanglanmei专属
import { buildGenericHostConfig } from '../../src/host/generic-host-config.js';
// 【游戏工厂来源·参数化】L1 生成 worker 写入的生成工厂(默认导出 GameHostFactory零引擎 import
// 占位期 = games/_generic/generated-factory.js 的占位 stubL1 出码替换该文件即换游戏,本壳零改。
import createGame from './generated-factory.js';
/**
* 【契约导出】GameHostFactorystudio host 从 window.__GameBundle.GameHostFactory 取它(契约冻结)。
* = 生成工厂createGame。L1 出码替换 generated-factory.js 的默认导出即换它。
* @type {import('../../src/core/game-host.d.ts').GameHostFactory}
*/
export const GameHostFactory = createGame;
// 默认导出同为 GameHostFactory便于 import default 取用;与具名导出同一引用)。
export default createGame;
/**
* 【boot 入口】供 studio host 在 iframe 内启动本 bundlestudio 仓无引擎,故由本 bundle 注入引擎后驱动)。
* - 动态 import 引擎Option C调用时才求值esbuild 已把引擎内联进本 bundle无外部请求
* - engineMode 强制 'real'studio 引擎包分支一律引擎掌帧)。
* - 插件/视口/wiring 取自 buildGenericHostConfig标准能力插件集 + 390×844
* - 工厂取 createGame本 bundle 内 generated-factory 默认导出studio 也可经 opts.factory 覆盖,缺省即用它)。
*
* @param {Object} opts studio host 传入的最小入参(调用形 {canvas, seed} 逐字对齐 inject.ts:248
* @param {HTMLCanvasElement} opts.canvas iframe 内目标画布real 通道引擎自建 mainCanvas本 canvas 作占位/输入兜底)。
* @param {HTMLElement} [opts.statusEl] 状态行(可空)。
* @param {number} [opts.seed] 主随机种子缺省固定值保确定性studio 由 versionId 派生后传)。
* @param {any} [opts.engine] 引擎名字空间覆盖(缺省=动态 import littlejsengine测试可注入桩引擎
* @param {import('../../src/core/game-host.d.ts').GameHostFactory} [opts.factory] 工厂覆盖(缺省=本 bundle 的 createGame
* @returns {Promise<object>} bootGameHost 的 host 句柄frameCount/stepFrames/tap/do/state 等)。
*/
export async function bootGameHost(opts) {
const o = opts || {};
// 动态 import 引擎求值时机延后到本函数被调用浏览器运行期。esbuild 内联,无外部请求。
// opts.engine 覆盖优先(测试可注桩引擎,免拉真引擎);缺省动态 import 真引擎。
const engine = o.engine || (await import('littlejsengine'));
// seed 缺省固定值(与 ref/inject 同口径:非数字回退 0x1234abcd规整无符号 32 位。
const seed = (o.seed != null ? o.seed : 0x1234abcd) >>> 0;
// generic 装配(标准能力插件集 / 偏序 / 视口 / wiring
const cfg = buildGenericHostConfig({ seed });
// 调通用宿主real 通道引擎掌帧canvas/statusEl 由 studio 传;其余取 generic 装配。
return bootGameHostCore({
canvas: o.canvas,
statusEl: o.statusEl || null,
engine,
seed,
mode: 'play', // studio 真玩=play
engineMode: 'real', // studio 引擎包分支一律引擎掌帧
viewport: cfg.viewport, // {w:390,h:844}P3 钉死)
factory: o.factory || cfg.factory || createGame, // 缺省用本 bundle 内置生成工厂
plugins: cfg.plugins,
registerOrder: cfg.registerOrder,
buildFactoryOpts: cfg.buildFactoryOpts,
assets: o.assets || [],
// studio 渠道产物:不注 recHook引擎 call-ID 取证是 ref harness 专属;渠道产物无副作用)。
// 无 onReadystudio 不消费 ref 取证全局;就绪信号经 SDK lifecycle game_loaded/game_endstudio 轨接)。
});
}