108 lines
5.8 KiB
Go
108 lines
5.8 KiB
Go
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
|
||
}
|
||
|