RTP Roadmap¶
Scope: This roadmap tracks known shortfalls in the current release and the concrete work planned
to address them, plus forward-looking features that are not driven by a known caveat. Version
anchor: 3.1.2 (see REQUIREMENTS.md).
Each item is expressed as a checklist line so completed work can be struck through with the commit/ADR that closed it.
Tier ordering reflects priority, not chronology:
- Tier 0 — must-ship items before
3.0.0loses the-beta.1tag. (All Tier 0 items complete;3.0.0shipped.) - Tier 1 — directly narrows a caveat currently documented in
docs/publishing/FRONT_PAGE.mdordocs/admin/. - Tier 2 — new capability that earns a
3.1.0/3.1.xrelease note. - Tier 3 — polish, long-tail, and infrastructure.
Tier 0 — Release blockers for 3.0.0 final¶
- [x] ~~Record current-release demo footage. The "Historical Demonstrations" section on the
front page is self-labelled as dated. Produce two ≤30s clips on
3.0.0-beta.1showing (a) the Anvil pre-filter's effect on MSPT under Spigot, (b) queue saturation and per-player isolation on Folia. Replace the YouTube IDs indocs/FRONT_PAGE.bbcodeand retitle the section back to "Performance Proofs & Demos".~~ - [x] ~~Close out every
@Ignored/@Disabledtest. Per project guidelines, releases must not ship with muted tests. Auditrtp-core, all platform adapters, andrtp-pluginbefore tagging.~~ - [x] ~~Freeze the ADR set for 3.0.0. Any architectural work started after
beta.1either lands before the final tag or is deferred to a3.1.0ADR file. Mixed-state ADRs confuse external reviewers reading the repo top-down.~~ - [x] ~~
CHANGELOG.mdKeep-A-Changelog pass. The3.0.0entry should read as a release announcement, not a git log — grouped by Added / Changed / Fixed / Removed with operator-visible framing.~~
Tier 1 — Caveat mitigations¶
Each subsection below matches a caveat that the front page currently admits. The goal for each is to convert the caveat from a trust claim ("bounded in practice") to an observable one ("here is the number, bound it yourself").
1.A — Spigot fallback: one on-tick getChunkAt¶
The Anvil pre-filter falls through to a live load only when the probe returns UNKNOWN (no region
file, unsupported data version, decode error, or un-populated chunk). On vanilla Spigot this costs
one on-tick chunk load per fallback.
- [x] ~~Document un-populated-chunk warming as the operator remedy. The
REQ-RTP-F-012world-scan lifecycle (start/pause/resume/reset/cancel) populates every candidate on disk and collapses the fallback to near-zero for warmed regions. Write this up indocs/admin/QUICK_START.mdas the recommended cold-start workflow.~~ - [x] ~~Add a
--until-populatedconvenience flag to the admin scan command (if not already present) so the cold-start workflow is one command, not a cron job.~~ - [x] ~~Tick-budget telemetry. Surface a rolling counter — fallbacks/minute and total μs spent
on the main thread per fallback — via
/rtp test fulland a dedicated stats subcommand. ASpigotPrefilterStatscompanion toMemoryTrackeris the likely shape.~~ - [x] ~~Optional "reject on unknown" mode. Config flag (default off) that skips candidates when
the probe returns
UNKNOWNinstead of paying the on-tick fallback. For operators who prefer a guaranteed zero main-thread cost over maximum throughput.~~
1.B — Folia fallback: one Region-Scheduler hop¶
On Folia, a confirmed candidate that the Anvil probe could not resolve pays one Region-Scheduler hop to the authoritative live load.
- [x] ~~Measure the hop cost. Add a traceable timing test (
FoliaRegionHopTimingTest, traceable toREQ-RTP-NF-002) that captures nanoseconds between Anvil-probe-complete and Region-Scheduler-ready on a representative candidate. Publish the p50/p95 numbers in the release notes; until then the caveat is unquantified.~~ - [x] ~~Investigate hop amortization. Can consecutive candidates within the same region share a single Region-Scheduler entry? If yes, implement and document with an ADR. If no, write the ADR explaining why — closing the question is as valuable as fixing it.~~
1.C — Un-populated chunks fall through to live load¶
- [x] ~~Regression test: live-load safety net cannot re-admit a prior reject. Assert that a chunk the Anvil probe rejected on populated data is never subsequently accepted by the live-load path. Must hold under Folia region-stealing and concurrent player teleports.~~
- [x] ~~Failure attribution bucket. Extend the
FailTypestaxonomy (or the equivalent telemetry surface) withunpopulatedFallthroughso/rtp test fullcan report its frequency distinctly from other fallbacks. Currently invisible.~~
1.D — Fabric: supported (stable as of 2026-05-26)¶
Fabric (rtp-fabric) is a first-class, in-scope, stable platform. The three standing blockers
documented in prior revisions of this section are resolved; the front page and REQUIREMENTS.md section 0
should be updated to reflect that Fabric is supported, not out of scope.
- [x] ~~Resolve the three standing blockers in
MULTI_PLATFORM_PLAN.md:~~ - [x] ~~S-005 violation in
FabricRTPWorld.getChunkAt.~~ —getChunkAtreturnsCompletableFuture<Long>and routes through an async chunk-load path; S-005 compliant. - [x] ~~Null stub in
FabricServerAccessor.getLocationGenerator.~~ — fully wired; throwsIllegalStateExceptionperREQ-RTP-S-006when called pre-init. - [x] ~~Unresolved Loom dependency.~~ — resolved via the obf/unobf carrier split (rtp-fabric-ADR-009).
- [x] ~~Update front-page / requirements wording.
docs/FRONT_PAGE.bbcodeandREQUIREMENTS.md section 0 Out of Scopestill describe Fabric as unsupported; reframe to first-class supported platform.~~ - [x] ~~Re-run the
rtp-apiinterface-sufficiency analysis and record the result as an ADR (April 2026 gap analysis concluded interfaces are sufficient; promote the finding fromMULTI_PLATFORM_PLAN.mdto an Accepted ADR).~~
1.E — Unsourced statistics on the front page¶
The Spatial Memory paragraph now cites a concrete ~45% Overworld-safe figure from a local profiling pass on a vanilla 1.21 seed set; Nether and End ratios remain qualitative ("dominated by lava seas", "almost entirely void"). The caveat has narrowed from "no numbers anywhere" to "one number, not yet reproducible by readers".
- [x] ~~Publish the reference profiling run in
docs/admin/BENCHMARKS.md— seed list, sample size, methodology, and per-dimension safe-fraction columns for Overworld / Nether / End. Until this exists, the ~45% figure is an author claim, not a reproducible one.~~ - [x] ~~Extend the existing bStats integration with custom charts. Default metrics are already
wired (bStats ID
30865, now sent by the in-treebstats-apiclient per bstats-api-ADR-001); what is missing isaddCustomChart(...)for RTP-specific aggregates — platform split, region count, queue depth, and observed safe-fraction histograms per dimension.~~ - [x] ~~Replace the qualitative Nether/End phrasing on the front page with measured figures once either path above lands.~~
Tier 2 — Upcoming features (not caveat-driven)¶
- [x] ~~Multi-entity subspace teleport addon (
LeafRTPGroupAddon).~~ Superseded and folded into the declarative scripted actions architecture (ADR-093) and implemented viaLeafRTPActionAddon(definitions/actions/*.yml). Replaces separate search paths for party, duel, skirmish, and pursuit with a single relative subspace shape that captures spatial memory from the parent region for O(1) candidate selection. - [x] ~~Region-confinement (tether) addon (
LeafRTPTetherAddon).~~ Superseded and folded into the active scripted actions and confinement architecture (ADR-093, ADR-095). Confinement is actively functional via the action engine (confinement.enabled: true, tether pull-back,MemoryShape.containsboundary enforcement) usingPlayerMoveDispatcher(ADR-075); the stand-alone addon experiment is abandoned. - [ ] Visual region creation & interactive cartography bridges (ADR-099). Eliminates manual coordinate entry for region setup via three zero-server primitives:
- In-game selection bridge (
SelectionBridgeSPI) hooking existing WorldEdit/FAWE (Polygonal2DRegion,CuboidRegion) across Paper/Folia/Fabric/NeoForge, and FTB Chunks claim contours on modded (/rtp region fromselection <name>). - Zero-backend web map vector drawing tool (
leaf-rtp-map-tool.js) generating one-click clipboard YAML snippets and in-game commands. - Cartography map item visual inspection (
maps-apiRegionBoundaryRenderervia/rtp map create region_boundary). - [ ] External web map raster layers (ADR-086). Zero-chunk-load on-demand raster heatmaps, coverage layers, and vector polygon overlays for Pl3xMap, BlueMap, and Dynmap.
- [ ] Seamless loading-screen-free Velocity transfers (rtp-proxy-ADR-021).
Eliminate the vanilla Minecraft "Downloading terrain..." loading screen during cross-server transfers by swapping backend Netty pipes in
PLAYmode and streaming pre-loaded chunks before origin teardown. - [ ] Adaptive tick-budget governor (ADR-087). Dynamic backpressure regulation and per-tick dispatch limits across Folia's regional ticking threads.
- [x] ~~Platform-neutral player-move event SPI (core, D-005 gated).~~ Complete:
PlayerMoveDispatcherandPlayerMoveEventlanded inrtp-api, exposed viaRTPAPI.playerMoveEventsandRTPAPI.watchPlayerMove(...)with per-player subscription scaling and comprehensive unit tests (PlayerMoveDispatcherTest). (ADR-075). - [ ] Investigate: spectator-during-wait (deferred, low priority). Some competitor plugins place a player in spectator mode while a destination is resolved. This is a poor architectural fit here - the default model is search-and-serve-else-queue (destinations are prepared ahead of time, so there is no command-then-search "limbo" window to paper over) - and forced spectator carries real risk (fall-through, exploit windows, gamemode restoration on disconnect/crash). Kept as a future investigation only; if pursued at all it belongs as an optional effect, not a core behavior.
- [x] ~~Config-file organization + discoverability (operator feedback).~~ Complete:
Delivered and superseded by ADR-076 (consolidated
7-object root layout with
definitions/andadvanced/doors), ADR-071 (relevance ordering and per-file enums), ADR-073 (@configdefaults inheritance), and the guided/rtp admin setupwizard suite. - [x] ~~Order settings by common relevance.~~ Everyday teleport knobs sort to the top of root files.
- [x] ~~Group all teleportation-related settings in one place.~~ Consolidated via root files and
definitions/. - [x] ~~
messages.ymlreorganization.~~ Split intoadvanced/messages/{commands, network, placeholders, player, system}.ymlwith full 12-locale co-located dotfile rename maps and greenLocaleParityTestin CI. - [x] ~~Constraints & migration.~~ Non-destructive read-legacy-warn migration, dotfile rename maps (ADR-076), and setup wizard.
- [x] ~~World-scan UX polish. The admin lifecycle exists; operator affordances around it do not.
Concretely: progress indication (both console and in-game bossbar), resume-across-restart
semantics, and a per-region "warmth report" export. This is what converts the feature from
implemented to sellable.~~ Resolved: the boss-bar progress indicator landed, resume-across-restart
was already shipped (
ScanTask.save/loadProgress+Regionwiring), and the "warmth report" need is covered by the delivered learned-state inspector. See the sub-items below. - [x] ~~In-game boss-bar progress indicator. A
BossBar(green, solid) is shown to all players with thertp.scanpermission while any world scan is active. The bar fills from 0 to 1 aslatestAbsolutePos / latestAbsoluteTotalacross all activeScanTasks; the title is the configurablescanBossBarkey inmessages.yml(same placeholders asscanStatus:[scan_regions],[scan_chunks],[scan_totalChunks],[scan_cps],[scan_landPercentage],[scan_eta]). SetscanBossBarto an empty string to disable. Bars are removed automatically when the scan finishes or is cancelled. Implemented inScanTaskProcessing(Bukkit-family adapter); Fabric uses the existing console/chat path.~~ - [x] ~~Resume-across-restart semantics.~~ Already shipped.
ScanTask.save()persists scan progress (scanIter,spatialResolution,currentOffset,isFine,scanPhase; transientGENSCANcollapsed toPRESCANon disk so a resumed scan skips the chunk-generation pre-pass) todatabase/regionData/<region>_<cacheKey>.scan, andScanTask.loadProgress()reads it back.Regionreschedules a partial scan at construction and again inrebindWorld(...)when0 < iter < range; thecacheKey()suffix (ADR-022) invalidates the resume on a config/seed change, and theMemoryShapebad-location bitmap survives the restart alongside it. - [ ] ~~Per-region "warmth report" export.~~ Dropped: the operator-facing "how warmed-up is this
region" need is already met by the delivered learned-state inspector on
/rtp info region:<name>([memCoveragePct],[memBadPct],[memBadCount],[memTopCause],[memTopCausePct]) plus the auto-exporteddatabase/regionData/debug/<region>.jsonscan dump. No distinct "warmth report" artifact was ever specified; reopen with a concrete definition (e.g. per-region L1/L2/L3 queue depths + coverage % to JSON) if a separate export is actually wanted. - [x] ~~Persistent learned-state inspector. A
/rtp memory dump <region>subcommand producing a human-readable summary — flagged-bad sector count, coverage %, age of oldest entry, last-write timestamp. The H2/SQLite persistence is a front-page promise; inspection is the operator's confirmation.~~ Delivered as a per-region learned-state summary on the existing/rtp info region:<name>surface rather than a redundant dump command (raw runs are already auto-exported todatabase/regionData/debug/<region>.jsonon every scan).MemoryShape.learnedStateSummary()feeds newregionInfoplaceholders[memCoveragePct],[memBadPct],[memBadCount],[memTopCause],[memTopCausePct]; documented indocs/admin/COMMANDS.md. - [x] ~~(v3.2) Region-sampled scan: region-major traversal + Hilbert-within-region.~~ Superseded by the dual-layer spiral-addressed Hilbert model (ADR-085, ADR-088, CircleOptimizedDualLayer, SquareOptimizedDualLayer, SegmentedKeyRunTable). Compacts run tables and guarantees spatial cache locality without disrupting 1D spiral bijections.
- [x] ~~Anvil PRESCAN accuracy measurement → conditional FULLSCAN retirement.~~ Retired:
the scan path in
ScanTaskhas been streamlined into a single hybrid pass. Generated chunks are probed off-tick via Anvil (.mca, or an addon-registered format), while ungenerated chunks route to targeted on-demand generation without globally switching the scan phase or requiring an unconditional Pass 2 FULLSCAN sweep. S-001 safety remains authoritatively enforced at teleport selection time. - [ ] Chunky-driven generation pass for
/rtp scan(near-term focus, D-005 + ADR gated). Today the full-load sub-step of a scan forces generation on an Anvil miss one chunk at a time through the server chunk manager (ScanTask.runFullLoadPath→RTPWorld.getOrLoadChunk). When Chunky (or any bulk pre-generator) is present, drive/sequence it to lay the region's chunks down on disk first, then let scan walk the already-written.mcathrough the cheap off-tick Anvil PRESCAN path instead of paying per-chunk worldgen stalls. The throughput win comes entirely from the pre-generator's own speed (a faster — incl. future GPU/CPU-accelerated — Chunky build makes it strictly better); the RTP-side value is UX/orchestration, not raw generation speed. Design constraints: - Soft-depend only, no hard dependency. Reuse the existing Chunky integration seam
(
ChunkyChecker/ChunkyRTPShape) and route throughRTPHooksper ADR-026; degrade cleanly to the current generate-as-you-go full load when Chunky is absent. Do not put inline pre-generator calls in the scan pipeline. - One command surface. Let an admin kick off + size a Chunky pregen for a region and then run
the scan consistently sized to it, instead of juggling
/chunkyand/rtp scanseparately (progress display, auto-sizing scan to the pregen radius). - Honest framing. Advertise as a convenience/sequencing hook, never as "Chunky makes scan faster" — the speedup is a property of the installed Chunky build, available with or without the hook.
- Gating. Crosses the external-integration surface and module boundaries → D-005 proposal + dedicated ADR (sibling to ADR-026) before implementation.
- [ ] Accelerated Anvil verification compute (exploration, D-005 + ADR gated). Offload the bulk
biome/material rejection sweep over decoded
.mcatiles to a high-throughput compute backend. The backend is deliberately left open — a native SIMD/vectorized pass, a GPU/OpenCL kernel, or an external accelerated generator/verifier (e.g. a standalone Rust worldgen+verify engine, the kind of project reportedly hitting ~17k cps on CPU alone) are all candidates; the headline is "go faster", not "use a GPU". This does not require LeafRTP to write a chunk generator: worldgen stays the server's / Chunky's job, and this only accelerates LeafRTP's own off-tick verification pass over already-written region files. Note that profiling shows off-tick scanning is bound by storage I/O and decompression; PCIe bus transmission overhead makes GPU/OpenCL offload economically unfavorable compared to host-side CPU vectorization (AVX-512/SIMD). Boundaries and gating: - The NBT/
.mcadecode stays on the CPU (branchy, I/O-bound; already parallelized acrossAnvilIoPool); only the decoded arrays are handed to the accelerated backend. - FULLSCAN / live-load paths cannot move (S-005 threading + server chunk manager).
- Any accelerated path is a new subsystem with its own pool/contract; a GPU or external-process backend additionally introduces a hard external dependency surface (OpenCL runtime/driver, or an out-of-process engine + IPC) that must degrade gracefully to the current CPU path when absent — D-005 proposal + a dedicated ADR (sibling to ADR-016) required before any implementation.
- Profile first: only worthwhile if predicate evaluation (not NBT decode, not disk) is shown to be the bottleneck on large scans. The backend choice should follow that profile (a native vectorized pass may close the gap with none of the GPU/IPC dependency cost).
- [ ] Safety-list grammar expansion. The token grammar shipped in
3.0.0-beta.1is the foundation; follow-ups: - [x] ~~Tag-group composition with set subtraction (
#minecraft:slabs - OAK_SLAB).~~ — ADR-017 amendment (v3.3.0). - [x] ~~Numeric range predicates (
[level>=5]) for fluids and light levels.~~ — ADR-017 amendment (2026-05-30); operators>=/<=/>/<with integer bounds, fail-open on absent/non-numeric live values. - [ ] Hot-reload on
safety.ymlfile edit (currently requires/rtp reload). - [ ] Relative ground-distance predicate (
#minecraft:leaves[_groundDistance>3]) so ground-level leaves/roots stay safe while tall-tree canopy is rejected. Design ADR accepted as Proposed: ADR-059 — a synthetic, pipeline-injected_groundDistanceblock-state property consumed by the numeric-range grammar above; lazily computed (zero cost when unused), bounded probe (safety.yml::groundDistanceMaxProbe), fail-open, full-edition only. - [x] ~~Claim-plugin integration audit.~~ Complete: Published
docs/admin/CLAIM_PLUGIN_COMPATIBILITY.mdwith complete compatibility and version matrices across all 18 claim checkers (16 Bukkit/Folia claim checkers, boundary providers, and 2 mod-side protection integrations: OPAC, FTB Chunks), verifying fail-closed execution, reflection safety, and Folia threading contracts. - [ ] CI matrix across platforms. The Jenkinsfile builds, but
rtp test fullshould run against Spigot + Paper + Folia + Fabric in parallel matrix form, even with mock servers where necessary. This is the step that convertsTRACEABILITY.mdfrom "documented" to "continuously enforced". - [x] ~~Addon-developer quickstart.
docs/FOR_ADDON_DEVELOPERS.mdis linked from the front page, but a one-page "register a custom shape in 20 lines" tutorial is the document that actually drives third-party adoption.~~ Addeddocs/ADDON_QUICKSTART.md(Gradle dep +ServiceLoaderdescriptor +RTPAddon.onLoad()callingRTP.addShape(...)), linked fromFOR_ADDON_DEVELOPERS.md. - [x] ~~Region-specific schematic (
.schem) support. Per-region arrival structures (small platform, lobby pad, arrival shrine) pasted at the chosenRTPLocationfrom a.schemfile.~~ Design ADR accepted: ADR-058 (Amendment 1, 2026-05-30: single cross-platform.schemformat decoded in-house; native block-state paste; no WorldEdit hard-dependency; the.nbt-on-Fabric split is withdrawn). Foundation landed: the platform-neutralSchematicPasterSPI (SchematicPaster,LoadedSchematic,SchematicSource,PasteOptions,PasteAnchor,PasteResult,NoOpSchematicPaster) plus the swappable per-adaptersetSchematicPaster/getSchematicPasterholder (mirroringsetBiomeGetter) onBukkitRTPWorld,FoliaRTPWorld,FabricRTPWorld. Decode + plan landed (Amendment 1): the dependency-freeSpongeSchematicDecoder(Sponge v2/v3) +DecodedSchematic+BlockEntityData, the platform-neutralSchematicPlacementPlanner(anchor math + air-skip),AbstractFileSchematicPasterbase, and the sharedio.github.dailystruggle.rtp.api.block.BlockStateStringtokenizer extracted fromSafetyTokenParser(ADR-017); pinned bySpongeSchematicDecoderTest+SkyblockIslandFixtureTestagainst the committedskyblock_island.schem. Bukkit-family native paster landed:BukkitSchematicPaster(nativeBukkit.createBlockData, S-004 audited) installed at bootstrap viaAbstractServerAccessor(inert until core invokes it). Core wiring landed (no config knob - the presence of a file is the knob):RegionSchematicServiceresolves<pluginDir>/schematics/<region>.schem(or.schematic) by file presence, andTeleportPipelineTaskloads/decodes it off the region thread (runLoad) then pastes it atSURFACE_CENTERon the arrival region's owning thread (runTeleport, dispatched viaRTP.scheduler.runTask(location, ...)for Folia region-safety) in place of the emergency platform, falling back to the platform whenever nothing is pasted (S-004); core reaches the active paster through a new instance accessorRTPWorld.schematicPaster()(default no-op, overridden onBukkitRTPWorld/FoliaRTPWorld/FabricRTPWorld). Verified end-to-end byRegionSchematicServiceTestagainst the committedskyblock_island.schem. Also landed: the Folia native paster (BukkitSchematicPasterinstalled byAbstractFoliaServerAccessor; the support gate keys on the underlyingorg.bukkit.WorldsoFoliaRTPWorldis accepted); container block-entity restore (chest inventories rebuilt from the decodedItemsNBT straight into the live tile); theSURFACE_CENTERanchor (drops the structure to a standable surface in one pass, no re-paste, keeping players inside roofed structures); and a decode cache inAbstractFileSchematicPaster(each.schemdecoded once, cleared on/rtp reload). Deferred follow-ups (tracked separately): the footprint claim check (S-003) ahead of the paste; non-container block-entity NBT (sign text, custom data - still placed as empty blocks, audited); and adocs/admin/page plus traceability rows for the paste-on-region-thread regression test. The Fabric native paster landed in3.1.2via the platform-neutralWorldBlockSchematicPaster(rtp-api) drivingRTPWorld.setBlocks/restoreBlockEntities; the deobf 26.x Fabric carriers implementsetBlocksviaBlockStateParser+ServerLevel.setBlockon the server thread (S-005-clean). The formerBukkitSchematicPasterwas removed and collapsed onto the same shared translator (BukkitBlockWriter). - [x] ~~Optional PvP / combat-tag check. Optional pre-flight check that refuses (or delays)
/rtpwhen the requesting player has recently taken or dealt PvP damage, so players cannot/rtpto escape mid-fight. Off by default.~~ Delivered via ADR-055: aPvPCombatStateRegistrySPI +PvPCombatActioninrtp-api, the nativeNativePvPCombatTracker, and thePvPGateevaluator inrtp-core, gated bysafety.ymlknobs (pvpCheckEnableddefault false,pvpCombatTagSeconds,pvpOnCombatDENY/DELAY, and a combat-state source preference) and the configurablemessages.yml#pvpInCombat(REQ-RTP-F-013, with full locale parity). The gate is consulted at the/rtppre-dispatch surface (RTPCmd.compute) and again inTeleportPipelineTaskahead of enrolment, fails open, and emits an S-004 audit on refusal. Soft-depend adapters for PvPManager / CombatLogX / Simple Combat Log (PvPIntegrations+ per-plugin checkers) with a catalog row inEXTERNAL_HOOKS.mdper ADR-026. Tests:PvPGateTest,NativePvPCombatTrackerTest,RTPCmdPvPGateTest,PvPCombatAdapterTest. -
[x] ~~NeoForge platform (
rtp-neoforge). First-class NeoForge support as a fifth platform family.~~ Complete as of 2026-06-13 — NeoForge is a complete, runtime-functional, first-class platform. Phase N0 (scope unlock, D-005 approval, ADR-033, rtp-neoforge-ADR-001) complete 2026-06-01. Phase N1 module skeleton (rtp-neoforge-common+rtp-neoforge-v1_21_R1,RTPNeoForgeMod,NeoForgeScheduler,NeoForgeCommandRegistrar) landed 2026-06-02. All Phase N2 steps (NA async chunk load, NBgetLocationGenerator, NC scheduler, ND database, NE event bridge, NE-perf anvil parity, NF permissions, NG Brigadier command tree, NH stabilization + runtime smoke, NI book-menu + chat-prompt, NJ network-mode backend parity incl. live boot + reservation-token redemption, NK maps API + metrics binding + backend-state sampler) and Phase N3 (docs, traceability, beta release) are complete. SeeMULTI_PLATFORM_PLAN.mdPhase 4 for the full step breakdown. -
[ ] Rich book-menu drawing via resource-pack soft-dependencies. The written-book menu renderer (Paper's
BookMenuRenderer, Fabric'sFabricBookMenuRendereron the 1.21+ / deobf 26.x carriers) currently renders text, colour, and click/hover only. Native books cannot draw images; plugins like vBestiary achieve "images in a book" purely through resource-pack glyph fonts supplied by ItemsAdder / Nexo / Oraxen. Add optional soft-dependencies on those glyph providers and, when one is detected at runtime, conditionally substitute their custom-font glyphs (icons, dividers, region thumbnails) into the book menu fragments; when none is present, fall back to the current text-and-numbered rendering with no behaviour change. Scope notes: soft-depend only (no hard dependency, no bundled assets), catalog each provider inEXTERNAL_HOOKS.mdper ADR-026, and route detection throughRTPHooksso the chat renderer and unsupported carriers degrade cleanly. Fabric 1.20.x stays on the chat renderer (book renderer off there for performance reasons) and therefore opts out of this feature. - [x] ~~Claim/faction-anchored RTP (
/rtp faction-style).~~ Shipped: ClaimBoundary,ClaimBoundaryProvider, andClaimBoundaryRegistrySPI inrtp-apiandDefaultRTPHooks.ClaimAnchoredRegionTrackerinrtp-corewith pinned center stability within claim boundaries, recomputation cooldowns, and cross-region hazard memory ingestion intoSubspaceShape.AnchorSource.claimBoundary(...)andSubspaceAnchorResolverintegration.ActionManagerautomated claim boundary resolution foranchor: faction/anchor: claimboundary.LeafRTPClaimAddonv1.1.0 boundary providers for Towny Advanced, GriefPrevention, and SaberFactions/FactionsUUID.- [x] ~~Cross-platform destination-selector seam + bundled default menu.~~ Shipped:
SelectionMenuBuilderprovides cross-platform curated selection pages (/rtp menu world|region|biome|prefab) inrtp-coredelegating cleanly without inventory GUIs. - [ ] BetterRTP API compatibility shim (absorb the inventory-GUI menu ecosystem). Inventory-GUI menu plugins (which capture more admin attention than book menus) are commonly built against BetterRTP. Rather than rebuild that ecosystem, RTP can register a stand-in for BetterRTP's public surface so those menu plugins transparently drive RTP. Design constraints:
- Absent-only, default off. Register only when BetterRTP is not installed/enabled
(
!isPluginEnabled("BetterRTP")) to avoid command/service collisions; stand down completely if the real plugin is present. Never shadow BetterRTP. - Thin adapter, correct module. Translate BetterRTP's public entry points (its
/rtp [player] [world]command forms and any Bukkit-Services API menu plugins call) into our existingRTPCmd/ selection path. Lives inrtp-plugin(Bukkit-family) or an addon, never inrtp-core/rtp-api. - Pin a documented subset. Emulate only the API surface menu plugins actually call (player / world targeting, biome / price flags), not all of BetterRTP; document the emulated version.
- Permissions + honesty. Map
betterrtp.*permission checks onto our permission model (or honor both); be explicit in logs/metrics that RTP is serving the request, not BetterRTP. - Catalog + ADR. Third-party-accommodating surface: catalog in
EXTERNAL_HOOKS.mdper ADR-026; emulating a competitor's API is a cross-module, D-005-gated decision requiring a dedicated ADR before implementation. Complements (does not replace) the selector seam + bundled menu item above. - [x] ~~BetterRTP parity: cooldown usage cap (
LockAfterequivalent).~~ Shipped:UsageCapTracker,TeleportLimitStore,ConfigKeys.lockAfterUses, andClearLimitCmd. - [x] ~~BetterRTP parity: persist RTP destination as a permanent spawn anchor (
SetAsRespawnequivalent).~~ Shipped:ConfigKeys.setAsRespawn. - [x] ~~BetterRTP parity: widen built-in claim-plugin coverage.~~ Complete: LeafRTP ships 16
claim integrations in
addons/LeafRTPClaimAddon(ClaimIntegrations: SaberFactions, FactionsBridge, GriefDefender, GriefPrevention, Lands, RedProtect, Residence, CrashClaim, HuskClaims, HuskTowns, PlotSquared, KingdomsX, TownyAdvanced, WorldGuard, UltimateClaims, MinePlots) with bidirectionalClaimBoundaryRegistryanchor support. - [ ] Locale coverage expansion (close the gap with BetterRTP, weighted by real server traffic).
RTP ships 12 parity-enforced locales (
en,de,es,fr,it,ja,ko,nl,pl,pt,ru,zh) plus thecatnovelty dialect, against BetterRTP's ~21 community-contributed locales. RTP's depth advantages stand (re-keying config keys via<file>.lang.ymlrename maps across every config file, and CI-enforced parity viaLocaleParityTest), so this item is purely about breadth. Weighting candidate languages by two observed "Server Location" distributions (rather than raw count or global speaker totals) shows RTP already covers ~70-82% of measurable server traffic with its 12 locales, and the whole gap to BetterRTP (4-6 points) is driven by the same short list: - Add the highest-value missing locales:
vi(Vietnamese),tr(Turkish),cs(Czech), andfi(Finnish - the single largest language neither plugin ships, ~3.4% of servers in one sampled distribution). Lower-priority follow-ups:id(Indonesian),th(Thai), and splittingzhinto Simplified/Traditional if demand warrants. - Caveat (do not over-trust server-location data): location charts measure where the server
is hosted, not where players/admins are. Remote/cloud-hosted communities (Korea is the clearest
example - large player base, frequently hosted in Singapore/Japan/US hubs or folded into "Other")
are systematically undercounted, so
koand similar locales carry latent value the charts cannot see. Treat the per-distribution weighting as a floor on a language's value, not the value itself; do not drop or deprioritize an existing locale on the strength of a location chart alone. - Each new locale follows the co-located dotfile rename-map workflow (ADR-076), must pass
LocaleParityTest, and should prefer native-speaker review over machine translation perTRANSLATION_GUIDE.md. No architecture change; pure content + parity work. - [x] Foreign config importer (
rtp config import <plugin>, one-shot migration aid). Design settled in ADR-066 (Accepted, D-005). Lower the switching cost for operators moving off a competitor by translating its on-disk config into RTP's config tree. This is a migration aid, not the live API shim above: it reads the competitor's YAML once, writes our files, and then RTP owns the config. A genericConfigImporterseam (inrtp-core, since file-only reading via the in-houseRtpYamlConfigparser is platform-neutral) with BetterRTP as the first source and EzRTP / JakesRTP to follow;rtp config importwith no argument auto-detects when exactly one source's files are present. Design constraints: - Explicit, non-destructive, dry-run-first. Trigger via an explicit
rtp config import <plugin>(never silent auto-overwrite on startup);rtp config importwith no argument auto-detects when exactly one source is present, else lists candidates. Default to a preview that lists every mapped key, every approximation, every deferred mapping, and every dropped key; only write on aconfirmsecond phase (parallel tortp prefabapply/confirm). Back up any RTP file we touch (reuse theprefab<file>.yml.bak.<epochMillis>mechanism). Refuse to clobber a customized RTP config without confirmation. - No hard dependency. Parse the competitor's YAML straight off disk via the in-house
RtpYamlConfigparser; do not link competitor classes or soft-depend on the plugin being installed. Because file-only reading is platform-neutral, theConfigImporterseam lives inrtp-core. Target each competitor's latest config schema. - Honest, lossy translation. Competitors and RTP model regions differently; classify each key
MAPPED/APPROXIMATED/DEFERRED/DROPPEDand log every approximation rather than implying parity. Known clean (MAPPED) mappings: BetterRTPShape: square→ RTPSQUAREshape (RTP ships both square and circle); arbitrary outlines →Polygon(ADR-034) vertices (APPROXIMATED);CenterX/CenterZ,MaxRadius/MinRadius→ region center + radius/minRadius;Cooldown/Delay→teleportCooldown/teleportDelay(seconds, 1:1);MaxAttempts→performance.yml#maxAttempts(1:1, same default 32);PreloadRadius→performance.yml#viewDistanceSelect/viewDistanceTeleport; per-world enable list → worlds/regions;Price/economy →economy.yml; biome/block blocklists →safety.ymlfilters. - Parity-dependent keys (
DEFERRED, not dropped).SetAsRespawn(persistent spawn anchor) andLockAfter(cooldown usage cap) map onto RTP parity features that are planned but not yet landed (their own ROADMAP items above). Until each target ships, the importer reports the key asDEFERRED("recognized, target not yet available"); when the parity feature lands, flip its row fromDEFERREDtoMAPPEDin the same change. -
D-005 + ADR. Design settled in ADR-066 (Proposed): generic
ConfigImporterseam with BetterRTP first, EzRTP / JakesRTP to follow. -
[x] ~~3D Archimedean helix coordinate generator (1.18+ vertical biome targeting).~~ Declined / Redundant: Closed as redundant. Mathematical analysis proved that coupling a vertical pitch term $y_n$ to the 1D spiral index segments biomes into thin helical ribbons (causing coverage loss), whereas stacked $[minY, maxY]$ regions provide full horizontal coverage at zero architectural complexity. Vertical interval skipping without chunk loads is already cleanly handled off-tick by the Anvil probe fast-path (
VerticalAdjustor.adjustFromProbe). - [x] ~~"Virtual Rift" warmup effects addon (
addons/LeafRTPRiftAddon).~~ Complete: Shipped as a standalone, platform-neutral reference addon inaddons/LeafRTPRiftAddon(RTPRiftAddon,RiftEffect). Registers theRIFTeffect prototype (RIFT.<radius>.<seconds>) withEffectFactoryineffects-api, installing an out-of-the-boxeffects/rift.ymldemo group. Carves client-side fake air, draws a portal gateway lower shell and obsidian catch-bowl, and snaps the world back on teleport completion or cancellation. - [ ] Adaptive queue demand scaler (in-memory, zero-config). Track the rate of change of queue
consumption (dQ/dt) and player connection frequency in-memory using an exponentially-weighted
moving average. When a surge is detected, dynamically scale up
AnvilIoPool's thread count (viaThreadPoolExecutor.setMaximumPoolSize) and expandbacklogCacheCapon-the-fly; throttle back when command velocity returns to baseline. No new dependencies -AnvilIoPoolis already a documented carve-out from the raw-executor prohibition (ADR-016) andMetricsBindingalready captures queue depth and TPS data the scaler would consume. The scaler reads fromRTP.metricsand writes only to the pool size and the existingbacklogCacheCapknob; all periodic work routes throughRTP.scheduler(no raw threads). Requires a D-005 proposal before implementation; the EWMA window and floor/ceiling pool sizes must be configurable with safe defaults. - [ ] LeafRTP engine workspace setup panel (ADR-104).
Append a visual interactive Setup Wizard panel to the browser-based LeafRTP Web Workspace / ephemeral editor
(
docs/editor/) that achieves full feature and workflow parity with the in-game/rtp admin setupcommand wizard (ADR-038). Operators can configure first-run or ongoing server topologies through a guided multi-stage UI: - 5-Stage Setup Parity: Replicate stages 1–5 (Stage 1: World Topology single vs. multi-world auto-expansion; Stage 2: Gameplay Style templates survival / arena / skyblock / oneblock; Stage 3: Performance Profile low / high / folia-tuned; Stage 4: Addon & Effect toggles claim integrations, economy, and cinematic effects; Stage 5: Dry-Run Diff Preview & Atomic Apply).
- Prefab & Recipe Compilation: Compose user answers into the identical ordered sparse
Prefabrecipe overlay pipeline asSetupRecipe, rendering live cumulative deltas acrossperformance.yml,safety.yml, anddefinitions/regions/*.ymlin the editor's Staging Diff Inspector before commit. - Dual Commit Path: Support both direct WebSocket hot-apply and offline token-based command fallback (
/rtp editor apply token=<token>) with server-side validation against geometry invariants (ADR-034) and automated non-destructive.bakfile backups. - [ ] Shared spatial memory across servers. Let backends that serve the same world share what each one has learned about it (rejected segments and their causes, biome results) through the SQL / Redis backends, so a scan or a rejection on one server saves the others the same work. Only valid between servers whose world files match; the design must say how that is detected and how concurrent writes merge. Requires a D-005 proposal and an ADR before implementation. Until it ships, the front page shall not describe spatial memory as shareable.
Tier 3 — Polish and long tail¶
- [ ] Pre-release runtime verification of
/rtp back. Command implementation is landed inrtp-core(BackCmdwith unit coverage inBackCmdTest), but requires runtime verification across live platform adapters and multi-server devstack before release (origin coordinate toggling, cross-server network mode target return, permission gating onrtp.back, and cooldown tracking). - [ ] Standalone
rtp-anvilpublication. The module is genuinely reusable outside RTP (any plugin wanting off-tick region-file reads could depend on it). If pursued, add a Maven Central publish target and write the "why this lives alone" ADR. - [ ]
SECURITY.mdaudit before release traffic hits. Confirm contact address, disclosure window, and scope are all current. - [ ] Glossary hygiene. Now that Fabric is an in-scope, supported platform (see 1.D), audit
docs/dev/GLOSSARY.mdand the Multipurpose Terms table for platform-specific terms that now need disambiguation (Regionmeans different things on Folia and Fabric). - [ ]
README.mdshapes section refresh. Theuser-images.githubusercontent.comURLs for the shape-distribution plots are pinned to a legacy account hash; re-host in the repo's owndocs/img/to survive future GitHub UI changes. - [ ] Retire
.bakfiles after every release. Project policy is to keep.bakcopies during in-flight edits only; a release tag is a natural cleanup checkpoint.
How to update this document¶
- Completed items: do not delete the line. Strike it through and append the commit short-SHA or ADR number that closed it. This preserves the velocity signal.
- New caveats discovered between releases: add under the appropriate Tier 1 subsection and mirror
it in the Caveats or FAQ section of
docs/publishing/FRONT_PAGE.md(then rebuild withscripts/release/build_front_pages.py) as a plain, non-technical summary (no REQ-*, no ADR identifiers — those stay in this document). - Features requested by operators: land in Tier 2 with the requesting issue linked, or get explicitly declined with a one-line rationale.
- This file is the only TODO source of truth for release planning. Do not duplicate it into CHANGELOG or per-module requirements.