DUXPLIMA Documentation

Events

The events uxmEssentials publishes, and the ones you can cancel.

Everything uxmEssentials does is published as an ordinary Bukkit event. What can be refused cleanly is published twice: once as a question you may cancel, once as the fact afterwards.

All of them live under com.uxplima.uxmessentials.api.bukkit.event, one package per context. You listen to them the way you listen to anything else:

@EventHandler
public void onHomeCreated(UxmHomeCreateEvent event) {
    getLogger().info(event.getPlayerName() + " set home " + event.getSlotNumber());
}

The two kinds

NotificationPre-event
NamedUxm<Thing><Action>EventUxm<Thing>Pre<Action>Event
Saysthis happenedthis is about to happen
Cancellablenoyes
Threadthe tick thread that owns the subjectwhichever thread the operation is on
Bukkit API in the handleryesno

Every context publishes notifications. Only nine operations have a pre-event, and that is deliberate: a veto point is a promise that the operation can be refused with nothing half-done and nothing charged, and most of what a server does cannot be taken back that way. A mail already read, a punishment already served, a warp already walked to.

What you can cancel

EventRefusing it meansAsked
UxmHomePreCreateEventthe home is not createdafter the slot and the limit are checked, before the player is charged
UxmHomePreDeleteEventthe home staysbefore the row is removed
UxmHomePreRelocateEventthe home stays where it isbefore the move and before any fee
UxmPlayerPreTeleportEventthe teleport does not happenbefore the warmup starts, so the player does not stand still for nothing
UxmWarpPreCreateEventthe warp is not createdbefore it is written
UxmWarpPreDeleteEventthe warp staysbefore it is removed
UxmPlayerWarpPreCreateEventthe player warp is not createdafter the owner's quota is checked, before anything is written
UxmPlayerWarpPreDeleteEventthe player warp staysonly on the irreversible delete, never on archiving
UxmKitPreClaimEventthe kit is not handed outafter the cooldown and permission pass, before the charge and before any item

A cancelled operation fails cleanly. Nothing is written, nothing is charged, no cooldown is stamped, and the player is told the action was blocked. It is not treated as an error, so nothing is logged as one. If you want them to know why, tell them yourself.

UxmPlayerPreTeleportEvent is asked at the one point every voluntary teleport passes through, so a listener that refuses teleports refuses /home, /warp, /spawn, /back, /tpa and /rtp alike, including whatever is added later. Two things are deliberately not asked: an arrival after respawn or first join, since there would be nowhere to leave the player, and a staff hard-delete of a player warp by id, since clearing an abusive warp must not be blockable by whatever else happens to be installed.

@EventHandler(ignoreCancelled = true)
public void onHomeCreating(UxmHomePreCreateEvent event) {
    // No Bukkit API here: this is not a tick thread.
    if (event.getLocation().world().endsWith("_nether")) {
        event.setCancelled(true);
    }
}

Threading

Notification events are delivered on the tick thread that owns their subject: the player's region on Folia, the main thread on Paper. Use the Bukkit API freely in those handlers.

Pre-events are different, and the difference is not cosmetic. The operation is blocked on your answer, so the event fires on whichever thread the operation is on, which is usually a database thread. In those handlers:

  • do not touch the Bukkit API, and
  • keep it quick, because a player is waiting.

Read the event, decide, return. If you need to do something afterwards, schedule it.

Nothing costs anything when nobody is listening. Both paths check for listeners before they build anything, so on a server with no plugin listening the whole mechanism is a map lookup: about 7 ns, no allocation, nothing scheduled. You never need to worry that adding a listener for one event makes the rest of the plugin slower.

Shared shapes

Most events carry a subject player, and those extend a common base:

MethodGives you
getPlayerId()the subject's UUID, always present, online or not
getPlayerName()their name at the time of the event
getOfflinePlayer()an OfflinePlayer, always
getPlayer()the online Player, or null if they are not online (notification events only)

Positions arrive as UxmLocation, a plain record of world, x, y, z, yaw and pitch. The world is its name rather than a Bukkit handle, because an event can describe a place in a world that is not loaded; turn it into a real location with Bukkit.getWorld(loc.world()), which answers null for an unloaded one. Money arrives as UxmMoney, an amount and its currency id, because a server can run more than one currency.

The catalogue

Homes

EventFires whenCarries
UxmHomeCreateEventa home was createdgetSlot(), getSlotNumber(), getLocation()
UxmHomeRelocateEventa home was movedslot
UxmHomeDeleteEventa home was deletedslot
UxmHomeRenameEventa home was renamedslot
UxmHomeIconChangeEventa home's icon changedslot
UxmHomeVisibilityChangeEventa home was made public or privateslot
UxmHomeLimitReachedEventa player tried to set one home too manygetCurrentCount(), getLimit()

Teleport

