Determine which action counts
The example for Paper 26.3 and Java 25 uses base Gradle project. In world world the Survival player breaks STONE and receives a message. A player-placed stone is also suitable: the origin of the block is not stored here.
First check the actual world name via the console minecraft:list and your world settings: the arena folder name may be different from world. The conditions in the code should describe the desired world, and not a random current server.
Register a listener instance
Replace the main Java file with the complete class below. registerEvents is called once in onEnable. On MONITOR, the handler observes the state and does not cancel the action; ignoreCancelled=true skips an attempt that is already prohibited.
package ru.example.trailnotes;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.plugin.java.JavaPlugin;
public final class TrailNotesPlugin extends JavaPlugin implements Listener {
@Override
public void onEnable() {
getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBreak(BlockBreakEvent event) {
if (!event.getBlock().getWorld().getName().equals("world")) return;
if (event.getPlayer().getGameMode() != GameMode.SURVIVAL) return;
if (event.getBlock().getType() != Material.STONE) return;
event.getPlayer().sendMessage("Разрешённое разрушение камня учтено.");
}
}Check positive and negative cases
Build the JAR, install it in a separate test Paper and log in without OP. First, make sure there is no plugin enable error in the log. Then perform four experiments.
| Experience | Expected |
|---|---|
| STONE, Survival, world, destruction allowed | One message |
| DIRT under the same conditions | No message |
| STONE in Creative or other world | No message |
| STONE is regionally banned | The block remains, there is no message |
Don't turn a notification into a repeatable reward
If there is no message, temporarily add a log before each early return: you will see which filter did not pass. If the message is repeated twice, check that the listener is registered twice and that there are two copies of the plugin. Synchronous SQL in each destruction will add latency to the game flow.
The BlockBreakEvent contract contains neither a block’s origin nor a payment operation ID. Send the confirmed event to a quest progress service; for a one-time reward, use a persistent key combining the player and task.
A unique key is needed when repeating an event and after a restart. Protect one-time reward.
The file and database are read separately from the game tick, checking the relevance of the response. Put up with slow work.
