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

EventFired WhenCancellable
PermissionCheckEventA permission is checkedNo (result modifiable)
GroupCreateEventA group is createdYes
GroupDeleteEventA group is deletedYes
GroupModifyEventA group is modifiedYes
UserGroupChangeEventA user is added to or removed from a groupYes
UserLoadEventA user's permission data is loadedNo
UserUnloadEventA user's permission data is unloadedNo
DataReloadEventAll permission data is reloadedNo
TrackPromotionEventA user is promoted on a trackYes
TrackDemotionEventA user is demoted on a trackYes

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:

PriorityDescription
LOWESTCalled first. Good for logging the original state.
LOWCalled early.
NORMALDefault priority. Most handlers should use this.
HIGHCalled late. Good for overriding earlier handlers.
HIGHESTCalled last before MONITOR. Good for final overrides.
MONITORCalled 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 cancelled
  • setCancelled(boolean) - Sets the cancellation state of the event
  • getCancelReason() - Get the reason for cancellation
  • setCancelReason(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 checked
  • getPermission() - The permission node being checked
  • getContexts() - The contexts for this check
  • getResult() - The calculated result
  • setResult(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

See Also