EventFires whenCarries
UxmPlayerTeleportEventa player was moved by uxmEssentialsgetKind(), getFrom(), getTo()
UxmWarmupStartEventa warmup begangetKind(), getOrigin(), getDuration()
UxmWarmupCancelEventa warmup was cut shortgetKind(), getReason()
UxmBackLocationCaptureEventa return point was recordedgetLocation(), getCause()
UxmTeleportRequestSendEventa /tpa or /tpahere was sentgetDirection(), getExpiresAt()
UxmTeleportRequestAcceptEventa request was acceptedrequest id, both players
UxmTeleportRequestDenyEventa request was deniedrequest id, both players
UxmTeleportRequestCancelEventthe requester withdrew itrequest id, both players
UxmTeleportRequestExpireEventa request timed outrequest id, both players

getKind() tells you which door the teleport came through: REQUEST, BACK, RANDOM, SPAWN, HOME, WARP, RESPAWN, ADMIN or POSITIONAL.

Warps and player warps

EventFires whenCarries
UxmWarpCreateEventa server warp was createdgetWarpName(), getLocation()
UxmWarpDeleteEventa server warp was deletedwarp name
UxmPlayerWarpCreateEventa player warp was createdgetWarpName(), getLocation()
UxmPlayerWarpDeleteEventa player warp was deleted for goodwarp name

Economy

EventFires whenCarries
UxmWalletCreditEventmoney arrivedgetAmount(), getBalance(), getTransactionId(), getOccurredAt()
UxmWalletDebitEventmoney leftgetAmount(), getBalance(), getTransactionId(), getOccurredAt()
UxmWalletRejectEventa transaction was refusedgetRequested(), getAvailable(), getReason()
UxmBankDepositEventa bank account was paid intogetBankId(), getAmount(), getBankBalance()
UxmBankWithdrawEventa bank account was drawn ongetBankId(), getAmount(), getBankBalance()
UxmLoanDisburseEventa loan was grantedgetLoanId(), getPrincipal()
UxmLoanRepayEventa loan payment was madegetLoanId(), getPaid(), getRemaining()

getReason() on a rejection is either INSUFFICIENT_FUNDS or BALANCE_MAX_EXCEEDED.

Kits

EventFires whenCarries
UxmKitClaimEventa kit was handed outgetKitId(), getActorId(), isSelfClaimed(), getAt()

Vaults

EventFires whenCarries
UxmVaultOpenEventa vault was openedgetIndex(), getViewerId(), isOwnVault()
UxmVaultContentsChangeEventa vault's contents changedgetIndex()

Moderation

EventFires whenCarries
UxmPlayerWarnEventa player was warnedgetIssuer(), getReason(), getExpiresAt(), getTotalWarnings()
UxmPlayerMuteEventa player was mutedgetIssuer(), getReason(), getUntil()
UxmPlayerUnmuteEventa mute was liftedsubject
UxmPlayerJailEventa player was jailedgetJail(), getIssuer(), getReason(), getUntil()
UxmPlayerUnjailEventa player was releasedsubject
UxmPlayerTempbanEventa player was temporarily bannedgetIssuer(), getReason(), getUntil()
UxmIpBanEventan address was bannedgetIp(), getTarget(), getUntil(), getIssuer()
UxmAltDetectedEventa join matched another account's addressgetIp(), getMatched(), isKicked()
UxmJailLocationDefineEventa jail was definedgetJail()
UxmJailLocationRemoveEventa jail was removedgetJail()

getIssuer() returns a UxmIssuer, which is a name plus an optional UUID, because the console issues punishments too and it has no UUID.

Player state

EventFires whenCarries
UxmPlayerHealEventa player was healedactor, isSelfInflicted()
UxmPlayerFeedEventa player was fedactor, isSelfInflicted()
UxmPlayerFlyToggleEventflight was turned on or offisEnabled()
UxmPlayerGodToggleEventgod mode was turned on or offisEnabled()
UxmPlayerGameModeChangeEventa game mode was setgetMode()
UxmPlayerSpeedChangeEventwalk or fly speed was setgetKind(), getScale()

Messaging, presence and communication

EventFires whenCarries
UxmPrivateMessageEventa /msg was deliveredgetRecipientId(), getMessage(), getSentAt()
UxmMailDeliverEventmail was put in an inboxgetSenderId(), getSenderName(), getMessage()
UxmHelpOpEventa player raised a /helpopgetMessage(), getRaisedAt()
UxmAfkEventa player went AFK or came backisAfk(), isAutomatic(), getReason()
UxmBroadcastOptOutEventa player opted in or out of announcementsisOptedOut()
UxmAnnouncerReloadEventthe announcement list was reloadedgetLineCount()

Staff, scoreboard and poses

EventFires whenCarries
UxmStaffModeEventstaff mode was entered or leftisEntered()
UxmStaffChatEventa staff-chat message was sentgetMessage()
UxmScoreboardVisibilityEventa player hid or showed the scoreboardisHidden()
UxmPoseEventa player sat, lay down or stood upisStarted(), getType(), getReturnLocation(), getTargetId()

Worlds

