[PR #134] [MERGED] kb: reading old ForzaTech burG .modelbin containers and the MakeH2O lineage #150

Closed
opened 2026-10-15 20:53:50 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/rehan-remade/universal-modder/pull/134
Author: @Selene0623
Created: 10/7/2026
Status: ✅ Merged
Merged: 10/8/2026
Merged by: @rehan-remade

Base: main ← Head: kb/forzatech-burg-modelbin-makeh2o


📝 Commits (4)

  • 143a1ab kb: read old ForzaTech burG .modelbin containers and the MakeH2O lineage
  • 5b08787 Merge origin/main into kb/forzatech-burg-modelbin-makeh2o; regenerate the knowledge index
  • 6b4d69d Merge main into kb/forzatech-burg-modelbin-makeh2o and regenerate the kb index
  • 33e205e kb: burG header and Skel fixes, Grub = burG, MinGW not Java, scope FH6-spec claims

📊 Changes

3 files changed (+286 additions, -1 deletions)

View changed files

📝 knowledge/INDEX.md (+2 -1)
📝 knowledge/index.json (+29 -0)
➕ knowledge/techniques/forzatech-burg-modelbin-containers-and-makeh2o.md (+255 -0)

📄 Description

One new technique note, plus the regenerated index.

The note

knowledge/techniques/forzatech-burg-modelbin-containers-and-makeh2o.md

Two things in one file, because they are the same story:

  1. The older ForzaTech .modelbin container. Magic burG (Grub reversed), the v1.0/v1.1
    header difference, the chunk table whose four-byte ids are ASCII-reversed (kelS = Skel,
    hseM = Mesh, BreV = VerB, …), the 16-byte <IIHHI header at the start of a VerB
    payload, the stride-8 position stream (three SNORM16) and the stride-40 stream (normals, four
    UV pairs, a tangent frame, an AO mask), and the bbox-relative position decode
    bbox_min + (raw + 32768) / 65535 · (max - min) with the box taken from the Name record.
  2. MakeH2O, the 2017 Forza converter. It is a GCJ-compiled Java GUI, one build per engine
    family; the Forza line's build suffixes and their changelog are known, and the copy in the
    workspace is an earlier build than any of the archived ones. It has no CLI, gates on the first
    byte being 'b', and finds geometry by hardcoded byte-pattern searches rather than reading the
    chunk table.

Verification

  • Read from real data: the container header bytes and chunk tags across a 53-file FH3 sample
    tree, with two tyre files in detail.
  • Read by disassembly: the tool's control flow, its format gate, its patterns, its numeric
    constants (1/256 for vertices, 1/65536 for UVs, 32768 for the position offset), and its OBJ
    emission.
  • Checked by re-implementation: I ported its scan loop and ran it over the FH3 tyre files. It
    finds zero matches for both of its hardcoded block patterns, so its own consistency check
    would fire. That is the mechanical explanation for the long "no scale found" part list its author
    documented.
  • Cross-checked against a public spec: the FH6-era spec (noidex0/fh6-model-tools, validated
    against 638 cars) describes the same lineage, which is where the bbox decode above comes from.

What is not verified

  • The tool never completed a conversion here. It is GUI-only, ignores its command line, and my
    attempts at driving it under Wine failed. The note says so rather than implying a successful run.
  • I could not reconcile the chunk-table stride between the v1.0 and v1.1 variants by hand. The
    note tells the reader to take it from a reference implementation instead of guessing it from
    hexdumps.
  • The build suffixes beyond the ones I archived (-jm9 is the newest) were not executed.

Also in here

Gotcha 8 is a tool-usage one: a reversing tool rejected provider_unavailable on a Ghidra install
that demonstrably works, because it compares the Ghidra version as an exact string and the Java
major as exactly 21. Filed upstream separately as morluto/rea#821; included as a gotcha with the
workaround rather than as a complaint.

No download links, no keys, no decompiled dumps — the tool's behaviour is written up in prose and
its patterns are described, not pasted as code.

um kb check --index passes (71 notes).


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/rehan-remade/universal-modder/pull/134 **Author:** [@Selene0623](https://github.com/Selene0623) **Created:** 10/7/2026 **Status:** ✅ Merged **Merged:** 10/8/2026 **Merged by:** [@rehan-remade](https://github.com/rehan-remade) **Base:** `main` ← **Head:** `kb/forzatech-burg-modelbin-makeh2o` --- ### 📝 Commits (4) - [`143a1ab`](https://github.com/rehan-remade/universal-modder/commit/143a1ab1247036563688a58a08b8546741ce68fb) kb: read old ForzaTech burG .modelbin containers and the MakeH2O lineage - [`5b08787`](https://github.com/rehan-remade/universal-modder/commit/5b08787432bbc52149c2ba73ea7e58f406dbe3cd) Merge origin/main into kb/forzatech-burg-modelbin-makeh2o; regenerate the knowledge index - [`6b4d69d`](https://github.com/rehan-remade/universal-modder/commit/6b4d69d1618125ea84f2692ad1f6483dd5b26678) Merge main into kb/forzatech-burg-modelbin-makeh2o and regenerate the kb index - [`33e205e`](https://github.com/rehan-remade/universal-modder/commit/33e205eb7ebe4c7ce384c6fc352acc2e89305973) kb: burG header and Skel fixes, Grub = burG, MinGW not Java, scope FH6-spec claims ### 📊 Changes **3 files changed** (+286 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `knowledge/INDEX.md` (+2 -1) 📝 `knowledge/index.json` (+29 -0) ➕ `knowledge/techniques/forzatech-burg-modelbin-containers-and-makeh2o.md` (+255 -0) </details> ### 📄 Description One new technique note, plus the regenerated index. ## The note `knowledge/techniques/forzatech-burg-modelbin-containers-and-makeh2o.md` Two things in one file, because they are the same story: 1. **The older ForzaTech `.modelbin` container.** Magic `burG` (`Grub` reversed), the v1.0/v1.1 header difference, the chunk table whose four-byte ids are ASCII-reversed (`kelS` = `Skel`, `hseM` = `Mesh`, `BreV` = `VerB`, …), the 16-byte `<IIHHI` header at the start of a `VerB` payload, the stride-8 position stream (three `SNORM16`) and the stride-40 stream (normals, four UV pairs, a tangent frame, an AO mask), and the bbox-relative position decode `bbox_min + (raw + 32768) / 65535 · (max - min)` with the box taken from the `Name` record. 2. **MakeH2O**, the 2017 Forza converter. It is a GCJ-compiled Java GUI, one build per engine family; the Forza line's build suffixes and their changelog are known, and the copy in the workspace is an earlier build than any of the archived ones. It has no CLI, gates on the first byte being `'b'`, and finds geometry by hardcoded byte-pattern searches rather than reading the chunk table. ## Verification - **Read from real data:** the container header bytes and chunk tags across a 53-file FH3 sample tree, with two tyre files in detail. - **Read by disassembly:** the tool's control flow, its format gate, its patterns, its numeric constants (1/256 for vertices, 1/65536 for UVs, 32768 for the position offset), and its OBJ emission. - **Checked by re-implementation:** I ported its scan loop and ran it over the FH3 tyre files. It finds **zero** matches for both of its hardcoded block patterns, so its own consistency check would fire. That is the mechanical explanation for the long "no scale found" part list its author documented. - **Cross-checked against a public spec:** the FH6-era spec (`noidex0/fh6-model-tools`, validated against 638 cars) describes the same lineage, which is where the bbox decode above comes from. ## What is *not* verified - The tool never completed a conversion here. It is GUI-only, ignores its command line, and my attempts at driving it under Wine failed. The note says so rather than implying a successful run. - I could not reconcile the chunk-table **stride** between the v1.0 and v1.1 variants by hand. The note tells the reader to take it from a reference implementation instead of guessing it from hexdumps. - The build suffixes beyond the ones I archived (`-jm9` is the newest) were not executed. ## Also in here Gotcha 8 is a tool-usage one: a reversing tool rejected `provider_unavailable` on a Ghidra install that demonstrably works, because it compares the Ghidra version as an exact string and the Java major as exactly 21. Filed upstream separately as morluto/rea#821; included as a gotcha with the workaround rather than as a complaint. No download links, no keys, no decompiled dumps — the tool's behaviour is written up in prose and its patterns are described, not pasted as code. `um kb check --index` passes (71 notes). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-15 20:53:50 +00:00
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rehan-remade/universal-modder#150
No description provided.