Commit Graph

7 Commits

Author SHA1 Message Date
Ludovic Marie 2822d4e1b7 Content mods: refuse more block states than chunks hold; the pack against NeoForge, measured
Loading the eight carried-over mods in the game (not only the probe) showed
two limits real packs reach. Block textures past 2048 layers are another PR;
this one handles block states and measures a pack.

- Chunk sections store a block state in 16 bits. Vanilla 26.3 has 35,723
  states; Macaw's four mods add 36,154, the eight 41,389. Past 65,536 ids
  wrapped onto other blocks (a trapdoor became a hanging sign).
  mod_content::build now refuses a set of mods past MAX_STATES and names the
  states per mod; the game then starts without content mods, as for any
  refused content.
- tools/mod_port_harness.py probes each mod on its own against vanilla, as a
  player adding it would load it.
- tools/perf_bench.py --game neoforge: Minecraft 1.21.1 on NeoForge 21.1.259
  with --mod-jars and --deps, driven by a dev-only NeoForge port of the bench
  mod (mods/horizon/src/neoforge-bench); --port-work loads a work folder's
  carried-over mods into Horizon. tools/neoforge_oracle.py installs the
  client once under .local/neoforge-oracle (the installer, then the vanilla
  libraries it inherits, sha1-checked) and builds the driver. A NeoForge
  start that crashes before the driver loads (FML reading fml.toml while
  creating it) is retried once.

Measured (docs/modpacks.md): six ported mods in Horizon against the same
mods on NeoForge, Mac mini M4 Pro, 2 games per row on a loaded machine. The
world is ready 3.1x sooner at 8 and 16 chunks, the flights run 1.7x and
3.6x the frames, and Horizon's RSS is not lower (+1.1 GB with the mods).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 04:55:20 +02:00
Ludovic Marie 0560bbf876 horizon-port-pack report: coverage per mod, and ATM10 measured
`report <work>` writes coverage.json and coverage.md: per mod ported,
partial, not yet or not needed with the reason, and the totals by class,
tier and licence family. It reads the inventory, each mod's carry report
and its harness result: ported is a green harness with nothing left out
(blocks with a class of their own are counted and named); partial lists
the failing checks, the blocks left out and what the templates miss; not
yet names the API tier or the dependency it waits for; not needed covers
libraries, performance mods and pack tooling. Unclassified mods are not
yet, never not needed.

`import` also reads Crash Assistant's modlist.json, the list ATM10
publishes in its repository (mod ids, names, versions, Modrinth hashes,
the loader entry), and the inventory uses its mod ids and names when
there is no jar.

ATM10 (496 files, the eight mods we downloaded carried and checked):
ported 1, partial 7, not yet 367, not needed 121.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:28:43 +02:00
Ludovic Marie 32f5f01e22 Per-mod parity harness against a dev-only NeoForge oracle
The harness the modpack design calls for, for data-tier mods:

- tools/neoforge_oracle.py installs a NeoForge 21.1.259 server (ATM10's)
  under .local/neoforge-oracle, builds the exporter in
  mods/horizon/src/neoforge-oracle (our code, never shipped), runs it
  headless with the user's jars and writes every block (class chain,
  states, per-state hardness, light, tool need, map colour, sounds,
  outline and collision; drops for hand, diamond tools, shears and silk
  touch; placement; BlockSetType and WoodType), item, recipe and tag of
  the mods' namespaces, plus the vanilla blocks for templates. About 30 s.
- examples/mod_port_probe.rs builds the content root from the carried
  mods and dumps what Horizon's loaders make of the same things.
- tools/mod_port_harness.py compares them per mod and writes
  <work>/mods/<id>/harness/result.json. 1.21.1 sound events map to 26.3's
  through vanilla blocks both have, and vanilla items newer than 1.21.1
  are not counted against a recipe.

