Files
Iris/docs/30 - Platform Differences.md
T
Brian Neumann-Fopiano 365205ad0a d
2026-08-12 13:52:16 -04:00

14 KiB

30 - Platform Differences

Iris runs the same generation core on Bukkit-family servers and on Fabric, Forge, and NeoForge. Terrain output is identical; everything around it differs, and this page is the reference matrix for those differences. Shared configuration is settings.json; mod loaders add modded.json. Related detail lives in 01 - Installation & Platforms.md, 03 - Configuration.md, and 04 - Commands & Permissions.md.

What actually differs

Five categories cover almost everything an operator runs into:

  • Command syntax. Bukkit uses VolmLib Director, where optional arguments are key=value in any order. Mod loaders use Brigadier, where arguments are positional and options are bare literals. The same feature reads very differently on each.
  • World lifecycle. Bukkit creates named worlds and can stage an exact replacement of a configured vanilla slot on restart. Mod loaders register dimension ids and enable or disable them.
  • Authoring tools that need Bukkit. Anything built on NMS, WorldEdit, or inventory GUIs is Bukkit-only: Jigsaw Studio, structure import and capture, vanilla import, schematic conversion, and the Studio loot and entity GUIs. Packs authored there run fine everywhere.
  • Permissions. Bukkit gates the entire /iris tree behind one permission. Mod loaders gate mutating commands at gamemaster level but leave inspection open to any player.
  • File locations. Both platforms have an Iris data directory, but the modded side splits it: settings live under one root and packs under another.

Terrain, biomes, objects, jigsaw runtime, caves, and structures behave the same on all four. If generated terrain differs between platforms, that is a determinism defect, not a platform difference — see 32 - Determinism & Goldenhash.md.

Artifacts and entry points

Surface Artifact Bootstrap
Bukkit / Paper / Folia CraftBukkit-shaded plugin jar plugin.yml / paper-plugin.yml, folia-supported: true, load STARTUP
Fabric Fabric mod jar IrisFabricBootstrap registers commands and services
Forge Forge mod jar IrisForgeBootstrap
NeoForge NeoForge mod jar IrisNeoForgeBootstrap

Core engine: core/. Shared modded logic: adapters/modded-common/. SPI: spi/.

Data directories

Item Bukkit Fabric / Forge / NeoForge
Settings plugins/Iris/settings.json <configDir>/iris/settings.json
Packs plugins/Iris/packs/ <configDir>/irisworldgen/packs/
Mod config <configDir>/irisworldgen/modded.json
GoldenHash baselines plugins/Iris/golden/ <configDir>/irisworldgen/golden/
Studio pack exports plugins/Iris/packs/exports/ <configDir>/irisworldgen/exports/
Generated datapack world datapacks/ + Iris ingest <configDir>/irisworldgen/generated/datapack/; dimension-type pack name iris under data/irisworldgen/dimension_type/
Parity / developer dumps under plugin data folder <configDir>/iris/parity/
Persistent dynamic-world registry plugins/Iris/worlds.json <world-root>/iris/iris-dimensions.json

On mod loaders only settings.json and the parity dumps use the iris/ root; every pack, config, and generated artifact uses irisworldgen/. Both roots sit under the loader config directory.

Hotload is polled on both platforms, at different rates:

Watcher Bukkit Modded
Pack / studio content 1 s scan over the shared reactive folder 250 ms scan, 1 s check latch, 2 s hold-off after recent generation
settings.json Reloaded through the same reactive path Dedicated 3 s poll

Both use the same invalidate, reload, and locale path once a change is detected.

World model

Concern Bukkit Modded
Create /iris create → managed world name, generator Iris, optional main-world; on Paper-family servers overwrite=true stages replacement of an existing exact Iris or vanilla slot for the next restart /iris create or /iris world enable → dimension id plus pack injection
Load / unload /iris load (alias import), /iris unload /iris world disable unloads; there is no separate load command
Remove / delete /iris remove, optionally deleting the folder /iris world delete wipes chunk and mantle data
Primary / main world main=true for a new level root, or name the configured main world with overwrite=true for journaled in-place replacement modded.json primaryWorld plus routePlayersToPrimaryWorld; /iris world mainworld (and mainworld off), /iris world replace-overworld
Evacuate /iris evacuate <world> — world argument required, player-only origin /iris evacuate [dimension] — defaults to the sender's current level; destination is always the vanilla overworld, and evacuating the overworld itself is refused
Studio world Transient studio world via StudioSVC; /iris jigsaw can select the Jigsaw Studio generator for one activation Studio dimension under irisworldgen:studio_*; no Jigsaw Studio authoring tree
Folia Regionized schedulers; pregen runtimeSchedulerMode always resolves to FOLIA on a regionized runtime Not applicable

