package routers
import (
"context"
"sync"
"time"
)
var _ = sync.Mutex{}
var _ = context.Background
var _ = time.Now
//
// Vehicle ownership + direct summon (Phase 2). Ported from the proven newcityps
// (4091149) direct-scene-spawn path, with 4229938 wire deltas applied
// (LogicVehicleClientInfo.VehicleSpoonName, PlayerVehicleClientDetail.IsPersistent).
// No road-planner/AI-task leg: the vehicle materializes beside the player,
// already interactable, and the stock client seat/drive lifecycle takes over.
// Enter/exit/move notifies are logged + tracked; pushes for those come after
// live-traffic observation (see KNOWLEDGEBASE.md §4).
//
// Call when despawning NPCs or resetting state to abort any active interaction monitor.
func GameRouter_Vehicle_ResetInteractionState(ctx context.Context, ) any {
// Router implementation for GameRouter_Vehicle_ResetInteractionState
var zero any; return zero
}
func GameRouter_Vehicle_GetVehicleRuntimeState(ctx context.Context, session *GameSession) any {
// Router implementation for GameRouter_Vehicle_GetVehicleRuntimeState
var zero any; return zero
}
func GameRouter_Vehicle_GetVehicleRuntime(ctx context.Context, rpcCtx *RpcContext) any {
// Router implementation for GameRouter_Vehicle_GetVehicleRuntime
var zero any; return zero
}
func GameRouter_Vehicle_VehicleOwnershipSnapshot(ctx context.Context, runtime any) []any {
// Router implementation for GameRouter_Vehicle_VehicleOwnershipSnapshot
return nil
}
func GameRouter_Vehicle_PublishVehicleOwnership(ctx context.Context, rpcCtx *RpcContext) any {
// Router implementation for GameRouter_Vehicle_PublishVehicleOwnership
var zero any; return zero
}
func GameRouter_Vehicle_EnsureAetherVehicleInit(ctx context.Context, rpcCtx *RpcContext) any {
// Router implementation for GameRouter_Vehicle_EnsureAetherVehicleInit
var zero any; return zero
}
// --- Aether city simulation: C2S calls -------------------------------------------
// The client owns the simulation (pedestrians / static NPCs / traffic). These handlers
// exist so the tasks it awaits after SyncAetherAIInitDatas are answered instead of
// stalling the spawner.
func GameRouter_Vehicle_AskMassHideAreas(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskMassHideAreas
var zero any; return zero
}
func GameRouter_Vehicle_AskAetherChangeQuality(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskAetherChangeQuality
var zero any; return zero
}
func GameRouter_Vehicle_AskAetherAIBorrowVehicle(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskAetherAIBorrowVehicle
var zero any; return zero
}
func GameRouter_Vehicle_AskChangePedToVehicleNpc(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskChangePedToVehicleNpc
var zero any; return zero
}
func GameRouter_Vehicle_AskReportAetherLeaflet(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskReportAetherLeaflet
var zero any; return zero
}
func GameRouter_Vehicle_AskAetherAICreateRaidVehicleAndClaimSeatByAether(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskAetherAICreateRaidVehicleAndClaimSeatByAether
var zero any; return zero
}
func GameRouter_Vehicle_AskAetherAIRaidVehicleRegressAether(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskAetherAIRaidVehicleRegressAether
var zero any; return zero
}
func GameRouter_Vehicle_AskRaidVehicleConvertToAether(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskRaidVehicleConvertToAether
var zero any; return zero
}
func GameRouter_Vehicle_ParseHexBytes(ctx context.Context, hex any) []byte {
// Router implementation for GameRouter_Vehicle_ParseHexBytes
return nil
}
// ⛑ 2026-10-02 对齐捐赠端:原来这里的 `FireExamAuto`(cmd=33/34 ⇒ 自动开盘查)已随
// `GameRouter.PoliceExamAuto.cs` 一起移除 —— 捐赠端**没有**"准星对准/对话 ⇒ 自动盘查"这条链,
// 它的入口只有原生 F(`PoliceFRequest`)和 GM `/api/lixi/police`。
// cmd=33/34 现在只保留 uid 记录与日志,不再触发盘查。
//
// Interact heartbeat/sync channel. Decoded + logged so a future F-press via the
// interact system is visible; currently accepted without side effects.
//
func GameRouter_Vehicle_AskInteractCmd(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskInteractCmd
var zero any; return zero
}
// Two-person interaction (双人 ACTION) invite channel. The client sends
// AskInvitePlayerInteractionAction as an Invoke (12b = inviteePid u64 + actionItemId u32)
// when the player picks an action. The NPC then shows "思考中" until the server acks.
// We auto-accept: push inviter+invitee state and SyncStartPlayerInteractionAction.
func GameRouter_Vehicle_AskInvitePlayerInteractionAction(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskInvitePlayerInteractionAction
var zero any; return zero
}
func GameRouter_Vehicle_AskStartPlayerInteractionAction(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskStartPlayerInteractionAction
var zero any; return zero
}
func GameRouter_Vehicle_AskReplyInvitePlayerInteractionAction(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskReplyInvitePlayerInteractionAction
var zero any; return zero
}
func GameRouter_Vehicle_AskGetUnlockedVehicles(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskGetUnlockedVehicles
var zero any; return zero
}
func GameRouter_Vehicle_AskSummonVehicle(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskSummonVehicle
var zero any; return zero
}
//
// 召唤车「开过来」到达之后,把权威位置钉死在它现在真正的位置(2026-10-03 实机修瞬移)。
// 症状:车能开到身边,玩家一上车就瞬移回生成点。
// 根因:服务端在生成时下发了 SyncAetherAIVehicleAddData(ClientVehicleInitData),
// 里面写的是生成点坐标且 LaneHandle=-1(不参与车道推进)⇒ 这份 Aether 坐标
// 之后再也没人更新。车是被 SyncAssignVehicleAITask 的 Cruise(Raid 通道)开过来的,
// 客户端两套表示就此分叉。玩家上车时客户端拿 Aether 那份数据对齐实体 ⇒ 车被拽回生成点。
// 服务端上车那几秒一条 S2C 位置包都没发(14:46:42–45 全是 C2S),所以不是我们回填错了,
// 是客户端自己的那份旧值。
// 对策:SyncTeleportVehicle(68088911) 是 Raid 通道的权威位置包(赛车 R309 /
// 改装店钉车 / 传送都在用,Reset=true = 客户端直接落位不插值)。位置取
// AskVehicleMove 上报的最新值 —— AI 开车期间客户端每秒都在报,所以这一发
// 视觉上是「原地不动」,只是把两边强行对齐。
//
func GameRouter_Vehicle_CompleteSummonDriveInAsync(ctx context.Context, conn any, runtime any, entityId uint64) any {
// Router implementation for GameRouter_Vehicle_CompleteSummonDriveInAsync
var zero any; return zero
}
//
// 召唤载具的「开过来」那一半(2026-10-03,SummonDriveInSettings)。
// 三步,顺序不能改:
//
// - SyncAetherAIChangeVehicleControl(2) —— 把车切回 RaidVehicle。
// 客户端会把有 VDE 的车交给 Aether 车道模拟,位移每帧被车道覆盖 ⇒ Cruise 变成
// 「轮胎在转、车在原地进行」(GameRouter.Taxi.cs:147-166,出租车踩过的)。
// - SyncVehicleAutonomousDrivingState(true) —— 必须早于 AI 任务,
// 否则客户端把这条任务当成「别人的车被接管」渲染 ⇒ 车门消失 / 角色缺模
// (2026-09-30 §43.1)。
// - SyncAssignVehicleAITask + Cruise,token 复用召唤回执那个。
//
//
// ⛑ 终点是「车道上离玩家最近的点」(靠边停车),不是玩家脚下:自定义标点吸附失败时
// 客户端一条 Cruise 都不下发,表现是「叫了车没反应」。解不出车道路径就只给终点,
// 交给客户端 C# NavigationHelper 自己导航(自驾已验证能到任意 POI)。
//
func GameRouter_Vehicle_StartSummonDriveInAsync(ctx context.Context, conn any, session *GameSession, entityId uint64, token uint64, spawn Vec3, stop Vec3, cfg any) any {
// Router implementation for GameRouter_Vehicle_StartSummonDriveInAsync
var zero any; return zero
}
//
// Direct scene spawn shared by client summon and the admin panel:
// SyncLogicVehicleEnter + SyncSpawnVehicle (interactable) + SyncChangeVehicleInteractable.
// Returns the new entity id + task token. Replaces the previous summoned vehicle.
//
//
// 给了就原样落在这(只 +0.15m 抬高),不再做「玩家右手边 5.5m」的偏移。
// 改装店换展示车必须走这条:工位在地下(y<0),按玩家朝向偏移会把车摆进墙里
// (donor 13:38 实测「车在你看的地方/卡墙」)。
//
func GameRouter_Vehicle_SpawnDirectAsync(ctx context.Context, session *GameSession, vehicleId uint32, nearPos Vec3, facing float32, reason string, exactPos any, createSourceType int32, destroyPrevious bool) any {
// Router implementation for GameRouter_Vehicle_SpawnDirectAsync
var zero any; return zero
}
func GameRouter_Vehicle_DestroyVehicleAsync(ctx context.Context, session *GameSession, runtime any, entityId uint64, reason string) any {
// Router implementation for GameRouter_Vehicle_DestroyVehicleAsync
var zero any; return zero
}
// --- Enter / exit / move tracking (notifies; logged + recorded, no speculative pushes yet) ---
func GameRouter_Vehicle_AskPlayerStartEnterOrExitVehicle(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskPlayerStartEnterOrExitVehicle
var zero any; return zero
}
func GameRouter_Vehicle_AskPlayerFinishEnterOrExitVehicle(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskPlayerFinishEnterOrExitVehicle
var zero any; return zero
}
func GameRouter_Vehicle_AskVehicleMove(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_AskVehicleMove
var zero any; return zero
}
// AskClaimVehicleSeat lives in GameRouter.VehicleStory.cs (story-aware seat re-pin).
// --- Drive-loop accepts (proven set from the sibling 08.05 build) ---
// The client keeps driving client-side; the server only has to accept the drive-loop
// notifies and answer the drive-state invokes with an empty OK so the loop never stalls.
func GameRouter_Vehicle_VehicleNotifyAccept(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_VehicleNotifyAccept
var zero any; return zero
}
// AskVehicleHorn / ReportDrivingVehicle / AskVehicleNitro already have logging/tracking
// handlers in GameRouter.UnhandledBatch.cs — do not re-register them here.
func GameRouter_Vehicle_VehicleInvokeAccept(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_Vehicle_VehicleInvokeAccept
var zero any; return zero
}
type VehicleRecord struct {
EntityId uint64 `json:"entityId"`
ConfigId uint32 `json:"configId"`
SeatCount int32 `json:"seatCount"`
Position Vec3 `json:"position"`
Facing float32 `json:"facing"`
ControllerPid uint64 `json:"controllerPid"`
Interactable bool `json:"interactable"`
TaskToken uint64 `json:"taskToken"`
LastBits []byte `json:"lastBits"`
MoveLogged bool `json:"moveLogged"`
DistanceDriven float64 `json:"distanceDriven"`
IsDriving bool `json:"isDriving"`
LastNitroValue float32 `json:"lastNitroValue"`
TopSpeed float32 `json:"topSpeed"`
HasTopSpeed bool `json:"hasTopSpeed"`
SeatReservations map[byte]uint64 `json:"seatReservations"`
SeatOccupants map[byte]uint64 `json:"seatOccupants"`
// T1-16 载具骇入 (ported from donor_7k). AetherRegistered is what makes a spawned
// car selectable by HackTargetSelector: it iterates AetherVehicleManager's
// VehicleId2IndexDict, which SyncSpawnVehicle alone never populates.
AetherRegistered bool `json:"aetherRegistered"`
HackBusyUntilUtc time.Time `json:"hackBusyUntilUtc"`
HackTaskToken uint64 `json:"hackTaskToken"`
HackTaskStatus byte `json:"hackTaskStatus"`
// ★ 真实车流(T3-7):由 GameRouter.Traffic.cs 生成、每 tick 被车道流推着跑的车。
// true ⇒ 仍在车道流里,服务端每 tick 用 SyncAetherAIVehicleLaneDatas 覆盖它的里程。
// false ⇒ 已被玩家骇入接管,脱离车道流(由 DetachTrafficVehicleFromLaneAsync 翻转)。
//
// 为什么必须能翻转:骇入下发的 SyncAssignVehicleAITask 是 RaidVehicle 通道,
// 而车道流每 50ms 覆盖一次里程 —— 两套驱动源同时作用的话,
// 车会表现为「加速一瞬间就被拽回原处」。所以接管的第一件事是把车摘出车道流。
IsTraffic bool `json:"isTraffic"`
}
type VehicleRuntimeState struct {
SyncRoot any `json:"syncRoot"`
Unlocked []uint32 `json:"unlocked"`
Vehicles map[uint64]VehicleRecord `json:"vehicles"`
SummonedEntity uint64 `json:"summonedEntity"`
CurrentVehicleId uint64 `json:"currentVehicleId"`
CurrentVehicleSeat int32 `json:"currentVehicleSeat"`
//
// 自驾状态(GameRouter.VehicleNav.cs,2026-09-27)。
// 客户端的自动驾驶是「一辆车」的开关:开关状态只由 S2C
// SyncVehicleAutonomousDrivingState 决定(DriveVehiclesManager.autoDrivingVehicleDict),
// 所以服务端必须记住「哪辆车正开着」,才能在 Stop / 下车时回推正确的 false。
// 存 session 而不是持久化:重进场景客户端会重新发 Start。
//
AutoDrivingVehicleId uint64 `json:"autoDrivingVehicleId"`
AutoDriving bool `json:"autoDriving"`
//
// 自驾下发的最后一个 AI 任务 token(2026-09-28 第三轮)。
// ⛑️ 必须记住它:客户端收到 SyncAssignVehicleAITask 后会回 AskUpdateVehicleAITaskStatus,
// 但**会一直把任务停在 Pending,直到服务端用 SyncChangeVehicleAITaskState 确认同一个
// entity + token**。不确认 ⇒ 任务永远不进 Running ⇒ 车纹丝不动。
//
AutoDriveTaskToken uint64 `json:"autoDriveTaskToken"`
AutoDriveTaskStatus byte `json:"autoDriveTaskStatus"`
AutoDriveHasTarget bool `json:"autoDriveHasTarget"`
AutoDriveTargetX float32 `json:"autoDriveTargetX"`
AutoDriveTargetY float32 `json:"autoDriveTargetY"`
AutoDriveTargetZ float32 `json:"autoDriveTargetZ"`
//
// 上次真正下发的巡航点集(2026-09-30,GM 调速用)。
// 改速度必须重发 Cruise 任务(速度写在任务参数里),而重发需要点集;
// 现算要走 SolveRoute,那是实例方法且要 Connection,GM 侧两者都没有。
// ⇒ 下发时缓存一份,热应用直接复用,顺带保证「换速度不换路线」。
//
AutoDriveLastPoints []UxVector3 `json:"autoDriveLastPoints"`
// 上次下发时用的速度(km/h)。值没变就不重发,避免 GM 手抖连点刷包。
AutoDriveSpeedKmh float32 `json:"autoDriveSpeedKmh"`
//
// 出租车行程(2026-09-30 新增,GameRouter.Taxi.cs)。null = 当前没有行程。
// ⛑ 只记「服务端自己派发的那一次」。客户端的原生出租车 UI(选目的地面板、
// 到达提示)状态全在客户端,服务端只负责:认单 → 派 Cruise → 判到达 → 收车费。
// ⛑ 与 AutoDriveTaskToken 的关系:出租车复用自驾那条
// SyncAssignVehicleAITask 通道,所以行程的 token 就是 AutoDriveTaskToken;
// 本字段额外记住「这趟是出租车」+ 目的地 + 起始里程,用来算车费和判到达。
//
TaxiTrip *TaxiTrip4229938 `json:"taxiTrip"`
//
// 玩家最近开过的车(上车时写,下车不清)。改装店事务要它:位移前客户端已经
// 把玩家自动请下车了(retail 的 SetSeatInteractOperation(0,6)),此时
// CurrentVehicleId 已被客户端的 exit 通知清零,只有这个还记得是谁。
//
LastDrivenVehicleId uint64 `json:"lastDrivenVehicleId"`
OwnershipSent bool `json:"ownershipSent"`
AetherInitSent bool `json:"aetherInitSent"`
// T1-16 载具骇入: serializes hack dispatch so a stale status notify cannot
// retarget a newer task while its SyncAssignVehicleAITask is still in flight.
HackDispatchGate *sync.Mutex `json:"hackDispatchGate"`
// S011 story/boarding state (single-player: one active enter/exit transaction).
StoryRootSent bool `json:"storyRootSent"`
StorySeenAnyRpc bool `json:"storySeenAnyRpc"`
StoryHighestConfirmedRpcId int64 `json:"storyHighestConfirmedRpcId"`
StoryPendingRpcIds any `json:"storyPendingRpcIds"`
StoryCommittedRpcIds []int64 `json:"storyCommittedRpcIds"`
StoryEnterVehicleId uint64 `json:"storyEnterVehicleId"`
StoryEnterSeat byte `json:"storyEnterSeat"`
StoryExitInProgress bool `json:"storyExitInProgress"`
StoryBoardingUnitId uint64 `json:"storyBoardingUnitId"`
}
func GameRouter_Vehicle_Clear(ctx context.Context, ) any {
// Router implementation for GameRouter_Vehicle_Clear
var zero any; return zero
}