Permissions and Access Control
The Hytale permission system provides fine-grained access control for server features, commands, and custom functionality. It supports user-level permissions, group-based inheritance, and wildcard matching.
Architecture
Section titled “Architecture”PermissionsModule (Core)├── PermissionProvider (Interface)│ └── HytalePermissionsProvider (Default Implementation)├── Permission Groups (OP, Default, Custom)├── User Permissions (Per-UUID)└── Virtual Groups (GameMode-based)
PermissionHolder (Interface)├── Player (Entity)└── CommandSender (Commands)Core Interfaces
Section titled “Core Interfaces”PermissionHolder
Section titled “PermissionHolder”The base interface for any entity that can hold permissions:
import com.hypixel.hytale.server.core.permissions.PermissionHolder;
public interface PermissionHolder { boolean hasPermission(@Nonnull String id); boolean hasPermission(@Nonnull String id, boolean defaultValue);}Both Player and CommandSender implement this interface, allowing consistent permission checking across commands and gameplay logic.
PermissionProvider
Section titled “PermissionProvider”Custom permission backends implement this interface:
import com.hypixel.hytale.server.core.permissions.provider.PermissionProvider;
public interface PermissionProvider { @Nonnull String getName();
// User permissions void addUserPermissions(@Nonnull UUID uuid, @Nonnull Set<String> permissions); void removeUserPermissions(@Nonnull UUID uuid, @Nonnull Set<String> permissions); Set<String> getUserPermissions(@Nonnull UUID uuid);
// Group permissions void addGroupPermissions(@Nonnull String group, @Nonnull Set<String> permissions); void removeGroupPermissions(@Nonnull String group, @Nonnull Set<String> permissions); Set<String> getGroupPermissions(@Nonnull String group);
// User-group membership void addUserToGroup(@Nonnull UUID uuid, @Nonnull String group); void removeUserFromGroup(@Nonnull UUID uuid, @Nonnull String group); Set<String> getGroupsForUser(@Nonnull UUID uuid);}Permission Syntax
Section titled “Permission Syntax”Permission Nodes
Section titled “Permission Nodes”Permissions use a dot-separated hierarchical format:
namespace.category.actionExamples:
hytale.command.gamemode.self- Change own game modehytale.command.gamemode.other- Change another player’s game modehytale.editor.brush.use- Use brush toolsmyplugin.admin.kick- Custom plugin permission
Wildcards
Section titled “Wildcards”The system supports wildcard permissions for granting broad access:
| Pattern | Description |
|---|---|
* | All permissions (full access) |
hytale.* | All hytale namespace permissions |
hytale.command.* | All command permissions |
myplugin.admin.* | All admin permissions for myplugin |
Negation
Section titled “Negation”Prefix permissions with - to explicitly deny:
| Pattern | Description |
|---|---|
-* | Deny all permissions |
-hytale.command.kick | Explicitly deny kick permission |
-myplugin.admin.* | Deny all admin permissions |
Negations take precedence and can override inherited group permissions.
Built-in Permissions
Section titled “Built-in Permissions”HytalePermissions Class
Section titled “HytalePermissions Class”The HytalePermissions class defines standard permission constants:
import com.hypixel.hytale.server.core.permissions.HytalePermissions;
public class HytalePermissions { public static final String NAMESPACE = "hytale"; public static final String COMMAND_BASE = "hytale.command";
// Asset editor permissions public static final String ASSET_EDITOR = "hytale.editor.asset"; public static final String ASSET_EDITOR_PACKS_CREATE = "hytale.editor.packs.create"; public static final String ASSET_EDITOR_PACKS_EDIT = "hytale.editor.packs.edit"; public static final String ASSET_EDITOR_PACKS_DELETE = "hytale.editor.packs.delete";
// Builder tools permissions public static final String BUILDER_TOOLS_EDITOR = "hytale.editor.builderTools";
// Brush permissions public static final String EDITOR_BRUSH_USE = "hytale.editor.brush.use"; public static final String EDITOR_BRUSH_CONFIG = "hytale.editor.brush.config";
// Prefab permissions public static final String EDITOR_PREFAB_USE = "hytale.editor.prefab.use"; public static final String EDITOR_PREFAB_MANAGE = "hytale.editor.prefab.manage";
// Selection permissions public static final String EDITOR_SELECTION_USE = "hytale.editor.selection.use"; public static final String EDITOR_SELECTION_CLIPBOARD = "hytale.editor.selection.clipboard"; public static final String EDITOR_SELECTION_MODIFY = "hytale.editor.selection.modify";
// History permission public static final String EDITOR_HISTORY = "hytale.editor.history";
// Camera permission public static final String FLY_CAM = "hytale.camera.flycam";
// Helper methods for command permissions @Nonnull public static String fromCommand(@Nonnull String name) { return "hytale.command." + name; }
@Nonnull public static String fromCommand(@Nonnull String name, @Nonnull String subCommand) { return "hytale.command." + name + "." + subCommand; }}Common Command Permissions
Section titled “Common Command Permissions”| Permission | Description |
|---|---|
hytale.command.gamemode.self | Change own game mode |
hytale.command.gamemode.other | Change another player’s game mode |
hytale.command.give.self | Give items to self |
hytale.command.give.other | Give items to others |
hytale.command.teleport.* | All teleport commands |
hytale.command.kick | Kick players |
hytale.command.op.add | Add players to OP group |
hytale.command.op.remove | Remove players from OP group |
Permission Groups
Section titled “Permission Groups”Default Groups
Section titled “Default Groups”The system includes two built-in groups defined in HytalePermissionsProvider:
public static final String DEFAULT_GROUP = "Default";public static final Set<String> DEFAULT_GROUP_LIST = Set.of("Default");public static final String OP_GROUP = "OP";
// Default group permissionspublic static final Map<String, Set<String>> DEFAULT_GROUPS = Map.ofEntries( Map.entry("OP", Set.of("*")), // OP has all permissions Map.entry("Default", Set.of()) // Default has no special permissions);- OP: Has the
*wildcard, granting all permissions - Default: All players belong to this group by default (no special permissions). If a user has no explicit groups assigned,
getGroupsForUser()returnsDEFAULT_GROUP_LIST.
Virtual Groups (GameMode-based)
Section titled “Virtual Groups (GameMode-based)”The system automatically assigns virtual permissions based on game mode. Virtual groups are initialized during the start() phase of PermissionsModule:
// In PermissionsModule.start()Map<String, Set<String>> virtualGroups = CommandManager.get().createVirtualPermissionGroups();virtualGroups.computeIfAbsent( GameMode.Creative.toString(), k -> new HashSet()).add("hytale.editor.builderTools");this.setVirtualGroups(virtualGroups);Virtual groups are checked after user permissions and group permissions when evaluating hasPermission().
Using the PermissionsModule
Section titled “Using the PermissionsModule”Getting the Module
Section titled “Getting the Module”import com.hypixel.hytale.server.core.permissions.PermissionsModule;
PermissionsModule permissions = PermissionsModule.get();Checking Permissions
Section titled “Checking Permissions”UUID playerUuid = player.getUuid();
// Basic check (returns false if not set)boolean canTeleport = permissions.hasPermission(playerUuid, "hytale.command.teleport");
// With default valueboolean canBuild = permissions.hasPermission(playerUuid, "myplugin.build", true);Managing User Permissions
Section titled “Managing User Permissions”UUID playerUuid = player.getUuid();
// Add permissionspermissions.addUserPermission(playerUuid, Set.of( "myplugin.feature.use", "myplugin.feature.configure"));
// Remove permissionspermissions.removeUserPermission(playerUuid, Set.of("myplugin.feature.configure"));Managing Groups
Section titled “Managing Groups”UUID playerUuid = player.getUuid();
// Add player to grouppermissions.addUserToGroup(playerUuid, "VIP");
// Remove player from grouppermissions.removeUserFromGroup(playerUuid, "VIP");
// Get player's groupsSet<String> groups = permissions.getGroupsForUser(playerUuid);Checking Permissions in Commands
Section titled “Checking Permissions in Commands”Using requirePermission()
Section titled “Using requirePermission()”Set a required permission in the command constructor:
public class MyCommand extends CommandBase { public MyCommand() { super("mycommand", "server.commands.mycommand.desc"); requirePermission(HytalePermissions.fromCommand("mycommand")); }
@Override protected void executeSync(@Nonnull CommandContext context) { // Only executed if player has hytale.command.mycommand }}Manual Permission Check
Section titled “Manual Permission Check”@Overrideprotected void executeSync(@Nonnull CommandContext context) { if (context.sender().hasPermission("myplugin.admin")) { // Admin-only logic performAdminAction(); } else { // Regular user logic performUserAction(); }}Permission Events
Section titled “Permission Events”PlayerPermissionChangeEvent
Section titled “PlayerPermissionChangeEvent”Fired when a player’s individual permissions change. The base class provides getPlayerUuid() and has several inner classes for specific events:
import com.hypixel.hytale.server.core.event.events.permissions.PlayerPermissionChangeEvent;
// Listen for permissions addedgetEventRegistry().register( PlayerPermissionChangeEvent.PermissionsAdded.class, event -> { UUID playerUuid = event.getPlayerUuid(); Set<String> added = event.getAddedPermissions(); getLogger().at(Level.INFO).log("Player " + playerUuid + " gained: " + added); });
// Listen for permissions removedgetEventRegistry().register( PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> { UUID playerUuid = event.getPlayerUuid(); Set<String> removed = event.getRemovedPermissions(); getLogger().at(Level.INFO).log("Player " + playerUuid + " lost: " + removed); });PlayerGroupEvent
Section titled “PlayerGroupEvent”Fired when a player is added to or removed from a group. Extends PlayerPermissionChangeEvent:
import com.hypixel.hytale.server.core.event.events.permissions.PlayerGroupEvent;
getEventRegistry().register( PlayerGroupEvent.Added.class, event -> { UUID playerUuid = event.getPlayerUuid(); String group = event.getGroupName(); getLogger().at(Level.INFO).log("Player " + playerUuid + " joined group: " + group); });
getEventRegistry().register( PlayerGroupEvent.Removed.class, event -> { UUID playerUuid = event.getPlayerUuid(); String group = event.getGroupName(); getLogger().at(Level.INFO).log("Player " + playerUuid + " left group: " + group); });GroupPermissionChangeEvent
Section titled “GroupPermissionChangeEvent”Fired when a group’s permissions are modified:
import com.hypixel.hytale.server.core.event.events.permissions.GroupPermissionChangeEvent;
getEventRegistry().register( GroupPermissionChangeEvent.Added.class, event -> { String group = event.getGroupName(); Set<String> added = event.getAddedPermissions(); getLogger().at(Level.INFO).log("Group " + group + " gained: " + added); });
getEventRegistry().register( GroupPermissionChangeEvent.Removed.class, event -> { String group = event.getGroupName(); Set<String> removed = event.getRemovedPermissions(); getLogger().at(Level.INFO).log("Group " + group + " lost: " + removed); });Permission Configuration File
Section titled “Permission Configuration File”Permissions are stored in permissions.json in the server directory:
{ "users": { "550e8400-e29b-41d4-a716-446655440000": { "permissions": ["myplugin.vip", "myplugin.special"], "groups": ["VIP", "Moderator"] } }, "groups": { "OP": ["*"], "Default": [], "VIP": ["myplugin.vip.*"], "Moderator": ["myplugin.mod.*", "hytale.command.kick"] }}Built-in Permission Commands
Section titled “Built-in Permission Commands”/op Commands
Section titled “/op Commands”/op self - Toggle own OP status (in singleplayer or with --allow-op flag)/op add <player> - Add player to OP group (requires hytale.command.op.add)/op remove <player> - Remove player from OP group (requires hytale.command.op.remove)Note: The /op self command has special restrictions:
- In singleplayer, only the world owner can use it
- In multiplayer, the server must be started with
--allow-opflag - Does not work if custom permission providers are installed
/perm Commands
Section titled “/perm Commands”/perm group list <group> - List group permissions/perm group add <group> <permissions...> - Add permissions to group/perm group remove <group> <permissions...> - Remove permissions from group/perm user list <uuid> - List user permissions/perm user add <uuid> <permissions...> - Add permissions to user/perm user remove <uuid> <permissions...> - Remove permissions 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 test <permission> - Test if you have a permissionBest Practices
Section titled “Best Practices”- Use hierarchical naming - Structure permissions logically:
myplugin.category.action - Provide granular permissions - Separate
selfandothervariants for player-targeting actions - Use groups for roles - Define groups like
Admin,Moderator,VIPrather than individual permissions - React to permission changes - Listen to permission events to enforce changes immediately
- Default to restrictive - Use
hasPermission(id, false)to default to denying access - Document your permissions - Create clear documentation of what each permission allows
- Use constants - Define permission strings as constants to avoid typos