Compatibility
Minecraft: Java Edition
Platforms
Tags
Creators
Details
Better Veinminer
Version: 1.4.0 | API: Paper 1.21+ | Author: Duong2012G
License: Apache-2.0 | Link: Modrinth
Mine an entire ore vein in one swing — with tier progression, persistent statistics, a custom event API, and deep configuration.
Features
Core
- 6-direction BFS — accurate face-adjacent vein detection matching vanilla ore generation; no false positives from diagonal neighbours
- Strict same-type matching — only collects blocks of the exact same material
- Fortune & Silk Touch — work automatically on every block in the vein
- Per-player toggle — each player can enable/disable independently with
/bvm toggle - Unbreaking-aware durability — matches vanilla's per-hit random probability model
- World whitelist/blacklist — restrict which worlds allow veinminer
- Hot reload —
/bvm reloadapplies config changes without a restart
Tier System
Players progress through 4 tiers as they mine more blocks:
| Tier | Blocks Required | Max Blocks (default) |
|---|---|---|
| 1 | 0 | 32 |
| 2 | 100,000 | 64 |
| 3 | 500,000 | 128 |
| 4 | 1,000,000 | 256 |
All thresholds and max-block limits are configurable. Check progress with /bvm tier.
Persistent Statistics
Stats survive server restarts. Saved per-player to
plugins/BetterVeinminer/stats/<uuid>.yml:
- Total blocks mined via veinminer
- Total veinmines performed
- Current tier
- Auto-save every 5 minutes (thread-safe snapshot) + on player quit
Custom Event API
BetterVeinmineEvent lets other plugins hook into every veinmine:
@EventHandler
public void onVeinmine(BetterVeinmineEvent event) {
// Cancel completely (e.g. in protected regions)
if (isProtected(event.getPlayer())) {
event.setCancelled(true);
return;
}
// Double EXP on ancient debris
if (event.getOreType() == Material.ANCIENT_DEBRIS) {
event.setExpReward(event.getExpReward() * 2);
}
plugin.getLogger().info(event.getPlayer().getName()
+ " veinmined " + event.getBlocks().size() + " blocks.");
}
Protection Plugin Support
A BlockBreakEvent is fired for each extra block before it is broken.
WorldGuard, GriefPrevention, Lands, and Residence can cancel individual blocks
within protected regions. Per-block events are guarded by an anti-recursion lock
so the plugin never triggers itself in a loop.
Permission-Based Limits
Give VIP/Premium players special treatment via permission-levels in config.
Ore Multipliers
Configure different EXP multipliers per ore type.
Per-Ore Cooldowns
Different cooldown per ore type.
Daily Limits
Cap veinmines per player per day. Resets at real midnight (persisted across restarts).
Installation
- Download
BetterVeinminer-1.4.0.jar - Drop into your server's
plugins/folder - Restart or reload the server
- Edit
plugins/BetterVeinminer/config.yml - Use
/bvm reloadto apply changes without restarting
Requirements: Paper (or any Paper fork) 1.21+, Java 21+
Permissions
| Permission | Description | Default |
|---|---|---|
betterveinminer.use |
Use veinminer + /bvm toggle/stats/tier |
true |
betterveinminer.admin |
Reload config (/bvm reload) |
op |
betterveinminer.vip |
VIP tier (custom limits via config) | false |
betterveinminer.premium |
Premium tier (best limits via config) | false |
Commands
| Command | Description | Permission |
|---|---|---|
/bvm toggle |
Enable/disable veinminer for yourself | betterveinminer.use |
/bvm stats |
View your mining statistics | betterveinminer.use |
/bvm tier |
Check your current tier & progression | betterveinminer.use |
/bvm reload |
Reload configuration file | betterveinminer.admin |
How to Use
- Hold a pickaxe from
tool-whitelist - Sneak (Shift) if
require-sneak: true - Break any ore block — the entire connected vein drops at once
Fortune and Silk Touch both work automatically on every block in the vein.
Configuration Reference
Basic Settings
enabled: true # Master on/off switch
require-sneak: true # Player must sneak to activate
require-pickaxe: true # Player must hold a whitelisted pickaxe
max-blocks: 64 # Max blocks per veinmine (fallback when tier system is off)
cooldown-ms: 200 # Cooldown between veinmines in milliseconds
damage-tool: true # Whether the pickaxe takes extra durability damage
damage-multiplier: 1.0 # Multiplier applied to the extra durability loss
Tier System
tier-system:
enabled: true
tier-2-threshold: 100000
tier-3-threshold: 500000
tier-4-threshold: 1000000
tier-1-max-blocks: 32
tier-2-max-blocks: 64
tier-3-max-blocks: 128
tier-4-max-blocks: 256
Ore Multipliers
ore-multipliers:
enabled: true
multipliers:
DIAMOND_ORE: 1.5
EMERALD_ORE: 2.0
COAL_ORE: 0.5
Per-Ore Cooldowns
per-ore-cooldowns:
enabled: false
cooldowns:
DIAMOND_ORE: 1000
COAL_ORE: 200
Permission Levels
permission-levels:
betterveinminer.vip:
max-blocks: 128
cooldown-ms: 100
betterveinminer.premium:
max-blocks: 256
cooldown-ms: 50
Daily Limits
daily-limits:
enabled: false
limit-per-day: 10
Custom Messages
All messages support § colour codes.
| Message key | Placeholders |
|---|---|
veinmine-success |
{count} |
tier-up |
{tier}, {blocks} |
stats |
{blocks}, {tier}, {uses} |
daily-limit |
— |
cooldown |
{remaining} |
EXP Rewards
exp-settings:
enabled: false
base-exp: 10
per-extra-block: 5
multiply-by-fortune: true
World Restrictions
whitelist-worlds: []
blacklist-worlds: []
Effects
particle-effect: true
sound-effect: true
effects:
particle-type: BLOCK
particle-color: "0xFFFFFF"
particle-speed: 1.0
completion-sound: BLOCK_STONE_BREAK
warning-sound: ENTITY_ITEM_PICKUP
Config Examples
Survival / Economy Server
tier-system:
enabled: true
tier-2-threshold: 50000
tier-3-threshold: 250000
tier-4-threshold: 500000
daily-limits:
enabled: true
limit-per-day: 5
ore-multipliers:
enabled: true
multipliers:
DIAMOND_ORE: 1.5
EMERALD_ORE: 2.0
Hardcore Mode
max-blocks: 16
cooldown-ms: 2000
tier-system:
enabled: false
damage-multiplier: 2.0
Developer API
Add as a soft dependency:
softdepend: [BetterVeinminer]
Listen to BetterVeinmineEvent:
import dev.duong2012g.bvm.BetterVeinmineEvent;
@EventHandler
public void onVeinmine(BetterVeinmineEvent event) {
Player player = event.getPlayer();
Material ore = event.getOreType();
List<Block> blocks = event.getBlocks(); // unmodifiable
int exp = event.getExpReward();
event.setExpReward(exp * 2);
event.setCancelled(true);
}
Bug Fixes in v1.4.0
| # | Bug | Status |
|---|---|---|
| 1 | Async save race condition — stats partially written while main thread modifies them | ✅ Fixed — snapshot taken on main thread before async I/O |
| 2 | Cooldown cleanup used hardcoded 60 s regardless of configured cooldown | ✅ Fixed — cleanup now uses config.getCooldownMs() |
| 3 | Daily reset based on server uptime ticks, not real calendar date | ✅ Fixed — LocalDate.now() with persistence in data.yml |
| 4 | 26-direction BFS could link two separate nearby veins | ✅ Fixed — changed to 6-direction (face-adjacent) matching vanilla ore generation |
| 5 | breakNaturally() bypassed protection plugins (WorldGuard, GriefPrevention…) |
✅ Fixed — BlockBreakEvent fired per block + anti-recursion guard |
| 6 | Unbreaking durability formula was deterministic average, not vanilla per-hit random | ✅ Fixed — vanilla-style per-hit random check |
| 7 | Tool swap exploit | ✅ Already fixed in v1.2.1 (slot + isSimilar() validation) |
| 8 | PlayerStats exposed public mutable fields — external code could set negative values |
✅ Fixed — private fields with validated getters/setters and copy() method |
| 9 | Config accepted invalid values (max-blocks: -1, damage-multiplier: -100) |
✅ Fixed — all numeric values clamped on load |
| 10 | Concurrent async writes could corrupt the same YAML file | ✅ Fixed — single-threaded ExecutorService serialises all file I/O |
Troubleshooting
Veinminer not activating:
- Check
enabled: truein config - Verify the ore is in
ore-types - Confirm you hold a pickaxe from
tool-whitelist - Check you are sneaking if
require-sneak: true - Verify the world is not blacklisted
Stats reset after restart:
- Check
plugins/BetterVeinminer/stats/is writable - Look for
"Failed to save stats"warnings in server logs
Daily limit resets too early / not resetting:
- Upgrade to v1.4.0 — the old tick-based timer drifted and was skipped on restarts
- The new system persists the last reset date to
data.yml
Changelog
See CHANGELOG.md
License
Apache-2.0 © Duong2012G


