package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // Scene ("raid") switching: re-push SyncEnterScene with a new raid/instance/universe // destination and re-arm the world-entry barrier lifecycle so the client's normal // AskLoadSceneCompleted → quartet → AskLoadingFinished → movement flow runs again. // Ported from the proven newcityps (4091149) airport handoff, adapted to the minimal // 4229938 world entry (no timelines, no AOI streaming). // // // Client -> server map/teleport request: AskPublicSwitchToPublicScene // (63491547, invoke raidId/delay/mapEntranceId). Known raid ids switch via the // preset arrivals; anything else is accepted and logged for future mapping. // func GameRouter_SceneSwitch_AskPublicSwitchToPublicScene(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_SceneSwitch_AskPublicSwitchToPublicScene var zero any; return zero } // // Client -> server EnterRaid (62899289, invoke raidId/immediate) —— GM 传送面板用的 // 原生副本切换请求。移植自捐赠端 DremkaPS(2026-09-24)。 // 捐赠端硬编码两个 raid(主城 / 重霄)加一个出生点,本服改成查既有的 // GameAdminBridge.ScenePresets —— 那份表覆盖的副本更多,落点还是 2026-09-20 // 实机量过的;没有 preset 的 raid 按本服既有约定「接受并记日志」,不静默丢弃。 // ⛑ 与同文件另两条不同,这里先回 EmptyOk 再切换(照捐赠端):EnterRaid 是 Invoke, // 客户端在 await 返回值,而 SwitchSceneAsync 要连发 SyncGamePause + // SyncEnterScene;先回包可以避免切换耗时把控制台那次调用拖到超时。 // func GameRouter_SceneSwitch_EnterRaid(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_SceneSwitch_EnterRaid var zero any; return zero } // // AskEnterRaidByMapEntrance(63510026, invoke u32 mapEntranceId): // 景点 / 电梯传送门(MapentranceConfig.Type == 1)。 //

⛑⛑ 2026-09-30:这里只 ack 不推 SyncTeleport,就是「进电梯黑屏、ESC 返回不了」的根因

// 客户端 RpcUtils.AskEnterRaidByMapEntrance(E:\lua\lua\LX6\Utils\RpcUtils.lua:88): // // AskTeleport(LoadingConfig.EnterExitRoomId=2, option, extParams, cb) // option.beforeResName = cfg.JiguanStartTimeline -- "loading_elevator02" // option.beforePosition = cfg.Coordinate -- 电梯门自己那一格 // option.afterResName = cfg.JiguanEndTimeline -- "loading_general_end" // option.afterPosition = (0,0,0) -- ★ 客户端不知道目的地 // option.customAfterTrans = false -- ★ 所以不会自己套 afterPosition // cb(= ReportPreTeleportFinish 被 ack 之后)→ gClientToGameDelegate:AskEnterRaidByMapEntrance(id) // // 实测(packets-latest.log): // // 01:07:55.716 C2S AskTeleport config=2 before=loading_elevator02 beforePosition=(2257.781,0,1458.242) // 01:07:55.717 S2C RETURN AskTeleport e=0 // 01:07:55.717 S2C NOTIFY SyncPreTeleportOption 146b ← EchoPreTeleport 回显成功 // 01:08:01.359 C2S ReportPreTeleportFinish {"teleportId":0} ← 过场动画播完 // 01:08:01.362 C2S AskEnterRaidByMapEntrance {"mapEntranceId":337} // 01:08:01.366 S2C RETURN AskEnterRaidByMapEntrance e=0 ← 只 ack,没有 SyncTeleport // 01:09:30.020 C2S ReportPostTeleportFinish {"result":2} ← 86 秒后放弃 ⇒ 黑屏 // // 对照同一份日志里成功的一次(01:07:39,大地图传送 / 地铁): // AskPlayerChangePositionByScenePortal → S2C NOTIFY SyncTeleport 31b → // ReportPostTeleportFinish result=0。差别就在那一帧 SyncTeleport。 // 目的地由 JiguanElevatorCatalog4229938 从 MapentranceConfig 自己推出来 // (客户端只给 Spoon 航点 id,本地没有 Spoon 图)。推不出目的地时退化成 // 「推到入口自己那一格」——仍然推,因为「不推」才是黑屏。 // 顺序照 AskPlayerChangePositionByScenePortal:先 SyncTeleport 再 ack。 // 回滚 = gameplay.mapEntrance.jiguanElevator=false(只 ack,逐字节回到改动前)。 // func GameRouter_SceneSwitch_AskEnterRaidByMapEntrance(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_SceneSwitch_AskEnterRaidByMapEntrance var zero any; return zero } // SyncTeleport.MapEntranceId 到底填哪个 id。 // "dest"(默认)= 落点那一层的门;"source" = 起点门(一修旧行为); // "none" = 0(逼客户端只用 Position,用来验证「客户端拿 MapEntranceId 去 // MapentranceConfig / Spoon 航点反查、本地没图所以落空」这个猜想)。 // 落点门为 0(推导失败)时退回起点门,保证 Position 与 MapEntranceId 不打架。 // func GameRouter_SceneSwitch_JiguanEntranceIdToSend(ctx context.Context, cfg any, sourceEntranceId uint32, dest any) uint32 { // Router implementation for GameRouter_SceneSwitch_JiguanEntranceIdToSend return 0 } // // Server-driven scene switch. Re-arms the world-entry transaction for a new // generation, then pushes SyncEnterScene. The existing barrier handlers // (OnLoadSceneCompleted / OnLoadingFinished / movement) complete the handoff. // func GameRouter_SceneSwitch_SwitchSceneAsync(ctx context.Context, session *GameSession, raidId uint32, instanceId uint64, universeId uint32, x float32, y float32, z float32, facing float32, reason string) any { // Router implementation for GameRouter_SceneSwitch_SwitchSceneAsync var zero any; return zero } func GameRouter_SceneSwitch_GetStateStatic(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_SceneSwitch_GetStateStatic var zero any; return zero }