Skip to content

Latest commit

 

History

History
188 lines (146 loc) · 7.11 KB

File metadata and controls

188 lines (146 loc) · 7.11 KB

Permissions System

Architecture

PermissionsModule (JavaPlugin singleton)
  ├── List<PermissionProvider> providers  (CopyOnWriteArrayList)
  │     ├── HytalePermissionsProvider (default, index 0)
  │     └── ... custom providers (e.g., HyperPermsPermissionProvider)
  ├── Map<String, Set<String>> virtualGroups (game-mode-based permissions)
  └── Built-in commands: /op, /perm

PermissionsModule

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

Singleton access: PermissionsModule.get()

Provider Management

public void addProvider(@Nonnull PermissionProvider provider);
public void removeProvider(@Nonnull PermissionProvider provider);
@Nonnull public List<PermissionProvider> getProviders();
public PermissionProvider getFirstPermissionProvider();  // First in list handles mutations
public boolean areProvidersTampered();                   // true if not just default provider

Permission Checks

public boolean hasPermission(@Nonnull UUID uuid, @Nonnull String id);
public boolean hasPermission(@Nonnull UUID uuid, @Nonnull String id, boolean def);

Check order:

  1. Iterates providers in order
  2. For each provider: checks getUserPermissions(uuid) for direct match
  3. Then checks each group in getGroupsForUser(uuid)getGroupPermissions(group)
  4. Then checks virtualGroups for group matches
  5. Returns def if no match found

Permission Matching Logic (static)

@Nullable
public static Boolean hasPermission(@Nullable Set<String> nodes, @Nonnull String id);

Matching rules (in order):

  1. * in nodes → TRUE (universal grant)
  2. -* in nodes → FALSE (universal deny)
  3. Exact id match → TRUE
  4. Exact -id match → FALSE
  5. Wildcard hierarchy: splits id by ., checks prefix.* and -prefix.* at each level
  6. No match → null (continue to next provider/group)

Group Management (delegates to first provider)

public void addUserPermission(@Nonnull UUID uuid, @Nonnull Set<String> permissions);
public void removeUserPermission(@Nonnull UUID uuid, @Nonnull Set<String> permissions);
public void addGroupPermission(@Nonnull String group, @Nonnull Set<String> permissions);
public void removeGroupPermission(@Nonnull String group, @Nonnull Set<String> permissions);
public void addUserToGroup(@Nonnull UUID uuid, @Nonnull String group);
public void removeUserFromGroup(@Nonnull UUID uuid, @Nonnull String group);
@Nonnull public Set<String> getGroupsForUser(@Nonnull UUID uuid); // Aggregates all providers

Each mutation dispatches corresponding events (see 02-event-system.md).

Virtual Groups

public void setVirtualGroups(@Nonnull Map<String, Set<String>> virtualGroups);

Virtual groups are game-mode-based permission sets. By default:

  • Creative mode grants hytale.editor.builderTools
  • Command permissions are grouped by GameMode via setPermissionGroup()

PermissionProvider Interface

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

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 groupName, @Nonnull Set<String> permissions);
    void removeGroupPermissions(@Nonnull String groupName, @Nonnull Set<String> permissions);
    Set<String> getGroupPermissions(@Nonnull String groupName);

    // User-group membership
    void addUserToGroup(@Nonnull UUID uuid, @Nonnull String groupName);
    void removeUserFromGroup(@Nonnull UUID uuid, @Nonnull String groupName);
    Set<String> getGroupsForUser(@Nonnull UUID uuid);
}

PermissionHolder Interface

public interface PermissionHolder {
    boolean hasPermission(String permission);
}

Used by CommandSender and other systems that need permission checks.

HytalePermissions Constants

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

public class HytalePermissions {
    public static final String NAMESPACE = "hytale";
    public static final String COMMAND_BASE = "hytale.command";

    // 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";
    public static final String BUILDER_TOOLS_EDITOR = "hytale.editor.builderTools";
    public static final String EDITOR_BRUSH_USE = "hytale.editor.brush.use";
    public static final String EDITOR_BRUSH_CONFIG = "hytale.editor.brush.config";
    public static final String EDITOR_PREFAB_USE = "hytale.editor.prefab.use";
    public static final String EDITOR_PREFAB_MANAGE = "hytale.editor.prefab.manage";
    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";
    public static final String EDITOR_HISTORY = "hytale.editor.history";
    public static final String FLY_CAM = "hytale.camera.flycam";

    // Helper methods
    @Nonnull public static String fromCommand(@Nonnull String name);
    // Returns: "hytale.command.{name}"

    @Nonnull public static String fromCommand(@Nonnull String name, @Nonnull String subCommand);
    // Returns: "hytale.command.{name}.{subCommand}"
}

HyperPerms Integration Pattern

public class HyperPermsPermissionProvider implements PermissionProvider {
    @Override
    public String getName() { return "HyperPerms"; }

    @Override
    public Set<String> getUserPermissions(UUID uuid) {
        // Return resolved permissions including wildcards, contexts, inheritance
        return new CaseInsensitiveSet(resolved.getExpandedPermissions(registry));
    }

    @Override
    public Set<String> getGroupsForUser(UUID uuid) {
        Set<String> allGroups = new HashSet<>();
        collectInheritedGroups(user.getInheritedGroups(), allGroups);
        // Add virtual user group for direct permissions
        allGroups.add("user:" + uuid.toString());
        return allGroups;
    }
}

// Registration in plugin start():
PermissionsModule.get().addProvider(permissionProvider);

// Removal in plugin shutdown():
PermissionsModule.get().removeProvider(permissionProvider);

Key Design Notes

  • First provider handles mutations: addUserPermission() etc. always delegate to getFirstPermissionProvider()
  • All providers checked for reads: hasPermission() and getGroupsForUser() iterate all providers
  • Case sensitivity: Hytale's built-in system is case-sensitive; HyperPerms wraps in CaseInsensitiveSet for compatibility
  • Wildcard support: Built-in supports *, -*, and prefix.* / -prefix.* hierarchies
  • Negation: Prefix - negates a permission node