Events
HyperPerms fires events when permissions are checked or modified. Subscribe to these events via the HyperPerms EventBus to integrate with other plugins or implement custom behavior.
Available Events
| Event | Fired When | Cancellable |
|---|---|---|
PermissionCheckEvent | A permission is checked | No (result modifiable) |
GroupCreateEvent | A group is created | Yes |
GroupDeleteEvent | A group is deleted | Yes |
GroupModifyEvent | A group is modified | Yes |
UserGroupChangeEvent | A user is added to or removed from a group | Yes |
UserLoadEvent | A user's permission data is loaded | No |
UserUnloadEvent | A user's permission data is unloaded | No |
DataReloadEvent | All permission data is reloaded | No |
TrackPromotionEvent | A user is promoted on a track | Yes |
TrackDemotionEvent | A user is demoted on a track | Yes |
Subscribing to Events
HyperPerms uses its own EventBus system. Subscribe to events using the API:
import com.hyperperms.api.event.EventBus;
import com.hyperperms.api.event.EventPriority;
import com.hyperperms.HyperPerms;
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
EventBus eventBus = HyperPerms.getApi().getEventBus();
// Subscribe to an event
eventBus.subscribe(GroupCreateEvent.class, EventPriority.NORMAL, event -> {
getLogger().info("Group created: " + event.getGroupName());
});
}
}
EventPriority
The EventPriority enum controls the order in which subscribers are called:
| Priority | Description |
|---|---|
LOWEST | Called first. Good for logging the original state. |
LOW | Called early. |
NORMAL | Default priority. Most handlers should use this. |
HIGH | Called late. Good for overriding earlier handlers. |
HIGHEST | Called last before MONITOR. Good for final overrides. |
MONITOR | Called absolutely last. Read-only; do not modify the event here. |
EventBus eventBus = HyperPerms.getApi().getEventBus();
// Called early - good for logging
eventBus.subscribe(PermissionCheckEvent.class, EventPriority.LOWEST, event -> {
// Log the original result
});
// Called late - good for overriding
eventBus.subscribe(PermissionCheckEvent.class, EventPriority.HIGHEST, event -> {
// Override the result if needed
});
Cancellable Interface
Events that implement Cancellable can be cancelled to prevent the action from completing.
Methods
isCancelled()- Returns whether the event has been cancelledsetCancelled(boolean)- Sets the cancellation state of the eventgetCancelReason()- Get the reason for cancellationsetCancelReason(String)- Set a reason (shown to command executor)
eventBus.subscribe(GroupDeleteEvent.class, EventPriority.NORMAL, event -> {
// Prevent deletion
event.setCancelled(true);
// Optionally provide a reason (shown to command executor)
event.setCancelReason("Group deletion is disabled");
});
Tip: When an event is cancelled, the action is prevented but the source (command or API call) will receive notification that it was cancelled.
PermissionCheckEvent
Fired every time a permission is checked for a player. Use this to modify permission results or log access.
import com.hyperperms.api.event.PermissionCheckEvent;
eventBus.subscribe(PermissionCheckEvent.class, EventPriority.NORMAL, event -> {
UUID player = event.getUser().getUuid();
String permission = event.getPermission();
boolean result = event.getResult();
// Log the check
System.out.println(player + " checked " + permission + " = " + result);
// Modify the result (use carefully!)
if (permission.equals("special.override")) {
event.setResult(true);
}
});
Event Properties
getUser()- The user being checkedgetPermission()- The permission node being checkedgetContexts()- The contexts for this checkgetResult()- The calculated resultsetResult(boolean)- Override the result
Warning: PermissionCheckEvent fires very frequently. Keep your handler fast to avoid performance issues. Avoid heavy operations in this event.
GroupCreateEvent
Fired when a new group is being created.
import com.hyperperms.api.event.GroupCreateEvent;
eventBus.subscribe(GroupCreateEvent.class, EventPriority.NORMAL, event -> {
String groupName = event.getGroupName();
// Prevent creation of certain groups
if (groupName.startsWith("reserved_")) {
event.setCancelled(true);
event.setCancelReason("Cannot create groups with 'reserved_' prefix");
return;
}
getLogger().info("Group created: " + groupName);
});
GroupDeleteEvent
Fired when a group is being deleted.
import com.hyperperms.api.event.GroupDeleteEvent;
eventBus.subscribe(GroupDeleteEvent.class, EventPriority.NORMAL, event -> {
Group group = event.getGroup();
// Prevent deletion of protected groups
if (group.getName().equals("default")) {
event.setCancelled(true);
event.setCancelReason("Cannot delete the default group");
return;
}
// Log the deletion
getLogger().info("Group deleted: " + group.getName());
});
GroupModifyEvent
Fired when a group's properties or permissions are modified.
import com.hyperperms.api.event.GroupModifyEvent;
import com.hyperperms.api.event.GroupModifyEvent.ModificationType;
eventBus.subscribe(GroupModifyEvent.class, EventPriority.NORMAL, event -> {
Group group = event.getGroup();
ModificationType type = event.getModificationType();
switch (type) {
case PERMISSION_ADD:
getLogger().info("Permission added to " + group.getName());
break;
case PERMISSION_REMOVE:
getLogger().info("Permission removed from " + group.getName());
break;
case PARENT_ADD:
getLogger().info("Parent added to " + group.getName());
break;
case PARENT_REMOVE:
getLogger().info("Parent removed from " + group.getName());
break;
case WEIGHT_CHANGE:
getLogger().info("Weight changed for " + group.getName());
break;
case PREFIX_CHANGE:
getLogger().info("Prefix changed for " + group.getName());
break;
case SUFFIX_CHANGE:
getLogger().info("Suffix changed for " + group.getName());
break;
}
});
UserGroupChangeEvent
Fired when a user is added to or removed from a group.
import com.hyperperms.api.event.UserGroupChangeEvent;
import com.hyperperms.api.event.UserGroupChangeEvent.ChangeType;
eventBus.subscribe(UserGroupChangeEvent.class, EventPriority.NORMAL, event -> {
User user = event.getUser();
Group group = event.getGroup();
ChangeType changeType = event.getChangeType();
switch (changeType) {
case ADD:
getLogger().info(user.getUsername() + " added to " + group.getName());
break;
case REMOVE:
getLogger().info(user.getUsername() + " removed from " + group.getName());
break;
case PRIMARY_CHANGE:
getLogger().info(user.getUsername() + " primary group set to " + group.getName());
break;
}
});
UserLoadEvent
Fired when a user's permission data is loaded (typically on join). Not cancellable.
import com.hyperperms.api.event.UserLoadEvent;
eventBus.subscribe(UserLoadEvent.class, EventPriority.NORMAL, event -> {
User user = event.getUser();
getLogger().info("Loaded permission data for " + user.getUsername());
});
UserUnloadEvent
Fired when a user's permission data is unloaded (typically on quit). Not cancellable.
import com.hyperperms.api.event.UserUnloadEvent;
eventBus.subscribe(UserUnloadEvent.class, EventPriority.NORMAL, event -> {
User user = event.getUser();
getLogger().info("Unloaded permission data for " + user.getUsername());
});
DataReloadEvent
Fired when all permission data is reloaded (e.g., via /hp reload). Not cancellable.
import com.hyperperms.api.event.DataReloadEvent;
eventBus.subscribe(DataReloadEvent.class, EventPriority.NORMAL, event -> {
getLogger().info("HyperPerms data reloaded, refreshing cached data...");
// Invalidate any caches that depend on permission data
});
TrackPromotionEvent
Fired when a user is promoted on a track.
import com.hyperperms.api.event.TrackPromotionEvent;
eventBus.subscribe(TrackPromotionEvent.class, EventPriority.NORMAL, event -> {
User user = event.getUser();
Track track = event.getTrack();
Group fromGroup = event.getFromGroup();
Group toGroup = event.getToGroup();
getLogger().info(String.format(
"%s promoted from %s to %s on track %s",
user.getUsername(),
fromGroup.getName(),
toGroup.getName(),
track.getName()
));
});
TrackDemotionEvent
Fired when a user is demoted on a track.
import com.hyperperms.api.event.TrackDemotionEvent;
eventBus.subscribe(TrackDemotionEvent.class, EventPriority.NORMAL, event -> {
User user = event.getUser();
Track track = event.getTrack();
Group fromGroup = event.getFromGroup();
Group toGroup = event.getToGroup();
getLogger().info(String.format(
"%s demoted from %s to %s on track %s",
user.getUsername(),
fromGroup.getName(),
toGroup.getName(),
track.getName()
));
});
EventBus Style
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
HyperPermsAPI api = HyperPermsProvider.get();
// Subscribe via EventBus
api.getEventBus().subscribe(UserGroupChangeEvent.class, this::handleGroupChange);
}
private void handleGroupChange(UserGroupChangeEvent event) {
// Handle the event
}
}
Best Practices
- Keep handlers fast - Especially for PermissionCheckEvent which fires frequently
- Use appropriate priority - Log at LOWEST, modify at NORMAL/HIGH, observe at MONITOR
- Don't block - Avoid I/O or network calls in event handlers
- Handle exceptions - Don't let errors propagate from handlers
- Be careful cancelling - Consider the user experience when cancelling events
- Use MONITOR for read-only - Never modify events at MONITOR priority