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
Ananta-ps/internal/gameserver/routers/game_router_racing_task_graph.go

122 lines
6.7 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
//
// 原版赛车图加载通道 — SyncPlayerSingleTask(64917604) + TaskSpoonViewInfo.
// WHY THIS FILE EXISTS (2026-09-23 evening, "还原大于一切")
// Until now the racing Spoon graph was force-merged by a CLIENT fastpatch that injected
// "<raidId>_RacingDriver" into EnterSceneInfo.SceneSpoonNames. That is NOT the original
// behaviour and we can now prove it: in the only 4 official-server captures we own
// (logs\packets-20260913-*.log; 09-14 onward is our own private server — the discriminator is
// that SyncAetherAIVehicleAddData first appears 09-14 15:41), the official server sends
// SceneSpoonNames: [] AND SceneSpoonMd5s: [] while the player stands inside the racing
// raid 23300888. RaidConfig carries no spoon field either. So the racing graph is NOT delivered
// as a scene spoon.
// The remaining native channel is the TASK graph:
// <code>
// SpoonTaskMgr (client, [ExportToLua])
// TASK_SPOON_FILE_PATH / TASK_RAID_FILE_PATH ← graphs are local files
// GetSpoonTaskFilePath(spRaidId, alias, out fileName) ← keyed by (spRaidId, alias)
// SyncPlayerSingleTask(taskId, TaskViewData, TaskSpoonViewInfo, TaskStateData) ← RPC entry
// LoadTaskWorkActionData(taskId, taskSpoon) → GetTaskWorkActionByTask
// </code>
// TaskSpoonViewInfo = { SpoonMd5, SpRaidId, StartTaskId, EndTaskId, Alias, EventId,
// EventStartTaskId } — and the racing track table authors exactly those two keys inside
// RacingDriverTrackInformationConfig.RaidSpoonName:
// <code>
// "23300888_RacingDriver" → SpRaidId 23300888, Alias "RacingDriver"
// "spoon23301289_RacingDriver" → SpRaidId 23301289, Alias "RacingDriver"
// </code>
// GameRouter.Task.cs already speaks this RPC, but ONLY for the demo story task and with a
// PLACEHOLDER SpoonMd5; the racing task 60000147 was never sent through it. That is the
// documented gap this file closes.
// WHAT IT SHOULD FIX
// The 2026-09-23 probes read task.workActions=0 and, in the client log,
// CarRaceManager.lua:291/417 nextRankPoint is nil + counter is nil spam at ~60/s — i.e.
// the racing task has NO work actions, which is exactly what LoadTaskWorkActionData fills in.
// Without them the client cannot build the checkpoint / rank-point list, so the arrow, the GPS track
// and the rank logic are all dead. Those checkpoints are also the only thing that could give the
// racing AI its route, which is why the AI opponents currently spawn but never drive.
// IS IT ORIGINAL?
// The RPC, the payload types and the key derivation are all native (client dump + client-generated
// readers). What is NOT original is the CONTENT: we synthesise the task-graph reference from
// RacingDriverTrackInformationConfig because the official server's task-Spoon config
// (TASK_SPOON_FILE_PATH / TASK_RAID_FILE_PATH source) is server-side and we do not have
// it. SpoonMd5 is therefore left empty, and the client then silently ignores the whole
// push (no error, no graph, workActions = 0). The real md5 is the one genuinely missing piece.
// ⛔ 已证伪的两个旧说法(别再用):
// 1. 「空 md5 客户端会容忍,只警告版本不一致、照旧跑图」—— 那是**场景**通道的行为
// (SpoonRaidMgr.cs:87),**任务图**通道不是。任务图这边是静默忽略。
// 2. 「填个非空假 md5 就能逼客户端走加载分支」—— 实测**硬崩**(R211b,2026-09-30 23:05)。
// 见 RacingTaskSpoonMd5。
// SAFETY
// Additive only: nothing already being sent changes, and a failure degrades to today's behaviour.
// Kill switch: RacingTaskSpoonLoadEnabled.
//
//
// Splits a RacingDriverTrackInformationConfig.RaidSpoonName into the two keys
// TaskSpoonViewInfo actually wants: SpRaidId (the numeric prefix, with an optional
// "spoon" word in front) and Alias (everything after the first underscore).
// Real values observed in the client config:
// <code>
// 23300888_RacingDriver → (23300888, "RacingDriver")
// 23300999_RacingDriver → (23300999, "RacingDriver")
// spoon23301289_RacingDriver → (23301289, "RacingDriver")
// spoon23301305_main → (23301305, "main")
// spoon23301294_23301294_Race_Chaos_Gadgets → (23301294, "23301294_Race_Chaos_Gadgets")
// </code>
// Returns false (and zero/empty) when the string cannot be parsed — the caller then skips the
// push rather than sending a nonsense graph key.
//
func GameRouter_RacingTaskGraph_TryParseRaidSpoonName(ctx context.Context, raidSpoonName any, spRaidId uint32, alias string) bool {
// Router implementation for GameRouter_RacingTaskGraph_TryParseRaidSpoonName
return true
}
//
// Racing task-graph reference for a track: SpRaidId + Alias parsed from the track's
// authored RaidSpoonName, plus the track's EventIds[0] for
// TaskSpoonViewInfo.EventId.
// The authored name is authoritative and self-contained (its numeric prefix IS the spoon raid),
// so is NOT used as a filter — the caller logs it for inspection only,
// because the client keys the graph on (spRaidId, alias) rather than on the player's raid.
// Alias precedence (highest first):
// 1. RacingTaskSpoonAliasOverride — manual A/B knob.
// 2. RacingTaskSpoonVerifiedAliases — alias literally read from a client asset.
// 3. parsed from RaidSpoonName (known to be the SCENE-spoon spelling, so it is only a
// last resort and is logged as such).
//
func GameRouter_RacingTaskGraph_TryResolveRacingTaskSpoon(ctx context.Context, trackId uint32, spRaidId uint32, alias string, eventId uint32, aliasSource string) bool {
// Router implementation for GameRouter_RacingTaskGraph_TryResolveRacingTaskSpoon
return true
}
// Back-compat overload without the alias-provenance output.
func GameRouter_RacingTaskGraph_TryResolveRacingTaskSpoon_2(ctx context.Context, trackId uint32, spRaidId uint32, alias string, eventId uint32) bool {
// Router implementation for GameRouter_RacingTaskGraph_TryResolveRacingTaskSpoon_2
return true
}
//
// Pushes SyncPlayerSingleTask(64917604) for one racing task so the client loads the racing
// TASK graph and populates its work actions (checkpoints / rank points).
// Wire (method-frame body, Inline — no root 0xFF marker; nested entities are Complex):
// TaskId = uint32
// TaskInfo = TaskViewData (0xFF)
// SpoonViewInfo = TaskSpoonViewInfo (0xFF)
// StateData = TaskStateData (0xFF)
// Best-effort: any failure is logged and swallowed so the race itself is unaffected.
//
func GameRouter_RacingTaskGraph_PublishRacingTaskSpoonAsync(ctx context.Context, rpcCtx *RpcContext, taskId uint32, trackId uint32, raidId uint32) any {
// Router implementation for GameRouter_RacingTaskGraph_PublishRacingTaskSpoonAsync
var zero any; return zero
}