zizi 8ea6133e63 fix(tier2): recHook 透传到资源系统——F 门/三联动门记 resource.* call-ID
F 门/三联动门读 window.__engineCalls 找 resource.addCoins/consumeIngredient 前缀,
但旧版只有 engine-caps(粒子/音频)经 recHook 记 __engineCalls,资源系统只记内部
_callCounts、不进 __engineCalls → calls=0、F 门 + 三联动门真接线判据永假。

修(additive,不破契约必填项):host 经 boot 上下文透传 recHook → main.js 喂
createGameCore → resource-system 完单真调 addCoins/合成真调 consumeIngredient 时
recHook('resource.addCoins'/'resource.consumeIngredient') 记进 __engineCalls。
headless/静态校验下 recHook 缺省 no-op、不抛错。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 20:48:40 +00:00

118 lines
6.9 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.

/**
* src/main.js —— mini-肥鹅 入口A3 entry · PhaserGameFactory 默认导出 · 平台预建装载胶水)
* ownertier2 引擎线M1 · scaffold platform 预建部分)
*
* ════════════════════════════════════════════════════════════════════════════
* 【这份是什么 · 工厂 + 实例(装载靶)】
* A3 源项目契约的 entry = src/main.js默认导出实现 PhaserGameFactory 的函数tier2/contracts/boot-phaser-host.d.ts
* build-phaser.mjs esbuild 打成 iife 后挂全局名 __Tier2GameBundlehostboot-phaser-host.js取它建 PhaserGameInstance。
* 本文件预建**装载胶水**(先天过 boot
* - 工厂创建 game-core三系统逻辑纯逻辑写死
* - PhaserGameInstance.boot接 host 注入的 boot 上下文,把核心逻辑接进 Phaser scene 树。
* - readState透传 game-core._forensicsView().state()A6 语义 statelatch 门读 phase
* - injectInput / destroy归一化输入入口 + 卸载卫生。
* **表现层 scene画棋盘 / 订单面板 / 点击命中坐标映射 / 动画)是 LLM 现写那约 56%,在 src/scenes/play-scene.js**——
* 本文件只负责把 scene 接进 Phaser 并把输入路由到 game-core 逻辑命令。
*
* 【受控随机派生】(确定性铁律)
* boot.seed 派生受控随机源(禁裸 Math.random对齐 fixture-spec / api.d.ts RandomSource
* harness 同 seed 可确定性重放driver 驱动可复现。
* ════════════════════════════════════════════════════════════════════════════
*/
'use strict';
// Phaser 名字空间iife 构建下经 external 'phaser' 解析为宿主预载的全局build-phaser.mjs external 配置)。
// 本 import 在 esbuild iife + external:phaser 下不打进 bundle运行时绑定宿主页面的 window.Phaser。
import Phaser from 'phaser';
import { createGameCore } from './game-core.js';
import { createPlayScene } from './scenes/play-scene.js';
import { createSeededRandom } from './util/seeded-random.js';
/**
* PhaserGameFactoryhost 调它建 PhaserGameInstanceA4 装载契约)。
* esbuild iife globalName=__Tier2GameBundlehost 取 window.__Tier2GameBundle.default 或 .createGame。
* @param {Record<string, unknown>} [opts] 工厂选项difficulty/variant 等spike 暂不用)
* @returns {import('../../../contracts/boot-phaser-host.d.ts').PhaserGameInstance}
*/
export default function createGame(opts) {
// 游戏核心(三系统逻辑)+ 受控随机boot 时按 seed 派生此处先占位boot 内据 seed 重建)。
/** @type {ReturnType<typeof createGameCore>|null} */
let core = null;
/** @type {any} 活跃的 play scene表现层boot 内由 Phaser scene 管理器建)。 */
let playScene = null;
/** @type {any} host 注入的 Phaser.Game 实例real 通道headless 为 null。 */
let phaserGame = null;
/** @type {any} host 注入的受控能力面(粒子/音频/math游戏经它做特效不调裸 Phaser。 */
let caps = null;
return {
/**
* 一次性启动PhaserGameInstance.boot。接 host 注入的 boot 上下文,建核心 + 接 Phaser scene。
* @param {import('../../../contracts/boot-phaser-host.d.ts').PhaserHostBootContext & { caps?: object }} ctx
*/
async boot(ctx) {
// 据 boot.seed 派生受控随机源(确定性;禁裸 Math.random
const random = createSeededRandom(ctx.seed >>> 0);
// 建游戏核心三系统逻辑平台预建写死。recHook 由 host 经 boot 上下文 additive 透传:
// 资源系统完单/合成时经它把 'resource.addCoins'/'resource.consumeIngredient' 记进 window.__engineCalls,
// 供 F 门 / 富游戏三联动门证真接线(headless 下 ctx.recHook 缺省 → no-op)。
core = createGameCore({ random, recHook: ctx.recHook });
core.start(); // title → playspike 直接进局;产线可加标题页)
// 受控能力面host 经 boot 上下文 additive 透传 capsheadless 下为 no-op 能力面)。
caps = ctx.caps || null;
phaserGame = ctx.game || null;
// real 通道:把表现层 play scene 接进 Phaser scene 管理器。
// headlessctx.game===null不接 scene逻辑核心已就绪readState 可读(供 headless 逻辑校验)。
if (phaserGame && phaserGame.scene && typeof phaserGame.scene.add === 'function') {
// 建表现层 sceneLLM 现写域):注入核心逻辑 + 受控能力面 + 资产。
playScene = createPlayScene({
core, // 三系统逻辑命令scene 点击命中后调 core.tapCell / fulfillOrder
caps, // 受控特效面(粒子/音频/math
assets: ctx.assets || {}, // 宿主预载资产(按 ref 键;缺=降级占位)
Phaser, // Phaser 名字空间scene 画图用)
});
// 注册并启动 scenePhaser 自掌帧、自渲;本 scene 的 update 推进 core 逻辑 + 重画 UI
phaserGame.scene.add('PlayScene', playScene, true);
}
},
/**
* 可观测状态A6 语义 statelatch 门 / 富游戏三门读它)。透传 game-core 导出视图,只读。
* @returns {import('../../../contracts/boot-phaser-host.d.ts').GameForensicsState}
*/
readState() {
if (!core) return { phase: 'booting' };
// 透传 _forensicsView().state()phase 不变量 + per-品类语义字段)。
return core._forensicsView().state();
},
/**
* 归一化输入入口harness 驱动;与 scene 内 Phaser input 订阅二者择一harness 优先走这里保确定性)。
* tap把屏幕坐标交给 play scene 做点击命中 → 命中棋盘格 / 订单 → 调 core 逻辑命令。
* @param {import('../../../contracts/boot-phaser-host.d.ts').PhaserInputEvent} ev
*/
injectInput(ev) {
if (!playScene || typeof playScene.handleNormalizedInput !== 'function') return;
// 路由给表现层做命中测试(命中映射在 scene逻辑命令在 core
playScene.handleNormalizedInput(ev);
},
/** 卸载幂等session 切换 / 多游戏复位;释放 scene。 */
destroy() {
try {
if (phaserGame && phaserGame.scene && playScene && typeof phaserGame.scene.remove === 'function') {
phaserGame.scene.remove('PlayScene');
}
} catch (e) { /* 幂等吞错 */ }
playScene = null;
core = null;
},
};
}
// 具名导出host 取工厂的兼容入口window.__Tier2GameBundle.createGame 或 .default
export { createGame };