
Better Veinminer
A Paper 1.21 Vein miner plugin that mines entire ore veins instantly.. Fully configurable via config.yml.
Список изменений
[1.5.0] — 2026-05-22
Fixed
-
[HIGH] Daily-limit counter not persisted — restart bypass —
dailyUsageTrackerexisted only in RAM. A server restart mid-day cleared the map to zero, allowing players who had already reached their daily cap to veinmine freely after any restart or plugin reload. The map is now saved todata.ymlvia the serialisedBVM-StatsIOexecutor on shutdown and on every daily reset. It is restored duringonEnable()before the reset check, so the data is properly cleared (not silently discarded) when a day boundary is crossed while the server was offline. -
[HIGH] Blocking file I/O from async timer thread —
saveLastResetDate()calledYamlConfiguration.save()directly on therunTaskTimerAsynchronouslythread, bypassing theBVM-StatsIOexecutor that serialises every other write in the plugin. This could race withonDisable()flushing the same file. The method is replaced bysaveDataYmlAsync(), which snapshots both the reset date and usage counters on the calling thread and submits the actual I/O to the existingBVM-StatsIOexecutor. -
[MEDIUM] Cooldown message with
{remaining}placeholder never sent — When a player triggered veinmine while still on cooldown, the listener silently returned without feedback. The config already declared acooldownmessage key with a{remaining}placeholder; it was simply never used. The remaining milliseconds are now calculated and the formatted message is sent to the player's action bar, matching the UX pattern of the success message. -
[MEDIUM] Permission priority non-deterministic — VIP+Premium received random limits —
getEffectiveCooldown()andgetEffectiveMaxBlocks()iteratedHashMapwhose entry order is not defined by Java. A player holding bothbetterveinminer.vipandbetterveinminer.premiumcould receive either tier's limits depending on hash collisions that vary between JVM instances and restarts. ThepermissionMaxBlocksandpermissionCooldownsmaps are nowLinkedHashMapinstances whose entries are inserted duringPluginConfig.reload()sorted bymax-blocksdescending. Iteration therefore always encounters the highest-privilege permission first. -
[MEDIUM] Daily counter incremented before veinmine task confirmed success —
dailyUsageTrackerwas incremented inonBlockBreak()beforeVeinmineTaskran. If theBetterVeinmineEventwas cancelled by another plugin, or all extra blocks were denied by protection plugins (extraCount == 0), the player lost one daily use without breaking anything. The increment is now deferred to insideVeinmineTask.run(), executed only afterextraCount > 0is confirmed. -
[MEDIUM] Cooldown cleanup evicted active entries for long per-ore cooldowns — The cleanup timer removed
cooldownsentries older thanconfig.getCooldownMs()(default 200 ms). If a per-ore cooldown (e.g.EMERALD_ORE: 1500) or a permission cooldown was longer than the base, an entry could be evicted while still within its own active window. The player's next break would findnullin the map and bypass the cooldown. The timer now callsconfig.getMaxConfiguredCooldown(), which returns the maximum of the base, all per-ore, and all permission cooldown values. -
[SMALL]
breakNaturally(tool)used stale 1-tick-old tool snapshot —VeinmineTaskcaptured the heldItemStackatBlockBreakEventtime and used it for everybreakNaturally()call one tick later. If a player legitimately swapped to a higher-Fortune pickaxe during that tick, all drops were calculated with the old tool's enchantments. The task now reads the item currently in the recorded slot at break time and falls back to the snapshot only if the slot is empty. -
[SMALL]
instancestatic field not cleared on disable —onDisable()did not setinstance = null. If a third-party plugin cached the return value ofBetterVeinminer.getInstance()and called it after the plugin was disabled (e.g. during/reload), it received a fully torn-down instance whosestatsManagerandconfigfields had already been discarded, potentially causing NPEs.instanceis now set tonullas the last action inonDisable(). -
[SMALL] BFS
visitedset unbounded on abnormally large ore clusters — The BFS loop stopped adding totoBreakatmaxBlocks, but continued enqueuing and visiting neighbours until the queue drained. On a world-gen-modded server with a massive ore deposit,visitedcould accumulate tens of thousands of entries in a single tick. A hard cap ofmaxBlocks × 4entries is now enforced on thevisitedset; the loop breaks immediately when the cap is reached.
Changed
BetterVeinminer.onDisable()now flushesdata.yml(daily usage + reset date) viasaveDataYmlAsync()before callingstatsManager.shutdown(), ensuring all data is written to the serialised executor queue before the 5-second drain begins.StatsManager.getIoExecutor()added to expose the single-threaded executor to other components within the plugin.PluginConfig.getMaxConfiguredCooldown()added to return the longest cooldown value across all configuration sources.BetterVeinminer.getDailyUsageTracker()added to allowVeinmineTask(inner class) to increment the map after confirmed success, without requiring a public field.
