Files
2026-01-20 20:33:59 +01:00

9.8 KiB

title, type, weight
title type weight
Permissions System docs 12

The Permissions system provides fine-grained access control for commands, editor features, and custom plugin functionality.

Package: com.hypixel.hytale.server.core.permissions

Overview

Hytale uses a permission system with:

  • User permissions - Directly assigned to individual players
  • Group permissions - Inherited by all members of a group
  • Permission providers - Custom logic for dynamic permissions

Accessing the Permissions Module

import com.hypixel.hytale.server.core.permissions.PermissionsModule;

// Use static get() method - NOT HytaleServer.get().getPermissionsModule()
PermissionsModule permissions = PermissionsModule.get();

Checking Permissions

UUID playerUuid = player.getPlayerRef().getUuid();

// Check if player has permission
boolean canEdit = permissions.hasPermission(playerUuid, "hytale.editor.asset");

// Check in command context
if (permissions.hasPermission(ctx.sender().getUuid(), "myplugin.admin")) {
    // Admin-only logic
}

User Permissions

Manage permissions for individual players:

UUID playerUuid = player.getPlayerRef().getUuid();

// Add permissions
permissions.addUserPermission(playerUuid, Set.of(
    "myplugin.feature.create",
    "myplugin.feature.delete"
));

// Remove permissions
permissions.removeUserPermission(playerUuid, Set.of(
    "myplugin.feature.delete"
));

Group Permissions

Groups allow shared permissions across multiple players:

Managing Groups

// Add player to a group
permissions.addUserToGroup(playerUuid, "moderators");

// Remove player from a group
permissions.removeUserFromGroup(playerUuid, "moderators");

// Get all groups for a player
Set<String> groups = permissions.getGroupsForUser(playerUuid);

Group Permission Events

Listen for group changes using specific event subclasses:

import com.hypixel.hytale.server.core.event.events.permissions.*;

// Player ADDED to group
getEventRegistry().register(PlayerGroupEvent.Added.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    String group = event.getGroupName();  // Note: getGroupName(), NOT getGroup()
    log("Player joined group: " + group);
});

// Player REMOVED from group
getEventRegistry().register(PlayerGroupEvent.Removed.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    String group = event.getGroupName();
    log("Player left group: " + group);
});

// Group permissions ADDED
getEventRegistry().register(GroupPermissionChangeEvent.Added.class, event -> {
    String group = event.getGroupName();
    Set<String> added = event.getAddedPermissions();
    log("Group " + group + " got permissions: " + added);
});

// Group permissions REMOVED
getEventRegistry().register(GroupPermissionChangeEvent.Removed.class, event -> {
    String group = event.getGroupName();
    Set<String> removed = event.getRemovedPermissions();
    log("Group " + group + " lost permissions: " + removed);
});

// Player permissions ADDED
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    Set<String> added = event.getAddedPermissions();
});

// Player permissions REMOVED
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
    UUID playerUuid = event.getPlayerUuid();
    Set<String> removed = event.getRemovedPermissions();
});

Built-in Permissions

Hytale includes many built-in permissions:

Command Permissions

Permission Description
hytale.command.* All command access
hytale.command.gamemode Change game mode
hytale.command.tp Teleportation
hytale.command.give Give items
hytale.command.time Time control

Editor Permissions

Permission Description
hytale.editor.asset Asset editing
hytale.editor.packs.* Pack management
hytale.editor.builderTools Builder tools access
hytale.editor.brush.* Brush tools
hytale.editor.prefab.* Prefab editing
hytale.editor.selection.* Selection tools
hytale.editor.history Undo/redo history

Camera Permissions

Permission Description
hytale.camera.flycam Free camera mode

Custom Permission Provider

Implement PermissionProvider for dynamic permission logic:

{{< callout type="info" >}} Note: PermissionProvider is an interface that provides sets of permissions, not a simple hasPermission check. The PermissionsModule checks these sets. {{< /callout >}}

import com.hypixel.hytale.server.core.permissions.provider.PermissionProvider;

public class VIPPermissionProvider implements PermissionProvider {
    private final Map<UUID, Set<String>> vipPermissions = new ConcurrentHashMap<>();
    private final Map<UUID, Set<String>> vipGroups = new ConcurrentHashMap<>();

    @Override
    @Nonnull
    public String getName() {
        return "VIPPermissionProvider";
    }