Startup installs the IrisDimensions Overworld and Underworld beta releases into packs/overworld and packs/underworld when missing. Paper bootstrap publishes both in one rollback scope before compiling the aggregate datapack; legacy Bukkit and modded startup use the same managed release sources.

Modded startup quarantines a corrupt persistent-dimension registry as iris-dimensions.json.broken-<timestamp> and continues without those dynamic worlds. Recovery: 06 - Worlds & Lifecycle.md.

Exact vanilla-slot replacement requires a full Paper-family plugin bootstrap. Without it the staging call fails outright, which is why the feature is Paper/Purpur/Leaf/Folia only.

Commands and permissions

Concern Bukkit Modded
Parser VolmLib Director; key=value optionals in any order Brigadier; positional arguments and bare flag literals
Root aliases iris, ir, irs iris, with ir and irs registered as redirects
Staff gate iris.all (declared in plugin.yml and paper-plugin.yml, default op) — required for every /iris subcommand LEVEL_GAMEMASTERS for anything that mutates, downloads, opens Studio, or starts a pregen
Open to any player Nothing LEVEL_ALL: help, version, info, worlds, height, metrics (alias measure), and the whole what subtree
Deliberately gated reads seed and accesslist stay at gamemaster level even though worlds shows similar output without the seed field
Tree feller iris.treefeller (plugin.yml and paper-plugin.yml, default op) Fabric irisworldgen:treefeller; Forge and NeoForge PermissionAPI node irisworldgen.treefeller, defaulting to gamemaster level
Help Director mini-menu ModdedCommandHelp sections with clickable pages

Full command tables and stubs: 04 - Commands & Permissions.md.

Feature matrix

Feature Bukkit Fabric Forge NeoForge
Core terrain / biomes / objects / jigsaw yes yes yes yes
Saved planar/spatial Iris jigsaw runtime yes yes yes yes
Jigsaw Studio (/iris jigsaw authoring tree) yes not registered not registered not registered
Pack validate / cleanup / restore / status yes yes yes yes
Pack download (/iris download, root-level on both) yes yes yes yes
Exact restart replacement of configured Overworld/Nether/End slots Paper/Purpur/Leaf/Folia no no no
Pregen yes (Paper-like / Folia modes) yes (moddedPregenInFlight) yes yes
Studio open / close / vscode / package yes yes yes yes
Studio importvanilla yes message: run on Bukkit same same
Studio loot GUI / entity spawn / profile / objects report yes message only message only message only
Object wand / paste / save / undo yes yes yes yes
Object contract / shift selection yes yes yes yes
Object expand selection no yes yes yes
Object WorldEdit import (we) yes (WorldEdit soft depend) message only message only message only
Object studio world yes message only message only message only
Schematic convert (.schem.iob) yes message only message only message only
Structure import / capture yes (v26 NMS binding) message only message only message only
Structure list / info / place / verify yes yes yes yes
Datapack Modrinth ingest / list / remove yes message only message only message only
Dimension-type datapack install / status not applicable yes yes yes
PlaceholderAPI soft depend no no no
Multiverse-Core soft depend / loadbefore no no no
Item plugins (ItemsAdder, Mythic, and similar) paper soft deps loader-specific / limited limited limited
Public API package art.arcane.iris.api plugin jar see 94 - API - Modded.md same same
Client HUD / protocol optional client mod optional client mod optional optional
Tree feller settings + iris.treefeller settings + loader permission same same
Auto Spigot/Paper timeout and watchdog config yes no no no
Custom biome restart prompts yes (iris.all / op) different datapack flow same same

