
TrialChamberPro
Because Trial Chambers deserve better than being a "one and done" dungeon.
1.7K
20
TrialChamberPro 1.4.2-mc26
release1 мая 2026 г.This plugin version is compatible with Minecraft 26.X.X
1.4.2 - 2026-05-02
Fixed
//undono longer gets hijacked by TCP after a chamber generation. The previousUndoListenercancelled//undoat HIGHEST priority and demandedconfirm/cancelin chat — but the chat handler only cleared the pending state on cancel, leaving the per-playerlastentry forever. Once any chamber had been generated in the session, every subsequent//undo(even for unrelated WorldEdit edits made hours later, or by a moderator joining after the fact) was intercepted, the chat prompt fired, and the actual WorldEdit undo never ran. There was also no path to retry: cancelling re-armed the same intercept, and confirming only deleted the DB registration without rolling back the placed blocks. The whole interception model was wrong — chamber registration is a DB write, not a WorldEdit edit, so it doesn't belong on WE's undo stack to begin with. New behavior: TCP never cancels//undo. WorldEdit's stack is fully untouched, any depth, any time. A new passivePostUndoHintListenerobserves//undo(and/undo) at MONITOR priority without cancelling and, only if the player happens to be standing inside a registered chamber when they run undo, posts a one-line tip suggesting/tcp delete <name>to also clean up the registration. Generation now also emits a one-timechamber-created-rollback-tipimmediately afterchamber-createdso users learn the two-step rollback (//undofor blocks →/tcp deletefor registration) up front.UndoListener.ktandUndoTracker.ktdeleted.
Localization
messages.yml: removed obsoleteundo-confirm,undo-confirm-pending,undo-deleted,undo-failed,undo-cancelled,undo-expired(the chat-prompt strings from the old confirmation flow). Addedundo-cleanup-hint(passive post-//undotip) andchamber-created-rollback-tip(post-generation tip). Thepaste-undo-hintkey is unchanged — schematic paste still references//undocorrectly because that path always was a normal WorldEdit edit.
TrialChamberPro 1.4.2
release1 мая 2026 г.1.4.2 - 2026-05-02
Fixed
//undono longer gets hijacked by TCP after a chamber generation. The previousUndoListenercancelled//undoat HIGHEST priority and demandedconfirm/cancelin chat — but the chat handler only cleared the pending state on cancel, leaving the per-playerlastentry forever. Once any chamber had been generated in the session, every subsequent//undo(even for unrelated WorldEdit edits made hours later, or by a moderator joining after the fact) was intercepted, the chat prompt fired, and the actual WorldEdit undo never ran. There was also no path to retry: cancelling re-armed the same intercept, and confirming only deleted the DB registration without rolling back the placed blocks. The whole interception model was wrong — chamber registration is a DB write, not a WorldEdit edit, so it doesn't belong on WE's undo stack to begin with. New behavior: TCP never cancels//undo. WorldEdit's stack is fully untouched, any depth, any time. A new passivePostUndoHintListenerobserves//undo(and/undo) at MONITOR priority without cancelling and, only if the player happens to be standing inside a registered chamber when they run undo, posts a one-line tip suggesting/tcp delete <name>to also clean up the registration. Generation now also emits a one-timechamber-created-rollback-tipimmediately afterchamber-createdso users learn the two-step rollback (//undofor blocks →/tcp deletefor registration) up front.UndoListener.ktandUndoTracker.ktdeleted.
Localization
messages.yml: removed obsoleteundo-confirm,undo-confirm-pending,undo-deleted,undo-failed,undo-cancelled,undo-expired(the chat-prompt strings from the old confirmation flow). Addedundo-cleanup-hint(passive post-//undotip) andchamber-created-rollback-tip(post-generation tip). Thepaste-undo-hintkey is unchanged — schematic paste still references//undocorrectly because that path always was a normal WorldEdit edit.
TrialChamberPro 1.4.1-mc26
release1 мая 2026 г.This plugin version is compatible with Minecraft 26.X.X
1.4.1 - 2026-04-29
Fixed
- Auto-discovery now merges adjacent chamber regions instead of double-registering them. The previous flow registered every BFS result as a fresh chamber and only short-circuited if the candidate's center fell inside an existing AABB. Two physically distinct vanilla chambers ~500 blocks apart, or a single physical chamber whose two halves seeded discovery from different chunks, would happily produce two side-by-side
auto_world_*entries (the user-reported case:auto_world_851_747+auto_world_891_765registered in the same millisecond, ~40 blocks apart on the X axis). New behavior: after BFS produces a candidate AABB,ChamberDiscoveryManagerscans cached chambers in the same world for any whose AABB sits withindiscovery.merge-distance-blocks(Chebyshev edge-to-edge, default 250) of the candidate. If found, the existing chamber's bounds are unioned with the candidate via the newChamberManager.updateBounds(...), the chamber is rescanned to absorb the new vaults/spawners, and (ifdiscovery.auto-snapshotis enabled) the snapshot is regenerated. If not found, registration proceeds as before. Newdiscovery.max-merged-volume(default 1,500,000 blocks) caps how far a runaway daisy-chain can grow so a pathological geometry can't swallow large regions into a single logical chamber. Setdiscovery.merge-distance-blocks: -1to disable merging entirely and restore the v1.2.25 behavior. - Discovery registration race closed. Two near-simultaneous BFS results (typical during the startup sweep) could both pass the existing-chamber check before either committed — the merge logic above wouldn't help if both registrations were already in flight. New
kotlinx.coroutines.sync.MutexinChamberDiscoveryManagerserializes the entire registration step (mutex acquisition → cache scan → merge-or-create → mark processed). Throughput cost is zero in practice — registration fires at most a handful of times per session and is gated by the chunk-load / startup-sweep cadence anyway.
Changed — UX & GUI
- Main menu flattened —
SettingsMenuViewremoved. The previous "Settings → Plugin Settings → Global Settings" path had two papercut bugs: clicking "Settings" on the main menu opened a "Plugin Settings" hub whose only meaningful contents (Global Settings, Protection Settings, Performance Info, Reload Configuration) could just as well live one level up; and the back button on Protection Settings landed on Plugin Settings instead of the main menu, leaving the user one step deeper than they started. New main menu is a 6-row layout: Chambers / Loot Tables / Global Settings / Protection Settings on row 1, Help / Performance Info / Statistics on row 2, Reload Configuration centered on row 4 (shift-click to fire so accidental clicks don't reload), Close on row 5.SettingsMenuView.ktdeleted;Screen.SETTINGS_MENUandMenuService.openSettingsMenuremoved; back-button destinations inGlobalSettingsViewandProtectionMenuViewupdated fromgui.common.dest-settings→gui.common.dest-main-menu.gui.settings-menu.*keys deleted frommessages.yml;gui.main-menu.settings-name/lorerenamedglobal-settings-name/lore; newperformance-name/loreandreload-name/lorekeys added undergui.main-menu.CustomMobProviderView's back button still usesdest-settingsbecause it goes back to chamber settings, not the deleted plugin-settings hub. - Loot editor now shows the effective drop rate per item. The Amount/Chance/Rolls model is technically accurate but genuinely confusing: a user looking at "Amount: 2-4" + "Chance: 20%" tends to read that as "20% chance of getting 2-4 of this item per opening", and the separate "Rolls: 1-3" tile multiplies the per-draw probability without making that visually obvious on the items themselves. Each item lore now includes a new
Expected: ≈X per vault openingline computed asavg(draws) × (weight / totalWeight) × avg(amount)for weighted items, andavg(amount)for guaranteed items (which always drop once per opening). Adaptive precision: ≥10 → integer, ≥1 → one decimal, <1 → two decimals (so a 1-in-50 tier item still reads≈0.02rather than rounding to 0). The per-item "Chance: X%" line is now suffixed with " per draw" to make the relationship explicit. The "Rolls Configuration" tile is renamed "Draws per Opening" and its lore opens with three plain-English lines explaining that each opening picks N items from the weighted list, each draw chooses one item using its chance, and more draws = more total loot. Bumping the draws slider visibly recomputes every Expected line in real time so the multiplicative relationship becomes self-evident. Pure presentation change —loot.ymldata model untouched. - Help view rebuilt to mirror
/tcp helpand cover every wired subcommand. Audit foundmobs(v1.3.0) was missing from chat help entirely, and bothmobsandgive(v1.3.1) were missing from the GUI Help view. Two dead chat-help keys (help-procgen,help-teleport— subcommands that don't exist) deleted. Chat help reordered into logical groups (Browse → Create → Manage → Loot/Mobs → Players & rewards → Admin) with a comment inTCPCommand.sendHelpnoting the order mirrors the GUI tile grouping so future edits don't drift. Wording tightened onhelp-generate,help-snapshot,help-loot,help-vault,help-key,help-leaderboard,help-info,help-list, andhelp-reloadto drop jargon ("WE wand", "saved var") and uninformative phrases ("Manage snapshots"). GUI Help view re-laid out to a 4 + 4 + 1 tile grid: row 1 overview (Commands / Permissions / About), row 2 gameplay command groups (Chambers / Loot / Vaults & Keys / Stats), row 3 admin & setup command groups (Snapshots / Generate / Custom Mobs / Spawner Presets), row 4 lone Admin Tools tile, row 5 navigation. Newmobs-cmdandgive-cmdtiles cover the previously absent commands. Every tile lore opens with one plain-English sentence describing the group ("Browse and manage existing chambers." / "View or override per-chamber loot." etc.) before listing the actual commands. Thepermissionstile expanded from 5 entries to ~13 organized into Admin / Player / Bypass / Notifications groups.
Localization
- Every text change in this release routes through
messages.yml. NoComponent.text(...)literals introduced anywhere; all new and changed strings are translatable through the existinggui.<view>.*and flat*key system. New keys:discovery-merged,gui.main-menu.global-settings-name/lore,gui.main-menu.performance-name/lore,gui.main-menu.reload-name/lore,gui.loot-editor.item-expected,gui.help-menu.mobs-cmd-name/lore,gui.help-menu.give-cmd-name/lore,help-mobs. Removed keys: every key undergui.settings-menu.*,help-procgen,help-teleport,gui.main-menu.settings-name/lore(renamed). Changed keys:gui.loot-editor.item-chance,gui.loot-editor.rolls-name,gui.loot-editor.rolls-lore,gui.main-menu.protection-name, everygui.help-menu.*lore. The chat-help block inmessages.ymlwas scattered across two locations (lines 152-166 and 225-228); all entries are now consolidated into a single contiguous block in the ordersendHelpemits them.
Added
- Startup schema check for
messages.yml. NewMessagesSchemaValidator(run fromonEnableimmediately afterConfigValidator) loads the JAR-bundledmessages.ymland the user's deployed copy, walks both for leaf keys (filtering outConfigurationSectioncontainers so a parent path doesn't mask a missing leaf), and logs a warning listing every key the bundle defines that the user's file lacks — up to 25 enumerated, then truncated with... and N more. Output includes a 4-step recovery path (rename → restart → port translations) and notes thedebug.skip-messages-schema-check: trueopt-out. Pure log surface — never modifies the user's file, never blocks startup. Motivated by a v1.4.0 user bug report where<missing: gui.loot-table-list.table-name-normal>reached the GUI because the deployedmessages.ymlwas an older copy that predated thegui.loot-table-list.*block; the check would have surfaced that as a console warning at startup.
Config additions
discovery.merge-distance-blocks(default250) — Chebyshev edge-to-edge distance below which two regions are folded into a single chamber. Set to-1to disable merging.discovery.max-merged-volume(default1500000) — hard cap on the post-merge bounding-box volume in blocks. Above this the merge is rejected and the new region is logged as a skip (region debounce still applies).debug.skip-messages-schema-check(defaultfalse) — set totrueto silence the newmessages.ymlschema check. Not recommended; the check is purely informative and the warning means GUI/chat surfaces are showing literal<missing: ...>placeholders.
TrialChamberPro 1.4.1
release1 мая 2026 г.1.4.1 - 2026-04-29
Fixed
- Auto-discovery now merges adjacent chamber regions instead of double-registering them. The previous flow registered every BFS result as a fresh chamber and only short-circuited if the candidate's center fell inside an existing AABB. Two physically distinct vanilla chambers ~500 blocks apart, or a single physical chamber whose two halves seeded discovery from different chunks, would happily produce two side-by-side
auto_world_*entries (the user-reported case:auto_world_851_747+auto_world_891_765registered in the same millisecond, ~40 blocks apart on the X axis). New behavior: after BFS produces a candidate AABB,ChamberDiscoveryManagerscans cached chambers in the same world for any whose AABB sits withindiscovery.merge-distance-blocks(Chebyshev edge-to-edge, default 250) of the candidate. If found, the existing chamber's bounds are unioned with the candidate via the newChamberManager.updateBounds(...), the chamber is rescanned to absorb the new vaults/spawners, and (ifdiscovery.auto-snapshotis enabled) the snapshot is regenerated. If not found, registration proceeds as before. Newdiscovery.max-merged-volume(default 1,500,000 blocks) caps how far a runaway daisy-chain can grow so a pathological geometry can't swallow large regions into a single logical chamber. Setdiscovery.merge-distance-blocks: -1to disable merging entirely and restore the v1.2.25 behavior. - Discovery registration race closed. Two near-simultaneous BFS results (typical during the startup sweep) could both pass the existing-chamber check before either committed — the merge logic above wouldn't help if both registrations were already in flight. New
kotlinx.coroutines.sync.MutexinChamberDiscoveryManagerserializes the entire registration step (mutex acquisition → cache scan → merge-or-create → mark processed). Throughput cost is zero in practice — registration fires at most a handful of times per session and is gated by the chunk-load / startup-sweep cadence anyway.
Changed — UX & GUI
- Main menu flattened —
SettingsMenuViewremoved. The previous "Settings → Plugin Settings → Global Settings" path had two papercut bugs: clicking "Settings" on the main menu opened a "Plugin Settings" hub whose only meaningful contents (Global Settings, Protection Settings, Performance Info, Reload Configuration) could just as well live one level up; and the back button on Protection Settings landed on Plugin Settings instead of the main menu, leaving the user one step deeper than they started. New main menu is a 6-row layout: Chambers / Loot Tables / Global Settings / Protection Settings on row 1, Help / Performance Info / Statistics on row 2, Reload Configuration centered on row 4 (shift-click to fire so accidental clicks don't reload), Close on row 5.SettingsMenuView.ktdeleted;Screen.SETTINGS_MENUandMenuService.openSettingsMenuremoved; back-button destinations inGlobalSettingsViewandProtectionMenuViewupdated fromgui.common.dest-settings→gui.common.dest-main-menu.gui.settings-menu.*keys deleted frommessages.yml;gui.main-menu.settings-name/lorerenamedglobal-settings-name/lore; newperformance-name/loreandreload-name/lorekeys added undergui.main-menu.CustomMobProviderView's back button still usesdest-settingsbecause it goes back to chamber settings, not the deleted plugin-settings hub. - Loot editor now shows the effective drop rate per item. The Amount/Chance/Rolls model is technically accurate but genuinely confusing: a user looking at "Amount: 2-4" + "Chance: 20%" tends to read that as "20% chance of getting 2-4 of this item per opening", and the separate "Rolls: 1-3" tile multiplies the per-draw probability without making that visually obvious on the items themselves. Each item lore now includes a new
Expected: ≈X per vault openingline computed asavg(draws) × (weight / totalWeight) × avg(amount)for weighted items, andavg(amount)for guaranteed items (which always drop once per opening). Adaptive precision: ≥10 → integer, ≥1 → one decimal, <1 → two decimals (so a 1-in-50 tier item still reads≈0.02rather than rounding to 0). The per-item "Chance: X%" line is now suffixed with " per draw" to make the relationship explicit. The "Rolls Configuration" tile is renamed "Draws per Opening" and its lore opens with three plain-English lines explaining that each opening picks N items from the weighted list, each draw chooses one item using its chance, and more draws = more total loot. Bumping the draws slider visibly recomputes every Expected line in real time so the multiplicative relationship becomes self-evident. Pure presentation change —loot.ymldata model untouched. - Help view rebuilt to mirror
/tcp helpand cover every wired subcommand. Audit foundmobs(v1.3.0) was missing from chat help entirely, and bothmobsandgive(v1.3.1) were missing from the GUI Help view. Two dead chat-help keys (help-procgen,help-teleport— subcommands that don't exist) deleted. Chat help reordered into logical groups (Browse → Create → Manage → Loot/Mobs → Players & rewards → Admin) with a comment inTCPCommand.sendHelpnoting the order mirrors the GUI tile grouping so future edits don't drift. Wording tightened onhelp-generate,help-snapshot,help-loot,help-vault,help-key,help-leaderboard,help-info,help-list, andhelp-reloadto drop jargon ("WE wand", "saved var") and uninformative phrases ("Manage snapshots"). GUI Help view re-laid out to a 4 + 4 + 1 tile grid: row 1 overview (Commands / Permissions / About), row 2 gameplay command groups (Chambers / Loot / Vaults & Keys / Stats), row 3 admin & setup command groups (Snapshots / Generate / Custom Mobs / Spawner Presets), row 4 lone Admin Tools tile, row 5 navigation. Newmobs-cmdandgive-cmdtiles cover the previously absent commands. Every tile lore opens with one plain-English sentence describing the group ("Browse and manage existing chambers." / "View or override per-chamber loot." etc.) before listing the actual commands. Thepermissionstile expanded from 5 entries to ~13 organized into Admin / Player / Bypass / Notifications groups.
Localization
- Every text change in this release routes through
messages.yml. NoComponent.text(...)literals introduced anywhere; all new and changed strings are translatable through the existinggui.<view>.*and flat*key system. New keys:discovery-merged,gui.main-menu.global-settings-name/lore,gui.main-menu.performance-name/lore,gui.main-menu.reload-name/lore,gui.loot-editor.item-expected,gui.help-menu.mobs-cmd-name/lore,gui.help-menu.give-cmd-name/lore,help-mobs. Removed keys: every key undergui.settings-menu.*,help-procgen,help-teleport,gui.main-menu.settings-name/lore(renamed). Changed keys:gui.loot-editor.item-chance,gui.loot-editor.rolls-name,gui.loot-editor.rolls-lore,gui.main-menu.protection-name, everygui.help-menu.*lore. The chat-help block inmessages.ymlwas scattered across two locations (lines 152-166 and 225-228); all entries are now consolidated into a single contiguous block in the ordersendHelpemits them.
Added
- Startup schema check for
messages.yml. NewMessagesSchemaValidator(run fromonEnableimmediately afterConfigValidator) loads the JAR-bundledmessages.ymland the user's deployed copy, walks both for leaf keys (filtering outConfigurationSectioncontainers so a parent path doesn't mask a missing leaf), and logs a warning listing every key the bundle defines that the user's file lacks — up to 25 enumerated, then truncated with... and N more. Output includes a 4-step recovery path (rename → restart → port translations) and notes thedebug.skip-messages-schema-check: trueopt-out. Pure log surface — never modifies the user's file, never blocks startup. Motivated by a v1.4.0 user bug report where<missing: gui.loot-table-list.table-name-normal>reached the GUI because the deployedmessages.ymlwas an older copy that predated thegui.loot-table-list.*block; the check would have surfaced that as a console warning at startup.
Config additions
discovery.merge-distance-blocks(default250) — Chebyshev edge-to-edge distance below which two regions are folded into a single chamber. Set to-1to disable merging.discovery.max-merged-volume(default1500000) — hard cap on the post-merge bounding-box volume in blocks. Above this the merge is rejected and the new region is logged as a skip (region debounce still applies).debug.skip-messages-schema-check(defaultfalse) — set totrueto silence the newmessages.ymlschema check. Not recommended; the check is purely informative and the warning means GUI/chat surfaces are showing literal<missing: ...>placeholders.
TrialChamberPro 1.4.0-mc26
release26 апреля 2026 г.This plugin version is compatible with Minecraft 26.X.X
1.4.0 - 2026-04-26
Added
- Phase 2 of the public extension API — three more seams aimed at premium add-on modules and third-party integrations. No breaking changes; all existing behavior preserved when no listener / service is registered.
DatabaseManageropened for extension. Class is nowopen(was final) and thepluginconstructor parameter isprotectedso subclasses in other packages can access it. The instance is auto-registered with Bukkit'sServicesManagerat TCP startup so consumers can resolve it viaBukkit.getServicesManager().load(DatabaseManager::class.java). Designed for the planned premium "Network Sync" module that adds Postgres / MariaDB / Redis backends. (Note: TCP itself currently still references its owndatabaseManagerfield directly throughout its own codebase, so subclass replacement only takes effect for callers that explicitly resolve via the services manager — full runtime substitution at every call site is planned for a future major version.)ChamberResetEvent.snapshotOverride(mutableByteArray?) — pre-reset hook lets listeners substitute a different snapshot for a single reset cycle without persistently modifying the chamber's on-disk snapshot. Bytes must be a gzip-compressed serializedSnapshotData(TCP's native snapshot format). NewSnapshotManager.loadSnapshotFromBytes(bytes, contextLabel)deserializes the override; falls back to the on-disk snapshot with a logged warning if the override fails to load. Designed for premium / third-party "schematic injection" or "instance variant" workflows.WildSpawnerResolverSPI inapi/— pluggable lookup for the question "should this wild trial spawner spawn custom-plugin mobs, and if so, which provider + mob ids?". Lifts the long-standing limitation that TCP's Custom Mob Provider only worked inside registered chambers. Implementations register as a Bukkit service (ServicesManager.register(WildSpawnerResolver::class.java, ...)); TCP'sSpawnerWaveListenerconsults the active resolver on every wild-spawner spawn observation. Returning a non-nullConfig(providerId, normalIds, ominousIds)triggers TCP's existing replace-after-spawn logic — vanilla mob removed the same tick, custom provider mob spawned at the same location, wave tracking and key drops preserved. The seam lives in free TCP; the resolver implementation will ship in the planned premium "Wild Custom-Mob Spawners" module (per the v1.3.1 architectural boundary: trial-spawner-only is the line, wild-spawner custom mobs are premium territory).SpawnerPresetManager.PRESET_ID_KEY_NAME+ automatic PDC tagging — every item produced bySpawnerPresetManager.getItem(i.e. given out via/tcp give <preset>) now carries atcp:preset_idPersistentDataContainer tag with the source preset's id.SpawnerPresetPlaceListener— copies thetcp:preset_idtag from a placed trial-spawner item onto the resulting block'sTileState. LetsWildSpawnerResolverimplementations identify which preset a placed wild spawner originated from, even after the source ItemStack is gone. Tag survives chamber resets, chunk unloads, and world reloads via Minecraft's standard TileEntity persistence. Vanilla/give minecraft:trial_spawneritems (no tag) are ignored.
Added — MiniMessage support
- First-class MiniMessage support across every user-facing text surface. New
MessageParserutility (utils/MessageParser.kt) translates rawmessages.ymlentries through MiniMessage as the primary syntax while remaining fully backwards-compatible with legacy&colour/format codes (and&#RRGGBBhex). Existingmessages.ymlfiles render unchanged; users adopt MM syntax entry-by-entry on their own schedule. Mixed input works too —&aHello <gradient:#ff0000:#0000ff>world</gradient>renders correctly. - MM features now usable in TCP messages that legacy
&codes can't express:- Gradients:
<gradient:#ff5500:#0000ff>Sunset to ocean</gradient> - Click events:
<click:run_command:'/tcp menu'>[Open menu]</click> - Hover tooltips:
<hover:show_text:'Bonus active'><gold>★</gold></hover> - Custom fonts (resource-pack supplied):
<font:server:fancy>...</font> - Cleaner hex syntax:
<#FF5500>instead of&#FF5500
- Gradients:
- New
TrialChamberPro.getMessageComponent(key, ...): Component— companion to the existinggetMessage()String method. Returns a fully-styled Adventure Component preserving all MiniMessage features (gradients, click/hover, fonts) end-to-end throughPlayer.sendMessage(Component). - All ~349
sendMessagecall sites in TCP migrated from the legacy String path togetMessageComponentso chat messages get full MiniMessage fidelity. Includes boss bar text, chat notifications (vault opened, chamber entered, reset warnings, spectator messages, discovery announcements, wave completion), death messages, and all command feedback. - GUI helpers (
getGuiText,getGuiLore) now route through MessageParser — item names and lore in all 18 admin GUI views support full MM fidelity. - Documentation updated (docs/configuration/messages.yml.md) — comprehensive coverage of both syntaxes side-by-side, mixed-format examples, and MM-only feature documentation. The
messages.ymlresource header explains the two formats with examples. - Conflict-free with other plugins — TCP parses its own messages internally; chat plugins (DiscordSRV, EssentialsXChat, ChatControl) only intercept
AsyncChatEvent(player-typed chat), not plugin-sent notifications, so there's no double-processing risk. This is the same pattern MythicMobs, EcoEnchants, LuckPerms, and CMI use.
Fixed
- Trial-spawner wave size off-by-one (the v1.3.2 follow-up). v1.3.2 introduced
SpawnerWaveManager.computeExpectedMobsto read the spawner's actualtotal_mobs/total_mobs_added_per_playerconfig instead of hard-coding 6. The formula wasbase + perPlayer × players, but Mojang's actualTrialSpawnerDataformula isbase + perPlayer × max(0, players - 1)— the FIRST detected player gets the base count, each ADDITIONAL player adds the per-player bonus. The off-by-one over-counted byperPlayerper nearby player, producing the user-reported bug "spawner has 20 configured, bar shows 1/30, wave actually ends at 20". Plugin now matches vanilla exactly:floor(base + perPlayer × additional)whereadditional = max(0, players - 1). Also switchedceil→floorto match Mojang's rounding. - Secondary fallback bug surfaced by the same code path. When Paper's
state.trackedPlayersreturned empty (e.g. between waves), the recompute fell back towave.participatingPlayers.size— which counts players within the boss-bar detection radius (default 20 blocks), not within the spawner'srequiredPlayerRange(default 14). With more players in the boss-bar radius than vanilla actually tracked, the fallback could inflate the result beyond whatstate.trackedPlayers.sizewould have produced. Fallback is now1so it can never exceed what the authoritative API would say.
Changed
ResetManager.resetChambernow consultsChamberResetEvent.snapshotOverrideafter firing the pre-event. If non-null, the override bytes are restored instead of the on-disk snapshot; if the override fails to load, the on-disk snapshot is used and a warning is logged. Internal helperrestoreFromSnapshotBlocksextracted to share the BlockRestorer call between the on-disk and override paths.SpawnerWaveListenergains a wild-spawner-replacement branch that fires immediately afterconfigureWildSpawnerCooldown. When noWildSpawnerResolverservice is registered (the default in free TCP), the branch is a single nullable lookup and a return-false — zero behavior change for end users.TrialChamberPro.onEnableregistersSpawnerPresetPlaceListeneralongside the existing listener block, and registers theDatabaseManagerinstance withServicesManagerimmediately after it initializes.TrialChamberPro.getMessageandgetMessageComponentshare a new private helperrawMessageWithPrefixfor placeholder substitution + chat-prefix logic. Behavior is identical to v1.3.x but the Component path now exists alongside the String path.SpawnerWaveManager's private boss-bargetMessageComponenthelper now delegates toplugin.getMessageComponentso boss bars inherit the same MM-aware parsing as chat messages. The localLegacyComponentSerializerimport is removed.
Совместимость
Детали
Лицензия:CC-BY-NC-ND-4.0
Опубликован:6 месяцев назад
Обновлён:2 дня назад