// world.js - 服务端世界状态:空间实例表 / 空间分类 / 未实现命令清单 // // M1 只承载「服务器需要记住什么」:客户端连过哪些空间、每个空间收到了哪些命令(尚未实现语义)。 // 这四个注册表(gameType / model / resource / space)在 M2 才会真正填内容—— // 现在先把「客户端要什么」记全,那就是施工图。 'use strict'; // 入口空间:真实服务器在 Hash Response 同一帧里下发(实测 0x5f691cc = 100045260) const ENTRANCE_SPACE = 100045260; // 空间分类。置信度如实标注: // 实测 = 抓包/源码直接对得上;容器 = 从该空间容器的模式表推出来的用途;待核实 = 只有命名线索 // 注意:超过 2^53 的 id 必须写成字符串(3074457345817190050 用数字字面量会掉精度) const SPACE_KIND = { 100045260: 'Entrance', // 实测:与 Hash Response 同帧下发,只有 3 条 s2c 100073070: 'Garage', // 实测:客户端上报 button_click "GARAGE" 后服务器 Open Space(100073070) 100072911: 'Shop', // 容器模式表 = Jj / ShopCategoryCC 100045720: 'Chat', // 容器模式表 = _t / Kz / ChatCC / ClanChatCC / NewsShowingCC 920007382011: 'Queue', // 待核实(旧注释写「快速战斗队列」) 100119080: 'Unknown', '3074457345817190050': 'Unknown', // 待核实:帧量极大(3551 条 s2c),疑似战斗 }; function MakeWorld() { const Spaces = new Map(); const Unimplemented = new Map(); let NoteCount = 0; function EnsureSpace(Id) { const Key = String(Id); let S = Spaces.get(Key); if (!S) { S = { Id: Key, Kind: ClassifySpace(Key), Commands: 0, Since: new Date().toISOString() }; Spaces.set(Key, S); } return S; } // 记一条「还没实现语义」的上行命令(按 空间类别 + 命令名 归并) function NoteUnimplemented(Kind, Name, MethodId, Target) { NoteCount++; const Key = Kind + ' ' + Name; let U = Unimplemented.get(Key); if (!U) { U = { Kind, Name, MethodId, Count: 0, Targets: new Set() }; Unimplemented.set(Key, U); } U.Count++; if (U.Targets.size < 5) U.Targets.add(String(Target)); } // 会话结束/定时打印用:按次数排序的未实现清单 function UnimplementedSummary() { const Rows = [...Unimplemented.values()] .sort((A, B) => B.Count - A.Count) .map((U) => ({ Kind: U.Kind, Name: U.Name, MethodId: U.MethodId, Count: U.Count, Targets: [...U.Targets] })); return { Total: NoteCount, Distinct: Rows.length, Rows }; } return { Spaces, Unimplemented, EnsureSpace, NoteUnimplemented, UnimplementedSummary }; } function ClassifySpace(Id) { return SPACE_KIND[String(Id)] || 'Unknown'; } module.exports = { MakeWorld, ClassifySpace, ENTRANCE_SPACE, SPACE_KIND };