Hytale Modding
Hytale Modding
Server Plugins

Permission Management

Learn how to manage permission nodes and groups in your Hytale plugin.

Written by Neil Revin, Bird, Craw, Ivan, ZenithDevHQ

In this guide, you'll learn how to manage permission nodes and groups in your Hytale plugin. Permissions control what actions players can perform on your server, from basic commands to advanced administrative functions.

What Are Permissions?

Permissions are string identifiers that control access to features and commands. When a player tries to perform an action (like using a command), the server checks if they have the required permission.

Example permission nodes:

  • hytale.command.gamemode - Permission to use the gamemode command
  • hytale.editor.brush.use - Permission to use brush tools
  • myplugin.teleport.home - A custom permission for your plugin

Permissions follow a hierarchical naming pattern: namespace.category.action

Key Concepts

Before diving into code, let's understand the core concepts:

ConceptDescription
Permission NodeA string like myplugin.feature.use that represents a specific permission
GroupA named collection of permissions (e.g., "Admin", "VIP", "Default")
ProviderThe backend that stores and retrieves permissions
WildcardA pattern like * or myplugin.* that matches multiple permissions

How Permissions Are Checked

When checking if a player has a permission, Hytale follows this order:

  1. User's direct permissions - Permissions granted directly to the player
  2. Group permissions - Permissions from groups the player belongs to
  3. Virtual groups - Game-mode-based permissions (e.g., Creative mode grants builder tools)
  4. Default value - Falls back to false if no match found
Info

The first definitive match wins. If a player has a permission granted at the user level, group permissions won't override it.


The PermissionsModule Class

The PermissionsModule class is the central hub for managing permissions. Access it using the singleton pattern:

PermissionsModule perms = PermissionsModule.get();

Available Operations

The module supports these operations:

OperationMethod
Add permissions to useraddUserPermission(uuid, permissions)
Remove permissions from userremoveUserPermission(uuid, permissions)
Add permissions to groupaddGroupPermission(groupName, permissions)
Remove permissions from groupremoveGroupPermission(groupName, permissions)
Add user to groupaddUserToGroup(uuid, groupName)
Remove user from groupremoveUserFromGroup(uuid, groupName)
Get user's groupsgetGroupsForUser(uuid)
Check permissionhasPermission(uuid, permissionNode)
Warning

The module does not support:

  • Listing all defined groups
  • Deleting a group entirely

Groups are implicitly created when you first add permissions to them.


Checking Permissions

The most common operation is checking if a player has a permission.

Basic Permission Check

// Returns true if player has the permission, false otherwise
boolean canUse = PermissionsModule.get().hasPermission(playerUUID, "myplugin.feature.use");

if (canUse) {
    // Player has permission, allow the action
} else {
    // Player lacks permission, deny or show error
}

Permission Check with Default Value

You can specify what to return when no permission is explicitly set:

// Returns true by default if no explicit permission is found
boolean canUse = PermissionsModule.get().hasPermission(playerUUID, "myplugin.feature.use", true);

This is useful for features that should be enabled by default but can be revoked.

Using PermissionHolder Interface

Players and command senders implement PermissionHolder, allowing direct checks:

// In a command or event handler where you have access to the player
if (player.hasPermission("myplugin.admin.manage")) {
    // Player has admin permission
}

Managing User Permissions

Adding Permissions to a User

Permissions are additive - new permissions are added on top of existing ones, not replaced.

PermissionsModule perms = PermissionsModule.get();

// Add a single permission
perms.addUserPermission(playerUUID, Set.of("myplugin.vip.chat"));

// Add multiple permissions at once
Set<String> newPerms = Set.of(
    "myplugin.vip.chat",
    "myplugin.vip.fly",
    "myplugin.vip.kit"
);
perms.addUserPermission(playerUUID, newPerms);

Removing Permissions from a User

PermissionsModule perms = PermissionsModule.get();

// Remove specific permissions
Set<String> toRemove = Set.of("myplugin.vip.fly");
perms.removeUserPermission(playerUUID, toRemove);

Managing Groups

Groups let you assign a collection of permissions to multiple players. This is more manageable than assigning permissions individually.

Adding Permissions to a Group

If the group doesn't exist, it will be created automatically.

PermissionsModule perms = PermissionsModule.get();

// Create/update the "VIP" group with permissions
Set<String> vipPerms = Set.of(
    "myplugin.vip.chat",
    "myplugin.vip.fly",
    "myplugin.vip.kit"
);
perms.addGroupPermission("VIP", vipPerms);

Removing Permissions from a Group

PermissionsModule perms = PermissionsModule.get();

