This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

280 lines
16 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// 载具路线规划 / 自驾(2026-09-24 移植自第九份捐赠端 GameRouter.VehicleNav.cs,但图换成我们自己的)。
// ★★ 为什么值得做:`logs/unknown-methods.log` 里今天 06:05 UTC 连着 **89 次**
// `AskVehicleNavigationPathPointsFromPos`(每秒一次,起点在动、终点固定)——玩家正在开车跑导航,
// 而我们每条都回的是 `DefaultReturnCatalog` 的 typed default:**空点集 + 长度 0**。
// 也就是客户端在问「怎么开过去」,服务端一直答「不知道」。
// ★★ 为什么不搬捐赠端的 `vehicle_nav_graph.bin`(2.36MB):那份是他们自己 generator 从另一份
// 数据打的私有格式(magic `ANGV` / ver 2 / 每车道 40B),provenance 不可考;我们手上已经有
// `vehicle_lanes.csv`(14171 条) + `vehicle_lane_links.csv`(多值后继覆盖 98.2%,见
// `GameRouter.VehicleLanes.cs` 头注),用同一份数据算出来的路线才是自洽的。
// ⛑️ 我们这份表的几何是「弦」不是真实样条 —— `_gen_vehicle_lanes.py` 压掉了中间点。
// 所以画出来的导航线是折线、切内弯;想提高精度要把 lane 折线点补回来,不是改这里。
// ⛑️ 只走**前向**后继(本帧生成车道的方向),与 T3-7 车流 `Advance` 的规则一致;
// 客户端这次带的是 `IgnoreDirection=true`,它接受单方向绕行,不构成违约。
// ⛑️ 回滚开关 = `gameplay.vehicleNavigation.enabled=false` ⇒ 逐字节回到空结果(见 EmptyResult)。
//
func GameRouter_VehicleNav_EmptyResult(ctx context.Context, navReqId uint32) any {
// Router implementation for GameRouter_VehicleNav_EmptyResult
var zero any; return zero
}
//
// 当前生效的巡航速度(米/秒)。
// 优先级:config/autonomous-driving.json(GM 面板写的) > gameplay.vehicleNavigation.cruiseSpeed。
// 前者不存在 = 没在 GM 里调过速 ⇒ 完全用主配置的值,与 2026-09-30 之前逐字节一致。
// ⛑ 单位换算(km/h → m/s)只在这里做;AutonomousDriveSpeedSettings 对外一律 km/h。
// ⛑ 文件被写坏时不能让玩家开不了车:吞掉异常退回主配置,GM 重新保存即可恢复。
//
func GameRouter_VehicleNav_EffectiveCruiseSpeedMs(ctx context.Context, ) float32 {
// Router implementation for GameRouter_VehicleNav_EffectiveCruiseSpeedMs
return 0
}
// -----------------------------------------------------------------------------------------
// AskVehicleNavigationPathPoints (67317431) — 起点由服务端自己找(最后一次上报的位置)
// -----------------------------------------------------------------------------------------
func GameRouter_VehicleNav_OnAskVehicleNavigationPathPoints(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleNavigationPathPoints
var zero any; return zero
}
// -----------------------------------------------------------------------------------------
// AskVehicleNavigationPathPointsFromPos (67650626) — 客户端自带起点(今天实际在用的就是这条)
// -----------------------------------------------------------------------------------------
func GameRouter_VehicleNav_OnAskVehicleNavigationPathPointsFromPos(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleNavigationPathPointsFromPos
var zero any; return zero
}
// -----------------------------------------------------------------------------------------
// AskVehicleNavigationPathLength (67519267) — 只要里程(float)
// -----------------------------------------------------------------------------------------
func GameRouter_VehicleNav_OnAskVehicleNavigationPathLength(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleNavigationPathLength
var zero any; return zero
}
// -----------------------------------------------------------------------------------------
// 自驾开关 Start / Stop / ChangeTarget / CancelTarget
//
// ★★ 2026-09-27 修「点了自动驾驶车不动」。根因不在 Start 的回执 —— 客户端的自动驾驶
// 开关是 **服务端推下来的 S2C**,不是本地状态:
// BaseVehicleControllerStore.OnAutoDriveBtnClick → AskVehicleStartAutonomousDriving
// GameSceneToClientImpl:1438 SyncVehicleAutonomousDrivingState(u64 车, bool isStart)
// → DriveVehiclesManager.autoDrivingVehicleDict[车] = true / nil
// → BaseVehicleControllerStore.SetAutoDriving(GetVehicleInAutonomousDriving(车))
// 真正的循迹 AI 在客户端 C# 的 LX6.Drive.DriveManager(包是 LuaAndCSharp,两边都收)。
// ⇒ 只要服务端不发 68349264,UI 上那个按钮按下去会立刻弹回来、车纹丝不动。
// ⇒ 反过来也解释了为什么 previously「挂了 Start/Stop 回执」毫无效果:回执只影响
// `AutoDrive.AskWait`,不影响 Driving 状态。
//
// ⛑️ 78636393(CancelTarget) 之前压根没注册 ⇒ 玩家在地图上删掉导航点时会 INVOKE 无回执、await 卡死(规则 84)。
// ⛑️ 服务端**不负责每帧开车**:车还是客户端本地物理。服务端只管「给不给自动驾驶许可」。
// 真要让另一端的观众也看到车在动,是另一件事(要服务端推位置环回),本次不做。
// -----------------------------------------------------------------------------------------
func GameRouter_VehicleNav_OnAskVehicleStartAutonomousDriving(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleStartAutonomousDriving
var zero any; return zero
}
func GameRouter_VehicleNav_OnAskVehicleStopAutonomousDriving(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleStopAutonomousDriving
var zero any; return zero
}
func GameRouter_VehicleNav_OnAskVehicleChangeAutonomousDrivingTarget(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleChangeAutonomousDrivingTarget
var zero any; return zero
}
//
// 把正在进行的自动驾驶改道到新终点(MethodId.AskVehicleChangeAutonomousDrivingTarget 用)。
// ⛑ 只重算 Cruise,**不重推** SyncVehicleAutonomousDrivingState:捐赠端那句
// "Keep the native autonomous HUD active; replace only our own Cruise." 就是这个意思 ——
// 重推会闪一次 UI,且客户端本来就在自动驾驶状态里。
// ⛑ 改道起点用车当前位置(VehiclePositionFor),不是原来的出发位置。
// ⛑ 解不出新路时保持现状(继续开向老终点)而不是停手:中途抛锚比开到旧目的地更难受,
// 玩家可以自己按 Stop。这与捐赠端不同(他们 no-route 就 Stop),是他们明确的选择差异。
//
func GameRouter_VehicleNav_RetargetAutonomousDrivingAsync(ctx context.Context, conn any, runtime any, msg any, tx float32, ty float32, tz float32) any {
// Router implementation for GameRouter_VehicleNav_RetargetAutonomousDrivingAsync
var zero any; return zero
}
//
// AskVehicleCancelAutonomousDrivingTarget(67836393)—— 2026-09-27 补,之前漏注册。
// 客户端在地图上删掉导航点时发,是 INVOKE ⇒ 不回执会让 lua 的 await 卡住。
// 语义只是「忘记导航目标」:车照开,只是没了终点(客户端会自己决定何时停下)。
//
func GameRouter_VehicleNav_OnAskVehicleCancelAutonomousDrivingTarget(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_VehicleNav_OnAskVehicleCancelAutonomousDrivingTarget
var zero any; return zero
}
//
// 自驾起点:优先用车自己上报的位置(AskVehicleMove 写进 VehicleRecord),
// 退化才用玩家位置。Start 请求不带起点,而玩家坐在车里时这两个坐标差着车长,
// 用错了会把起点吸到旁边的车道上。
//
func GameRouter_VehicleNav_VehiclePositionFor(ctx context.Context, runtime any, vehicleId uint64, msg any) any {
// Router implementation for GameRouter_VehicleNav_VehiclePositionFor
var zero any; return zero
}
//
// 下发「沿路径巡航」的 AI 任务(SyncAssignVehicleAITask + VehicleCruiseParameters)。
// 取证:GameRouter.VehicleControls.cs 的 action 4 就是用这个参数类型(带
// TargetPointList)让空车倒车挪位;车流/T3-7 与载具骇入都走同一条
// SyncAssignVehicleAITask 通道。 ⇒ 这就是服务端驱动车动的唯一入口。
// ⛑️ Count 填的是点数量(语义未实测:若车只开到第一个点,改成 1 再试)。
// ⛑️⛑️ 2026-09-30 两处按捐赠端 v0.5-2 对齐(都有回滚开关,见 PrivateServerConfig):
// ① DrivingFlags:以前只留 DFStopForCars(1) ⇒ 车不会绕开静止车辆/行人/物件,
// 前面一停就顶死,也不等红灯。现在默认 VehicleNavigationSettings.CruiseDrivingFlags
// = 1|2|8|16|32|128|16384(枚举语义见 ux_rpc/payload_types.dump.cs:193)。
// ② TargetPointList:默认只给终点一个点(VehicleNavigationSettings.CruiseSingleTarget),
// 让客户端 C# 的 NavigationHelper 自己导航 —— 我们这份车道几何是「弦」不是样条,
// 喂整串点会切内弯。PathFindFlags=0(正向,按道路方向)。
// 而不是 Connection:GM 面板没有 Connection,
// 热应用调速(ApplyAutonomousDriveSpeedAsync)要复用同一条下发路径。
//
//
// 下发 Cruise(沿一串点巡航)任务。自驾与出租车共用这一条通道
// (2026-09-30:出租车接入)。
//
// 速度覆盖(m/s)。null = 用自驾配置的速度(EffectiveCruiseSpeedMs)。
// 出租车必须传自己的值:正常 15、加速 25(捐赠端 BuildTaxiDriveTask4229938
// 原值),不能跟着 GM 的自驾调速走 —— 那会让「加速」按钮和 GM 滑条互相打架。
//
// 复用一个已经有了的 token,而不是自己 mint 一个新的(2026-10-03,召唤载具开过来)。
// 客户端 SummonVehicleManager 在 AskSummonVehicle 回执里拿到
// SummonVehicleResult.TaskToken 后就用它 RegisterTaskAIStartedEvent(token)
// —— 两边对不上,原生那套「召唤演出」永远不会触发。⇒ 那台车的到达任务必须带同一个 token。
//
//
func GameRouter_VehicleNav_AssignAutonomousCruiseAsync(ctx context.Context, session *GameSession, runtime any, vehicleId uint64, path []any, speedMsOverride any, tokenOverride any) any {
// Router implementation for GameRouter_VehicleNav_AssignAutonomousCruiseAsync
var zero any; return zero
}
//
// GM 实时调速(2026-09-30,/api/vehicle/autodrive-speed)。
// ① 先落盘 config/autonomous-driving.json(一定执行,与有没有在开车无关);
// ② 再对正在自动驾驶的那辆车热应用:撤回旧任务 → 用新速度重建 → 再确认一次。
// ⛑ 返回 false 只代表「这次没法热应用」(没在车上 / 没在自驾 / 上次点集没缓存),
// 速度仍然已经保存,下一次按自动驾驶就会生效 —— 别把它当失败提示给用户。
// ⛑⛑ 为什么复用 AutoDriveLastPoints 而不是重算路线:SolveRoute 是实例方法
// (要 Connection + LogNavOnce),GM 这条路径上根本没有 Connection。
// 缓存还有个好处:换速度时路线逐点不变,不会因为重算而突然改道。
//
func GameRouter_VehicleNav_ApplyAutonomousDriveSpeedAsync(ctx context.Context, session *GameSession, kmh float32) bool {
// Router implementation for GameRouter_VehicleNav_ApplyAutonomousDriveSpeedAsync
return true
}
//
// 回推 SyncChangeVehicleAITaskState 设置自驾任务状态。客户端靠这个包把任务从 Pending
// 推进到 Running —— **没有这一步车就不会动**。
// VehicleAIStatus:0 Pending / 1 Running / 2 Success / 3 Pause / 4 Abort / 5 Override
// (客户端枚举,ux_rpc/ux_game_all.dump.cs:181155)。
//
func GameRouter_VehicleNav_AcknowledgeAutoDriveTaskAsync(ctx context.Context, session *GameSession, vehicleId uint64, token uint64, status byte) any {
// Router implementation for GameRouter_VehicleNav_AcknowledgeAutoDriveTaskAsync
var zero any; return zero
}
//
// 自驾任务的状态机:只要求 token 匹配。客户端会连发 Running(1),
// 所以 1→1 必须被接受(骇入那套 IsAllowedHackTaskTransition 会拒掉重复,自驾不能照抄)。
//
func GameRouter_VehicleNav_TryApplyAutoDriveTaskStatus(ctx context.Context, runtime any, token uint64, next byte) bool {
// Router implementation for GameRouter_VehicleNav_TryApplyAutoDriveTaskStatus
return true
}
// 停止 AI 任务(action 0)。与 AssignAutonomousCruiseAsync 成对。
func GameRouter_VehicleNav_AssignAutonomousStopAsync(ctx context.Context, session *GameSession, runtime any, vehicleId uint64) any {
// Router implementation for GameRouter_VehicleNav_AssignAutonomousStopAsync
var zero any; return zero
}
func GameRouter_VehicleNav_PushVehicleAutonomousStateAsync(ctx context.Context, conn any, vehicleEntityId uint64, isStart bool) any {
// Router implementation for GameRouter_VehicleNav_PushVehicleAutonomousStateAsync
var zero any; return zero
}
func GameRouter_VehicleNav_PushPlayerAutonomousStateAsync(ctx context.Context, conn any) any {
// Router implementation for GameRouter_VehicleNav_PushPlayerAutonomousStateAsync
var zero any; return zero
}
func GameRouter_VehicleNav_SolveRoute(ctx context.Context, conn any, sx float32, sy float32, sz float32, tx float32, ty float32, tz float32, needCenter bool, tag string) any {
// Router implementation for GameRouter_VehicleNav_SolveRoute
var zero any; return zero
}
func GameRouter_VehicleNav_AnswerNavAsync(ctx context.Context, conn any, msg any, fallback any, route any) any {
// Router implementation for GameRouter_VehicleNav_AnswerNavAsync
var zero any; return zero
}
func GameRouter_VehicleNav_LogNavOnce(ctx context.Context, conn any, message string, bytes int32) any {
// Router implementation for GameRouter_VehicleNav_LogNavOnce
var zero any; return zero
}
// 服务端最后一次看到的玩家位置,退化时退回世界出生点。
func GameRouter_VehicleNav_CurrentVehiclePosition(ctx context.Context, msg any) any {
// Router implementation for GameRouter_VehicleNav_CurrentVehiclePosition
var zero any; return zero
}
func GameRouter_VehicleNav_AddPoint(ctx context.Context, list []any, prevX float32, prevZ float32, x float32, y float32, z float32, minSpacing float32) any {
// Router implementation for GameRouter_VehicleNav_AddPoint
var zero any; return zero
}
// 点数超过上限时按等距抽稀,首位必有。
func GameRouter_VehicleNav_Decimate(ctx context.Context, source []any, limit int32) []any {
// Router implementation for GameRouter_VehicleNav_Decimate
return nil
}
//
// 车道图上的前向 Dijkstra(代价 = 米)。返回跳数 0 表示不通, 是
// 起点→终点的车道序列。第一跳的代价是「起点所在车道剩余里程」,这样同车道起步也算得准。
//
func GameRouter_VehicleNav_Dijkstra(ctx context.Context, startLane int32, targetLane int32, maxExpansions int32, lanes []any) int32 {
// Router implementation for GameRouter_VehicleNav_Dijkstra
return 0
}
// -----------------------------------------------------------------------------------------
// 求解:把两张点吸到车道上,再在车道图上跑一次 Dijkstra(代价 = 米)
// -----------------------------------------------------------------------------------------
//
// = 给导航线的点(可能被 ReversePoints 翻成「终点 → 车」);
// = 给 AI 巡航任务的点,恒为「车 → 终点」正向
// (2026-09-28:反转只对画线的箭头有意义,喂给 AI 会让车掉头)。
//
type NavRoute struct {
Ok bool `json:"ok"`
Points []UxVector3 `json:"points"`
Center []UxVector3 `json:"center"`
DrivePoints []UxVector3 `json:"drivePoints"`
Length float32 `json:"length"`
Hops int32 `json:"hops"`
Note string `json:"note"`
}