"Message only" means the command exists and prints an explanation of where to run it instead — it is not a silent failure.

Jigsaw pack resources are shared runtime data; only the in-game authoring surface is Bukkit-only. Bukkit exposes one global Studio project and world and one owning Jigsaw session: non-owner block, inventory, interaction, and mutating-command changes are cancelled across that Studio world, while autosave and graph-operation barriers serialize the owner's changes. On Folia a save schedules every intersecting chunk snapshot on its owning region and writes only after the complete capture validates. These protections have automated coverage but still need the live multi-region runbook in 31 - Operator Runbooks.md. A strict VANILLA_PORTABLE export targets unmodded Minecraft 26.2 and is a separate compatibility gate.

Platform-sensitive settings

Setting Where it matters
pregen.runtimeSchedulerMode Bukkit only; resolved from Bukkit/Folia detection, and a regionized runtime always resolves to Folia
pregen.paperLikeBackendMode Bukkit only; ticket versus service chunk acquisition
pregen.moddedPregenInFlight Mod loaders only; concurrent pregen chunk budget
autoConfiguration.* Bukkit only; Spigot keep-alive, Paper watchdog, custom-biome restart
world.worldEditWandCUI Bukkit only; requires WorldEdit
general.autoIngestDatapacks / general.autoImportDatapackStructures Bukkit datapack ingest pipeline is the primary consumer
gui.useServerLaunchedGuis Both, but the host implementation differs (BukkitGuiHost versus ModdedGuiHost)

modded.json keys exist only on mod loaders.

Integrations

Integration Bukkit Modded
WorldEdit soft depend; object we import not wired
Multiverse-Core load order / link not used
PlaceholderAPI %iris_…% no
MythicMobs and item plugins paper-plugin optional deps not the Bukkit pipeline
Tree feller plugin permission loader permission node

See 28 - Integrations.md and 09 - PlaceholderAPI.md.

NMS and version binding

  • The Bukkit plugin binds to a specific Paper/CraftBukkit revision (the in-tree v26 NMS module).
  • Structure import and capture, and the vanilla import studio path, require that binding. This is why they cannot be ported to mod loaders as-is.
  • Mod adapters use Minecraft mappings for the same game version line, without the Bukkit plugin APIs.

Determinism and parity

GoldenHash exists on both surfaces; only the command placement differs (Bukkit under developer, modded at the root). Use disposable worlds. Bukkit exposes mantle-reset and deep-dump options that modded does not, and modded always resets mantle. Cross-platform comparisons always emit a Minecraft-version warning because the two platforms report the version string differently. Full procedure: 32 - Determinism & Goldenhash.md.

Moving a pack between platform families

  1. Freeze the pack bytes and seed. Validate and package on the source platform.
  2. Finish anything Bukkit-only first: structure and vanilla imports, schematic conversion, WorldEdit imports, and Jigsaw Studio work. Complete the atomic saves before copying.
  3. Copy only packs/<key>/ into the destination packs root. Never copy a Bukkit world folder into a modded world or the reverse.
  4. Restart so destination registries and forced datapacks are built before any world is created.
  5. Align the settings.json keys that affect generation (generator, performance, treeFeller). Bukkit-only autoConfiguration keys can be ignored.
  6. On mod loaders, set modded.json primaryWorld if you need overworld replacement.
  7. Re-run /iris pack validate, then /iris datapack status on modded or the ingest flow on Bukkit.
  8. Create a disposable world with the same seed and run the same small GoldenHash inputs plus the platform's fresh-install runbook.

The move passes when validation, world creation, restart, and the deterministic comparison all pass. Matching screenshots are useful context, but the hash comparison is what counts.

  • 01 - Installation & Platforms.md
  • 03 - Configuration.md
  • 04 - Commands & Permissions.md
  • 06 - Worlds & Lifecycle.md
  • 07 - Pregeneration.md
  • 21 - Jigsaw Structures.md
  • 22 - Native Structures & Datapacks.md
  • 28 - Integrations.md
  • 29 - Client HUD & Protocol.md
  • 31 - Operator Runbooks.md
  • 32 - Determinism & Goldenhash.md
  • 94 - API - Modded.md