Horldsence
|
a93ae065cf
|
desktop: 双方血条(角上平行四边形)、归零即击败、去掉受击抖动、裁判端可改队名
界面改动都在浏览器预览里逐条核对过(DOM 尺寸 + 视觉),截图留在 desktop/screenshots/
(该目录不进仓库)。
1. 客户端显示对手的血量
快照里两端都给两支队伍(顺序固定为队伍号 0/1),界面按 `team` 取那一格,不再靠
数组下标。顺带修掉一个真 bug:用户端"对手那一格"以前会走 `armor_id`——那是我自己
绑定的主板,于是右上角显示的是自己的血,比不显示更糟。现在只有"自己那一块"才用
`armor_id`;同理 `assigned_armor` 里的裁判端槽位指定对用户端不再生效。
2. 血条改到画面两个上角,平行四边形,一条分 5 格
左上角自己、右上角对手(裁判端两格各贴自己的角,读法一致)。整条 skewX(-15deg),
右条再 scaleX(-1) 镜像,两条斜边朝外对称、**都从靠中心的一侧开始灭**。一格 20 点血。
条挂在绝对定位的一层上并 pointer-events:none(那一层盖着画面,而画面要能滚轮缩放、
拖动),倍率与复位徽标因此从上沿挪到下沿。未接入显示"装甲板未接入"而不是 0。
注意:不要在 JS 里再反转一次数组——那会和 CSS 的 scaleX(-1) 互相抵消,表现是右条
从外侧开始灭(代码里写了注释钉住这件事)。
3. 受击画面不抖动
删掉整幅图(含瞄准器)的位移与 shakeOffset。`HitFeedbackConfig::shake` 字段保留但
**不再生效**:配置文件是 deny_unknown_fields 的,删字段会让所有写过 shake = true 的
配置解析失败,而配置解析失败等于程序起不来。默认值改 false,设置面板去掉开关,
并有单测钉住"旧配置读得进来、默认不抖"。
4. 血量归零算击败,不显示"损毁"
血条上不再出现"已击毁/损毁",归零的结论放到图传中央:胜利 / 击败 / 平局。结论在
Rust 侧算(snapshot::resolve_outcomes,4 条单测),规则有意不对称——**输只看自己**
(自己归零就是输,哪怕对手主板掉线),**赢要看两边**(对手归零且自己还有血),
两边同时归零是平局。它一直显示到血量被重置,不做几秒淡出,否则截图与回放里就再也
没有"这局结束了"的痕迹。
5. 裁判端可以改队伍名
两格画面各自下面一个输入框:回车/失焦生效、Esc 取消、超 12 字截断、留空回落到
「队伍一 / 队伍二」。命令是 `set_team_name(team, name)`,**一次只改一边**——传整个
两条的数组就成了"读两条、改一条、写两条",而读来的那两条来自最多 200ms 前的快照,
紧接着改另一边会把上一次的改动覆盖回去。规范化统一在 `config::sanitize_team_name`
(合并空白、按字符截断、留空回落),并同样过密码闸门(裁判端本来就没有密码)。
名字只有一个来源(快照的 `teamNames` / DTO 的 `name`):装甲板表、槽位标签、设置
面板与"等待图传"的占位文字都跟着改,不再有第二处自己拼"队伍一/队伍二"。
测试:core 80(69→80)、src-tauri 30、protocol 15;`pnpm build`(tsc + vite)通过。
|
2026-10-14 20:48:12 +08:00 |
|
Horldsence
|
fd71b83e3a
|
reference: 早先那版 C 写的装甲板固件(ESP-IDF 工程)
`armor/` 是它的 Rust 改写版,这一份留着当参考:ADC 阈值的 2000 就是从它标定出来的
(`.env.example` 里那句 "same as the reference firmware" 指的就是它),而且它的 README
记着实测设备与 MAC,换硬件时是有用的现场记录。
只收了 20 个源文件。它自带的 `.gitignore` 已经排掉 `build/`(211 MB 的 ESP-IDF 构建产物)
与生成的 `sdkconfig`,所以仓库里不会多出这些东西。
两处顺带处理:
- `reference/armor/.git` 是一个**空的**仓库壳(`git init` 过,零提交、零 remote、零 ref),
而外层 git 正因为它的存在而拒绝索引 `reference/` 下的任何文件
(`error: 'reference/armor/' does not have a commit checked out`)。它被挪到
`desktop/.dev/backup/reference-armor-git`(可逆,且该目录已被忽略),不是删除。
- 它的 README 指着 `../armor-platformio-backup/`,那份备份并不存在。改成明说"没有进仓库",
免得以后有人照着找一个不存在的目录。
另外把 `/docs/` 加进 .gitignore:那是工作区里另起的一个 Astro 文档站,与本仓库无关。
|
2026-10-14 19:45:15 +08:00 |
|
Horldsence
|
a30eb3200a
|
armor: ESP32-C3 装甲板固件(一主三从)+ 烧录脚本,之前一直没提交
这一块代码本来就写好了、根 README 里也按"已实现"描述,但一直没有进仓库,
只存在于工作区里。同一个提交里带上 `.env.example` 的两个新变量(ARMOR_TEAM、
ARMOR_THRESHOLD)——它们的说明文字就是为这套固件写的。
内容:
- armor-protocol:规则层(血量、每板独立 50ms 受击冷却、受击后只有那一路灯带全黑、
按键 FSM、上报编码)。纯计算,主机上 22 个测试,已跑通。
- armor-firmware:四路压电片 ADC 连续采样、四路 WS2812(C3 只有一个 RMT 通道可用,
靠 rmt_tx_switch_gpio 轮流驱动)、NVS、BOOT 键、WiFi + UDP 广播。
- scripts:build_armor.sh / flash_armor.sh / armor_probe.py(不开界面单看广播)。
armor/ 是独立 workspace(目标 RISC-V 的 ESP32-C3),与外层 Xtensa 的图传固件互不相干,
各自 .cargo/config.toml 就是这条边界。构建产物由根 .gitignore 的 `/armor/target/` 覆盖,
本次没有把任何 target/ 或 build/ 下的东西加进来。
顺带把 `.DS_Store` 加进 .gitignore。
|
2026-10-14 19:43:14 +08:00 |
|
Horldsence
|
7fdebe3ec7
|
desktop: 修两处小问题(预览模式的命中节奏、设置面板里漏出来的 **)
- 浏览器预览的掉血脚本写成"打空就重置,然后按 to >= from 判断"——两块板子都打空之后
每一次都是重置,命中再也不出现,盯着界面等闪红会等到超时。现在打空那一拍只重置、
其余每一拍都出命中。
- 设置面板里"偏移存的是**画面比例**"直接写进了 JSX,`**` 原样显示出来了。JSX 不渲染
Markdown,改成 <span class="em">。
顺带把界面截图落到 desktop/screenshots/(不进仓库):这个环境里 Page.captureScreenshot
不可用(空白页也超时),改用 Page.printToPDF + sips 转 PNG;打印路径不渲染 box-shadow
的模糊半径(会变成实心块),所以 .dev/shoot.js 在拍之前把它去掉。
|
2026-10-14 19:37:59 +08:00 |
|
Horldsence
|
4f7a142a39
|
desktop: 用户端与裁判端两套页面(Tauri v2 + React),删掉 Slint 客户端
界面部分。后端在前一个提交里,这一提交把它接上,并删掉 client/。
用户端:
- 底部胶囊血条(宽度/数字/阈值/脉动可配),未接入时显示占位说明而不是 0;
- 瞄准器画在 canvas 上并与画面共用同一次变换计算——位置跟着缩放走、大小不跟,
像真瞄具;偏移校准存的是画面比例而不是像素,换分辨率不会失效;
- 命中反馈:整屏闪红 + 抖动 + 准星旁的伤害数字。大号数字刻意不放画面正中:
第一版放了,正好压住瞄准点。掉血事件由相邻两次读数之差派生(主板只报"现在多少血");
- 摄像头/装甲板下拉绑定、队伍号、镜像;改动要密码,退出/关闭也要。
裁判端:
- 两路等宽(flex: 1 1 0 + min-width: 0)各自独立缩放;
- 装甲板发现列表:id、地址、自报队伍、血量、四条齐不齐、静默多久、分到哪个槽位;
- 截图 PNG + ffmpeg 录 mp4,界面内回放(资源协议白名单外的目录给"用系统播放器打开"的退路)。
密码:Argon2id PHC,首启强制设置,会话内解锁一次。执行点在 Rust 侧命令里,界面上的
解锁对话框只是入口。故意不做 --camera-id 这类命令行覆盖:那是一条不用密码就能改绑的路。
其它:
- 配置换成 serde + toml,字段名统一 camelCase(磁盘=IPC=TS),仍然拒绝未知键名,
原子写;旧客户端配置首次启动导入并备份成 .bak(只在默认路径下做);
- 演示模式(CAM_DEMO=1)合成协议数据报喂进真实接收路径,没有板子也能把整条链路跑起来;
- 仅 dev 的浏览器预览(?preview=referee),两重门保证不进正式产物(已验证);
- CSP 收紧成白名单,验证方式是"前端能不能连上后端":clients 从 0 变成 1 同时证明
JS 加载、IPC、WebSocket、React effect 四件事。
删掉 client/:它的功能全部被 desktop/ 覆盖,且其中有几处真 bug 在新实现里改掉了
(槽位分配会让两格显示同一块板子、帧率窗口基线、密码哈希截断被当成密码错、录制文件名
同秒互相覆盖)。注意 client/ 里那几处**未提交**的改动随之丢弃,历史里的版本还在。
测试:protocol 15、cam-core 69、src-tauri 30;前端 tsc + vite build 通过。
|
2026-10-14 19:28:49 +08:00 |
|
Horldsence
|
a89d7ae5fb
|
desktop: Tauri v2 后端 + 共享网络层(用户端/裁判端双身份)
把桌面端从 Slint 迁到 Tauri v2,后端先落地,界面待接。拆成三层:
- desktop/core(cam-core,67 测试):从旧 client/ 抽出的非界面部分。UDP 接收按
发送方重组、装甲板发现与血量、帧率窗口、槽位分配、配置与密码。
- desktop/src-tauri(27 测试):Tauri 后端。回环 WebSocket 推二进制 JPEG、
每 200ms 一份状态快照、密码闸门、截图、ffmpeg 录制 mp4、演示数据源。
- protocol:新增 ArmorHealth::decode_from,把帧头里的 sender_id 交出来——
装甲板一直带着 MAC 派生 id 在广播,旧解码路径把它丢了,所以"装甲板下拉可选"
不需要改固件。
几个改对了的旧问题:
- 槽位分配:旧实现只排除"槽位自己原来那个 id",于是队伍一的板子一离线,它的槽位
会去拿队伍二那块,两格显示同一块板子。现在候选要排除另一个槽位占着的 id。
- 帧率窗口的基线:掉线又回来的板子带着一个很大的累计帧数回来,从 0 起算会报出
几百 fps。改成 seeded + 用"已结算窗口数"判断有没有读数。
- 密码哈希:password-hash 能解析 `$argon2id$broken` 这种截断串,于是"配置坏了"
会被读成"密码错了"。现在要求盐与摘要都在。
- 录制文件名:同一秒停一次再开一次会用同一个名字,ffmpeg 的 -y 静默覆盖上一段。
现在先收尾上一段再开新的,并且重名往后排号。
- 两道闸门:帧的限制与发现列表的限制分开。设置界面需要列候选摄像头,但**画面**
不需要——旧版把两件事绑在一道闸门上,只能在"能列候选"和"挡住对手"之间二选一。
测试:protocol 15、cam-core 67、desktop 27,其中录制那条真的起 ffmpeg 并用
ffprobe 读回帧数与分辨率(只断言"文件存在"会漏掉空容器)。
|
2026-10-14 19:14:16 +08:00 |
|