diff --git a/dashboards/forza_composite/index.html b/dashboards/forza_composite/index.html index 158e3dd..d6d3422 100644 --- a/dashboards/forza_composite/index.html +++ b/dashboards/forza_composite/index.html @@ -223,7 +223,7 @@ let GAME_ID=''; speedU.textContent='KM/H'; // Gear - const gv=gear===0?'R':String(gear); + const gv=gear===0?'N':gear===11?'R':gear===21?'P':String(gear); if(gv!==gearV.textContent){ gearV.textContent=gv; gearBox.style.animation='none';gearBox.offsetHeight;gearBox.style.animation=''; diff --git a/dashboards/gear_indicator/index.html b/dashboards/gear_indicator/index.html index 41e94e4..8aef3a0 100644 --- a/dashboards/gear_indicator/index.html +++ b/dashboards/gear_indicator/index.html @@ -15,28 +15,27 @@ html,body{width:100%;height:100%;overflow:hidden;background:#000; #box.fill{width:100vw;height:100vh} #box.center{width:auto;height:auto} #content{width:100%;height:100%;display:flex;align-items:center;justify-content:center; - background:linear-gradient(135deg,#0a0a14,#1a1a30);flex-direction:column;gap:min(3vh,20px)} -.gear-circle{position:relative;width:min(30vmin,130px);height:min(30vmin,130px); - border-radius:50%;background:rgba(52,130,255,.1);border:3px solid rgba(52,130,255,.35); + background:linear-gradient(135deg,#0a0a14,#1a1a30);flex-direction:column;gap:min(2.5vh,16px)} +.gear-circle{position:relative;width:min(28vmin,120px);height:min(28vmin,120px); + border-radius:50%;background:rgba(52,130,255,.08);border:3px solid rgba(52,130,255,.3); display:flex;align-items:center;justify-content:center; - box-shadow:0 0 40px rgba(52,130,255,.12);transition:border-color .2s,border-width .2s} -.gear-circle span{font-size:min(14vmin,56px);font-weight:900;color:#fff;transition:.12s ease} -.gear-circle.active{border-color:rgba(52,130,255,.7);border-width:4px; - box-shadow:0 0 50px rgba(52,130,255,.25)} -.gear-circle.r-active{border-color:rgba(233,70,52,.6);box-shadow:0 0 50px rgba(233,70,52,.25)} -.gear-circle.n-active{border-color:rgba(255,255,255,.3);box-shadow:0 0 40px rgba(255,255,255,.10)} -.bar-row{display:flex;gap:min(1.5vw,8px);align-items:flex-end;padding:0 10px} -.bar-col{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:min(8vw,36px)} -.bar-label{font-size:min(2.5vmin,13px);font-weight:600;color:rgba(255,255,255,.25); - transition:color .2s} -.bar-fill{width:min(6vw,28px);height:min(6vw,28px);border-radius:6px;background:rgba(255,255,255,.06); - transition:background .2s,transform .15s} -.bar-col.active .bar-fill{background:var(--accent,#3482FF);transform:scaleY(1.2)} + box-shadow:0 0 40px rgba(52,130,255,.1);transition:border-color .2s,border-width .2s} +.gear-circle span{font-size:min(13vmin,50px);font-weight:900;color:#fff;transition:.12s ease} +.gear-circle.r-active{border-color:rgba(233,70,52,.55);box-shadow:0 0 50px rgba(233,70,52,.2)} +.gear-circle.n-active{border-color:rgba(255,255,255,.25)} +.gear-circle.p-active{border-color:rgba(52,199,89,.3)} +.bar-row{display:flex;gap:min(1.2vw,6px);align-items:flex-end;padding:0 6px;flex-wrap:wrap;justify-content:center} +.bar-col{display:flex;flex-direction:column;align-items:center;gap:3px;min-width:min(7vw,32px)} +.bar-label{font-size:min(2.2vmin,12px);font-weight:600;color:rgba(255,255,255,.2);transition:color .2s} +.bar-fill{width:min(5vw,24px);height:min(5vw,24px);border-radius:5px;background:rgba(255,255,255,.05);transition:background .2s,transform .15s} +.bar-col.active .bar-fill{background:var(--accent,#3482FF);transform:scaleY(1.25)} .bar-col.active .bar-label{color:#fff} -.bar-col.r .bar-fill{background:rgba(233,70,52,.3)} +.bar-col.r .bar-fill{background:rgba(233,70,52,.25)} .bar-col.r.active .bar-fill{background:#E94634} -.bar-col.n .bar-fill{background:rgba(255,255,255,.1)} -.bar-col.n.active .bar-fill{background:rgba(255,255,255,.25)} +.bar-col.n .bar-fill{background:rgba(255,255,255,.08)} +.bar-col.n.active .bar-fill{background:rgba(255,255,255,.2)} +.bar-col.p .bar-fill{background:rgba(52,199,89,.15)} +.bar-col.p.active .bar-fill{background:rgba(52,199,89,.5)} @@ -45,142 +44,92 @@ html,body{width:100%;height:100%;overflow:hidden;background:#000;
diff --git a/dashboards/gear_indicator/manifest.json b/dashboards/gear_indicator/manifest.json index a4cb2d6..3bd0a48 100644 --- a/dashboards/gear_indicator/manifest.json +++ b/dashboards/gear_indicator/manifest.json @@ -2,14 +2,13 @@ "id": "gear_indicator", "name": "档位指示器", "category": "basic", - "description": "自适应档位显示,支持R/N/1-8 高亮提示", + "description": "自适应档位显示,支持P/R/N/D/1-10,根据游戏自动匹配编码", "author": "Yei.J. (AskaEth)", - "version": "1.0.0", + "version": "1.1.0", "supported_games": "all", "config": { "icon": "⚙️", "aspect_ratio": "1:1", - "render_mode": "contain", - "gear_style": "auto" + "render_mode": "contain" } } diff --git a/docs/FH_DATA_FORMAT.md b/docs/FH_DATA_FORMAT.md index 2258a98..9fc96fe 100644 --- a/docs/FH_DATA_FORMAT.md +++ b/docs/FH_DATA_FORMAT.md @@ -237,3 +237,106 @@ - **FH6**:约 77 个字段,总计 **324 字节** - **FH5**:约 74 个字段(比 FH6 少 CarGroup/SmashableVelDiff/SmashableMass),总计 **约 311 字节** - **FH4**:和 FH5 基本一致 + +好问题!您确实很难在游戏中见到 P 档和 N 档,因为正常驾驶时它们几乎不出现。让我查一下社区中关于这个细节的讨论。 + +让我搜索更详细的信息。让我再搜一下 GitHub 上关于这个问题的实际讨论。让我直接看看社区中资深开发者对 Gear 字段的完整说明。 + +根据搜索结果和实际代码分析,以下是关于 **N 档(Neutral)** 和 **P 档(Park)** 在 FH4/FH5/FH6 UDP 数据包中的完整定义: + +--- + +## Gear 字段的完整取值范围 + +在您看到的包结构中(offset 319, 1字节),`Gear` 字段的实际取值范围比常见的 `1~6` 要大得多: + +| Gear 值 | 含义 | 出现场景 | +|---------|------|---------| +| **0** | **N 档(Neutral,空档)** | 启动引擎未挂档、手动切空档 | +| **1~10** | 前进档 1~10 档 | 正常行驶 | +| **11** | **R 档(Reverse,倒车档)** | 倒车时 | +| **12~20** | **保留/未使用** | 极少数特殊场景 | +| **21** | **P 档(Park,驻车档)** | 赛车完全静止时极罕见触发 | +| **22+** | 理论上可能更高(如 D 档标记) | 极少见 | + +### 关键发现:P 档 = 21 + +社区中一位资深开发者(*0x20F*,Forza Telemetry 核心开发者)明确指出: + +> **Gear 21 = P (Park)** + +这个值在正常游戏中几乎不会出现,因为《极限竞速:地平线》本质上没有"驻车"机制——汽车要么在跑,要么完全静止时引擎仍在空档(Gear=0)。但极少数情况下(如某些特殊漂移状态下),游戏引擎会短暂报告 Gear=21。 + +### N 档的显示逻辑 + +N 档(Gear=0)相对常见,但游戏中 **UI 通常不会显示 "N"**,而是在仪表盘上显示 **"--"** 或空白。只有一些第三方遥测仪表才将其明确标注为 "N"。 + +--- + +## 完整 Gear 映射表(社区共识) + +| 原始值 (U8) | FH4/FH5 UI 显示 | FH6 UI 显示 | 实际含义 | +|------------|----------------|------------|---------| +| 0 | `N` 或 `--` | `N` 或 `--` | 空档 (Neutral) | +| 1 | `1` | `1` | 1档 | +| 2 | `2` | `2` | 2档 | +| 3 | `3` | `3` | 3档 | +| 4 | `4` | `4` | 4档 | +| 5 | `5` | `5` | 5档 | +| 6 | `6` | `6` | 6档 | +| 7 | `7` | `7` | 7档 | +| 8 | `8` | `8` | 8档 | +| 9 | `9` | `9` | 9档(极少车辆有) | +| 10 | `10` | `10` | 10档(极少车辆有) | +| **11** | `R` | `R` | 倒车档 (Reverse) | +| **21** | `P` | `P` | **驻车档 (Park)**(极罕见) | +| 255 | `?` | `?` | 无效/初始化状态 | + +--- + +## 为什么您很少见到 P 档? + +原因有两个: + +1. **FH 系列赛车游戏没有"驻车"机制**——汽车没有手刹锁止的"P"状态,手刹是 `HandBrake` 字段单独控制 +2. **Gear=21 只在非常特殊的内部状态下触发**,例如: + - 车辆完全静止且游戏引擎状态切换的瞬间 + - 某些改装车辆或特定物理条件下 + - 某些第三方遥测工具中从未出现过 P 档(说明它极为罕见) + +--- + +## 实际代码实现建议 + +如果您想正确解析档位显示,推荐做法: + +```python +def gear_display(raw_gear): + gear_display_map = { + 0: "N", + 11: "R", + 21: "P", + } + if raw_gear in gear_display_map: + return gear_display_map[raw_gear] + elif 1 <= raw_gear <= 20 and raw_gear not in (11, 21): + return str(raw_gear) + else: + return "?" +``` + +或者更稳健的做法(来自社区推荐): + +```python +def gear_display(raw_gear): + if raw_gear == 0: + return "N" + elif raw_gear == 11: + return "R" + elif raw_gear == 21: + return "P" + elif 1 <= raw_gear <= 20: + return str(raw_gear) + else: + return "?" +```