// Remove specific permissions from the group
Set<String> toRemove = Set.of("myplugin.vip.fly");
perms.removeGroupPermission("VIP", toRemove);

Adding a User to a Group

PermissionsModule perms = PermissionsModule.get();

// Add player to the VIP group - they now have all VIP permissions
perms.addUserToGroup(playerUUID, "VIP");

Removing a User from a Group

PermissionsModule perms = PermissionsModule.get();

// Remove player from VIP group
perms.removeUserFromGroup(playerUUID, "VIP");

Getting a User's Groups

PermissionsModule perms = PermissionsModule.get();

// Get all groups the player belongs to
Set<String> groups = perms.getGroupsForUser(playerUUID);

for (String group : groups) {
    System.out.println("Player is in group: " + group);
}

Built-in Groups

Hytale includes two default groups:

GroupDefault PermissionsPurpose
OP* (all permissions)Server operators with full access
DefaultNoneBase group for all players

Players without any explicit group assignment are automatically part of the Default group.


Wildcards

Wildcards let you grant or deny multiple permissions with a single pattern.

Wildcard Patterns

PatternMeaning
*Grants all permissions
myplugin.*Grants all permissions starting with myplugin.
-*Denies all permissions
-myplugin.admin.*Denies all admin permissions in your plugin

Example: Admin Group with Wildcards

// Grant all permissions to admins
perms.addGroupPermission("Admin", Set.of("*"));

// Grant all plugin permissions to moderators
perms.addGroupPermission("Moderator", Set.of("myplugin.*"));

// Grant all permissions except admin commands
perms.addGroupPermission("Helper", Set.of(
    "*",
    "-myplugin.admin.*"  // Deny admin permissions
));
Warning

Negation permissions (starting with -) take precedence at each level. Use them carefully to avoid accidentally blocking permissions.


Built-in Permission Nodes

Hytale provides constants for common permissions in the HytalePermissions class:

Command Permissions

// Generate permission for a command
String perm = HytalePermissions.fromCommand("gamemode");
// Result: "hytale.command.gamemode"

// Generate permission for a subcommand
String perm = HytalePermissions.fromCommand("gamemode", "creative");
// Result: "hytale.command.gamemode.creative"

Common Permission Nodes

PermissionDescription
hytale.command.op.addAdd players to OP group
hytale.command.op.removeRemove players from OP group
hytale.editor.brush.useUse brush tools
hytale.editor.prefab.useUse prefabs
hytale.editor.selection.useUse selection tools
hytale.editor.historyUndo/redo operations
hytale.camera.flycamUse fly camera mode

Listening to Permission Events

You can react to permission changes using Hytale's event system.

Available Events

EventTriggered When
PlayerPermissionChangeEvent.PermissionsAddedPermissions added to a user
PlayerPermissionChangeEvent.PermissionsRemovedPermissions removed from a user
PlayerGroupEvent.AddedUser added to a group
PlayerGroupEvent.RemovedUser removed from a group
GroupPermissionChangeEvent.AddedPermissions added to a group
GroupPermissionChangeEvent.RemovedPermissions removed from a group

Example: Reacting to Permission Changes

public class PermissionListener {

    public static void onPermissionsAdded(PlayerPermissionChangeEvent.PermissionsAdded event) {
        UUID playerUUID = event.getPlayerUuid();
        Set<String> added = event.getAddedPermissions();

        System.out.println("Permissions added to " + playerUUID + ": " + added);

        // Maybe notify the player or update cached data
    }

    public static void onGroupAdded(PlayerGroupEvent.Added event) {
        UUID playerUUID = event.getPlayerUuid();
        String groupName = event.getGroupName();

        System.out.println("Player " + playerUUID + " joined group: " + groupName);
    }
}

Registering the Events

public class MyPlugin extends JavaPlugin {

    @Override
    public void setup() {
        EventRegistry events = this.getEventRegistry();

        events.registerGlobal(
            PlayerPermissionChangeEvent.PermissionsAdded.class,
            PermissionListener::onPermissionsAdded
        );

        events.registerGlobal(
            PlayerGroupEvent.Added.class,
            PermissionListener::onGroupAdded
        );
    }
}

Creating a Custom Permission Provider

For advanced use cases, you can create your own permission provider. This is useful for:

  • Database-backed permissions (MySQL, MongoDB, etc.)
  • Cross-server permission synchronization
  • Custom features like permission expiry or contexts

Implementing PermissionProvider

public class DatabasePermissionProvider implements PermissionProvider {

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

    // User permission methods
    @Override
    public void addUserPermissions(@Nonnull UUID uuid, @Nonnull Set<String> permissions) {
        // Save to your database
    }

