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 }