TDX Leaderboards
Changelog
Version history and release notes for TDX Leaderboards.
All notable changes to TDX Leaderboards are documented here. Versions are listed newest-first.
v1.9.20 (Latest)
- DELTA boards can show a player's lifetime total as this period's progress when the baseline under it is wrong. Two causes are now handled
- A baseline read as 0 before the player's data had loaded. The join baseline is now taken five seconds after a join instead of five ticks, and a value of 0 is only stored for a player who first joined this period or has been online for two minutes. Anyone left without a baseline gets one on the next update cycle. Existing baselines are never overwritten
- A lifetime value that jumped after the baseline was taken, because player statistics or another plugin's data were restored, merged or imported mid-period. The plugin cannot prevent that, but it can now show it and clear it
- New
/lbadmin baselines. It reports, per DELTA board, how many baselines there are, how many zero baselines belong to players who joined before the period began, and how many players show more playtime than has passed this period, which is the sure sign of a jump /lbadmin baselines repair confirmremoves only those zero baselines./lbadmin baselines reset <board|all> confirmremoves every baseline of one DELTA board or of all of them. Both also clear the cached standings of the boards they touch. The players affected start again from the value they have the next time they are online. Their earlier progress this period cannot be recovered, because the right starting value was never recorded- Boards the plugin counts itself (ACCUMULATE) have no baselines and are never touched by these commands
v1.9.19
- Fixed the reset countdown showing the wrong time. Since v1.9.8 the reset happens when the calendar period changes (midnight on the 1st, midnight on Monday, or midnight on every second Monday), but the countdown in the GUI and
%tdxleaderboards_reset_time%still counted down toreset-dayandreset-hour. With anything but the default values it showed a moment nothing happened at. It now counts down to the real reset reset-dayandreset-hourare documented as unused inconfig.yml. They stay in the file so existing configs keep loading, and changing them does nothing- Period keys are unchanged, so no stored data moves
v1.9.18
- Fixed
&x&r&r&g&g&b&bcolours. The converter dropped the first digit of every colour and produced a five digit tag, so the colour never applied - Fixed sounds with an underscore in their key never playing.
ENTITY_EXPERIENCE_ORB_PICKUPand more than half of all sounds resolved to nothing, for a board'ssound, the GUI open and close sounds and the milestone sound - Fixed the Discord results post showing the wrong standings. It read the live boards, which already hold the new period by the time a reset runs, so a normal rollover posted a nearly empty embed and
/lbadmin archiveposted the current month under the old period's name. It now posts the standings of the period that ended - Fixed
/lbadmin setstaton an offline player corrupting aDELTAboard. It stored a negative starting point, and the next time the player joined their value became their lifetime stat plus the number typed. For an offline player it now only changes their row on the board, which lasts until they next join, and the command says so - Fixed reward positions being taken by stale totals. A player who had dropped off every board kept their old points total in storage, and the period reset pays out from those rows. A total is now cleared once the player holds no points, and the reset ignores anybody on 0
- Fixed queued rewards being lost when a winner logged out in the moment between the rewards being claimed and being run. They are put back for the next join
v1.9.17
- New board types counted by the plugin itself:
CUSTOM_BLOCKS_BROKEN(blocks broken),CUSTOM_WOOD(natural logs, stems and stripped logs chopped),CUSTOM_POTIONS_BREWED(bottles brewed, credited to whoever used the brewing stand last) andCUSTOM_TAMED(animals tamed) CUSTOM_BLOCKS_BROKENandCUSTOM_WOODskip blocks the player placed first, so nobody can farm a board by placing and breaking the same block. The plugin remembers the most recently placed blocks, sized bycustom-tracking.blocks-broken.placed-block-memory(default100000, about 10 MB of memory,0turns it off).ignore-instant-breaksleaves out grass, flowers, torches and crops- New
CUSTOM_COUNTERboard type that only moves when a command adds to it. Put/lbadmin addstat <player> <board-id> <amount>in another plugin's reward commands to feed a board from outside, for example event wins. It uses the sametdxleaderboards.admin.setstatpermission assetstat - New per-board
hidden: trueoption for a board that only feeds placeholders, such as a spawn hologram. A hidden board has no menu tile, gives no points or rewards and is never announced. Read it with%tdxleaderboards_board_<id>_name_<1-10>%and%tdxleaderboards_board_<id>_value_<1-10>% - New
general.hide-banned-players(defaulttrue). A board only refreshes a player while they are online, so somebody banned while sitting at #1 used to stay there all month. Banned players now drop off within one update cycle. Uses LiteBans when it is installed, otherwise the vanilla ban list
v1.9.16
- New
CUSTOM_DAMAGE_DEALTboard type. Damage is counted by the plugin on the same scale as the vanilla statistic (10 per heart), but only for health actually taken off the target, so overkill does not count custom-tracking.damage-dealt.exclude-spawner-mobs(defaulttrue) ignores damage done to mobs that came out of a spawner, vanilla or RoseStacker, which keeps mob grinders off the combat board.count-player-damage(defaulttrue) decides whether damage to other players counts- The bundled
damage-dealtpreset now usesCUSTOM_DAMAGE_DEALTwithtracking: ACCUMULATE. An existing config keepsSTATISTICwithDAMAGE_DEALTuntil you change it - New
CUSTOM_QUESTSboard type that counts quests completed on the AxQuestBoard board. Needs the AxQuestBoard plugin, and counts from the moment the board is set up - This version was never published as its own download. v1.9.17 contains everything listed here
v1.9.15
- Fixed the distance board being farmable by falling.
CUSTOM_DISTANCEcounted vertical movement too, so a player could dive into the void, score a block for every Y level on the way down, get teleported back to spawn and repeat. Only horizontal movement counts now, which is what "blocks traveled" always meant
v1.9.14
- Fixed the personal "You" line on each board showing 0 while the top-N rows showed the correct value. The async pre-fetch in
openMainGuiwas callingPlayer.getStatistic()from a background thread (unreliable on Paper) and storing the resulting 0 into a per-viewer cache; the top entries were rescued by theboard_cachemerge inupdateBoardbut the personal lookup had no merge fallback, so the two values disagreed placeBoardItemsandplacePointsItemnow read the viewer's value straight from the in-memory leaderboard (board.getAllEntries()/pointsManager.getPointsLeaderboard()), same source the top rows render from, so the values can never disagree again- Removed the
viewerDatacache,ViewerDatarecord, async pre-fetch inopenMainGui, and theclearViewerDataclose-handler call. Restored the simple 1-tick delayed re-fill for ResetVault interference defense - Trade-off: viewer's row is now refreshed by the periodic
updateBoardcycle (default 30s) rather than per-open. Net win: GUI opens are sync-fast and never disagree with themselves
v1.9.13
- Fixed
/lbadmin reset confirmleaving DELTA boards empty until each online player relogged. The command was clearingmonthly_snapshots(along with the rest of the period's data) but never re-establishing baselines, sogetMonthlyValuereturned 0 for every online player andupdateBoardsilently skipped them. Boards stayed frozen empty until the natural per-join snapshot path re-populated rows /lbadmin reset confirmnow: clears month data → wipes in-memory leaderboard caches → callsforceSnapshotAllPlayersto take fresh DELTA baselines (idempotent IF-ABSENT, can't clobber existing) → kicks off an asyncupdateAllBoardsso the GUI catches up immediately- New
/lbadmin snapshot confirmrecovery command. Takes fresh snapshots for online players without clearing any data, use this if you already ran the broken/lbadmin reseton a pre-v1.9.13 install and lost DELTA-board tracking; ACCUMULATE-board progress is untouched
v1.9.12
- Fixed the new History GUI getting stuck on "Loading…" forever.
player.openInventory()was being called from inside theInventoryClickEventthat triggered the open, Bukkit's behaviour for opening a new inventory mid-click is unreliable, and the title rendered while later mutations from the async refill failed to sync to the client view - Both
openInventoryand the chained async DB read now defer to the next tick viarunTask. The async fetch is scheduled inside the deferred open so the order is guaranteed - Async DB reads are wrapped in try/catch with a visible failure card ("Failed to load, see server console for details") instead of an indefinite spinner. Console gets the stacktrace
- Same deferral applied to back-button navigation from the period list to the main GUI
v1.9.11
- Fixed
/lbadmin archive <past period>wiping current-period progress for online DELTA-board players.forceSnapshotAllPlayerswas overwriting existing new-period snapshots with the player's current stat, which zeroed the monthly value of anyone online at the moment of the archive forceSnapshotAllPlayersnow usessaveSnapshotsIfAbsentBatch(INSERT … DO NOTHING/INSERT IGNORE), same idempotent path the join handler already uses. Live rollovers behave identically (no existing rows → every write succeeds); catch-up archives leave the new period's already-established baselines alone- Symptom this fixes: large negative
%rank_change%lore indicators (-114,-186, etc.) appearing on boards right after running/lbadmin archive
v1.9.10
- Per-board period history GUI. New "Past Periods" button on the main
/lbGUI opens a three-tier flow: pick a past period → pick a board (or "Points overall") → see that period's archived top 10 with player heads - The chat-only
/lb history <period> <board>command is unchanged for power users - Reads
period_archiveandpoints_archiveasync with a "Loading…" placeholder, so opening the GUI never blocks the main thread - New
HistoryGuiManager,HistoryHolder(with type/period/board state + slot mappings), and history button entry inmain-leaderboard.yml - Config-merge friendly: existing installs get the history button on next reload; legacy GUIs without the
items.historyblock silently skip placement
v1.9.9
- Reward delivery is now offline-aware. When a winner is offline at period rollover, the reward command is queued in a new
pending_rewardstable and replayed when they next join,give %player% diamondand other online-only commands no longer silently disappear - New
pending_rewardstable with a uuid index. SQLite uses its global lock for serialised drain; MySQL usesSELECT … FOR UPDATEinside a transaction so two backends sharing one DB can't both claim the same queue when a player joins both at once - Per-period idempotency markers (
rewards_distributed_<period>,archived_<period>) in themetadatatable. A mid-reset crash, or a second/lbadmin archive 2026-04 confirminvocation, no longer re-runs distribution and double-rewards winners - 2-second delay before draining the offline queue so the player's chunks and inventory finish loading before
give-style commands fire - Removed dead
RewardManager.distributeRewards()legacy code path that read from in-memory caches (replaced bydistributeRewardsForreading the period's frozen DB caches)
v1.9.8
- Fixed monthly reset silently failing to archive + distribute rewards. Three compounding bugs:
lastResetPerioddefaulted to the current period on every startup (so missed crossings became invisible after a restart), the field was in-memory only (so a successful reset was forgotten across restarts), andisResetTimerequiredgetHour() == resetHourexactly, which the hourly tick frequently missed - New
metadatak/v table. The last successfully reset period is persisted there, so reboots no longer mask missed resets - Reset is now triggered by period-key change, not exact-hour matching. Check interval lowered to 5 minutes; the reset fires once when
currentPeriodKey() != lastResetPeriod - Reset reads final standings from the period's frozen
board_cache/points_cacherows, so catch-up resets (period rollover happened while server was offline) work the same as live resets - New
/lbadmin archive <period> confirmadmin command to retroactively archive + distribute rewards for a past period, use this to fix April after upgrading
v1.9.7
- Fixed two more main-thread SQLite freezes the v1.9.6 batch fix didn't cover
/lbGUI open now pre-fetches the viewer's per-board monthly value and points total on an async worker, then refills the inventory from a per-viewer cache, no DB read happens on the main thread while rendering. Refills triggered by category-tab clicks and ResetVault interference reuse the same cachePlayerJoinListener's "show points on join" message now readsgetPlayerPointsasync and hops back to main thread only to send the chat line- Per-viewer cache is dropped on inventory close so it doesn't grow
v1.9.6
- Fixed server-thread freezes on player join when DELTA boards were configured. The join handler called
snapshotAllPlayers()synchronously, iterating every online player × every DELTA board with a locked SQLite write per row, so a single join could stall the tick loop for 30+ seconds while contending with the async board-update cycle for the sameReentrantLock - New
BoardManager.snapshotPlayerAsync(Player)only snapshots the joining player and dispatches the writes off-thread - New
DatabaseProvider.saveSnapshotsIfAbsentBatch(...)writes all rows in a single transaction usingINSERT … ON CONFLICT DO NOTHING(SQLite) /INSERT IGNORE(MySQL), one fsync per join instead of one per row, no read-then-write roundtrip
v1.9.5
- Compatibility with Paper 1.20.x through 1.21.11+
- MySQL / MariaDB storage backend alongside SQLite
- DecentHolograms integration for physical leaderboard displays
- 16 board types including PlaceholderAPI-driven boards
- Points-from-position scoring across all boards
- Milestone alerts with configurable thresholds
- Per-board reward overrides at period end
- Weekly and biweekly reset schedules (in addition to monthly)
- Config-version auto-merge so upgrades preserve your customisations
v1.0, Initial Release
Date: 2026-02-26
Features
- 11 default leaderboard boards: Balance, Player Kills, Playtime, Votes, Skills XP, Monsters Killed, Animals Bred, Fish Caught, Crops Harvested, Blocks Placed, Ores Mined
- Monthly tracking with automatic resets
- Points system: awards 10 for 1st, 9 for 2nd down to 1 for 10th across all boards
- Automatic rewards: configurable commands at month end based on points ranking
- Customisable GUI: MiniMessage-formatted chest GUI with configurable layout, materials, and custom model data
- Built-in event tracking for ores mined, crops harvested, and blocks placed
- Vault integration for balance leaderboard
- PlaceholderAPI support with expansions for all boards, points, and rankings
- SQLite storage with WAL mode for performance
Board Types
STATISTIC, Minecraft vanilla statistics (delta tracking)CUSTOM_ORES/CUSTOM_CROPS/CUSTOM_BLOCKS, Plugin event trackingVAULT_BALANCE, Vault economy (current value)PLACEHOLDER, Any PlaceholderAPI placeholder