# 22 - Native Structures & Datapacks Structures that originate outside Iris packs: vanilla structures in Iris worlds, datapack structures, the Minecraft structure-block / `.nbt` system, and converting native structures into editable Iris resources. Objects and Iris jigsaws are `19 - Objects.md`, `20 - Object Placement.md`, and `21 - Jigsaw Structures.md`. Terminology: - **registered / native structure** — anything in Minecraft's live structure registry (vanilla, mod, datapack). Keys are namespaced (`minecraft:village_plains`, `towns_and_towers:village_ocean`). - **Iris structure** — editable `structures/.json` inside a pack. Command listings are Bukkit/Paper; modded loaders expose a reduced set. ## 1. Vanilla structures in Iris worlds ### 1.1 Default: everything generates Every registered structure generates through its own native placement unless its key is disabled or a dimension-level Iris placement replaces its source. Changes only affect newly generated chunks. ### 1.2 Biome mapping for structure filters Vanilla tests biomes against structure biome filters. Iris answers per Iris biome: | Field on biome | Default | Purpose | |---|---|---| | `derivative` | `minecraft:the_void` | Vanilla biome this Iris biome reports generally. | | `vanillaDerivative` | unset | Optional override for structure selection, spawn tables, imported features, biome tags. Wins when set. | Refinements: a sea-role biome whose derivative is not ocean/river-like resolves to `minecraft:the_void`; shore-role falls back to `minecraft:beach`. **Non-`minecraft:` namespaces pass through** — point `vanillaDerivative` at a datapack/mod biome key that exists in the live registry. A datapack structure whose filter lists only its own biomes never generates until an Iris biome reports one of those keys via `vanillaDerivative`. `/iris structure verify` reports `[unreachable] needs `. ```json { "derivative": "minecraft:plains", "vanillaDerivative": "towns_and_towers:some_custom_biome" } ``` ### 1.3 `importedStructures` (dimension) | Field | Default | Meaning | |---|---|---| | `disabled` | `[]` | Structure keys/prefixes to deny. | | `undergroundYShift` | `0` (-512..512) | Vertical offset for underground-step structures only. Surface structures never use it. | | `datapackOverrides` | `true` | Whether ingested datapacks may replace `minecraft:`-namespaced structure content (2.5). | | `adjustments` | `[]` | Per-structure adjustments for structures still generating natively (1.4). | #### Prefix matching Used by `disabled` and `adjustments[].match`. Both sides trimmed and lowercased; key must start with pattern; then: - Equal length → match. - Pattern ends with `:`, `/`, or `_` → match (e.g. `"nova_structures:"` disables a namespace). - Otherwise next character after pattern must be `/` or `_`. `"minecraft:village"` matches village variants; `"nova_structures"` without trailing colon does **not** match the namespace. ```json { "importedStructures": { "disabled": ["minecraft:village", "minecraft:pillager_outpost"] } } ``` ### 1.4 `adjustments[]` Each entry (`match` selects targets by the same prefix rule): | Field | Default | Meaning | |---|---|---| | `match` | `[]` | Keys/prefixes. Empty matches nothing. | | `yShift` | `0` (-512..512) | Vertical offset; stacks across matches; clamped to build bounds. | | `yBand` | unset | Absolute world-Y band `{min, max}`: structure midpoint lands in band, deterministic per start chunk. | | `preserveSourceY` | `false` | Skip Iris burial repositioning; keep vanilla Y. `undergroundYShift` and `yShift` still apply on top. | | `stilt` | unset | Foundation columns: `maxDepth` (default 64), `palette` (default cobblestone), `spacing`. (`supportNonOccluding` applies to Iris-assembled structures.) | | `terrain` | unset (= `SOURCE`) | Terrain-integration override. | Vegetation clearing is automatic (trees intersecting piece envelopes removed). **Merge:** `yShift` adds; `preserveSourceY` OR-ed; `stilt`, `terrain`, `yBand` last-match-wins. Broad prefix first, specific overrides after. **Vertical precedence:** ``` preserveSourceY > yBand > burial (underground steps) > plain yShift ``` Three structures honor only `yShift` among these controls: `minecraft:monument` (aligned 24 below sea level), `minecraft:desert_pyramid` (one block above lowest surface Y of footprint), `minecraft:jungle_pyramid` (one block above average surface Y). #### Terrain modes | Mode | Behavior | |---|---| | `SOURCE` (default) | Replay structure's registered terrain adaptation, including vanilla BURY/ENCAPSULATE fill reimplemented with surrounding terrain material. | | `PRESERVE` | Disable terrain integration. | | `BORE` | Clear padded piece volume (box) before placement. | | `FORCE_CARVE` | Clear padded envelope with `shape`: `BOX` / `ROUNDED` / `ERODED`. | | `VACUUM` | Raise surface terrain to structure ground planes with fixed 12-block falloff. Never lowers ground. | | `ENCASE` | Fill padded volume with solid blocks before placement (air/liquid only). Structure carves interiors. `encasePalette` optional (defaults: stone/deepslate overworld, netherrack nether, end stone end). | Padding: `horizontalPadding` (0..128), `ceilingPadding` (0..128), `floorPadding` (0..64; 0 preserves floor). ERODED: `erosionStrength` (default 0.8), `erosionFrequency` (0.07), `lobeFrequency`, `lobeStrength` (0.85). #### Examples Stronghold deep band + encase: ```json { "match": ["minecraft:stronghold"], "yBand": { "min": -120, "max": -20 }, "terrain": { "mode": "ENCASE", "horizontalPadding": 4, "ceilingPadding": 4, "floorPadding": 4, "encasePalette": { "zoom": 1, "palette": [ { "block": "minecraft:stone_bricks", "weight": 6 }, { "block": "minecraft:mossy_stone_bricks", "weight": 2 }, { "block": "minecraft:cracked_stone_bricks", "weight": 2 }, { "block": "minecraft:cobblestone", "weight": 1 } ] } } } ``` Shift trial chambers; preserve mineshaft Y; stilt villages: ```json [ { "match": ["minecraft:trial_chambers"], "yShift": -64 }, { "match": ["minecraft:mineshaft"], "preserveSourceY": true }, { "match": ["minecraft:village"], "stilt": { "maxDepth": 768, "palette": { "palette": [ { "block": "minecraft:cobblestone" } ] } } } ] ``` Broad then specific (last-match-wins): ```json [ { "match": ["towns_and_towers:"], "terrain": { "mode": "VACUUM" } }, { "match": [ "towns_and_towers:mimic_desert", "towns_and_towers:pillager_outpost_ocean", "towns_and_towers:village_ocean", "towns_and_towers:wreckage_ocean" ], "terrain": { "mode": "PRESERVE" } } ] ``` ## 2. Datapack structures ### 2.1 `datapackImports` Dimension-file list of datapack sources Iris downloads and installs: ```json { "datapackImports": [ "https://modrinth.com/datapack/towns-and-towers", "https://modrinth.com/datapack/dungeons-and-taverns" ] } ``` Accepted URL forms: - **Modrinth project page** — latest datapack version for the server's Minecraft version. - **Pinned Modrinth version** — any `.../version/` URL. - **Any other URL** — direct zip download, tracked by ETag/hash. Checksum-verified when Modrinth publishes a hash; size-capped. ### 2.2 Where files land; when ingest runs Installed datapacks are real Minecraft datapacks at `/datapacks//`, each with `.iris-managed.json`. Unmanaged datapacks are never touched; id `iris` is reserved. Cache/staging/manifest under `plugins/Iris/datapacks/`. Ingest runs shortly after plugin enable when `general.autoIngestDatapacks` is true (default). Minecraft builds worldgen registries at server start, so a **newly installed** datapack is not registered on the boot that installed it — auto-ingest **restarts the server** when anything changed. After that restart, keys are live. A repair path reinstalls staged datapacks that went missing without re-downloading. ### 2.3 Manual commands ``` /iris datapack ingest [restart=false] (alias: pull) /iris datapack list (alias: ls) /iris datapack remove (alias: rm) ``` `ingest` aggregates `datapackImports` from every dimension of every loaded pack. `restart` defaults false (Iris tells you a restart is required). `remove` refuses unmanaged datapacks — also delete the URL or next ingest reinstalls it. ### 2.4 Usage patterns **(a) Natural generation.** Import, restart. Check with `/iris structure list ` (writes `/.iris/structure-index.json`) and `/iris structure verify ` (`[native-eligible]` vs `[unreachable]`). Fix unreachable biomes via `vanillaDerivative`, or use (c). **(b) Replace vanilla.** Disable vanilla families; datapack replacements keep generating: ```json { "importedStructures": { "datapackOverrides": true, "disabled": [ "minecraft:village", "minecraft:pillager_outpost", "nova_structures:" ], "adjustments": [ { "match": ["towns_and_towers:"], "terrain": { "mode": "VACUUM" } }, { "match": ["towns_and_towers:mimic_desert", "towns_and_towers:pillager_outpost_ocean", "towns_and_towers:village_ocean", "towns_and_towers:wreckage_ocean"], "terrain": { "mode": "PRESERVE" } } ] } } ``` **(c) Manual placement only.** Disable the datapack namespace, then place specific keys with `nativeStructures` — `disabled` never blocks explicit placements (3.2): ```json { "structures": [ { "placementId": "dnt-taverns-temperate", "nativeStructures": [ { "structure": "nova_structures:tavern_oak", "weight": 4 }, { "structure": "nova_structures:tavern_birch", "weight": 3 }, { "structure": "nova_structures:tavern_cherry", "weight": 2 }, { "structure": "nova_structures:shrine_tower", "weight": 1 } ], "distribution": "RANDOM_SPREAD", "spacing": 24, "separation": 6, "salt": 776215551 } ] } ``` ### 2.5 `datapackOverrides` When `false`, Iris strips `data/minecraft/worldgen/structure_set|structure|template_pool/` and `data/minecraft/structure/` from every installed copy. Resolves **globally** — one dimension setting `false` strips for all. Non-`minecraft:` content is unaffected (disable those keys explicitly). ## 3. Placing specific native structures (`nativeStructures`) `structures[]` on dimension/region/biome hosts two backends — exactly one per placement: - `structures: [""]` — Iris assemblies (`21 - Jigsaw Structures.md`). - `nativeStructures: [{ structure, weight, jigsaw }]` — registered structures via Minecraft machinery at Iris-chosen points, full native fidelity. ### 3.1 Entry fields | Field | Default | Meaning | |---|---|---| | `structure` | required | Registered structure key (must exist live). | | `weight` | `1` (min 1) | Weighted selection among sources. | | `jigsaw` | unset | Overrides for registered **jigsaw** structures only: `startPool`, `startJigsawName`, `maxDepth` (0..20), `maxDistanceHorizontal` (1..128), `maxDistanceVertical` (1..4064), `useExpansionHack`, `projectStartToHeightmap` (`SOURCE`/`NONE`/heightmap types), `dimensionPaddingBottom` and `dimensionPaddingTop` (nonnegative distance from floor/ceiling), and `liquidSettings`. Null/unset values preserve the registered definition. | Placement grid fields (`distribution`, `spacing`/`separation`/`salt`, `density`, rings, heights, `underground`, `underwater`, `placementId`) match `21 - Jigsaw Structures.md` section 3.1, except the native backend supports **every** terrain mode including `VACUUM` and `ENCASE`, plus `stilt` (including `spacing`). Scoping matches Iris placements. Validation requires the structure's effective assembly span stay inside Minecraft's 128-block (8-chunk) structure reference range. ### 3.2 `disabled` never blocks an explicit placement The placement injector generates planned starts without consulting `disabled` and bypasses the structure's own biome filter. "Disable namespace, re-place explicitly" is supported. ### 3.3 `nativeSuppression: REPLACE_SOURCE` - **Dimension-level placements only** — blocking pack error elsewhere. - With `nativeStructures`: suppresses that key's natural generation so it exists only where the placement puts it. - With Iris `structures`: suppresses each referenced structure's `vanillaSource`; pack validation demands the graph guarantees output — no native fallback. Iris-backend `REPLACE_SOURCE` that produces nothing throws at runtime. Native-backend unusable starts are recorded invalid and skipped silently (still suppressed). Example — ancient cities replaced by Iris-positioned native starts: ```json { "nativeStructures": [ { "structure": "minecraft:ancient_city" } ], "placementId": "ancient-city-native", "nativeSuppression": "REPLACE_SOURCE", "underground": true, "minHeight": -220, "maxHeight": -220, "distribution": "RANDOM_SPREAD", "spacing": 64, "separation": 5, "salt": 42069, "terrain": { "mode": "FORCE_CARVE", "horizontalPadding": 14, "ceilingPadding": 12, "shape": "ERODED", "erosionStrength": 1.0, "erosionFrequency": 0.05 }, "stilt": { "maxDepth": 768, "palette": { "palette": [ { "block": "minecraft:deepslate_bricks", "weight": 6 }, { "block": "minecraft:cracked_deepslate_bricks", "weight": 1 }, { "block": "minecraft:deepslate_tiles", "weight": 2 }, { "block": "minecraft:cracked_deepslate_tiles", "weight": 1 } ] } } } ``` ### 3.4 Tool reporting | Configuration | `/iris structure verify` | `/iris goto structure ` | |---|---|---| | Registered, not disabled, not placed | `[native-eligible]` or `[unreachable] ... needs ` | Vanilla locate | | Placed via `nativeStructures` (even if also disabled) | `[iris-planned] @ x,y,z` / `[iris-not-found]` | Iris grid search | | Disabled, not placed | `[disabled]` | "disabled by this dimension's importedStructures settings" | A key that is both disabled and placed reports as Iris-placed. ## 4. Minecraft structure-block system Structure blocks save/load `.nbt` templates; jigsaw blocks wire pools. Iris does not re-teach vanilla tools — see Minecraft wiki Structure Block and datapack tutorials. How an authored `.nbt` reaches an Iris world: **(a) Through a datapack (native generation).** Ship under `data//structure/`, add `worldgen/template_pool`, `worldgen/structure`, `worldgen/structure_set`, zip, host or Modrinth, add URL to `datapackImports`, `/iris datapack ingest restart=true`. Then natural generation, `adjustments`, or `nativeStructures`. **(b) Import into Iris resources.** `/iris structure import ` (section 5). Template pass enumerates **registered** templates only — loose saves in `/generated/` are not enumerated; package them into a datapack first. Template-import fidelity (lossy by design): first palette only; structure voids and structure blocks dropped; jigsaw blocks resolved to `final_state` (graph rebuilt by separate jigsaw pass); entities not converted; block entities captured. ## 5. Importing native structures into Iris resources You do not need import just to place — `nativeStructures` places any registered key with full fidelity. Import when you want to **edit** blocks, pools, pieces. ### 5.1 `/iris structure import ` Four passes, always overwriting its own previous output: 1. **Jigsaw rebuild** — registered jigsaw structures → editable pools/pieces/objects. 2. **Template import** — registered `.nbt` templates → `objects/.iob` + single-piece `jigsaw-pieces/.json`. 3. **Template groups** — fixed multi-template structures (shipwrecks, ruined portals, ocean ruins, nether fossils) → one Iris structure each with every variant in the pool. 4. **Capture** — code-generated structures without templates (swamp huts, igloos, ...) via scratch world (also alone as `/iris structure capture `). Structures spanning more than **48 blocks** on any axis are skipped (strongholds, mansions, monuments stay native-only). Naming: `minecraft:village_plains` → `minecraft_village_plains`. Generated structures carry `vanillaSource` for locate and `REPLACE_SOURCE`. `/iris studio importvanilla [variants=3] [structures=true]` also imports vanilla trees/features as objects, plus structure passes when `structures=true`. ### 5.2 Ownership and `unowned_resource` Imports use per-bundle ownership manifests (`/.iris/structure-manifests/`). Failure: ``` Import conflict for '': is unowned_resource. Existing authored files were preserved. ``` Iris found a file it did not write and refused to clobber it. `modified_resource` means Iris wrote it, you edited it, hash no longer matches. Rename or leave the key native. ### 5.3 Automatic datapack import `general.autoImportDatapackStructures` (default **false**) converts each ingested datapack's structures into editable pack resources on ingest. Off by default because native generation and `nativeStructures` never need the copies, and conversion can write thousands of files. If auto-import fails (often `unowned_resource`), the manifest stays pending and import **retries every boot** until resolved or the setting is disabled. Removing a URL from `datapackImports` cleans bundles that import wrote for it. ## 6. Verification and debugging ``` /iris structure list # write + print key index /iris structure verify [radius=48] # eligibility + placement (alias: locateall) /iris structure info # Iris: compile + sample assembly /iris structure place # Iris: stamp at feet (player) /iris goto structure # locate + teleport /iris goto unregistered # excluded keys + reasons ``` `verify` tags: `[iris-planned]`, `[iris-not-found]`, `[iris-search-limit]`, `[disabled]`, `[unreachable]`, `[native-eligible]`, `[error]`. Placements checked first — disabled-but-placed shows as `[iris-planned]`. ### Traps - Worlds snapshot the pack — push with `/iris developer update-world world= pack= confirm=true`, then restart. Backup first. - Keyed optional args: `radius=200`, not bare `200`. - New datapack structures need a restart for registry registration. - Only new chunks change. - Namespace disables need the colon: `"nova_structures:"`. - `REPLACE_SOURCE` has no fallback — validate the graph before shipping. - `datapackOverrides: false` anywhere strips `minecraft:` overrides server-wide. ## Command reference | Command | Aliases | Parameters | |---|---|---| | `/iris datapack ingest` | `pull` | `restart=false` | | `/iris datapack list` | `ls` | | | `/iris datapack remove ` | `rm` | | | `/iris structure list ` | `ls` | | | `/iris structure import ` | `import-all`, `reimport`, `imp`, `all` | | | `/iris structure capture ` | `cap` | | | `/iris structure verify ` | `locateall` | `radius=48` (1..1000 chunks) | | `/iris structure info ` | | | | `/iris structure place ` | `p` | player only | | `/iris goto structure ` | `/iris find structure` | | | `/iris goto unregistered` | | | | `/iris developer update-world` | | `world= pack= confirm=true [fresh-download=false]` — all keyed | Related dimension fields: `datapackImports`, `importedStructures`, `structures[]`. Settings (`plugins/Iris/settings.json`): `general.autoIngestDatapacks` (default true), `general.autoImportDatapackStructures` (default false).