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

169 lines
9.3 KiB
Go
Raw Permalink Normal View History

package routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// 赛车检查点门(R247 · 2026-10-01)—— 服务端显式摆放。
// 症状:整条赛道上一道绿框门都没有(用户:「开始赛车了,没有看到绿框门」)。
// 为什么没有:门是 gadget 对
// Racing_challenge01_CheckPoint / Racing_challenge01_CheckPointEnd,
// 官方**按检查点位置在运行时 spawn**;而检查点来自
// RacingDriverTrackInformationConfig.RaidSpoonName 指向的 Spoon 图 ——
// 这张图**从未合并进客户端**(SpoonMd5="" ⇒ SpoonRaidMgr 走
// #NoCreateIssue),所以官方那条链一次都没执行过,门**从来没人 spawn**。
// 不是坏了,是没装。
// 为什么必须服务端摆:R244 已经试过「客户端 Lua 自己
// gResourceManager:LoadAssetWithCallBack + GameObject.Instantiate」,
// 实机证据是 16/16 全部实例化成功、go0.active=true、scale=1/1/1、
// children=2、全程**零** Load asset FAILED —— 但**肉眼一道都看不见**。
// 这与「家具全无 / 健身器材 / 摊位补给」是同一个病根:**客户端不会自己实例化这类物件**,
// 必须由服务端经 gadget 通道下发。
// 通道:SpawnGadgetAsync(健身器材 / PropRestock / 摊位补给都走它,实测可见)。
// ⛔ iScale 必须传 0:100(GM 面板默认)出来是 transform scale (0,0,1)
// 的**零缩放空壳、没有 prefab** —— 正是保龄球球瓶「有物理有音效但看不见」的根因。
// 坐标:客户端 R225 已用 LoadRaceTrackData 采出 16 个检查点(沿弧长等分),
// R247 把它们与**服务端那套 pathId** 一起落到 config/racing-gates.json。
// 服务端读表摆放 —— 与健身器材 _gym_capture.py 的「离线采样 → 落配置 → 服务端摆」完全同构。
// 拿不到表时:在玩家四周摆 4 道「验证信标」。它的价值是把
// 「通道对不对」和「坐标对不对」两个变量解耦:看得见信标 ⇒ 通道没问题,只差坐标。
// 回滚:world.content.racingGates.enabled = false(不用重编译)。
//
// R255:把内置官方表变成摆位计划(含 YawOffset 修正)。
//
// ★★★ R256 —— **默认改用官方自己的检查点 prefab**(RacingGateCheckPointPathId),
// 不再用 R253 选的 Jobrace_gongmen(拱门)。
// <para>为什么换回去:config/racing-gates.json 里(客户端探针写的)
// 每个检查点本来就是 pathId 884611825 / 终点 271608686 ——
// 也就是 Res/Prefab/Gadget/Racing_challenge01_CheckPoint.prefab。
// 是 R253 起用 PathIdOverride=64493331 把它**覆盖**成了拱门。</para>
// <para>R254 的注释写过「884611825 资源从未随包 ⇒ 隐形」,**该判断已被推翻**:
// 关卡块 vfc_1479 里官方**实实在在地摆了 16 个该 prefab**
// (+2 个 ...End,见 _r256_gate_instances.py / _r190_racing_checkpoints.json)
// ⇒ 客户端一定能渲染它,资源必然随包。
// 当轮"看不见"的真因是 **yaw 算错**(见下)把门转到了错误方向/位置。</para>
// <para>切换开关:racingGates.pathIdOverride。
// 0(默认)= 官方检查点 prefab(终点自动用 ...End);
// 64493331 = 回退到 R253~R255 的拱门(此时终点同 prefab)。</para>
//
func GameRouter_RacingGates_BuildOfficialTrackGates(ctx context.Context, cfg any) []any {
// Router implementation for GameRouter_RacingGates_BuildOfficialTrackGates
return nil
}
//
// ⛔⛔ R258 定案:这个开关 = 「我们自己造的门宽」,不是官方数据 ⇒ 默认必须关。
// 用户的两条纠正(R258,决定了本开关的命运):
// 「<i>路宽不一定代表门宽啊,不要查错方向了</i>」+「<i>赛道的宽度也是根据检查点的宽度来计算的</i>」
// ⇒ 门宽是「门」这件物件自带的,赛道按它建;所以**没有**需要我们填的宽度,
// 也就不该有 pairMirror / pairOffset 这两个旋钮。
// R257 把它们打开,等于「我们自己在给门调宽」—— 已被明确叫停。
// R258 的官方摆位判据(这才是「一个实例够不够」的正确证法):
// gym_tools/_r190_racing_checkpoints.json 里官方静态摆了 **14 个**
// Racing_challenge01_CheckPoint,两两**最近距离 131.69 m、完全不成对**
// ⇒ 官方就是「**一个检查点摆一个实例**」。
// 再加上 gadget 注册表(vfc_907)里带「拱门」语义的物件**只有一个**
// (Jobrace_gongmen 64493331,其 prefab 自带 _left/_right/_up)
// ⇒ **一扇门 = 一个实例**,宽度由 prefab 自身决定,我们没有可填的数。
// R254 的假设(已推翻):看到画面只有一根立柱 + 顶端向内弯折 ⇒ 认为
// 一个 Jobrace_gongmen 实例只是**半扇拱门**,要同坐标摆两个(yaw 差 180°)才成整扇。
// R255d 的实测证据(推翻它):
// ① 资产扫描(`gym_tools/_r255c_gate_prefab_scan.py`,全库 1682 块)——
// vfc_1583 里 **同一个 prefab** 自带三件套:
// gp_arch_gongmen_blue_left(+`_left_lod2`)、
// gp_arch_gongmen_blue_right(+`_right_lod12`)、
// gp_arch_gongmen_blue_up(+`_up_lod`)⇒ **一个实例就是完整一扇门**。
// R254 当时看到的「只有右半」,最可能是**左半被棕榈树 / 那栋黑楼挡住**。
// ② 打开本开关后用户实测原话:「**门叠在一块了**」——
// 因为两个完整门被摆在**同一坐标**,只能互相 z-fighting 重叠。
// 结论:`pairMirror` 保持 **false**(配置 world.content.racingGates.pairMirror)。
// <para>⛔ R258 更正本条:R257 把 A、B 拆到对侧(-ox/-oz)本身没错,
// 但**整个「成对」模型是自造的**(见上)。官方每检查点只摆 1 个实例
// ⇒ 一扇门 = 一个 prefab,不需要第二个实例,也就没有「柱到中线的距离」要调。
// 所以 pairOffset 的真实语义只是「把整道门横向平移」,与「门宽」无关。</para>
//
func GameRouter_RacingGates_ExpandGatePairs(ctx context.Context, plan []any, cfg any) []any {
// Router implementation for GameRouter_RacingGates_ExpandGatePairs
return nil
}
// 同一个 session 只提醒一次「表还没有」——缺采集文件是设置步骤,不是运行错误。
func GameRouter_RacingGates_RacingGateNoticed(ctx context.Context, session *GameSession) bool {
// Router implementation for GameRouter_RacingGates_RacingGateNoticed
return true
}
//
// 在一局赛车开始时摆门。由 RunRacingAutoStartAsync 在 DISPLAY 推出去之后调用
// (倒计时 3 秒期间门就该在了)。
//
func GameRouter_RacingGates_SpawnRacingGatesAsync(ctx context.Context, session *GameSession, state any, trackId uint32, taskId uint32) any {
// Router implementation for GameRouter_RacingGates_SpawnRacingGatesAsync
var zero any; return zero
}
// R294:撤这一局可能摆过的**所有**赛车门 pathId。
func GameRouter_RacingGates_RacingGatePathIdSet(ctx context.Context, cfg any) []any {
// Router implementation for GameRouter_RacingGates_RacingGatePathIdSet
return nil
}
//
// R294:撤掉**第 个检查点**那对门(A/B 两半)。
// 返回撤掉的个数(0 = 这个点本来就没摆 / 已经撤过)。
//
func GameRouter_RacingGates_RemoveCheckpointGatesAsync(ctx context.Context, session *GameSession, state any, cpIndex int32) int32 {
// Router implementation for GameRouter_RacingGates_RemoveCheckpointGatesAsync
return 0
}
//
// R312:**真正的按坐标撤门**(纯执行,不含任何策略/宽限期/挂起逻辑)。
// <para>抽出来是为了让「R311 撤门宽限期」和「R312 前 N 个门延迟到第 N+1 个通过再撤」
// 两条策略都能调它,而**不会互相重入** —— 否则 `cpIndex &lt; keepFirstN` 的那两个点
// 会在递归里被**再次挂起** ⇒ 永远撤不掉(自己给自己下套)。</para>
//
func GameRouter_RacingGates_RemoveCheckpointGatesCoreAsync(ctx context.Context, session *GameSession, state any, cpIndex int32, gateCfg any) int32 {
// Router implementation for GameRouter_RacingGates_RemoveCheckpointGatesCoreAsync
return 0
}
// R294:撤掉这一局摆过的**全部**赛车门(比赛结束 / 完成上报时调)。
func GameRouter_RacingGates_RemoveAllRacingGatesAsync(ctx context.Context, session *GameSession, state any) int32 {
// Router implementation for GameRouter_RacingGates_RemoveAllRacingGatesAsync
return 0
}
//
// 读客户端 R247 落下的检查点表。文件不存在 / 解析失败都只是「还没有坐标」,
// 退回信标模式,绝不抛。
//
func GameRouter_RacingGates_LoadRacingGateTable(ctx context.Context, session *GameSession, cfg any) []any {
// Router implementation for GameRouter_RacingGates_LoadRacingGateTable
return nil
}
//
// 「验证信标」:在玩家四周各摆一道门。用途只有一个 ——
// 把「通道对不对」与「坐标对不对」解耦。看得见 ⇒ 通道没问题,只差那张坐标表。
//
func GameRouter_RacingGates_BuildRacingGateBeacons(ctx context.Context, state any, cfg any) []any {
// Router implementation for GameRouter_RacingGates_BuildRacingGateBeacons
return nil
}
// 一条待摆放的门。
type RacingGatePlacement struct {
PathId int32 `json:"pathId"`
X float32 `json:"x"`
Y float32 `json:"y"`
Z float32 `json:"z"`
Yaw float32 `json:"yaw"`
Label string `json:"label"`
}