    @Override
    public Set<String> getUserPermissions(@Nonnull UUID uuid) {
        // Return the permissions for this user
        // VIP users get extra permissions automatically
        if (isVIP(uuid)) {
            Set<String> perms = new HashSet<>(vipPermissions.getOrDefault(uuid, Collections.emptySet()));
            perms.add("vip.lounge");
            perms.add("vip.cosmetics");
            return perms;
        }
        return vipPermissions.getOrDefault(uuid, Collections.emptySet());
    }

    @Override
    public void addUserPermissions(@Nonnull UUID uuid, @Nonnull Set<String> permissions) {
        vipPermissions.computeIfAbsent(uuid, k -> new HashSet<>()).addAll(permissions);
    }

    @Override
    public void removeUserPermissions(@Nonnull UUID uuid, @Nonnull Set<String> permissions) {
        Set<String> userPerms = vipPermissions.get(uuid);
        if (userPerms != null) {
            userPerms.removeAll(permissions);
        }
    }

    @Override
    public Set<String> getGroupPermissions(@Nonnull String group) {
        return Collections.emptySet();
    }

    @Override
    public void addGroupPermissions(@Nonnull String group, @Nonnull Set<String> permissions) {}

    @Override
    public void removeGroupPermissions(@Nonnull String group, @Nonnull Set<String> permissions) {}

    @Override
    public Set<String> getGroupsForUser(@Nonnull UUID uuid) {
        return vipGroups.getOrDefault(uuid, Collections.emptySet());
    }

    @Override
    public void addUserToGroup(@Nonnull UUID uuid, @Nonnull String group) {
        vipGroups.computeIfAbsent(uuid, k -> new HashSet<>()).add(group);
    }

    @Override
    public void removeUserFromGroup(@Nonnull UUID uuid, @Nonnull String group) {
        Set<String> groups = vipGroups.get(uuid);
        if (groups != null) {
            groups.remove(group);
        }
    }

    private boolean isVIP(UUID uuid) {
        // Your VIP checking logic
        return vipDatabase.contains(uuid);
    }
}

Registering Custom Providers

@Override
public void start() {
    PermissionsModule permissions = PermissionsModule.get();
    permissions.addProvider(new VIPPermissionProvider());
}

Permission Wildcards

Permissions support wildcard matching:

// Grant all permissions under a namespace
permissions.addUserPermission(playerUuid, Set.of("myplugin.*"));

// This now passes:
permissions.hasPermission(playerUuid, "myplugin.anything");
permissions.hasPermission(playerUuid, "myplugin.feature.nested");

Command Permission Integration

Commands automatically check permissions based on their ID:

public class AdminCommand extends AbstractCommand {

    public AdminCommand() {
        super("admin", "myplugin.commands.admin.description");
        // Permission check is automatic based on command registration
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext ctx) {
        // Only players with appropriate permission reach here
        return null;
    }
}

Practical Examples

Role-Based Access

public class RoleManager {
    private final PermissionsModule permissions;

    public RoleManager() {
        this.permissions = PermissionsModule.get();
    }

    public void promoteToModerator(UUID playerUuid) {
        permissions.addUserToGroup(playerUuid, "moderators");
        permissions.addUserPermission(playerUuid, Set.of(
            "server.kick",
            "server.mute",
            "server.warn"
        ));
    }

    public void demoteFromModerator(UUID playerUuid) {
        permissions.removeUserFromGroup(playerUuid, "moderators");
        permissions.removeUserPermission(playerUuid, Set.of(
            "server.kick",
            "server.mute",
            "server.warn"
        ));
    }

    public boolean canModerate(UUID playerUuid) {
        return permissions.getGroupsForUser(playerUuid).contains("moderators");
    }
}

Feature Gating

public void useFeature(Player player, String featureName) {
    UUID uuid = player.getPlayerRef().getUuid();
    PermissionsModule perms = PermissionsModule.get();

    String permission = "myplugin.feature." + featureName;
    if (!perms.hasPermission(uuid, permission)) {
        player.sendMessage(Message.translation("error.no_permission"));
        return;
    }

    // Execute feature
    executeFeature(player, featureName);
}

Best Practices

{{< callout type="info" >}} Permission Guidelines:

  • Use namespaced permissions (e.g., myplugin.feature.name)
  • Prefer groups for role-based access over individual permissions
  • Check permissions at entry points, not deep in logic
  • Use wildcards sparingly and intentionally {{< /callout >}}

{{< callout type="warning" >}} Security Note: Always validate permissions server-side. Never trust client-reported permission states. {{< /callout >}}