Event listeners
Listen for and handle server events in C++.
Endstone raises an event whenever something happens in the game - a player joins, a block breaks, a message is sent. A plugin reacts by registering a listener for the events it cares about. The scenarios below go from simply observing an event to changing or vetoing what the server does.
Write a handler
Add a method that takes the event by reference:
#include <endstone/endstone.hpp>
namespace es = endstone;
class MyPlugin : public es::Plugin {
public:
void onPlayerJoin(es::PlayerJoinEvent &event)
{
getServer().broadcastMessage(
es::ColorFormat::Yellow + "{} has joined the server",
event.getPlayer().getName());
}
};Register the listener
Handlers only fire once registered. Call registerEvent in onEnable, pointing it at your handler:
void onEnable() override
{
registerEvent(&MyPlugin::onPlayerJoin, *this);
}Use one registerEvent call per handler, and add as many as you need to listen for more events.
Cancel an event
Many events are cancellable - calling event.setCancelled(true) tells the server not to do the thing it was about to. Here, only operators may break blocks:
void onBlockBreak(es::BlockBreakEvent &event)
{
if (!event.getPlayer().isOp()) {
event.setCancelled(true);
event.getPlayer().sendMessage("You can't break blocks here.");
}
}Change an event
Some events let you rewrite their data before the server acts on it. PlayerChatEvent exposes the outgoing message through getMessage and setMessage:
void onPlayerChat(es::PlayerChatEvent &event)
{
event.setMessage("[member] " + event.getMessage());
}Run at a set priority
When several listeners handle the same event, they run in order: Lowest → Low → Normal (the default) → High → Highest → Monitor. Pass a priority as the third argument to registerEvent to control where yours falls. Monitor runs last and is meant for observing the final outcome, not changing it:
void onEnable() override
{
registerEvent(&MyPlugin::onBlockBreak, *this, es::EventPriority::Monitor);
}
void onBlockBreak(es::BlockBreakEvent &event)
{
if (!event.isCancelled()) {
getLogger().info("{} broke a block", event.getPlayer().getName());
}
}Skip already-cancelled events
By default a handler still runs even if an earlier listener cancelled the event. Pass true as the fourth argument (ignore_cancelled) to bow out when that's already happened:
void onEnable() override
{
// priority Normal, ignore_cancelled = true
registerEvent(&MyPlugin::onBlockBreak, *this, es::EventPriority::Normal, true);
}