On ATM10's own jars (MIT): Macaw's Trapdoors passes everything; Doors,
Fences, Paths, Glassential, Factory Blocks and Cloud Glass pass every
drop, recipe, tag and placement and fail only on what API 0.2 cannot say
(shapes and sound events of their own, blocks of classes no vanilla block
shares). Jars, facts and results stay in the work folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:27:20 +02:00
Ludovic Marie 886def4360 horizon-port-pack carry: templates and numbers from the NeoForge oracle, 1.21.1 loot upgraded
Carrying over seven real ATM10 mods (Cloud Glass, Factory Blocks,
Glassential, Macaw's Doors, Fences, Paths and Trapdoors) showed what the
guesses missed:

- Loot tables: 1.21.1's `conditions` lists, `functions` and
  `condition`/`function` kinds are now 26.3's single `condition`,
  `modifier` and `type`; silk-touch and shears tool matches become
  `minecraft:tool/can_silk_touch` and `can_shear`. Before, every drop
  condition was ignored (glass dropped itself by hand, upper door halves
  dropped doors, double slabs dropped one).
- With the oracle's facts (<work>/oracle/facts.json, from
  tools/neoforge_oracle.py in the next PR), every registered block gets
  the vanilla template of the same vanilla class and states that matches
  its shapes, sounds, BlockSetType and WoodType best, and the mod's own
  hardness, blast resistance, light, tool need, friction, map colour and
  sounds. Items get stack size and rarity. The carry report lists what a
  template does not reproduce and why a block was left out.
- Convention tags a recipe uses (c:dyes/red) are written from the
  oracle's tags, vanilla and own members only; the jar's own c tags stay
  inside the mod.
- Without the oracle, blockstates that omit properties their models
  ignore (powered, waterlogged) still find their template, and names pick
  between fences and panes, doors and trapdoors.
- `version = "${file.jarVersion}"` is read from MANIFEST.MF.
- `--resources <prepared>` limits templates to blocks Horizon has.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:25:54 +02:00
Ludovic Marie 673ac84724 horizon-port-pack carry: a jar's data and assets as a content mod
carry <work> [<mod id>...] turns each content mod with a jar into a folder
content mod (API 0.2) in <work>/mods/<id>/carry/, for local use:

- assets/<id>/, data/<id>/ and data/minecraft/tags/ are copied; other
  namespaces and vanilla data go to outside/ for review; no class file is
  copied.
- Vanilla-type recipes get 26.3 ingredients ("id", "#tag", lists);
  custom types and NeoForge conditions are kept and listed.
- Item models get the items/ client definitions 1.21.4 introduced.
- Each block is declared from a vanilla template guessed from its
  blockstate properties; unknown property sets are listed. Items
  without a block are declared from minecraft:stick.

The test builds a small NeoForge jar, carries it over, and reads the
result with horizon-mods' own Content reader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:25:28 +02:00
Ludovic Marie 85858610bf horizon-port-pack: import a modpack and classify its mods
A CLI for the first steps of docs/modpacks.md's pipeline:

- import: a Modrinth .mrpack, a CurseForge zip or a Prism / MultiMC
  instance (or a folder of jars) to pack.json: Minecraft and loader
  versions, each file with its hash and sides, and the overrides.
- inventory: Modrinth metadata by SHA-1 (cached in modrinth.json, so
  reruns work offline), and the jars when the user's instance has them
  (neoforge.mods.toml / mods.toml / fabric.mod.json and a file census,
  without decompiling). Each mod gets a class and API tier from the
  reviewed ATM10 table, then rules on categories, sides and the census,
  and a dependency layer. Writes inventory.json and inventory.csv.

Only metadata is downloaded; jars are never fetched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:25:04 +02:00
Ludovic Marie a06367edf1 docs: modpacks design, with ATM10's real mod list classified
docs/modpacks.md: how any pack (ATM10 down to small Fabric packs) gets to
Horizon: import (.mrpack, CurseForge zip or instance, Prism, packwiz),
inventory and classification, dependency order, mechanical carry-over of
data and assets, one agent per mod for code with a per-mod harness against
a dev-only NeoForge/Fabric oracle, and a coverage report. Also the mod API
gaps against 0.1, the registries 0.2 design (template blocks through the
overlay root), licence handling, how "10x" is measured against NeoForge,
and the scope for 2026-10-23.

docs/modpacks/atm10-mods.csv: ATM10's 495 jars from the pack's own
crash_assistant modlist (2026-10-15), with Modrinth metadata looked up by
hash: class, API tier, licence, sides. Metadata only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:08:23 +02:00