Clean-room implementation from spec-lithostitched.md §3-§5 and spec-ctov.md §4.
The game reads Lithostitched's processors as its data writes them
(processor/litho.rs): block_swap (only the properties the new block can
have: ripe wheat becomes ripe carrots, beetroot keeps its default age),
reference, apply_random, condition (with else, one processor or a list),
set_block (simple and weighted providers, preserve_state, block entity
modifier) and discard_input; the conditions all_of, any_of, not,
random_chance, true and matching_blocks (input or location, properties).
Their random follows random_mode per block or per piece; Lithostitched's own
seeding is open (OPEN-L6), so a positional random of the world seed and the
processor stands in (impl-questions IQ-7).
horizon-port-pack's new lithostitched module carries the processors as they
are, with the processors nested in them carried, drops those the game cannot
read (lists named by tag, other providers) as Java processors, turns CTOV's
modular_compat into a reference when its mod is ported along (else nothing),
maps lithostitched:jigsaw to vanilla's jigsaw (vanilla layouts, the decision
on OPEN-L5), unwraps limited/guaranteed/delegating elements to their
delegate (limits counted as lost until the next PR) and writes
add_template_pool_elements modifiers as horizon:add_to pools when their
NeoForge load conditions pass.
Deleted unread: legacy_structure_mods/lithostitched.rs and horizon-world's
structure/processor/lithostitched.rs. Blind edits to the legacy folder,
located by exact text or the compiler's error position: its module line
removed, dead_code allowed on ctov (its modular compat is unused now) and on a
test helper, and ctov's modular compat test ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A developer of Iris showed that Horizon's shader pack code was written from
Iris's source. This removes it: the horizon-shaderpack crate, Java pack
loading and its render stages, Horizon's own WGSL packs and the example
packs, the Shader Packs screen and its option, the launcher's shader pack
browsing and installing, and the docs about them. Shader packs may come
back later as a clean-room rewrite.
The vanilla renderer and its post-processing (resolution scale, FXAA) are
unchanged. Options files that name a pack load and drop the key; the
launcher reads manifests that list a shader pack, and files in
`shaderpacks/` are never deleted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removes docs/performance/java-perf-mods.md (a survey of eight Java
performance mods' techniques) and docs/research/java-mod-compat.md (notes
on how Fabric, NeoForge and Mixin work, with a list of mods to port).
Links to them now point at mods.md, which says in two lines why Java jars
don't run in Horizon.
docs/modpacks.md no longer lists a mod's decompiled code as an input of a
port: a mod's code is never decompiled, read, quoted or paraphrased, and
ports are written from the mod's observed behaviour (the oracle and the
harness), its own data files and its public documentation only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pack lists them with the mods left off, the port's log and fetch label say
the same, and docs/modpacks.md no longer asks for a key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Importing a modpack from the Mods page (or `mods install`) now ports it right away
for the selected version, so Play works straight after. port-pack leaves a
namespace two carried mods both claim to none of them (YUNG's mods all ship
`yungsapi`, which made the game drop three of them), and the launcher applies
the game's first-wins rule before it starts a pack, listing what it left off.
Measured on Vanilla Perfected, Slimes Adventure and All the Mods 10 (docs/modpacks.md):
2, 20 and 42 mods ported, every world loads, no crash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`horizon-port-pack check <jar> <out>` carries a single jar into a folder content
mod and reads its class files (constant pool, superclass, declared methods) for
what the carry can't take: block entities, menus, entities, blocks and items with
behaviour of their own, recipe types, worldgen code, Mixins, game events. The
verdict and the lists of what ports and what is skipped go to check.json, for the
launcher's mod browser to show before install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).
Pack-wide numbers after the modpacks-12 PRs (#1175, #1176, #1177, #1191):
structures that start, processors carried and dropped per mod, content,
load time and the play-through, and the gaps ranked by how much a player
notices them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Formations' PiecedStructure starts like its SimpleStructure, then lays out
the element's jigsaw children with vanilla's jigsaw. The game's jigsaw
assembler now exposes its child layout (add_children) for a start piece
placed by another structure type; horizon:formations reads horizon:pieced
(max_depth, max_distance_from_center), which carry writes for
formations:pieced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ctov:modular_compat runs another processor list only when the mod it names
is loaded: carry writes that list in when the mod is ported along and takes
the hook out otherwise (142 copies in ATM10, all for Nature's Spirit).
Repurposed Structures' mineshaft_sky_view_processor (71 lists) becomes the
game's horizon:mineshaft_sky_view: nothing at or above the world's
OCEAN_FLOOR_WG height, except plain rails over a block that can occlude,
waterlogged where the world holds water. Placement contexts gain
can_occlude.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Carry maps mostructures:generic to vanilla's jigsaw with horizon:start_checks
(terrain_radius 2, terrain_range = heightRange) and mostructures:type to a
random spread with the config's default spacing and separation and its sets
to avoid as horizon:exclusion_zone. The game's exclusion zone gains
"their_zones": false, which tests the avoided sets by spread and frequency
alone, as ModStructurePlacement does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: merged. Verify passed. Integration proof (main + #1041#1043#1021#1020#1032#659#1029#1066), 2026-10-21: 97 of 100 harnesses passed on the desktop. world_reopen and save_roundtrip need a display there; they pass on the Mac mini with #1041/#1043. dedicated_server is a pre-existing flake: it fails on plain main too, and is pass/fail in 2 runs on the integration.
🤖 Agent: merged. Verify passed. Integration proof (main + #1041#1043#1021#1020#1032#659#1029#1066), 2026-10-21: 97 of 100 harnesses passed on the desktop. world_reopen and save_roundtrip need a display there; they pass on the Mac mini with #1041/#1043. dedicated_server is a pre-existing flake: it fails on plain main too, and is pass/fail in 2 runs on the integration.
🤖 Agent: merged after verify and CI parity passed (modpacks-11: Chipped's 11 vines carried as vines; the 11 blockstate errors are gone from the game log).
repurposed_structures:structure_void_processor returns null for a
template's structure_void blocks, which is what vanilla's block_ignore
does with blocks: [structure_void]. Carry writes it that way, so the
82 lists that use it (its mineshafts, ocean village and temples, the
jungle pyramid's hidden room, swamp village) no longer place structure
voids over the terrain.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mod's file for a vanilla, convention or other mod's tag adds its values in
load order; one with "replace": true now drops vanilla's entries and the
earlier mods' first, as a higher data pack does, and the log says which mod
replaced what (kept with the cached root, so a reused root warns too).
Carry keeps such tags instead of setting them aside: Towns and Towers'
seven minecraft:has_structure biome tags load. Mods still own no other
minecraft content.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
26.3's EnterBlockTrigger reads a block list from 'blocks' and skips
1.21.1's 'block', so a carried criterion matched any block the player
entered: Regions Unexplored's Downer, From the Tree Tops and Light as a
Frog were granted on the first dive into the sea. Carry renames the
field (20 advancements in Regions Unexplored, with its boat recipes'
in-water criteria).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without the oracle, a block's template is guessed from its blockstate's
property names, and a vine's (east, north, south, up, west) fit
cobblestone_wall. The game then refused Chipped's 11 vine blockstates:
a wall's sides are none, low or tall, so 'true' is an unknown multipart
property value. block_template looks at the sides' values and makes those
vines; Luminax's 32 walls stay walls.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: merged after verify passed and a local check on main + #983 + #984 (clippy clean; chunk_generation and locator_bar, the two harnesses that failed in CI on the old head, both pass; modpacks-10's integration ran 301/301). Structures built under the sea are flooded and waterlogged; Better Ocean Monuments' processors carried.
🤖 Agent: merged after verify and CI parity passed, plus modpacks-10's local integration (parity 301/301, structure-start oracle 150/150 and 134/134). Towns and Towers' namespaces carried in its manifest.
🤖 Agent: merged after verify and CI parity passed, plus modpacks-10's local integration (all nine branches on main: parity 301/301, structure-start oracle 150/150 and 134/134). Content mods may own namespaces besides their id; two mods may not share one.
🤖 Agent: merged after verify and CI parity passed, plus modpacks-10's local integration (all nine branches on main: parity 301/301, structure-start oracle 150/150 and 134/134). Mod loot tables from every namespace, so modded structure chests are filled.
🤖 Agent: merged after verify and CI parity passed (modpacks-10, reviewed with local harness proof in the agent's report). Carries Formations' structures.
Its formations:simple becomes the game's horizon:formations (its pool and
placement), and its single pool element vanilla's with its ground_level
under horizon:ground_level. Its pieced structure (one) stays out; its
processors are still dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Better Ocean Monuments' ten processors (no fields; their behaviour is in
its Java) become vanilla's rule, the game's horizon:pick (one new
nextFloat per chance), horizon:flood_air, horizon:waterlog,
horizon:keep_world_block and horizon:yung_pillar; Better Witch Huts' log
and fence legs become horizon:yung_pillar. Its monuments are no longer
dry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repurposed Structures' and Moog's pillar_processor, Repurposed's
bottom_pillar_processor and close_off_fluid_sources_processor, YUNG's
pillar_processor (Better Fortresses, Better Jungle Temples) and Better
Fortresses' stair_pillar_processor become the game's horizon:pillar,
horizon:bottom_pillar, horizon:close_off_fluid_sources,
horizon:yung_pillar and horizon:stair_pillar. A pillar's own processor
list is written in, with the Java processors in it dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Towns and Towers ships its 60 structures under kaisyn and towns_and_towers,
not its mod id t_and_t, so carry left them outside. A namespace is now the
mod's when its own files (its id's, its tag additions, the namespaces
already claimed) name ids in it and no mod of the pack has it as its id.
Compat files for other mods and pack mods' configs stay outside; of ATM10's
42 jars only T&T claims any. A replacing tag of its own is an addition.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A content mod's manifest may list namespaces its files use besides its id
(Towns and Towers ships kaisyn and towns_and_towers under mod id t_and_t).
They are the mod's as its id is: files load, loaders read them. minecraft,
c and horizon cannot be listed. Two mods that are on owning one namespace
is an error naming both; the game keeps the first and leaves the other's
content out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The loot loader read data/minecraft/ only, so every chest in a carried
mod's structure that names its mod's loot table opened empty. It now reads
every namespace (a vanilla root has only minecraft). Integers written as
floats (rolls 3.0, as Towns and Towers writes them) read as vanilla's int
codecs read them. 534 of the 675 non-block tables in ATM10's carried mods
now fill a chest; vanilla's chest fills are byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: merged after verify and CI parity passed, and a combined check with rdbt's #796 on current main (fmt, clippy, 359 tests, 14 world-gen harnesses). YUNG/Moog terrain adaptation around structures (Better Fortresses netherrack inside bridges 39–41 % → 2.5–7 %), its carry, and YUNG modifiers.
🤖 Agent: merged after verify and CI parity passed, and a combined check with rdbt's #796 on current main (fmt, clippy, 359 tests, 14 world-gen harnesses). YUNG/Moog terrain adaptation around structures (Better Fortresses netherrack inside bridges 39–41 % → 2.5–7 %), its carry, and YUNG modifiers.
processors.rs tests: keep both #926's trial spawner and vault tests and
#920's Repurposed rule-test test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ChoiceTheorem's Overhauled Village swaps blocks in its templates through
Lithostitched's block_swap processor (137 lists): a map of block to
block, the new one taking Block.withPropertiesOf the old state, and the
block left alone when the new one is not registered. Carry dropped it.
- Game: horizon:block_swap, the same map; the new block's default state
with each property of the old one it has too (by name, when the value
is one of its own).
- Carry: lithostitched:block_swap becomes it.
ATM10: processors carried 136 -> 273 of 1,427 (dropped 1,291 -> 1,154).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Better Dungeons' small dungeon templates hold several chests; its Java
chest processor keeps the first, then each other one on nextFloat <= 0.2
until two have stayed, and turns the rest into cave air. Carry dropped it,
so every chest stayed.
- Game: horizon:count_cap. Of `blocks`, the first `min` a placement meets
stay, then each stays on settings.getRandom(pos).nextFloat() <= chance
until `max` have; the others become `replacement`. Counted per
placement (PlaceSettings, reset in process_infos), like the mod's
DungeonContext, set up per StructureTemplate.placeInWorld.
- Carry: betterdungeons:small_dungeon_chest_processor becomes it with the
mod's config defaults (1, 2, 0.2; chest and trapped chest).
Seed 1234, five small dungeons decorated: 12 chests -> 6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>