Permission System Overview
Permission System Overview
Section titled “Permission System Overview”The Permission System controls access to commands and features. It uses a hierarchical node-based structure with support for groups, wildcards, and custom providers.
Package Location
Section titled “Package Location”- Core:
com.hypixel.hytale.server.core.permissions - Providers:
com.hypixel.hytale.server.core.permissions.provider - Commands:
com.hypixel.hytale.server.core.permissions.commands - Events:
com.hypixel.hytale.server.core.event.events.permissions
Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────────────────────┐│ Permission System ││ ││ ┌──────────────────┐ ┌───────────────────────────────┐ ││ │ PermissionHolder │ │ PermissionsModule │ ││ │ (Player, etc.) │───────►│ (Singleton) │ ││ └──────────────────┘ └───────────────┬───────────────┘ ││ │ ││ ┌──────────────────┼──────────────────┐││ ▼ ▼ ▼││ ┌───────────────┐ ┌───────────────┐ ┌──────┐││ │ Default │ │ Custom │ │ ... │││ │ Provider │ │ Provider │ │ │││ └───────────────┘ └───────────────┘ └──────┘│└─────────────────────────────────────────────────────────────────┘Core Interfaces
Section titled “Core Interfaces”PermissionHolder
Section titled “PermissionHolder”Interface implemented by entities that can have permissions:
package com.hypixel.hytale.server.core.permissions;
public interface PermissionHolder { // Check permission (default: false) boolean hasPermission(String permission);
// Check permission with custom default boolean hasPermission(String permission, boolean defaultValue);}Implemented by:
PlayerCommandSenderConsoleSender(always returns true)
PermissionProvider
Section titled “PermissionProvider”Interface for custom permission backends:
package com.hypixel.hytale.server.core.permissions.provider;
public interface PermissionProvider { // Provider name String getName();
// User permissions void addUserPermissions(UUID uuid, Set<String> permissions); void removeUserPermissions(UUID uuid, Set<String> permissions); Set<String> getUserPermissions(UUID uuid);
// Group permissions void addGroupPermissions(String group, Set<String> permissions); void removeGroupPermissions(String group, Set<String> permissions); Set<String> getGroupPermissions(String group);
// Group membership void addUserToGroup(UUID uuid, String group); void removeUserFromGroup(UUID uuid, String group); Set<String> getGroupsForUser(UUID uuid);}PermissionsModule
Section titled “PermissionsModule”The central permission management singleton:
package com.hypixel.hytale.server.core.permissions;
public class PermissionsModule extends JavaPlugin { // Singleton access public static PermissionsModule get();
// Check permissions public boolean hasPermission(UUID uuid, String permission); public boolean hasPermission(UUID uuid, String permission, boolean defaultValue);
// User permissions public void addUserPermission(UUID uuid, Set<String> permissions); public void removeUserPermission(UUID uuid, Set<String> permissions);
// Group management public void addUserToGroup(UUID uuid, String group); public void removeUserFromGroup(UUID uuid, String group); public Set<String> getGroupsForUser(UUID uuid);
// Group permissions public void addGroupPermission(String group, Set<String> permissions); public void removeGroupPermission(String group, Set<String> permissions);
// Provider management public void addProvider(PermissionProvider provider); public void removeProvider(PermissionProvider provider); public List<PermissionProvider> getProviders();}Permission Node Syntax
Section titled “Permission Node Syntax”Permission nodes use a dot-separated hierarchical structure:
Basic Syntax
Section titled “Basic Syntax”| Pattern | Meaning |
|---|---|
permission.node | Grant specific permission |
-permission.node | Deny specific permission |
permission.* | Grant all under namespace |
-permission.* | Deny all under namespace |
* | Grant all permissions |
-* | Deny all permissions |
Matching Algorithm
Section titled “Matching Algorithm”For permission check hytale.command.teleport:
- Check exact match:
hytale.command.teleport - Check parent wildcard:
hytale.command.* - Check grandparent wildcard:
hytale.* - Check root wildcard:
*
At each level, negation (- prefix) is also checked.
Examples
Section titled “Examples”# Grant specific commandhytale.command.teleport
# Deny specific command-hytale.command.kick
# Grant all commandshytale.command.*
# Grant all permissions*
# Grant all but deny specific*-hytale.command.banBuilt-in Permission Nodes
Section titled “Built-in Permission Nodes”Common permission nodes (from HytalePermissions):
| Node | Description |
|---|---|
hytale.command.* | All commands |
hytale.editor.asset | Asset editor access |
hytale.editor.packs.create | Create asset packs |
hytale.editor.packs.edit | Edit asset packs |
hytale.editor.packs.delete | Delete asset packs |
hytale.editor.builderTools | Builder tools |
hytale.editor.brush.* | Brush editor |
hytale.camera.flycam | Fly camera |
Default Groups
Section titled “Default Groups”The default provider includes two groups:
| Group | Permissions |
|---|---|
OP | * (all permissions) |
Default | (none) |
Permission Checking
Section titled “Permission Checking”For Players/CommandSenders
Section titled “For Players/CommandSenders”// Check permission (false if not set)if (sender.hasPermission("myplugin.feature")) { // Allowed}
// Check with default valueif (sender.hasPermission("myplugin.feature", true)) { // Allowed if not explicitly denied}Using CommandUtil
Section titled “Using CommandUtil”import com.hypixel.hytale.server.core.command.system.CommandUtil;
public void execute(CommandContext context) { // Throws NoPermissionException if denied CommandUtil.requirePermission(context.getSender(), "myplugin.admin");
// Permission granted, continue...}In Commands
Section titled “In Commands”import com.hypixel.hytale.server.core.command.system.AbstractCommand;
public class MyCommand extends AbstractCommand { public MyCommand() { super("mycommand", "Description"); // Set required permission this.requirePermission("myplugin.command.mycommand"); }
@Override public boolean hasPermission(CommandSender sender) { return sender.hasPermission(getPermission()); }}Command Permissions
Section titled “Command Permissions”Auto-Generated Format
Section titled “Auto-Generated Format”Commands automatically generate permission nodes:
- Plugin commands:
{plugin.base}.command.{command.name} - System commands:
hytale.system.command.{command.name} - Sub-commands:
{parent}.{subcommand.name}
Argument Permissions
Section titled “Argument Permissions”// Require permission for specific argumentarg.setPermission("myplugin.command.special.option");Permission Events
Section titled “Permission Events”Events fired when permissions change:
| Event | Description |
|---|---|
PlayerPermissionChangeEvent.PermissionsAdded | Permissions added to player |
PlayerPermissionChangeEvent.PermissionsRemoved | Permissions removed from player |
PlayerGroupEvent.Added | Player added to group |
PlayerGroupEvent.Removed | Player removed from group |
GroupPermissionChangeEvent.Added | Permissions added to group |
GroupPermissionChangeEvent.Removed | Permissions removed from group |
Listening to Permission Changes
Section titled “Listening to Permission Changes”import com.hypixel.hytale.server.core.event.events.permissions.*;
@Overrideprotected void setup() { getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> { UUID player = event.getPlayerUUID(); Set<String> added = event.getPermissions(); getLogger().info("Permissions added to " + player + ": " + added); } );}Built-in Commands
Section titled “Built-in Commands”| Command | Description |
|---|---|
/perm user add <uuid> <permissions...> | Add permissions to user |
/perm user remove <uuid> <permissions...> | Remove permissions from user |
/perm user group add <uuid> <group> | Add user to group |
/perm user group remove <uuid> <group> | Remove user from group |
/perm group add <group> <permissions...> | Add permissions to group |
/perm group remove <group> <permissions...> | Remove permissions from group |
/perm test <permissions...> | Test if sender has permissions |
Creating a Custom Provider
Section titled “Creating a Custom Provider”import com.hypixel.hytale.server.core.permissions.provider.PermissionProvider;import java.util.*;
public class MyPermissionProvider implements PermissionProvider { private final Map<UUID, Set<String>> userPermissions = new HashMap<>(); private final Map<String, Set<String>> groupPermissions = new HashMap<>(); private final Map<UUID, Set<String>> userGroups = new HashMap<>();
@Override public String getName() { return "MyProvider"; }
@Override public void addUserPermissions(UUID uuid, Set<String> permissions) { userPermissions.computeIfAbsent(uuid, k -> new HashSet<>()) .addAll(permissions); }
@Override public void removeUserPermissions(UUID uuid, Set<String> permissions) { Set<String> perms = userPermissions.get(uuid); if (perms != null) { perms.removeAll(permissions); } }
@Override public Set<String> getUserPermissions(UUID uuid) { return userPermissions.getOrDefault(uuid, Collections.emptySet()); }
@Override public void addGroupPermissions(String group, Set<String> permissions) { groupPermissions.computeIfAbsent(group, k -> new HashSet<>()) .addAll(permissions); }
@Override public void removeGroupPermissions(String group, Set<String> permissions) { Set<String> perms = groupPermissions.get(group); if (perms != null) { perms.removeAll(permissions); } }
@Override public Set<String> getGroupPermissions(String group) { return groupPermissions.getOrDefault(group, Collections.emptySet()); }
@Override public void addUserToGroup(UUID uuid, String group) { userGroups.computeIfAbsent(uuid, k -> new HashSet<>()).add(group); }
@Override public void removeUserFromGroup(UUID uuid, String group) { Set<String> groups = userGroups.get(uuid); if (groups != null) { groups.remove(group); } }
@Override public Set<String> getGroupsForUser(UUID uuid) { return userGroups.getOrDefault(uuid, Collections.emptySet()); }}Registering the Provider
Section titled “Registering the Provider”import com.hypixel.hytale.server.core.permissions.PermissionsModule;
@Overrideprotected void setup() { PermissionsModule.get().addProvider(new MyPermissionProvider());}
@Overrideprotected void shutdown() { // Optional: remove provider on shutdown PermissionsModule.get().removeProvider(myProvider);}Storage
Section titled “Storage”The default provider stores permissions in permissions.json in the universe folder.
Best Practices
Section titled “Best Practices”- Use hierarchical nodes:
myplugin.feature.subfeature - Document permissions: List all permissions your plugin uses
- Provide defaults: Use
hasPermission(perm, true)for non-critical features - Use groups: Assign permissions via groups, not individual users
- Test permissions: Use
/perm testto verify
Related
Section titled “Related”- Command System - Command permissions
- Event System - Permission events
- Plugin Lifecycle - Provider registration