Carry 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>
This commit is contained in:
Ludovic Marie
2026-10-19 08:34:35 +02:00
parent 0af3dd3900
commit 8beeea55ff
2 changed files with 62 additions and 5 deletions
+51 -3
View File
@@ -507,6 +507,12 @@ fn upgrade_types(
v["type"] = "minecraft:jigsaw".into();
true
}
// Formations' SimpleStructure: its pool and placement, laid out
// by the game (`horizon_world::worldgen::structure::formations`).
Some("formations:simple") => {
v["type"] = "horizon:formations".into();
true
}
Some(t) if !t.starts_with("minecraft:") => {
unsupported(t);
false
@@ -565,6 +571,15 @@ fn upgrade_types(
} else if t == "yungsapi:yung_single_element" {
yung_element(element, lost);
changed = true;
} else if t == "formations:single_pool_element" {
// Vanilla's element with its own ground level (1 when
// missing, as its codec reads it).
element["element_type"] = "minecraft:single_pool_element".into();
if let Some(o) = element.as_object_mut() {
let ground = o.remove("ground_level").unwrap_or(1.into());
o.insert("horizon:ground_level".into(), ground);
}
changed = true;
} else if !t.starts_with("minecraft:") {
unsupported(t);
}
@@ -1204,14 +1219,47 @@ mod tests {
const NO_TAGS: BTreeMap<String, Vec<String>> = BTreeMap::new();
#[test]
fn formations_become_the_games() {
let mut report = Upgrade::default();
let mut s = json!({"type": "formations:simple", "template": "f:campsites",
"placement": "surface", "biomes": "#f:x", "step": "surface_structures",
"terrain_adaptation": "beard_thin", "spawn_overrides": {}});
assert!(upgrade("structure", &mut s, &mut report, &NO_TAGS));
assert_eq!(s["type"], "horizon:formations");
assert_eq!(s["placement"], "surface");
let mut pool = json!({"elements": [
{"weight": 1, "element": {"element_type": "formations:single_pool_element",
"location": "f:a", "projection": "rigid", "ground_level": 6, "processors": []}},
{"weight": 1, "element": {"element_type": "formations:single_pool_element",
"location": "f:b", "projection": "rigid", "processors": []}}]});
assert!(upgrade("template_pool", &mut pool, &mut report, &NO_TAGS));
let e = |i: usize| &pool["elements"][i]["element"];
assert_eq!(e(0)["element_type"], "minecraft:single_pool_element");
assert_eq!(
(
e(0)["horizon:ground_level"].clone(),
e(1)["horizon:ground_level"].clone()
),
(json!(6), json!(1))
);
assert!(e(0).get("ground_level").is_none());
// The pieced structure stays out.
let mut pieced = json!({"type": "formations:pieced", "start_pool": "f:p", "max_depth": 2,
"max_distance_from_center": 40, "placement": "surface", "biomes": "#f:x"});
assert!(!upgrade("structure", &mut pieced, &mut report, &NO_TAGS));
assert_eq!(report.unsupported.get("formations:pieced"), Some(&1));
assert_eq!(report.unsupported.len(), 1);
}
#[test]
fn maps_library_types_to_vanillas() {
let mut report = Upgrade::default();
let mut s = json!({"type": "lithostitched:jigsaw", "start_pool": "a:b"});
assert!(upgrade("structure", &mut s, &mut report, &NO_TAGS));
assert_eq!(s["type"], "minecraft:jigsaw");
let mut formation = json!({"type": "formations:simple"});
assert!(!upgrade("structure", &mut formation, &mut report, &NO_TAGS));
let mut other = json!({"type": "somelib:structure"});
assert!(!upgrade("structure", &mut other, &mut report, &NO_TAGS));
let mut set = json!({"placement": {"type": "moogs_structures:advanced_random_spread",
"spacing": 10, "separation": 5, "min_distance_from_world_origin": 250}});
assert!(upgrade("structure_set", &mut set, &mut report, &NO_TAGS));
@@ -1255,8 +1303,8 @@ mod tests {
assert_eq!(
report.unsupported,
BTreeMap::from([
("formations:simple".into(), 1),
("somelib:element".into(), 1),
("somelib:structure".into(), 1),
])
);
}
+11 -2
View File
@@ -548,14 +548,23 @@ Two cases the oracle fills in:
its mod id `t_and_t`, and a mod's content may only use its own namespace (docs/mods.md), so
carry leaves them out and its 60 structures are missing.
- Still lost, written in Java:
- Formations' structure and element types (179): their placements read block states in the
noise column (solid, water, lava), which the structure context doesn't give yet;
- Formations' pieced structure (1, its one jigsaw-like type);
- Repurposed's mineshafts, mansions and monuments, Better Mineshafts and two Better
Dungeons types: Java structure types;
- the block processors written in Java
(YUNG's banners, legs and decorations, Repurposed's pillars and fluid fixes,
Lithostitched's block swaps);
- MO Structures (38; its library is only on CurseForge).
- **Formations** (Overworld and Nether: 50 structures, 128 pool elements) places one
template per start at a height found in the noise columns under its corners and centre: on
the surface, on water or lava, or in a cave (on its floor, under its ceiling, buried in
stone, on a lava lake). Carry writes its `formations:simple` as the game's
`horizon:formations` (`horizon-world`'s `structure/formations.rs`, which reads the blocks
of ChunkGenerator.getBaseColumn through the structure context) and its pool element as
vanilla's with its `ground_level` under `horizon:ground_level`. In chunks -64..63 that adds
39 Overworld and 672 Nether starts at seed 1234 (51 and 643 at seed 2), and leaves every
other start as it was. Its processors (biome replacements, aged blocks, bed colours,
plants) are still dropped, so its structures keep their templates' blocks.
With every structure PR above, the same square (seed 1234, chunks -64..63) holds 362
overworld starts with 22,026 pieces. CTOV has 7, Better Dungeons 72 and Better Ocean