    @Override
    public void removeUserPermissions(@Nonnull UUID uuid, @Nonnull Set<String> permissions) {
        // Remove from your database
    }

    @Override
    public Set<String> getUserPermissions(@Nonnull UUID uuid) {
        // Query your database
        return Set.of();
    }

    // Group permission methods
    @Override
    public void addGroupPermissions(@Nonnull String group, @Nonnull Set<String> permissions) {
        // Save to your database
    }

    @Override
    public void removeGroupPermissions(@Nonnull String group, @Nonnull Set<String> permissions) {
        // Remove from your database
    }

    @Override
    public Set<String> getGroupPermissions(@Nonnull String group) {
        // Query your database
        return Set.of();
    }

    // User-group membership methods
    @Override
    public void addUserToGroup(@Nonnull UUID uuid, @Nonnull String group) {
        // Save to your database
    }

    @Override
    public void removeUserFromGroup(@Nonnull UUID uuid, @Nonnull String group) {
        // Remove from your database
    }

    @Override
    public Set<String> getGroupsForUser(@Nonnull UUID uuid) {
        // Query your database
        return Set.of("Default");
    }
}
Warning

Hytale automatically assigns players to game-mode groups (like Creative or Adventure) using the first available provider.

If your provider throws an error when the group doesn't exist, the player will be disconnected! Always handle missing groups gracefully.

Registering Your Provider

public class MyPlugin extends JavaPlugin {

    @Override
    public void setup() {
        // Add your provider alongside the default one
        PermissionsModule.get().addProvider(new DatabasePermissionProvider());
    }
}

The PermissionsModule aggregates permissions from all registered providers. This means:

  • Permission checks query all providers
  • Write operations (add/remove) use the first provider

Replacing the Default Provider

If you want full control, you can remove the default provider:

public class MyPlugin extends JavaPlugin {

    @Override
    public void setup() {
        PermissionsModule perms = PermissionsModule.get();

        // Remove the default provider FIRST
        perms.removeProvider(perms.getFirstPermissionProvider());

        // Then add your provider
        perms.addProvider(new DatabasePermissionProvider());
    }
}
Info

When you remove the default provider, the /op self command will stop working since it checks for provider tampering.


Best Practices

Permission Naming Conventions

Follow the pattern: namespace.category.action

// Good - clear hierarchy
"myplugin.admin.ban"
"myplugin.user.teleport.home"
"myplugin.vip.chat.color"

// Bad - unclear structure
"myplugin_ban"
"teleport"
"vipChatColor"

Use Constants for Permissions

Define your permissions as constants to avoid typos:

public final class MyPermissions {
    public static final String ADMIN_BAN = "myplugin.admin.ban";
    public static final String ADMIN_KICK = "myplugin.admin.kick";
    public static final String USER_HOME = "myplugin.user.home";
    public static final String VIP_FLY = "myplugin.vip.fly";
}

// Usage
if (player.hasPermission(MyPermissions.ADMIN_BAN)) {
    // ...
}

Don't Over-Permission

Only create permissions for actions that genuinely need access control. Not everything needs a permission check.

Thread Safety

If you create a custom provider, ensure it's thread-safe. Permission checks can occur from multiple threads simultaneously. Use ReadWriteLock or ConcurrentHashMap for your data structures.


In-Game Commands

Hytale provides built-in commands for managing permissions:

/op Command

CommandDescription
/op selfToggle your own OP status (singleplayer or with --allow-op flag)
/op add <player>Add a player to the OP group
/op remove <player>Remove a player from the OP group

/perm Command

Use /perm --help in-game for full usage. Common operations:

CommandDescription
/perm user list <uuid>List user's permissions
/perm user add <uuid> <perm>Add permission to user
/perm user remove <uuid> <perm>Remove permission from user
/perm user group list <uuid>List user's groups
/perm user group add <uuid> <group>Add user to group
/perm user group remove <uuid> <group>Remove user from group
/perm group list <group>List group's permissions
/perm group add <group> <perm>Add permission to group
/perm group remove <group> <perm>Remove permission from group
/perm test <perm>Test if you have a permission

Summary

You've learned how to:

  • Check permissions using PermissionsModule.hasPermission()
  • Manage user permissions with addUserPermission() and removeUserPermission()
  • Work with groups using addGroupPermission(), addUserToGroup(), etc.
  • Use wildcards like * and myplugin.* for bulk permissions
  • Listen to events for permission changes
  • Create custom providers for database-backed permissions

For more advanced permission systems with features like inheritance, expiry, and contexts, we're looking into expanding this guide with advanced permission management techniques in the future.