Events¶
Events are how your plugin reacts to things that happen in the game. You've already used two, PlayerJoinEvent and PlayerQuitEvent. In this lesson you'll learn how to see what an event gives you and how to cancel one so the thing never happens, and you'll finish with a plugin that protects certain blocks from being broken.
All the examples in this lesson use the same event, so replace the previous example each time instead of adding to it.
To see which events exist, check the event list, which has every event grouped by category.
Part 1: See what an event gives you¶
When something happens in the game, Spigot makes an event that describes it and hands it to your function. Different events describe different things. A PlayerJoinEvent knows which player joined, and a BlockBreakEvent knows which player broke which block:
plugin.registerEvent("BlockBreakEvent", function(event)
local player = event:getPlayer()
local block = event:getBlock()
player:sendMessage("You broke: " .. block:getType():name())
end)
event:getPlayer() and event:getBlock() ask the event for the player and the block. Then block:getType() gives the kind of block it was, and :name() turns that into text like STONE or DIRT, so it can go in a message.
Every call here uses a colon, because the event and everything on it comes from Spigot.
Try it by breaking a few different blocks and reading what comes back.
Part 2: Cancel an event¶
Events happen in two steps. First Minecraft says "this is about to happen", and your plugin gets to look at it. Then, if nobody stops it, it goes ahead. Calling event:setCancelled(true) is how you stop it:
plugin.registerEvent("BlockBreakEvent", function(event)
event:setCancelled(true)
event:getPlayer():sendMessage("You can't break blocks here!")
end)
Now no block breaks, and the player gets a message instead.
This one stops everyone, including you
Once this is running, nobody can break any block. Take it out when you're done trying it.
Not every event can be cancelled. You can't cancel someone joining, for example, because it has already happened. The table at the end of this page shows which ones you can, and the event list shows it for every event.
Part 3: Only cancel certain blocks¶
Stopping every block isn't very useful, so let's check which block it is first:
plugin.registerEvent("BlockBreakEvent", function(event)
local name = event:getBlock():getType():name()
if name == "OBSIDIAN" then
event:setCancelled(true)
event:getPlayer():sendMessage("You can't break obsidian!")
end
end)
That first line does a lot at once, so let's slow it down. Here is the same thing written as three separate steps:
local block = event:getBlock()
local blockType = block:getType()
local name = blockType:name()
blockis the block that was broken: one specific block in the world, sitting in one specific spot. If a player breaks two obsidian blocks, those are two different blocks.blockTypeis what kind of block it is. Both of those obsidian blocks have the same type, which is obsidian. It isn't text, though. It's a Spigot object called a Material, so you can't compare it with a piece of text like"OBSIDIAN".nameis that type written out as text, like"OBSIDIAN". Now we have a piece of text, which is something we can compare.
Each : takes the answer from the step before and asks it the next question, so the one-line version is the same thing with the middle steps skipped. You'll see chains like this a lot in Spigot.
Next we use == to ask whether it's equal to "OBSIDIAN". A single = sets something, and a double == compares two things, so watch for that one. If it matches, we cancel the event and send the message, and any other block breaks as normal.
Block names are all capitals with underscores, like DIAMOND_BLOCK, and they have to match exactly. You can find every name in the Material list.
Names can change between versions
Many block names changed in Minecraft 1.13, so check the list for your server's version.
Putting it together¶
To protect more than one block, use or. Replace your plugin's block event with this:
plugin.registerEvent("BlockBreakEvent", function(event)
local name = event:getBlock():getType():name()
if name == "OBSIDIAN" or name == "DIAMOND_BLOCK" then
event:setCancelled(true)
event:getPlayer():sendMessage("You can't break " .. name .. "!")
end
end)
or means either one is enough, so the event is cancelled for obsidian or for diamond blocks. The message includes the block's name, so the player knows what they tried to break.
Try these in survival mode:
- Break a dirt or stone block, and it breaks as normal.
- Break obsidian, and it stays put with a message.
- Break a diamond block, and the same thing happens.
Quick reference¶
These are some of the most-used events. Call things on them with a colon, like event:getPlayer(). Click an event's name to see its whole category, or open the event list to browse them all. Any Spigot event works, not just these.
| Event | When it happens | Can you cancel it? | Useful calls |
|---|---|---|---|
PlayerJoinEvent |
A player joins | No | getPlayer() |
PlayerQuitEvent |
A player leaves | No | getPlayer() |
PlayerDeathEvent |
A player dies | No | getEntity() |
PlayerInteractEvent |
A player clicks or uses something | Yes | getPlayer(), getItem(), getClickedBlock() |
PlayerMoveEvent |
A player moves, which happens very often | Yes | getPlayer(), getFrom(), getTo() |
PlayerDropItemEvent |
A player drops an item | Yes | getPlayer(), getItemDrop() |
PlayerCommandPreprocessEvent |
A player types a command, just before it runs | Yes | getPlayer(), getMessage() |
BlockBreakEvent |
A player breaks a block | Yes | getPlayer(), getBlock() |
BlockPlaceEvent |
A player places a block | Yes | getPlayer(), getBlock() |
EntityDamageEvent |
Anything takes damage | Yes | getEntity(), getDamage(), getCause() |
EntityDamageByEntityEvent |
Something is hurt by something else | Yes | getEntity(), getDamager(), getDamage() |
EntityDeathEvent |
A mob or other entity dies | No | getEntity() |
InventoryClickEvent |
Someone clicks in an inventory | Yes | getWhoClicked(), getCurrentItem(), getSlot() |
Names must be exact
Event names are case sensitive, so PlayerJoinEvent works and playerjoinevent doesn't. If LuaCord can't find an event by its short name, try its full class name instead, like org.bukkit.event.player.PlayerJoinEvent.
Next up is messages and colors.