package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // 大地图入口(传送点 / 地铁站)—— 2026-09-27 从 kpect 捐赠端移植的「入口四连发 + 点击真传送」。 // ## 为什么之前大地图上什么都没有 // 客户端地图入口是**服务端下发驱动**的,四条 S2C 在此之前**全服零命中**(grep 过整个 v0.3): // · SyncMapEntrance (64067363) 全量清单 → MapUtils._visibleEntrance / _unlockedEntrance // · UpdateMapEntrance (64239821) 逐点开关 // · SyncPrepareMapEntrance (64610549) 逐点准备(交通层入口的注册步骤) // · SyncSubwayFare (64660858) 地铁票价 // 判据链:MapUtils.IsEntranceVisible(id) 只查 _visibleEntrance,而这个表 // **只能**由上面前两条帧写入 ⇒ 一条不发 = 地图上一个传送点图标都没有。 // ## 点击传送 // AskTouchMapEntrance(63284182) 是客户端 Notify(void,不等回包), // 调用点 MapCsApi.Legacy_DoFightMapEntrance(gRaidDataManager.RaidId, mapEntranceId)。 // 以前没有 handler ⇒ 落到 RPC 兜底 ⇒ 点了没反应。 // · 同 raid → TeleportPlayerWithLoadingAsync(官方 loading 传送流程) // · 跨 raid → SwitchSceneAsync(GameRouter.SceneSwitch.cs,换图事务) // ## 数据来源 // 用我们自己的 MapentranceConfig(93 行)+ RaidConfig // (SceneCatalog4229938.MapEntrances),**不用** kpect 的 ExtraCatalog, // 也不动主线已经完整的 GameRouter.Metro.cs(SyncRunningMetroInfos 68333359)。 // ## 回滚 // gameplay.mapEntrance.enabled=false ⇒ 四帧都不发、点击也不传送,逐字节回到移植前。 // 逐帧也能单独关(pushSync / pushUpdate / pushPrepare / pushSubwayFare)。 // // // 进世界后推一次地图入口四连发。 // ⛑ 派发量:93 个入口 × (UpdateMapEntrance + SyncPrepareMapEntrance) = 186 帧。 // 收包循环是串行的(读完一帧 → await DispatchAsync → 才读下一帧),同步连发会把 // 客户端这一秒的上报全部堵住 —— 与 PublishMapFogUnlockAsync 那次 260 帧 // 是同一个坑,所以这里照抄它的「后台分批 + 10ms/25 帧」摊平写法。 // func GameRouter_MapEntrance_PublishMapEntrancesAsync(ctx context.Context, rpcCtx *RpcContext) any { // Router implementation for GameRouter_MapEntrance_PublishMapEntrancesAsync var zero any; return zero } // // AskTouchMapEntrance (63284182):客户端 void notify。命中配置就真传送。 // 判据分支(grep [MAP-TOUCH]): // ① teleport-in-place 同 raid 命中并传送 // ② switch-raid 跨 raid 命中并换图 // ③ unknown-id / raid-mismatch / bad-coordinate / malformed / no-world-state / disabled // func GameRouter_MapEntrance_AskTouchMapEntrance(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_MapEntrance_AskTouchMapEntrance var zero any; return zero } // // 载荷解析:主路径 = 严格 8 B(raidId @0 / mapEntranceId @4,小端裸值)。 // 长度不为 8 时做一次自校验容错扫描(要求第二个 u32 能命中入口表、第一个与该行 RaidId 一致), // 命中即采用并在判据行里写明「容错扫描@N」,不会静默成功。 // func GameRouter_MapEntrance_TryParseMapTouchBody(ctx context.Context, body []byte, raidId uint32, entranceId uint32, note string) bool { // Router implementation for GameRouter_MapEntrance_TryParseMapTouchBody return true } // // AskPlayerChangePositionByScenePortal (67006840, invoke u32 mapEntranceId): // 大地图「交通直达」(地铁站 / 公交站 / 传送点)**同图**传送的 domain RPC。 // 客户端 MapSubSystem_Entrance.lua:559 MapTeleport 的时序: // ① gLoadingManager:AskTeleport(loadingConfigId, preTeleportOption, ...) —— 客户端 // 自己填好了 afterPosition(=MapTeleportPos) / afterResName(=TeleportEndTimeLine) / // loadingResName,服务端 AskTeleport handler 只登记 + ack; // ② ack 回来后回调里 gClientUtils.MapTeleport()(**只关 UI,不动坐标**),再按 // 「目标 raid == 当前 raid」分流:同图 → 本 RPC;跨图 → AskPublicSwitchToPublicScene; // ③ 本 RPC 回 Ok 才 StopLoading。 // ⛑ 本 RPC 之前**连 method id 都没有**(服务端 0 处引用),又是 Invoke ⇒ 客户端 await // 永久挂起 ⇒ 「长按 F / 点交通直达没反应」。跨图那条(AskPublicSwitchToPublicScene) // 早就有 handler,所以只有同图(25 个地铁站绝大多数都在 23300888 内)表现为完全无响应。 // 位移用 SyncTeleport 推,teleportId 取客户端自己那次 AskTeleport 登记的 // PendingTeleportId(客户端只认自己事务的那一帧)。 // 判据分支(grep [MAP-PORTAL]): // disabled / malformed / unknown-id / bad-coordinate / no-world-state / ok。 // func GameRouter_MapEntrance_AskPlayerChangePositionByScenePortal(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_MapEntrance_AskPlayerChangePositionByScenePortal var zero any; return zero } // // 载荷解析:主路径 = 严格 4 B(mapEntranceId u32 小端裸值)。 // 长度不为 4 时做一次自校验容错扫描(要求该 u32 能命中入口表),命中即采用并写明 // 「容错扫描@N」,不会静默成功。 // func GameRouter_MapEntrance_TryParsePortalBody(ctx context.Context, body []byte, entranceId uint32, note string) bool { // Router implementation for GameRouter_MapEntrance_TryParsePortalBody return true } // 坐标可用性:有限数且不在原点(表里有 (0,0,0) 占位行)。 func GameRouter_MapEntrance_IsUsableEntranceCoordinate(ctx context.Context, x float32, y float32, z float32) bool { // Router implementation for GameRouter_MapEntrance_IsUsableEntranceCoordinate return true }