Skip to content

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:

main.lua
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:

main.lua
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:

main.lua
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:

main.lua
local block = event:getBlock()
local blockType = block:getType()
local name = blockType:name()
  • block is 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.
  • blockType is 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".
  • name is 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:

main.lua
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.