dend/filmshell

GitHub: dend/filmshell

一个用于解析Halo Infinite回放文件、提取玩家轨迹与战斗数据并生成SVG可视化的命令行工具。

Stars: 3 | Forks: 1

filmshell logo

FilmShell

🎥 助你分析 Halo Infinite 影片文件的 CLI

FilmShell 连接到 Halo Infinite API,下载剧院影片数据,并将其转换为你可视化的内容。它从原始二进制块中提取每个玩家的移动数据,获取地图元数据 (MVAR) 以确定物体位置,并渲染叠加在地图几何结构上的玩家路径 SVG 可视化图。关于促成此项目的早期探索背景,请参阅 [从 Halo Infinite 影片文件中提取统计数据](https://den.dev/blog/extracting-stats-film-files-halo-infinite/)。

FilmShell CLI demo

## 目录 - [前置条件](#prerequisites) - [创建 Entra 应用程序](#creating-the-entra-application) - [设置](#setup) - [用法](#usage) - [输出](#output) - [物体 ID](#object-ids) - [参考影片](#reference-films) - [工作原理](#how-it-works) - [二进制查看器](#binary-viewer) - [许可证](#license) - [致谢](#acknowledgements) ## 前置条件 - [Node.js](https://nodejs.org/) 18 或更高版本 - 一个注册用于 Xbox Live 身份验证的 Microsoft Entra 应用程序([见下文](#creating-the-entra-application)) ## 创建 Entra 应用程序 FilmShell 通过 Xbox Live 使用个人 Microsoft 账户进行身份验证。你需要 Azure 门户中注册一个应用程序以获取客户端 ID。 1. 前往 [Azure 门户](https://portal.azure.com/) 并导航至 **Microsoft Entra ID** > **App registrations** > **New registration**。 2. 为应用程序命名(例如 "FilmShell")。 3. 在 **Supported account types** 下,选择 **Personal Microsoft accounts only**。 4. 在 **Redirect URI** 下,选择 **Mobile and desktop applications** 平台并输入 `http://localhost/callback`。 5. 点击 **Register**。从概览页面复制 **Application (client) ID** - 这就是你的客户端 ID。 无需配置额外的 API 权限。Xbox Live 作用域(`Xboxlive.signin` 和 `Xboxlive.offline_access`)会在运行时自动请求。 ## 设置 1. 克隆仓库并安装依赖项: git clone https://github.com/dend/filmshell.git cd filmshell npm install 2. 复制示例配置并添加你的客户端 ID: cp config.example.json config.json 编辑 `config.json` 并将 `YOUR_ENTRA_CLIENT_ID_HERE` 替换为[上一步](#creating-the-entra-application)中的 Application (client) ID。 3. 构建项目: npm run build ## 用法 ### 下载并处理你最近的比赛 ``` npm start ``` 这将: 1. 打开基于浏览器的 Microsoft 登录流程 2. 从 Halo Infinite API 获取你最近的比赛 3. 下载并解压影片块 4. 获取地图的 MVAR 资产并提取物体位置(生成点、武器、装备) 5. 从影片二进制数据中提取玩家移动数据 6. 在影片输出目录中生成 SVG 可视化 ### 处理多场近期比赛 ``` npm start -- --count 5 ``` ### 重新处理已下载的影片 如果你之前下载过影片,可以不经身份验证直接重新处理: ``` npm start -- --match-id ``` 比赛 GUID 对应于 `films/` 下的一个目录。 ### 开发模式 一步构建并运行: ``` npm run dev ``` ## 输出 每场处理过的比赛都会在 `films//` 下创建一个目录,包含: | 文件 | 描述 | |---|---| | `match-metadata.json` | 来自 Halo API 的比赛统计数据 | | `film-metadata.json` | 影片资产元数据(块、时长) | | `filmChunkN_dec` | 解压后的影片块二进制文件 | | `mvar.json` | 解析后的地图变体 Bond 文档(如果获取了 MVAR) | | `objects.json` | 提取的地图物体及其世界坐标 | | `path.svg` | 玩家移动路径可视化 | ## 物体 ID FilmShell 使用 `src/objects.json` 将 MVAR 数据中的数字物体 ID 映射为人类可读的名称(例如生成点、武器、旗帜)。Halo Infinite 二进制格式不直接包含物体名称——只有整数引用。 发现新物体 ID 最可靠的方法是在 Forge 中创建具有已知物体位置的自定义地图,然后对这些地图进行 MVAR 转储,以将 ID 与你放置的物体相关联。这让你可以在遇到新物体类型时逐步建立映射。 ## 参考影片 仓库在 `films/` 中包含了八个预下载的影片,可用于在无需 API 访问的情况下验证实现。所有比赛均在 [Aquarius](https://www.halowaypoint.com/halo-infinite/ugc/maps/33c0766c-ef15-48f8-b298-34aba5bff3b4) 上进行。前六场是人类玩家在地图上完整绕圈;第七场是单人战斗测试;第八场是 PvE 机器人战斗。使用以下命令重新处理其中任何一个: ``` npm start -- --match-id ``` | 比赛 ID | 玩家 | 类型 | 备注 | |---|---|---|---| | `53a98da9-718d-4374-b739-b0ee2e7033ba` | 2 名人类 | PvP | 完整绕圈 | | `a422938f-dd2e-4c9d-88a5-fab76e6c9efa` | 2 名人类 | PvP | 完整绕圈 | | `4bfdd8b9-0a51-4646-a25c-4e28c2b2f8a1` | 1 名人类 + 1 个机器人 | PvE | 完整绕圈 | | `b632adeb-1756-4c7b-b230-f2fd95d9b85b` | 1 名人类 + 1 个机器人 | PvE | 完整绕圈 | | `152dd30f-a99b-4e51-addb-7679c566a725` | 1 名人类 | Solo | 完整绕圈 | | `2cf8d130-4363-48b1-b7b8-62b5a6e01454` | 1 名人类 | Solo | 完整绕圈 | | `b49f075b-f82b-4ad6-940b-fc31f53756bb` | 1 名人类 | Solo | 半圆,在南侧生成点发射 MA40 AR,在北侧生成点发射 MK50 Sidekick | | `3f5b80c8-c5f2-4f3f-a3b9-ff286100866e` | 1 名人类 + 1 个机器人 | PvE | 机器人战斗,人类与机器人交战 | 每个影片目录都包含解压后的影片块、比赛/影片元数据、缓存的地图物体、解析后的 MVAR 文档以及生成的 SVG 路径可视化。 ## 工作原理 1. **身份验证** - 通过 Microsoft Entra 的 OAuth 流程,使用 [conch](https://www.npmjs.com/package/@dendotdev/conch) 获取 Xbox Live token,然后使用 [grunt](https://www.npmjs.com/package/@dendotdev/grunt) 将其交换为 Halo Infinite API 的 Spartan token。 2. **影片下载** - 使用 grunt 的 `HaloInfiniteClient` 获取比赛历史记录,检索影片资产,并下载/解压 zlib 压缩的影片块。 3. **地图元数据** - 获取地图变体 (MVAR) 资产,解析 Bond Compact Binary v2 格式,并提取具有世界坐标的物体位置(生成点、武器、目标)。 4. **运动提取** - 扫描影片块二进制文件以查找帧标记(`A0 7B 42`),自动检测每个玩家的位置编码变体,并将坐标增量累积成移动路径。支持不同地图的多种编码格式。 5. **SVG 生成** - 使用地图边界将运动数据缩放到世界坐标,将路径锚定到检测到的生成位置,并渲染带有地图物体叠加层的每个玩家的移动轨迹。 ## 武器开火事件 武器开火事件编码在影片块位流中,位于距离字节边界 **4 位偏移** 处。每个开火事件包含武器 ID、武器槽位、滚动开火计数器以及使用 [八面体编码](https://stackoverflow.com/a/74745666) 的瞄准向量。 ### 开火事件结构 所有字段都在 4 位移位处进行位打包: | 偏移量 | 大小 | 字段 | 备注 | |---|---|---|---| | 0 | 1 byte | 引导字节 | 开火事件为 `0x0d` | | 1 | 1 byte | 玩家/常量 | `0x26` — 与玩家索引进行位打包 | | 2 | 1 byte | 常量 | `0x00` | | 3 | 1 byte | 常量 | `0x40`(低 2 位可能变化) | | 4 | 1 byte | 开火计数器 | 每次射击增加 4,在 256 处回绕 | | 5 | 1 byte | 武器槽位 | `0x01` = 主武器,`0x03` = 副武器 | | 6 | 8 bytes | 武器 ID | 见下表 | | 14 | 1 byte | 瞄准八分区 | 0–7,选择八面体投影中的面 | | 15 | 2 bytes | 瞄准向量 | uint16 编码八分面内的位置 | | 17 | 2+ bytes | 瞄准数据 | 额外的瞄准向量分量 | 由于 4 位移位,武器 ID 不会以字面字节序列出现在文件中。要搜索,请计算移位后的 7 字节模式: ``` pattern[k] = ((weaponId[k] << 4) | (weaponId[k+1] >> 4)) & 0xFF, for k = 0..6 ``` ### 已知武器 ID 由 [Andy Curtis](https://github.com/acurtis166) 发现。武器变体(例如 S7 Flexfire)与基础武器共享相同的 ID。大多数 ID 共享 `42 c9 67 9f` 后缀。 | 武器 | ID | |---|---| | Bandit Evo | `6a cd c4 4d 42 c9 67 9f` | | BR75 | `2b 18 24 d5 42 c9 67 9f` | | Cindershot | `23 04 47 b1 42 c9 67 9f` | | CQS48 Bulldog | `b6 19 d8 4a 42 c9 67 9f` | | Disruptor | `84 bd 29 ed 42 c9 67 9f` | | Heatwave | `2a c9 c2 ff 42 c9 67 9f` | | M392 Bandit | `2f b2 1c 87 42 c9 67 9f` | | M41 SPNKr | `71 ab 0a 2c 42 c9 67 9f` | | MA40 AR | `48 c1 9d 2d 42 c9 67 9f` | | MA5K Avenger | `f5 c3 35 df e7 23 2c 0b` | | Mangler | `80 97 7b a5 42 c9 67 9f` | | Mk51 Sidekick | `f4 08 19 0f 42 c9 67 9f` | | MLRS-2 Hydra | `76 7d b9 6d 42 c9 67 9f` | | Needler | `b5 33 95 7e 42 c9 67 9f` | | Plasma Pistol | `c3 54 29 46 42 c9 67 9f` | | Pulse Carbine | `30 48 4e a6 42 c9 67 9f` | | Ravager | `c3 0d 87 c7 42 c9 67 9f` | | S7 Sniper | `0a 19 92 bc 42 c9 67 9f` | | Shock Rifle | `93 87 a8 b9 42 c9 67 9f` | | Skewer | `0d 20 c4 69 42 c9 67 9f` | | Stalker Rifle | `da f1 93 c7 42 c9 67 9f` | | VK78 Commando | `fd 98 55 4c 42 c9 67 9f` | | Vestige Carbine | `3e 07 02 17 42 c9 67 9f` | ## 二进制查看器 仓库包含一个基于浏览器的二进制查看器,用于检查原始影片数据。它旨在作为逆向工程工具,帮助映射帧字段并发现新模式。 ``` npm run viewer # launch dev server npm run viewer:build # production build to dist/viewer/ ``` 查看器提供: - 按 字段类型(标记、滴答、帧类型、格式字节、位置数据、状态数据、扩展数据)进行颜色编码字节的 **十六进制转储** - 可按玩家、基础类型子类型和 d0 高半字节过滤的 **帧表** - **双向链接** — 在任一视图中点击帧即可在两者中高亮显示 - 显示相对块大小并支持点击导航的 **块映射** - 十六进制视图中的帧边界标记 ## 许可证 [MIT](LICENSE) ## 致谢 - Logo: Video camera icons created by siens - Flaticon - 物体 ID 映射来自 [artificeslab/mvar_decoder](https://github.com/artificeslab/mvar_decoder/blob/main/object_IDs.json) - MVAR 格式见解来自 [soupstream/InfiniteVariantTool](https://github.com/soupstream/InfiniteVariantTool) - 通用标签详情来自 [Gamergotten/Infinite-runtime-tagviewer](https://github.com/Gamergotten/Infinite-runtime-tagviewer) - Halo Infinite 资产解析参考来自 [Surasia/libpyinfinite](https://github.com/Surasia/libpyinfinite) - [Andy Curtis](https://github.com/acurtis166) 提供了[影片文件探索](https://github.com/dend/blog-comments/issues/5)、武器开火事件解码、武器 ID 发现以及八面体瞄准向量分析
标签:CLI 工具, DNS解析, GNU通用公共许可证, Halo Infinite, IP 地址批量处理, MITM代理, MVAR 元数据, Node.js, OAuth 认证, SVG 路径渲染, Xbox Live API, 二进制解析, 云资产清单, 光环无限, 命令行界面, 地图分析, 开源项目, 微软 Entra ID, 游戏录像分析, 游戏数据挖掘, 玩家轨迹追踪, 电竞数据, 自动化攻击, 逆向工程