events.on(name, callback) adds a listener and returns an id. events.off(id) removes it again.
disable. See
Scripts and modules.
Listening needs no permission, but the plugin has to be enabled: a listener belonging to a
disabled plugin is skipped when the event fires. An unrecognised event name is accepted and
warned about in the log, together with the list of names that do exist, since nothing would ever
fire it.
The catalogue
title and anticheatFlag hand your callback two and three separate arguments rather than
one object. Every other event passes a single value.Payload shapes
A few of them are easier to misread than they look.
ChatData gives you the line three ways round: message has the colour codes stripped,
formatted is the line exactly as it was sent, and isSystem is true for a message shown above
the hotbar rather than in chat.
ActionBarData is the text above your hotbar, which on Hypixel carries timers, counters and pickup
messages: it fires many times a second in a game, so keep the listener cheap. Returning false
hides that line from you.
ServerModData is what a server pushed to Lunar or Badlion for one of that client’s own mods.
mod is the wire name the client uses (waypoints, tntTime, teamMarker on Badlion;
waypoint, server_rule, mod_setting on Lunar) and payload is the JSON it carried, as text.
Only the channel belonging to the client you are running is read, so a plugin on Forge never sees
this event, and there is nothing to send back: it is what the server said, not a way to say
anything.
MovementData is the position the server has put you at, not the one you walked to, so it
fires on teleports and rubber-banding rather than on every step.
PlayerConnectionData follows the tab list rather than the world, which on Hypixel is what you
want: it fires as players enter and leave your lobby. name may be null for an entry the server
sent without a profile.
EntityVelocityData is already converted to blocks per tick, so you can compare it against
movement.getMotionX() directly.
InteractionData currently only ever reports "SLEEP", and ScoreboardObjectiveData uses mode
0 for created, 1 for removed and 2 for updated.
title is the odd one out and hands your callback two arguments. type is one of TITLE,
SUBTITLE, TIMES, CLEAR or RESET, and message has its colour codes stripped. The last
three carry no text, so expect an empty string for those:
anticheatFlag hands you three: the flagged player’s UUID, the check’s id and its display name.
anticheat.onFlag is the supported way to receive the same thing, and reads better alongside a
check you registered yourself.
Cancelling
Returningfalse from a chat, actionBar or packet listener stops that message, line or packet
reaching the rest of the client, which is how a plugin hides a line or drops a packet:
false from a tick or serverMod listener does nothing.
When your listener runs
chat, packet and renderOverlay run inline, on the thread that produced them, because each
of them can be acted on before the client sees it. chat and packet therefore run on the network
thread, and renderOverlay on the render thread.
Everything else is scheduled onto the client thread and arrives a moment later, which is why those
events cannot be cancelled.
tick only fires while you are actually in a world, and renderOverlay only while no screen is
open, so an overlay disappears while the inventory or a menu is up.
Whatever the event, your listener has two seconds. A listener that passes that budget stops
that plugin and leaves the rest of the client running, so keep the body short and hand anything
slow to a timer.
Packets
packet fires for every packet the server sends and hands you the object Minecraft built rather
than a copy of it, so read it through its Java accessors: getX(), not .x.
events.isPacket(packet, name) narrows one by its simple class name, which is also what tells your
editor the real signatures:
ServerPacketMap in seraph.d.ts, from
S00PacketKeepAlive through to S49PacketUpdateEntityNBT. A packet Seraph has no type for still
arrives; it simply has no completion behind it.
This is the busiest event there is, several hundred times a second in a full lobby, so check the
type first and do as little as possible in the branch. If a named event above covers what you want,
use that instead: windowOpen is cheaper than watching for S2DPacketOpenWindow yourself.
Java values you will meet
A packet’s accessors return Java objects, not plain JavaScript ones. They are typed inseraph.d.ts and behave the way Java does.
toArray() is the quickest way out of Java and into ordinary JavaScript:
name() rather than against the value itself, since two wrappers around the
same constant are not === equal:
Next
API reference
Every global object a plugin can reach.
Examples
Complete plugins you can drop straight into the folder.