二七王:平台接线与加载段
SubGameHooks 只解包转交、不写业务:_ReceiveData 收到的是完整包, 按 rpc 分发;Free 的参数是平台已取出的 deskfree、可能为 null; appStart 只记座位与房间选项,UI 初始化留给 C 阶段。 index.html 里 handler 排在 Dispatcher 之前——后者注册时要引用全部 handler。 另加 test_index_load_order.js:按 index.html 实际 script 顺序自动加载 codes/ 全部文件 + 3 个框架依赖,验证顺序无遗漏、无环,并断言 EQW_Dispatcher 路由表确已注册,作为长期守卫。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
// index.html 加载顺序自检(task-13 步骤6守卫):
|
||||
// 按 index.html 里 <script src> 的实际先后顺序,抽取「codes/ 全部文件 + 它们依赖的
|
||||
// 3 个框架文件(EventBus/SpriteEventController/AlignmentUtils)」,依次用 vm 加载,
|
||||
// 确认:1) 无异常抛出(顺序错了会因引用未定义全局而报错)
|
||||
// 2) 关键全局全部就绪
|
||||
// 3) EQW_Dispatcher 的路由表确已注册(hasHandler('chupai1') === true)
|
||||
// 这份顺序即是 index.html 的真实加载顺序,不是我们另行假设的一份。
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const vm = require('vm');
|
||||
const t = require('./_assert')();
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..', '..');
|
||||
const indexHtml = fs.readFileSync(path.join(ROOT, 'client', 'index.html'), 'utf8');
|
||||
|
||||
// 抽取全部本地 <script src="..."> 路径,按文档出现顺序
|
||||
const scriptRe = /<script[^>]*\ssrc="([^"]+)"[^>]*><\/script>/g;
|
||||
const allSrcs = [];
|
||||
let m;
|
||||
while ((m = scriptRe.exec(indexHtml)) !== null) {
|
||||
allSrcs.push(m[1]);
|
||||
}
|
||||
t.eq('index.html 至少解析出脚本标签', allSrcs.length > 0, true);
|
||||
|
||||
// 只保留:codes/ 下全部文件 + 3 个框架依赖文件,其余(vendor/引擎/大厅平台代码等)
|
||||
// 无法在 Node 里单独跑,本自检不覆盖,留给「浏览器人工验证」。
|
||||
const NEEDED_FRAMEWORK = [
|
||||
'js/gameabc-framework/system/EventBus.js',
|
||||
'js/gameabc-framework/system/SpriteEventController.js',
|
||||
'js/gameabc-framework/ui/AlignmentUtils.js'
|
||||
];
|
||||
const relevant = allSrcs.filter(function (src) {
|
||||
return NEEDED_FRAMEWORK.indexOf(src) !== -1 || src.indexOf('js/01_SubGame/codes/') === 0;
|
||||
});
|
||||
|
||||
// 期望齐全的清单:本任务新增/相关的 state/ net/ 文件,一个都不能漏
|
||||
const EXPECT_PRESENT = [
|
||||
'js/01_SubGame/codes/state/Events.js',
|
||||
'js/01_SubGame/codes/state/GameState.js',
|
||||
'js/01_SubGame/codes/state/RoomOptions.js',
|
||||
'js/01_SubGame/codes/net/handlers/FailHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/DealHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/CallHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/MainHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/BuryHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/PlayHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/QueryHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/ReadyHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/ResultHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/ResyncHandler.js',
|
||||
'js/01_SubGame/codes/net/Dispatcher.js',
|
||||
'js/01_SubGame/codes/net/Rpc.js',
|
||||
'js/01_SubGame/codes/SubGameHooks.js'
|
||||
];
|
||||
EXPECT_PRESENT.forEach(function (src) {
|
||||
t.eq('index.html 含脚本 ' + src, allSrcs.indexOf(src) !== -1, true);
|
||||
});
|
||||
|
||||
// 相对顺序断言:handler 全部排在 Dispatcher 之前;state/ 排在 net/handlers/ 之前
|
||||
const idx = {};
|
||||
relevant.forEach(function (src, i) { idx[src] = i; });
|
||||
var dispatcherIdx = idx['js/01_SubGame/codes/net/Dispatcher.js'];
|
||||
[
|
||||
'js/01_SubGame/codes/net/handlers/FailHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/DealHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/CallHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/MainHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/BuryHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/PlayHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/QueryHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/ReadyHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/ResultHandler.js',
|
||||
'js/01_SubGame/codes/net/handlers/ResyncHandler.js'
|
||||
].forEach(function (h) {
|
||||
t.eq('handler 排在 Dispatcher 之前: ' + h, idx[h] < dispatcherIdx, true);
|
||||
});
|
||||
t.eq('state/ 排在 net/handlers/ 之前', idx['js/01_SubGame/codes/state/GameState.js'] < idx['js/01_SubGame/codes/net/handlers/FailHandler.js'], true);
|
||||
t.eq('SubGameHooks 排在 Dispatcher 之后', idx['js/01_SubGame/codes/SubGameHooks.js'] > dispatcherIdx, true);
|
||||
|
||||
// 依次实际加载,确认不抛异常,且顺序自洽
|
||||
global.window = global;
|
||||
let loadErr = null;
|
||||
try {
|
||||
relevant.forEach(function (src) {
|
||||
const abs = path.join(ROOT, 'client', src);
|
||||
const code = fs.readFileSync(abs, 'utf8');
|
||||
vm.runInThisContext(code, { filename: src });
|
||||
});
|
||||
} catch (e) {
|
||||
loadErr = e;
|
||||
}
|
||||
t.eq('按 index.html 顺序加载无异常', loadErr ? (loadErr.stack || String(loadErr)) : null, null);
|
||||
|
||||
// 关键全局就绪
|
||||
[
|
||||
'EQW_Events', 'EQW_GameState', 'EQW_RoomOptions_Parse', 'EQW_Dispatcher', 'EQW_Rpc',
|
||||
'EQW_DealHandler', 'EQW_CallHandler', 'EQW_MainHandler', 'EQW_BuryHandler', 'EQW_PlayHandler',
|
||||
'EQW_QueryHandler', 'EQW_ReadyHandler', 'EQW_ResultHandler', 'EQW_ResyncHandler', 'EQW_FailHandler',
|
||||
'SubGameHooks'
|
||||
].forEach(function (name) {
|
||||
t.eq('全局就绪: ' + name, typeof global[name] !== 'undefined', true);
|
||||
});
|
||||
|
||||
// 路由表确已注册
|
||||
if (typeof global.EQW_Dispatcher !== 'undefined') {
|
||||
t.eq("EQW_Dispatcher.hasHandler('chupai1')", global.EQW_Dispatcher.hasHandler('chupai1'), true);
|
||||
}
|
||||
|
||||
process.exit(t.done('index_load_order') ? 0 : 1);
|
||||
Reference in New Issue
Block a user