mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 04:37:47 +00:00
181 lines
9.8 KiB
Markdown
181 lines
9.8 KiB
Markdown
# 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; related runtime and integration details are in `07 - Pregeneration.md` and `28 - Integrations.md`.
|
||
|
||
## Tutorial: verify a placeholder before using it in another plugin
|
||
|
||
Prerequisites: Bukkit-family Iris, PlaceholderAPI installed before Iris enables, a full server restart, and a player in a loaded Iris world.
|
||
|
||
1. Confirm registration: `/papi info iris`. The output must list expansion id `iris` and its published paths.
|
||
2. Confirm the service: `/papi parse me %iris_available%`. Expect `true` while Iris terrain service is live.
|
||
3. Confirm player context: `/papi parse me %iris_world.available%`. Expect `true` while the named player is in an Iris world.
|
||
4. Parse a concrete terrain value: `/papi parse me %iris_world.biome-key%`. Expect a load key such as `desert/hot-dunes`, not `---`.
|
||
5. While standing in the Iris world, run `/iris pregen start 352 center=0,0 gui=false`, then parse `/papi parse me %iris_pregen.percent%`. Expect a numeric value from `0.00` through `100.00` with no percent sign.
|
||
6. Stop with `/iris pregen stop` or let the job finish, then run `/papi parse me %iris_pregen.available%`. Expect `false`; other pregen values return `---` after the snapshot clears.
|
||
7. Copy the exact verified placeholder into the scoreboard, chat, or HUD plugin and test that consumer once more.
|
||
|
||
The workflow passes when registration, player-scoped terrain, and global pregen values each produce their documented value shape. Do not debug formatting in the consuming plugin until direct `/papi parse` succeeds.
|
||
|
||
### Recovery
|
||
|
||
| Symptom | Meaning | Recovery |
|
||
|---|---|---|
|
||
| `/papi info iris` has no expansion | PlaceholderAPI was unavailable when Iris scheduled registration | Perform a full restart with both plugins installed; `/papi reload` alone does not trigger Iris registration |
|
||
| Placeholder remains literal | Path is unknown or uses a removed pre-2.0 name | Copy an exact path from `/papi info iris` or the full table below |
|
||
| World value is `---` | No online player context, player is outside Iris, or terrain service has no reading | Parse as a named online player after entering a loaded Iris world |
|
||
| `world.available` is true but biome lags movement | Player view cache is within its one-second TTL | Wait one second or trigger an immediate publish by teleport/world change before diagnosing the consumer |
|
||
| Pregen value is `---` | No global job snapshot is active | Start a job and wait for its first event; use `pregen.available` as the guard in board templates |
|
||
| Scoreboard adds `%` twice | `pregen.percent` deliberately omits the suffix | Add one literal `%` in the consumer format, not in the placeholder |
|
||
|
||
## 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.
|