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

346 lines
17 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"
"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 实机修瞬移)。
// <para>症状:车能开到身边,玩家一上车就瞬移回生成点。</para>
// <para>根因:服务端在生成时下发了 SyncAetherAIVehicleAddData(ClientVehicleInitData),
// 里面写的是生成点坐标且 LaneHandle=-1(不参与车道推进)⇒ 这份 Aether 坐标
// 之后再也没人更新。车是被 SyncAssignVehicleAITask 的 Cruise(Raid 通道)开过来的,
// 客户端两套表示就此分叉。玩家上车时客户端拿 Aether 那份数据对齐实体 ⇒ 车被拽回生成点。
// 服务端上车那几秒一条 S2C 位置包都没发(14:46:42–45 全是 C2S),所以不是我们回填错了,
// 是客户端自己的那份旧值。</para>
// <para>对策:SyncTeleportVehicle(68088911) 是 Raid 通道的权威位置包(赛车 R309 /
// 改装店钉车 / 传送都在用,Reset=true = 客户端直接落位不插值)。位置取
// AskVehicleMove 上报的最新值 —— AI 开车期间客户端每秒都在报,所以这一发
// 视觉上是「原地不动」,只是把两边强行对齐。</para>
//
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)。
// <para>三步,顺序不能改:
// <list type="number">
// <item>SyncAetherAIChangeVehicleControl(2) —— 把车切回 RaidVehicle。
// 客户端会把有 VDE 的车交给 Aether 车道模拟,位移每帧被车道覆盖 ⇒ Cruise 变成
// 「轮胎在转、车在原地进行」(GameRouter.Taxi.cs:147-166,出租车踩过的)。</item>
// <item>SyncVehicleAutonomousDrivingState(true) —— 必须早于 AI 任务,
// 否则客户端把这条任务当成「别人的车被接管」渲染 ⇒ 车门消失 / 角色缺模
// (2026-09-30 §43.1)。</item>
// <item>SyncAssignVehicleAITask + Cruise,token 复用召唤回执那个。</item>
// </list>
// </para>
// <para>⛑ 终点是「车道上离玩家最近的点」(靠边停车),不是玩家脚下:自定义标点吸附失败时
// 客户端一条 Cruise 都不下发,表现是「叫了车没反应」。解不出车道路径就只给终点,
// 交给客户端 C# NavigationHelper 自己导航(自驾已验证能到任意 POI)。</para>
//
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&lt;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 = 当前没有行程。
// <para>⛑ 只记「服务端自己派发的那一次」。客户端的原生出租车 UI(选目的地面板、
// 到达提示)状态全在客户端,服务端只负责:认单 → 派 Cruise → 判到达 → 收车费。</para>
// <para>⛑ 与 AutoDriveTaskToken 的关系:出租车复用自驾那条
// SyncAssignVehicleAITask 通道,所以行程的 token 就是 AutoDriveTaskToken;
// 本字段额外记住「这趟是出租车」+ 目的地 + 起始里程,用来算车费和判到达。</para>
//
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
}