7.3 KiB
09 - PlaceholderAPI
Iris registers the iris PlaceholderAPI expansion on Bukkit-family servers when PlaceholderAPI is enabled at Iris enable time. It publishes sixteen keys: seven world-family readings for the player and nine global pregeneration keys. This is an operator board contract, not a Java API; plugins that need the same data with more precision use 90 - API - Getting Started.md, 91 - API - Terrain.md, and 92 - API - World Events.md. PlaceholderAPI is not available on Fabric/Forge/NeoForge. See also 07 - Pregeneration.md and 28 - Integrations.md.
Registration
| Item | Value |
|---|---|
| Expansion id | iris |
| Expansion version | 2.0.0 |
| Author string | Volmit Software |
| Required plugin | Iris |
| Soft-depend | PlaceholderAPI in plugin.yml |
persist() |
true — survives /papi reload without Iris restart |
Iris schedules setup after enable. If PlaceholderAPI is not enabled then, the expansion is not registered and there is no late PluginEnableEvent re-attempt. Soft-depend alone does not load PlaceholderAPI.
List published paths with /papi info iris.
Value grammar
| Rule | Detail |
|---|---|
| Path form | Dot-separated, lowercase, no underscores. Iris lowercases the path before resolve, so %iris_WORLD.BIOME% works, but write lowercase |
| Plain text only | No color codes, no unit suffixes, no % in values, . as decimal separator, no thousands grouping |
| Pack name scrubbing | Section-sign sequences and % characters inside pack-authored names are stripped before return |
| Real zero | 0 (or 0.00 for two-decimal numbers), never --- |
Three answers:
| Answer | When | Board shows |
|---|---|---|
| A value | Known key with data | The value |
--- |
Known key with no data right now | --- |
| Nothing (null to PAPI) | Unknown path | Literal %iris_...% |
Unknown paths stay visible on purpose. There is no catch-all blank fallback.
Full key table
World family
| Placeholder | Value |
|---|---|
%iris_available% |
true when the Iris terrain service is live, false otherwise |
%iris_world.available% |
true when the reading player is in an Iris world and a reading exists |
%iris_world.biome% |
Surface biome display name at the player column (example: Hot Desert Dunes) |
%iris_world.biome-key% |
Surface biome load key (example: desert/hot-dunes) |
%iris_world.region% |
Region display name at the player column |
%iris_world.region-key% |
Region load key |
%iris_world.dimension% |
Dimension (pack) load key of the player's world |
%iris_available% does not need a player. Every other world.* key needs a tracked online player. Console, offline player, or untracked position: world.available is false and the rest are ---.
Pregeneration family
| Placeholder | Value |
|---|---|
%iris_pregen.available% |
true while a pregeneration job is running |
%iris_pregen.world% |
World name the running job is pregenerating |
%iris_pregen.percent% |
Completion 0.00–100.00, no % character |
%iris_pregen.eta% |
Estimated seconds remaining, whole number |
%iris_pregen.eta-text% |
Same estimate as 45s, 2m 5s, or 1h 30m |
%iris_pregen.chunks% |
Chunks generated so far |
%iris_pregen.total% |
Chunks in the job |
%iris_pregen.chunks-per-second% |
Current rate, two decimal places |
%iris_pregen.paused% |
true while the job is paused |
pregen.* is global (one job per server). Values match for every player and the console. Snapshot is published on pregen events (STARTED, TICK, PAUSED, RESUMED, SAVING) and cleared on COMPLETED or CANCELLED. After clear, pregen.available is false and other pregen.* keys are ---. Before enough chunks exist for an ETA, eta/eta-text read 0 / 0s.
Paths as reported by /papi info iris
available
pregen.available
pregen.chunks
pregen.chunks-per-second
pregen.eta
pregen.eta-text
pregen.paused
pregen.percent
pregen.total
pregen.world
world.available
world.biome
world.biome-key
world.dimension
world.region
world.region-key
Prefix each with %iris_ and suffix with %.
Surface readings and cache
world.biome, world.biome-key, world.region, and world.region-key are surface column readings: the biome/region the generator places at ground level for that X/Z. A player in a cave under an overhang still reads the surface biome above, not the cave biome.
Position tracking
| Event | Publish |
|---|---|
Walking (PlayerMoveEvent) |
At most once per second per player; skipped while the player stays in the same block column |
Join, respawn, world change, portal, any teleport (including /iris goto, /tp, ender pearl, random TP) |
Immediate |
Standing still never keeps a stale column from a previous place after an immediate publish. Quit releases the player's position and world view.
View rebuild TTL
World views rebuild at most once per second per player (VIEW_TTL_MS = 1000), and only when something reads a world.* key that needs the view. Consequences:
- A board full of
world.*keys costs one rebuild per player per second - Values can lag a sprinting player by up to one second
- An unread board costs no terrain queries
Pregen snapshot
Pregen values come from a single global snapshot updated by IrisPregenerationEvent, not per-player polling.
Permissions
Iris never gates a placeholder on a permission. Values that should not be public (for example world seed) are not published.
Failure policy
| Situation | Shown |
|---|---|
| Unknown path | Nothing (literal %iris_...%) |
| Known path, no data | --- |
No player context on world.* |
--- and world.available = false |
| Player not in an Iris world | --- and world.available = false |
| Terrain service not registered | --- / world.available = false / %iris_available% = false |
| No pregen job | --- / pregen.available = false |
| Resolver throws | ---; one warning per distinct path, max 64 distinct paths |
Failed keys are not quarantined; they keep answering ---.
Migration from pre-2.0 keys
Pre-2.0 underscore keys are gone. No alias and no dual-accept window. Old keys render literally.
| Old key | New key | Notes |
|---|---|---|
%iris_biome_name% |
%iris_world.biome% |
Dot grammar |
%iris_biome_id% |
%iris_world.biome-key% |
id was always the load key |
%iris_region_name% |
%iris_world.region% |
Dot grammar |
%iris_region_id% |
%iris_world.region-key% |
id was always the load key |
%iris_biome_file% |
removed | Exposed absolute server paths; threw without a backing file |
%iris_region_file% |
removed | Same as biome_file |
%iris_world_seed% |
removed | No permission context on scoreboards; use terrain API IrisWorldInfo.seed() when a plugin needs seed |
%iris_terrain_height% |
removed | Generated height before objects/edits; disagreed with the block underfoot |
%iris_terrain_slope% |
removed | Expensive pack-authoring diagnostic |
%iris_world_mode% |
removed | Studio vs production is not a live-board concern |
%iris_world_speed% |
removed | Mutated engine rate-window state on read; use %iris_pregen.chunks-per-second% for pregen rate |
Behavior change inside the renames: old keys sampled two blocks above the player's feet (cave/overhang Y). New keys are always surface for the column. %iris_world.dimension% is new and has no pre-2.0 equivalent.