- feat(client): 界面换成墨黑蓝底 + 单支红的矩形语言,切角全部去掉,仅装甲条保留平行四边形 - feat(client): 自托管 HarmonyOS Sans SC 与 JetBrains Mono,中文与拉丁数字逐字回退 - feat(client): 新增启动序列、首启门、用户端 HUD、裁判端控制台、设置抽屉与固件维护页 - feat(client): 裁判端中缝与下方控制台可拖,鼠标落在哪一路下方就看哪一路 - feat(client): 设置抽屉常驻实时预览,与画面共用同一份准星绘制代码 - feat(client): 动效改用 Material 3 的缓动曲线与时长,逐条替换掉自造的贝塞尔 - feat(version): 版本号与 CHANGELOG 由 scripts/version.mjs 从 git 历史算出,不再手写 - feat(firmware): Hello 报文携带语义化版本、构建号与自报协议号,负载向后兼容 - feat(client): 固件版本显示在绑定列表与裁判端每一格;协议不匹配时给出具体原因 - feat(firmware): 固件包版本与客户端同源,都从 version.json 读 - fix(client): getCurrentWindow() 在没有 Tauri 注入时同步抛异常,浏览器预览整棵树被卸载 - fix(client): 启动序列的淡出 effect 清掉了自己刚设的 setTimeout,界面永远停在启动页 - fix(client): 设置抽屉左侧导航的锚点没挂到 section 上,且用错了坐标系 - fix(protocol): Hello 改用宽松帧头解析,让协议不匹配的板子能被解释而不是静默消失 - fix(build): Windows 上 bindgen 加载不了 libclang 的同目录依赖,构建脚本补上搜索路径 - fix(build): esp-idf-sys 在长路径下拒绝构建,固件构建改用短的目标目录 - build(client): 队标图标,含光学尺寸分级与手工拼的多尺寸 ICO - build(ci): 守门 job 增加版本一致性检查,产物名改为 rmic-2026-* - docs: 补充界面语言、版本机制与协议通告布局的说明
80 lines
3.1 KiB
Rust
80 lines
3.1 KiB
Rust
// ESP-IDF 的环境导出 + 固件版本信息注入。
|
||
//
|
||
// # 版本号为什么在这里注入
|
||
//
|
||
// 固件的版本必须和客户端、和 `version.json` 是**同一个数**。手工在 `src/` 里写一个
|
||
// 常量,第一次忘了改就分叉了,而且没有任何东西会报错——现场只会表现为"界面说固件 0.2.0,
|
||
// 实际烧的是别的"。
|
||
//
|
||
// 所以这里在编译期把 `version.json` 读进来,导出成 `cargo:rustc-env`,源码里用
|
||
// `env!()` 取。`version.json` 由 `scripts/version.mjs` 从 git 历史算出来,于是
|
||
// 一条链是通的:git → version.json → 固件二进制 → Hello 报文 → 客户端界面。
|
||
|
||
use std::fs;
|
||
use std::path::Path;
|
||
|
||
fn main() {
|
||
embuild::espidf::sysenv::output();
|
||
emit_version_env();
|
||
}
|
||
|
||
/// 把 `version.json` 里的版本拆成几个编译期常量。
|
||
fn emit_version_env() {
|
||
let manifest = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR");
|
||
let path = Path::new(&manifest).join("version.json");
|
||
|
||
// 这个文件改了要重新编译,否则版本号会停在旧值上而二进制看起来是新的。
|
||
println!("cargo:rerun-if-changed={}", path.display());
|
||
|
||
// 没有 version.json 也要能编:直接 cargo build 的人可能还没跑过生成脚本。
|
||
// 这时退回 0.0.0+0 并留一条编译器警告——比编不过友好,比编出一个假的版本诚实。
|
||
let (major, minor, patch, build) = match fs::read_to_string(&path) {
|
||
Ok(text) => match parse(&text) {
|
||
Some(parsed) => parsed,
|
||
None => {
|
||
println!("cargo:warning=version.json 解析失败,固件版本回退为 0.0.0+0");
|
||
(0, 0, 0, 0)
|
||
}
|
||
},
|
||
Err(_) => {
|
||
println!(
|
||
"cargo:warning=找不到 version.json,固件版本回退为 0.0.0+0(先跑 node scripts/version.mjs --write)"
|
||
);
|
||
(0, 0, 0, 0)
|
||
}
|
||
};
|
||
|
||
let packed = ((major as u32) << 16) | (((minor as u32) & 0xff) << 8) | ((patch as u32) & 0xff);
|
||
|
||
println!("cargo:rustc-env=RMIC_VERSION={major}.{minor}.{patch}");
|
||
println!("cargo:rustc-env=RMIC_VERSION_PACKED={packed}");
|
||
println!("cargo:rustc-env=RMIC_BUILD={build}");
|
||
}
|
||
|
||
/// 从 `version.json` 里抠出四段数字。
|
||
///
|
||
/// 刻意不引入 `serde_json`:解析四个字段不值得多一个编译期依赖,而固件的构建时间本来
|
||
/// 就是这个项目里最贵的东西。
|
||
fn parse(text: &str) -> Option<(u64, u64, u64, u64)> {
|
||
let field = |name: &str| -> Option<u64> {
|
||
let key = format!("\"{name}\"");
|
||
let at = text.find(&key)?;
|
||
let rest = &text[at + key.len()..];
|
||
let colon = rest.find(':')?;
|
||
let rest = &rest[colon + 1..];
|
||
let start = rest.find(|c: char| c.is_ascii_digit())?;
|
||
let digits: String = rest[start..]
|
||
.chars()
|
||
.take_while(|c| c.is_ascii_digit())
|
||
.collect();
|
||
digits.parse().ok()
|
||
};
|
||
|
||
Some((
|
||
field("major")?,
|
||
field("minor")?,
|
||
field("patch")?,
|
||
field("build")?,
|
||
))
|
||
}
|