Skip to content

Modernize placeholder integration (PlaceholderAPI, component-native)#143

Merged
minoneer merged 9 commits into
masterfrom
modernize-placeholders
Jun 11, 2026
Merged

Modernize placeholder integration (PlaceholderAPI, component-native)#143
minoneer merged 9 commits into
masterfrom
modernize-placeholders

Conversation

@minoneer

Copy link
Copy Markdown
Member

Closes #134 (placeholder provider/consumer modernization; the chat-delivery follow-ups from that issue are tracked separately below).

Summary

Replaces the MVdW-era String placeholder pipeline with a component-native system, designed from scratch (spec-driven):

  • Core placeholder package: PlaceholderSource (the 26 island values as Adventure Components, any-thread contract), PlaceholderService (MiniMessage TagResolver composition — placeholders are tags now), PlaceholderIntegration SPI discovered via ServiceLoader.
  • <usb:KEY> tags in island/party chat formats, always available; unknown keys render literally without degrading the message. Legacy {usb_*} tokens in user configs migrate automatically (config v124).
  • New uSkyBlock-PAPI module (FAWE-style, shaded, me.clip isolated): bundles the uskyblock PlaceholderAPI expansion — all 26 placeholders as %uskyblock_*%, registered automatically, superseding the dormant eCloud expansion — and contributes the <papi:PLACEHOLDER> tag so other plugins' placeholders render in our chat formats (legacy-deserialized, never MiniMessage-parsed: injection-safe).
  • Caching redesigned: the uniform 20s cache is gone; only the genuinely expensive creature counts are snapshotted — per island, main-thread-confined, async callers get stale-or-pending. The old design ran main-thread-only entity scans on whatever thread hit a cache miss.
  • ChatLogic renders components end-to-end — the first sendLegacy call site removed; legacy output stays byte-identical (pinned by test).
  • Deleted: MVdW hook + dead be.maximvdw dependency and its dead repo (this makes the build cold-cache resolvable again — same rot that broke CI on Harden world loading against missing void generator #142), the {usb_*} regex engine, both flag-gated listeners (one was a no-op bug), the placeholder.* config flags.

Notes

  • 49 new unit tests; 263 total green across modules. E2E-verified on Paper 1.21.11 + PlaceholderAPI 2.12.2: expansion registers, config live-migrates 123→124, <usb:...>/<papi:...> resolve. The e2e caught (and this branch fixes) a lifecycle bug: integrations now enable in delayed-enable, after POSTWORLD plugins exist.
  • /usb reload re-registers the expansion; PAPI 2.12.2 replaces same-identifier internal expansions (verified against its bytecode), so no duplicate/stale registration.
  • Shares the Maven-repo-fix commit with Harden world loading against missing void generator #142 (dedupes on merge, either order).
  • Post-merge maintainer action: archive uSkyBlock-Expansion with a README pointer to the bundled expansion.
  • Follow-up (tracked in Modernize placeholder integration and move chat delivery to components #134's remaining scope): the other 8 sendLegacy call sites and the bukkit-utils command framework's legacy surface.

🤖 Generated with Claude Code

minoneer added 9 commits June 11, 2026 15:49
- Delete 9 legacy handler/placeholder classes and TextPlaceholderTest
- Add ConfigMigrationV124: rewrites {usb_*} tokens to <usb:*> tags in
  chat formats, drops `placeholder:` config section and placeholderCache key
- Update config.yml: remove placeholder section, bump version 123→124
- Remove RuntimeConfig.Placeholder record and Advanced.placeholderCacheSpec
- Swap Services.java PlaceholderModule→PlaceholderIntegrations
- Guard PlaceholderIntegrations.startup against bad service entries (try/catch)
- Remove MVdW compileOnly dep, catalog entries, and mvdw-software repo block
- Remove MVdWPlaceholderAPI from plugin.yml softdepend
- Fix positional record constructions in 5 test files + RuntimeConfigFactoryTest
- Fix alphabetical import order in SkyblockModule
uSkyBlock loads at STARTUP, so its onEnable runs before POSTWORLD
plugins like PlaceholderAPI have enabled - the isPluginEnabled gate
in PlaceholderIntegrations.startup could never pass when called from
Services.startup. Move the call to delayedEnable, which runs via the
Bukkit scheduler after the first tick, alongside the other third-party
plugin hooks. Covered by a ServiceLoader-backed regression test.
@minoneer

Copy link
Copy Markdown
Member Author

Live in-game verification completed on the dev server (Paper 1.21.11, PlaceholderAPI 2.12.2): island chat with format [L<usb:island_level>|R<papi:uskyblock_island_rank>] rendered [L1.9|R1] after /is level + /is top — confirming the internal <usb:...> tag, the full PAPI round-trip (<papi:...> → PAPI → bundled uskyblock expansion → back), the unpopulated-data fallbacks (0/N/A on a fresh island), and component-native chat delivery, all live.

@minoneer

Copy link
Copy Markdown
Member Author

Entity-count placeholders also verified live: /papi parse me %uskyblock_island_monsters% / %uskyblock_island_animals% returned correct live counts with the 10s snapshot TTL behaving as designed (stale value within the window, refreshed after).

@minoneer minoneer merged commit 64cbf28 into master Jun 11, 2026
1 check passed
@minoneer minoneer deleted the modernize-placeholders branch June 11, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modernize placeholder integration and move chat delivery to components

1 participant