package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // ROUTE A race-start experiment (§59.14 §7.9): push a single SyncGameGroundZoneInfo // (68004609) carrying a RacingZoneInfo and watch what the client does with it. // The question this answers is the only remaining unknown in the racing chain: // // 68004609 → C# GameSceneToClientImpl.SyncGameGroundZoneInfo (dump.cs:184816) // → lua GameSceneToClientImpl.SyncGameGroundZoneInfo (lua:1135) // → Racing branch → gChallengeManager:OnSyncRacingZoneInfo (lua:526) // → ...and then? lua never calls L50.Spoon.CarRaceManager.Instance:SyncCarRaceGame // // Either the C# hop stops at the C# CarRaceManager itself (in which case this single packet is // enough to stage the grid, run the countdown and start the lap clock), or the race only runs when // a Spoon graph calls SyncCarRaceGame (IDMAP 49071), in which case nothing happens and // Route A stays blocked on the Spoon md5 problem. // Observable outcomes (see VEHICLE-RACING-INVESTIGATION.md §7.9): // • cars appear on the track / countdown panel / AI dots on the minimap (gMapCsApi.OnCarRaceStart) // ⇒ (a) C#-internal wiring — Route A is unblocked, only participants + settlement remain. // • absolutely nothing, and no CarRaceManager line in Player.log // ⇒ (b) Spoon-graph driven — Route A needs the Spoon md5. // Nothing here is wired into normal gameplay: the only entry point is the debug HTTP API // (/api/racing/zone-probe), so this is inert until deliberately fired. // // // Options surfaced to the debug panel / HTTP caller. cfgId is a // RacingDriverTrackInformationConfig Id (the "Id" column, NOT an EventId). // func GameRouter_RacingZoneProbe_RacingZoneProbeStatus(ctx context.Context, ) any { // Router implementation for GameRouter_RacingZoneProbe_RacingZoneProbeStatus var zero any; return zero } // // Build the AI opponent grid for a racing zone. Returns BOTH: // • AIVehicleInfos — the plain dict (vehicleInstanceId → cfgId) that drives the minimap // blue dots (client GetAllVehicleAIIds reads AIVehicleInfos); and // • ParticipantInfos — real AI opponents, each a GameGroundParticipantInfo4229938 // (0xFF marker + 8 base fields), which is the element shape the client's own // Auto.WriteRacingZoneInfo uses. (R203: the earlier RacingParticipantInfo/TypeMark=14 // shape desynced the packet by 28 B/participant.) // Returns empty lists when ≤ 0 (byte-compatible with the pre-AI probe). // Opponent cfgIds come from the track's HighAI/MiddleAI/LowAI pools (RacingTrackRow); if the row is // missing or the pools are empty, no AI is produced. // func GameRouter_RacingZoneProbe_BuildRacingAiGrid(ctx context.Context, trackCfgId uint32, count int32, realVehicles []any) any { // Router implementation for GameRouter_RacingZoneProbe_BuildRacingAiGrid var zero any; return zero } // // One AI opponent entry, typed as the BASE GameGroundParticipantInfo — which is what the // client's own Auto.WriteRacingZoneInfo writes for this list // (Base.WriteComplexWrap(Auto.WriteGameGroundParticipantInfo, …)): each element is // 0xFF (present marker) + 8 base fields, no TypeMark. // is the SCENE ENTITY id (it is also what the client keys // AIVehicleInfos by) and is the VehicleConfig the car // was built from. It lands in VehicleInstanceId / AIAgentInfo.VehicleId; the // Racing-only extras (AiVehicleCfgId / Lap / RacingTotalTimeMilli …) are NOT // part of this shape — R203 proved adding them desyncs the packet by 28 B per participant. // func GameRouter_RacingZoneProbe_BuildRacingParticipant(ctx context.Context, agentInstanceId uint64, aiCfgId uint32, vehicleCfgId uint32, seatIndex int32) any { // Router implementation for GameRouter_RacingZoneProbe_BuildRacingParticipant var zero any; return zero } // // Build the payload the client's Auto.Dispatch[449] expects: the RacingZoneInfo // discriminator (0x0F, emitted by [UxContract(TypeMark = 15)]) followed by the Racing // fields and then the GameGroundZoneInfo fields. // When > 0 the grid is populated with that many AI opponents // (cfgIds from the track's HighAI/MiddleAI/LowAI pools); when 0 or omitted the grid stays empty, // which is also the byte-compatible original probe. The LinkAIAgentInfo contract is now declared // (RacingZoneMethods.cs), so a non-empty grid serialises correctly. // // / are unix seconds for // GameGroundZoneCountDownInfo (dump.cs:1918571). They drive the client's countdown panel // and therefore the vehicle-control release — an all-zero countdown is what left the player in // an undrivable car on 2026-09-22 (see GameRouter.RacingAutoStart.cs). Both default to 0 so the // debug /api/racing/zone-probe payload stays byte-identical to the original 71-byte probe. // // func GameRouter_RacingZoneProbe_BuildRacingZoneProbe(ctx context.Context, cfgId uint32, taskId uint32, zoneState byte, syncReason byte, zoneSessionId any, gadgetUId uint64, startTime uint32, gameTimeEnd uint32, prepareEnd uint32, displayEnd uint32, aiCount int32, realAiVehicles []any) any { // Router implementation for GameRouter_RacingZoneProbe_BuildRacingZoneProbe var zero any; return zero } // // Human-readable sanity check for the caller-supplied cfgId, so a bad id is caught before it // reaches the client (an unknown cfgId would make InitAetherClientData a no-op and // silently produce a "nothing happened" result that looks like outcome (b)). // func GameRouter_RacingZoneProbe_ValidateRacingCfgId(ctx context.Context, cfgId uint32) any { // Router implementation for GameRouter_RacingZoneProbe_ValidateRacingCfgId var zero any; return zero } // // A null complex: exactly one 0x00 byte. The client's // GameSceneToClientImpl.SyncGameGroundZoneInfo treats a nil zone as "tear down the // current zone", which is also the only way to undo the probe without relogging. // func GameRouter_RacingZoneProbe_BuildRacingZoneClearBody(ctx context.Context, ) []byte { // Router implementation for GameRouter_RacingZoneProbe_BuildRacingZoneClearBody return nil }