EventFires whenCarries
UxmWorldCreateEventa managed world was createdgetWorldName()
UxmWorldImportEventan existing world folder was importedworld name
UxmWorldAdoptEventa world already on the server was adoptedworld name
UxmWorldLoadEventa managed world was loadedworld name
UxmWorldUnloadEventa managed world was unloadedworld name
UxmWorldDeleteEventa managed world was deletedworld name
UxmWorldUnregisterEventa world stopped being managedworld name
UxmWorldSettingChangeEventa world setting was changedgetSettingKey(), getSettingValue()
UxmWorldEntryDeniedEventa player was refused entrygetPlayerId(), getReason()

Holograms and NPCs

EventFires whenCarries
UxmHologramCreateEventa hologram was createdgetHologramName(), getLocation()
UxmHologramDeleteEventa hologram was deletedhologram name
UxmNpcCreateEventan NPC was createdgetNpcName(), getLocation()
UxmNpcMoveEventan NPC was re-anchorednpc name, getLocation()
UxmNpcDeleteEventan NPC was deletednpc name

Trade

EventFires whenCarries
UxmTradeCompleteEventboth sides confirmed and the swap settledgetInitiatorItems(), getPartnerItems(), getInitiatorMoney(), getPartnerMoney(), getInitiatorExperience(), getPartnerExperience()
UxmTradeCancelEventa trade ended without a swapgetTradeId(), both sides' ids and names

Both name two players rather than one, so they extend UxmEvent and not the player event. A cancel covers a cancel, a closed window and a disconnect alike: which of the three it was is not carried, because all three reach the same path. The completion event fires whether or not the operator has the trade audit switched on.

Ranks

EventFires whenCarries
UxmRankUpEventa player moved up a runggetFromRank(), getToRank()
UxmRankSetEventan administrator set a rank directlygetPreviousRank(), getRank()
UxmPrestigeEventa player prestigedgetLevel(), getRewardMultiplier()

A rankup fires after the new rank is stored and its actions have run. UxmRankSetEvent may be about a player who is offline, and getPreviousRank() is empty for one who had never been ranked before.

EventFires whenCarries
UxmAccountLinkEventa code was redeemed and the accounts are boundgetDiscordId(), getLinkedAt()
UxmAccountUnlinkEventa binding was removedgetDiscordId()

The code is redeemed on Discord's side, so the link event very often fires for a player who is not online. Do not assume a live player from it. The unlink event carries the account that was bound because by the time it fires there is nowhere left to look it up, and it covers all three ways a binding ends: the player, an operator, or a plugin.

Inventory snapshots

EventFires whenCarries
UxmInventoryRestoreEventa stored snapshot was put backgetSnapshotId(), getCause(), getTakenAt()

Fires after the items are set, so a listener reading the inventory sees the restored one. The safety copy taken of what was there before is a capture rather than a restore, and fires nothing.

Security

EventFires whenCarries
UxmVerificationPassEventa player proved their second factorplayer id and name
UxmVerificationFailEventa submitted value proved nothinggetRemainingAttempts()
UxmSecurityLockoutEventan account ran out of attemptsgetLockout(), isBanned()

The attempt that spends the last try fires the lockout rather than another failure, so one submission never fires both. Which factor was presented is not carried, because the verification does not learn it either: that is what makes the comparison constant-time.

A pass fires only for a proof that was actually made. A player holding no factor is never asked for one, and one waved through by a remembered device proved nothing this time.

Vanish

EventFires whenCarries
UxmVanishToggleEventa player went hidden, or came back into viewisVanished(), getLevel()

Fires for every door into vanish: the command, the staff-mode toggle, the presence panel, and a plugin calling the published action. By the time it fires the player is already hidden or already visible, so a listener mirroring the state elsewhere can read it straight off the event.

The level is the tier they are hidden at, counting from one. On a reveal it is the tier they were hidden at until a moment ago, which is what a listener needs to undo whatever it did when they vanished.

A quit does not fire it. A player who logs out hidden logs back in hidden, and treating a disconnect as a reveal would make every listener flicker on a server hop.

Voting and item or world utilities

EventFires whenCarries
UxmVoteReceiveEventa vote was creditedgetService()
UxmVotePartyEventa vote party firedgetThreshold()
UxmMobSpawnEventstaff spawned mobsgetEntityType(), getRequested(), getSpawned()
UxmEntityPurgeEvententities were clearedgetScope(), getCategory(), getRadius(), getRemoved()

Registering your listener

Nothing special is needed. There is no guard, no soft dependency, no load-order dance:

@Override
public void onEnable() {
    getServer().getPluginManager().registerEvents(new MyListener(), this);
}

Your listener's signatures name uxmEssentials classes, which resolve from the API artifact you compiled against and are present at runtime inside the plugin jar. If uxmEssentials is not installed, your listener simply never fires.

A disabled module fires nothing

Nine modules ship switched off. Silence from one of them means the operator turned it off, not that nothing happened. Use api.isModuleEnabled("homes") when you need to tell the difference.

Next steps