---
title: Permission Events
type: docs
weight: 4
---

Events triggered when permissions or group memberships change. These events allow plugins to react to permission system modifications.

{{< callout type="info" >}}
**Note:** These events fire when permissions change, not when they are checked. They are useful for synchronization, logging, and reacting to permission modifications.
{{< /callout >}}

## Player Permission Events

### PlayerPermissionChangeEvent

Abstract base class for all player permission change events.

**Package:** `com.hypixel.hytale.server.core.event.events.permissions`

{{< tabs items="Fields,Methods" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the UUID of the player whose permissions changed
{{< /tab >}}
{{< /tabs >}}

---

### PlayerPermissionChangeEvent.PermissionsAdded

Fired when permissions are directly added to a player.

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| addedPermissions | `Set<String>` | Set of permission nodes added |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getAddedPermissions()` - Returns unmodifiable set of added permissions
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    Set<String> addedPerms = event.getAddedPermissions();

    getLogger().at(Level.INFO).log("Player " + playerUuid + " gained permissions: " + addedPerms);

    // Notify online player
    Player player = Universe.get().getPlayer(playerUuid);
    if (player != null) {
        player.sendMessage(Message.raw("You gained new permissions!"));
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

### PlayerPermissionChangeEvent.PermissionsRemoved

Fired when permissions are directly removed from a player.

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| removedPermissions | `Set<String>` | Set of permission nodes removed |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getRemovedPermissions()` - Returns unmodifiable set of removed permissions
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    Set<String> removedPerms = event.getRemovedPermissions();

    getLogger().at(Level.INFO).log("Player " + playerUuid + " lost permissions: " + removedPerms);

    // Check if player lost admin permission
    if (removedPerms.contains("admin.*")) {
        notifyAdmins("Player " + playerUuid + " is no longer an admin");
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

### PlayerPermissionChangeEvent.GroupAdded

Fired when a player is added to a permission group (via PlayerPermissionChangeEvent).

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| groupName | `String` | Name of the group added |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getGroupName()` - Returns the group name
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlayerPermissionChangeEvent.GroupAdded.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    String group = event.getGroupName();

    getLogger().at(Level.INFO).log("Player " + playerUuid + " added to group: " + group);
});
```
{{< /tab >}}
{{< /tabs >}}

---

### PlayerPermissionChangeEvent.GroupRemoved

Fired when a player is removed from a permission group (via PlayerPermissionChangeEvent).

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| groupName | `String` | Name of the group removed |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getGroupName()` - Returns the group name
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlayerPermissionChangeEvent.GroupRemoved.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    String group = event.getGroupName();

    getLogger().at(Level.INFO).log("Player " + playerUuid + " removed from group: " + group);
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Group Permission Events

### GroupPermissionChangeEvent

Abstract base class for group permission change events.

**Package:** `com.hypixel.hytale.server.core.event.events.permissions`

{{< tabs items="Fields,Methods" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| groupName | `String` | Name of the affected group |
{{< /tab >}}
{{< tab >}}
- `getGroupName()` - Returns the name of the group whose permissions changed
{{< /tab >}}
{{< /tabs >}}

---

### GroupPermissionChangeEvent.Added

Fired when permissions are added to a group.

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| groupName | `String` | Name of the affected group |
| addedPermissions | `Set<String>` | Set of permission nodes added |
{{< /tab >}}
{{< tab >}}
- `getGroupName()` - Returns the group name
- `getAddedPermissions()` - Returns unmodifiable set of added permissions
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(GroupPermissionChangeEvent.Added.class, event -> {
    String group = event.getGroupName();
    Set<String> addedPerms = event.getAddedPermissions();

    getLogger().at(Level.INFO).log("Group " + group + " gained permissions: " + addedPerms);

    // Notify all online players in this group
    notifyGroupMembers(group, "Your group gained new permissions!");
});
```
{{< /tab >}}
{{< /tabs >}}

---

### GroupPermissionChangeEvent.Removed

Fired when permissions are removed from a group.

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| groupName | `String` | Name of the affected group |
| removedPermissions | `Set<String>` | Set of permission nodes removed |
{{< /tab >}}
{{< tab >}}
- `getGroupName()` - Returns the group name
- `getRemovedPermissions()` - Returns unmodifiable set of removed permissions
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(GroupPermissionChangeEvent.Removed.class, event -> {
    String group = event.getGroupName();
    Set<String> removedPerms = event.getRemovedPermissions();

    getLogger().at(Level.INFO).log("Group " + group + " lost permissions: " + removedPerms);
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Player Group Events

### PlayerGroupEvent

Fired when a player's group membership changes. Extends `PlayerPermissionChangeEvent`.

**Package:** `com.hypixel.hytale.server.core.event.events.permissions`

{{< tabs items="Fields,Methods" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| groupName | `String` | Name of the group |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getGroupName()` - Returns the group name
{{< /tab >}}
{{< /tabs >}}

---

### PlayerGroupEvent.Added

Fired when a player is added to a group.

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| groupName | `String` | Name of the group joined |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getGroupName()` - Returns the group name
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlayerGroupEvent.Added.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    String group = event.getGroupName();

    getLogger().at(Level.INFO).log("Player " + playerUuid + " joined group: " + group);

    // Welcome message for VIP group
    if (group.equals("vip")) {
        Player player = Universe.get().getPlayer(playerUuid);
        if (player != null) {
            player.sendMessage(Message.raw("Welcome to the VIP group!"));
        }
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

### PlayerGroupEvent.Removed

Fired when a player is removed from a group.

{{< tabs items="Fields,Methods,Example" >}}
{{< tab >}}
| Field | Type | Description |
|-------|------|-------------|
| playerUuid | `UUID` | UUID of the affected player |
| groupName | `String` | Name of the group left |
{{< /tab >}}
{{< tab >}}
- `getPlayerUuid()` - Returns the player's UUID
- `getGroupName()` - Returns the group name
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlayerGroupEvent.Removed.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    String group = event.getGroupName();

    getLogger().at(Level.INFO).log("Player " + playerUuid + " left group: " + group);

    // Log staff changes
    if (group.equals("staff") || group.equals("admin")) {
        logStaffChange(playerUuid, group, "removed");
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Practical Examples

### Permission Audit Logger

```java
public class PermissionAuditPlugin extends JavaPlugin {

    @Override
    public void start() {
        // Log all player permission changes
        getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
            logAudit("PERM_ADD", event.getPlayerUuid(), event.getAddedPermissions());
        });

        getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
            logAudit("PERM_REMOVE", event.getPlayerUuid(), event.getRemovedPermissions());
        });

        // Log all group membership changes
        getEventRegistry().register(PlayerGroupEvent.Added.class, event -> {
            logAudit("GROUP_JOIN", event.getPlayerUuid(), Set.of(event.getGroupName()));
        });

        getEventRegistry().register(PlayerGroupEvent.Removed.class, event -> {
            logAudit("GROUP_LEAVE", event.getPlayerUuid(), Set.of(event.getGroupName()));
        });

        // Log group permission changes
        getEventRegistry().register(GroupPermissionChangeEvent.Added.class, event -> {
            logGroupAudit("GROUP_PERM_ADD", event.getGroupName(), event.getAddedPermissions());
        });

        getEventRegistry().register(GroupPermissionChangeEvent.Removed.class, event -> {
            logGroupAudit("GROUP_PERM_REMOVE", event.getGroupName(), event.getRemovedPermissions());
        });
    }

    private void logAudit(String action, UUID player, Set<String> items) {
        getLogger().at(Level.INFO).log(String.format("[AUDIT] %s: player=%s items=%s", action, player, items));
    }

    private void logGroupAudit(String action, String group, Set<String> items) {
        getLogger().at(Level.INFO).log(String.format("[AUDIT] %s: group=%s items=%s", action, group, items));
    }
}
```

### Permission Synchronization

```java
public class PermissionSyncPlugin extends JavaPlugin {

    private final Map<UUID, Set<String>> cachedPermissions = new HashMap<>();

    @Override
    public void start() {
        // Keep cache synchronized with permission changes
        getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
            cachedPermissions.computeIfAbsent(event.getPlayerUuid(), k -> new HashSet<>())
                .addAll(event.getAddedPermissions());
        });

        getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
            Set<String> perms = cachedPermissions.get(event.getPlayerUuid());
            if (perms != null) {
                perms.removeAll(event.getRemovedPermissions());
            }
        });
    }

    public Set<String> getCachedPermissions(UUID player) {
        return cachedPermissions.getOrDefault(player, Collections.emptySet());
    }
}
```

## Best Practices

{{< callout type="info" >}}
**Permission Event Guidelines:**
- These events fire after permissions have changed, not before
- Use for logging, synchronization, and notifications
- The returned permission sets are unmodifiable - do not try to modify them
- Player may be offline when permission changes occur - check for null
{{< /callout >}}

{{< callout type="warning" >}}
**Important:** These events do not allow you to intercept or modify permission checks. They only notify you when permissions have been modified through the permission system.
{{< /callout >}}
