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

88 lines
7.1 KiB
JavaScript
Raw 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-bundle.template.js —— W-G1 通用 bundle 入口模板(逐字拷进每个生成 game 目录为 entry-bundle.js)
* owner:W-G1 lane | 消费方:esbuild --global-name=__GameBundle → P1 宿主 bootGameHost 真玩
*
* ════════════════════════════════════════════════════════════════════════════
* 【职责】把「生成的游戏工厂 + 通用宿主 + 标准 7 插件 wiring + 引擎」汇成一个 iife 全局 __GameBundle。
* 产出靶契约(冻结·逐字对齐 entry-bundle.js / game-package.schema.json engineBundle):
* iife 顶层全局名固定 **__GameBundle**;宿主从 window.__GameBundle 取 GameHostFactory 与 bootGameHost。
*
* 【最大化复用·最小新代码】
* - 宿主:复用 src/host/boot-game-host.js 的通用 bootGameHost(不改)。
* - 插件 wiring:用官方 L0 通用装载壳 src/host/generic-host-config.js 的 buildGenericHostConfig(标准 7 插件 + 偏序 + 视口 + 工厂 wiring,与官方 entry-generic.js 同一份),
* override factory 为本目录生成的工厂 → 生成游戏跑在【官方 generic 标准装配】上。
* - 注:本入口 = 官方 entry-generic.js 的「harness 可取证」超集——多透传 recHook/onReady 供 CDP 八门(F门真接线);
* studio 渠道调 bootGameHost({canvas,seed}) 时 recHook 为空=no-op,feed 照常(一份 bundle 同时服务 feed + 取证门)。
* - 引擎:Option C 动态 import(node import 本入口不触引擎,保 import-safe;esbuild 把引擎内联进单文件 iife)。
*
* 【Q4 铁律】本入口是「集成段 host」唯一引擎 import 落点(动态 import 后经 opts.engine 注入);
* ./factory.js 游戏工厂零引擎 import,能力一律经 boot.ctx.getEngine()。
* ════════════════════════════════════════════════════════════════════════════
*/
'use strict';
// 通用宿主(引擎骨架参数化;本身零引擎 import,引擎经 opts.engine 注入)。
import { bootGameHost as bootGameHostCore } from '../../../src/host/boot-game-host.js';
// 标准插件装配(官方 L0 通用装载壳 buildGenericHostConfig:collision/physics/gamefeel/juice/palettePost/audioMusic/save + 偏序 + 390×844 视口;零 wanglanmei 专属)。
import { buildGenericHostConfig } from '../../../src/host/generic-host-config.js';
// 本目录生成的游戏工厂(默认导出 GameHostFactory,零引擎 import,A3 硬独立文件;官方靶名 generated-factory.js)。
import gameFactory from './generated-factory.js';
/** 【契约导出】GameHostFactory:宿主从 window.__GameBundle.GameHostFactory 取它(契约冻结)。= 本目录生成的工厂。 */
export const GameHostFactory = gameFactory;
// 默认导出同为 GameHostFactory(便于 import default 取用;与具名导出同一引用)。
export default gameFactory;
/**
* 【P2/W-G1 boot 入口】供 host 页在浏览器内启动本 bundle(引擎由本 bundle 注入后驱动)。
* - 动态 import 引擎(Option C):调用时才求值,esbuild 已把引擎内联进本 bundle(无外部请求)。
* - engineMode 强制 'real'(W-G1 真玩取证一律引擎掌帧)。
* - 插件/视口/工厂 wiring 取自 buildRefHostConfig(与 ref 同一标准集),factory override 为生成工厂。
* - recHook / onReady 透传:供取证 harness 注入「引擎 call-ID 探针」与「internals(uncaught) 收集」(假绿守卫)。
*
* @param {Object} opts host 页传入入参。
* @param {HTMLCanvasElement} opts.canvas 页面 #game 画布(real 通道引擎自建 mainCanvas#game-engine,本 canvas 作占位/输入兜底)。
* @param {HTMLElement} [opts.statusEl] 状态行(可空)。
* @param {number} [opts.seed] 主随机种子(缺省固定值,保确定性)。
* @param {Function} [opts.recHook] 引擎 call-ID 取证钩子 id=>void(取证路径注入 window.__engineCalls.push;渠道产物不注)。
* @param {Function} [opts.onReady] (host, internals)=>void 就绪回调(取证收集 internals.uncaught 等)。
* @param {Iterable<string>} [opts.allowedGameEventTypes] 当前可信 profile 的业务事件 type 白名单。
* @param {Array<object>} [opts.assets] Studio 已完成字节校验的素材描述。
* @param {any} [opts.engine] 覆盖引擎名字空间(缺省动态 import littlejsengine)。
* @returns {Promise<object>} bootGameHost 的 host 句柄(frameCount/stepFrames/tap/do/state 等)。
*/
export async function bootGameHost(opts) {
const o = opts || {};
// 动态 import 引擎:求值时机延后到本函数被调用(浏览器运行期)。esbuild 内联,无外部请求。
const engine = o.engine || (await import('littlejsengine'));
// 主随机种子(缺省固定值,与 ref 取证同口径,保确定性可复现)。
const seed = (o.seed != null ? o.seed : 0x1234abcd) >>> 0;
// 官方 generic 标准装配(7 插件 + 偏序 + 视口 + 工厂 wiring;与 entry-generic.js 同一 buildGenericHostConfig)。
const cfg = buildGenericHostConfig({ seed });
// playtest/3 seed 握手:入口是实际 seed 的唯一裁决点,先公开实际采用值,再把同一值传给宿主与插件装配。
// 渠道正常启动同样会得到缺省 seed 的只读观测值,不改变既有运行行为。
if (typeof window !== 'undefined') window.__playtestActualSeed = seed;
// 调通用宿主:real 通道引擎掌帧;factory override 为本目录生成工厂;其余 wiring 取标准集。
return bootGameHostCore({
canvas: o.canvas,
statusEl: o.statusEl || null,
engine,
seed,
mode: o.mode || 'play', // W-G1 真玩=play
engineMode: 'real', // 一律引擎掌帧(real 通道)
viewport: cfg.viewport, // 390×844(与 ref 同,移动竖屏基准)
factory: gameFactory, // ★ override:本目录【生成的游戏】(其余 wiring 全复用 ref)
plugins: cfg.plugins, // 标准 7 插件实例集(经 opts.runtime.plugins 注入给工厂)
registerOrder: cfg.registerOrder, // 注册偏序(保六锚)
producerCapability: cfg.producerCapability, // 品类装配若声明受保护生产能力,必须原样交给可信宿主
buildFactoryOpts: cfg.buildFactoryOpts, // 注入 runtime:{plugins,bundle,getRealAudioCtx}
// 生产 runner 可按已解析 profile 收窄;普通渠道仅接受 generic config 明确声明,否则空集 fail-closed。
allowedGameEventTypes: o.allowedGameEventTypes != null
? o.allowedGameEventTypes : (cfg.allowedGameEventTypes || []),
recHook: o.recHook || null, // 取证:引擎 call-ID 探针(默认 no-op)
onReady: o.onReady || null, // 取证:收集 internals(uncaught)
assets: o.assets || [], // studio 已逐字节校验后注入的内存素材描述
});
}