Permission Integration Guide
How MMO Skill Tree integrates with LuckPerms and HyperPerms — and how you can do the same
The Problem
Hytale does not have a standard permission API. There is no shared interface that all mods agree on for granting, revoking, or querying permissions. Yet server owners expect fine-grained access control through mods like LuckPerms and HyperPerms.
The question becomes: how do you make your mod's features controllable by any permission mod, without importing or depending on a specific one?
The Solution
Hytale's Player class exposes a native method:
player.hasPermission(String permissionNode) // returns booleanPermission mods like LuckPerms and HyperPerms hook into this method. When your mod calls player.hasPermission("yourmod.some.node"), the permission mod intercepts the call, checks its own database, and returns the result.
This means your mod never needs to import or depend on any permission mod. You define permission node strings, check them with the native API, and let whatever permission mod the server runs handle the rest.
The Pattern
The integration follows three steps:
- Define permission nodes as plain strings with a consistent naming convention
- Check permissions at runtime using
player.hasPermission() - Document every node so server owners know what to grant
Step 1: Define Permission Nodes
Choose a prefix based on your mod ID and organize nodes into a hierarchy. Use dots as separators and keep names lowercase.
// Convention: <modid>.<category>.<specific>
"mmoskilltree.skill.mining" // skill XP gain
"mmoskilltree.command.xp" // command access
"mmoskilltree.admin" // admin features
// For complex features, encode parameters in the node itself:
"mmoskilltree.xpboosts.mining.self.2_0.30.120"
// target scope mult dur cdThe key insight is that permission nodes are just strings — you can encode any data you want in them. MMO Skill Tree encodes the full boost definition (target, scope, multiplier, duration, cooldown) directly in each permission node. This means the server owner grants a single permission and the mod knows exactly what boost to offer.
Step 2: Check Permissions at Runtime
Call player.hasPermission() wherever you need to gate access. Permission results are live — no caching or reloading required.
import com.hypixel.hytale.server.core.entity.entities.Player;
// Simple boolean gate
public boolean canPlayerUseFeature(Player player, String feature) {
return player.hasPermission("yourmod.feature." + feature);
}
// Wildcard support — check specific first, then wildcard
public boolean canGainSkillXp(Player player, String skill) {
if (player.hasPermission("yourmod.skill.*")) {
return true;
}
return player.hasPermission("yourmod.skill." + skill);
}
// Filtering a list based on permissions
public List<Template> getAvailableTemplates(Player player) {
List<Template> available = new ArrayList<>();
for (Template template : allTemplates) {
if (player.hasPermission(template.getPermissionNode())) {
available.add(template);
}
}
return available;
}Step 3: Double-Check on Action
Always verify the permission again when the player actually performs the action, not just when rendering the UI. Permissions can change between the time the UI was built and when the player clicks a button.
// When rendering the UI:
List<Boost> available = getAvailableBoosts(player); // filters by permission
renderBoostButtons(available);
// When player clicks "Activate":
public String activateBoost(Player player, BoostPermission perm) {
// Re-check permission at activation time
if (!player.hasPermission(perm.getPermissionNode())) {
return "You don't have permission for this boost";
}
// Proceed with activation...
}Encoding Data in Permission Nodes
For features with many variants (like XP boosts with different multipliers and durations), encoding the configuration directly in the permission node avoids needing a separate mapping file. Here is how MMO Skill Tree does it:
The Format
mmoskilltree.xpboosts.<target>.<scope>.<multiplier>.<duration>.<cooldown>
// Examples:
mmoskilltree.xpboosts.all.self.1_5.30.60 // 1.5x all skills, personal, 30min, 1hr cd
mmoskilltree.xpboosts.mining.all.2_0.60.120 // 2x mining, global, 1hr, 2hr cdUse underscores for decimal points since dots are already the hierarchy separator (1_5 = 1.5, 2_0 = 2.0).
Parsing Permission Nodes
Write a parser that extracts the parameters back out of the string. Validate the format and return null for anything invalid.
public static BoostPermission parseFromPermission(String node) {
// Expected: mmoskilltree.xpboosts.<target>.<scope>.<mult>.<dur>.<cd>
String[] parts = node.split("\\.");
if (parts.length < 7) return null;
String target = parts[2]; // "mining", "all", "combat"
String scope = parts[3]; // "self" or "all"
String multStr = parts[4]; // "1_5" or "2_0"
String durStr = parts[5]; // "30"
String cdStr = parts[6]; // "60"
double multiplier = Double.parseDouble(multStr.replace('_', '.'));
int duration = Integer.parseInt(durStr);
int cooldown = Integer.parseInt(cdStr);
return new BoostPermission(node, target, scope, multiplier, duration, cooldown);
}Pre-Define All Templates
Since permission mods can only grant or deny nodes that your mod recognizes, you need to pre-define every valid combination. Store them as defaults that the server owner can customize or disable:
// Define sensible defaults covering common use cases
List<String> defaults = new ArrayList<>();
// Tiered personal boosts: low/medium/high multiplier × short/long duration
defaults.add("yourmod.xpboosts.all.self.1_25.15.30"); // low tier
defaults.add("yourmod.xpboosts.all.self.1_5.30.120"); // mid tier
defaults.add("yourmod.xpboosts.all.self.2_0.30.180"); // high tier
defaults.add("yourmod.xpboosts.all.self.3_0.15.240"); // premium tier
// Per-skill variants
for (SkillType skill : SkillType.values()) {
String name = skill.name().toLowerCase();
defaults.add("yourmod.xpboosts." + name + ".self.1_5.30.60");
defaults.add("yourmod.xpboosts." + name + ".self.2_0.30.120");
}Making Templates Configurable
Hard-coded templates are limiting. An override-based config system lets server owners customize multipliers, durations, and cooldowns — or disable templates entirely — without losing their changes on mod updates.
The pattern:
- Defaults class — defines all built-in templates (never modified at runtime)
- Config class — loads user overrides from a JSON file, merges with defaults
- Effective definitions — defaults + overrides = what the mod actually uses
// Only user customizations are saved to disk:
// mods/yourmod/boost-templates.json
{
"schemaVersion": 1,
"overrides": {
"yourmod.xpboosts.all.self.2_0.30.180": {
"multiplier": 2.5,
"durationMinutes": 45
},
"yourmod.xpboosts.mining.self.1_5.30.60": {
"disabled": true
}
}
}When the mod loads, it merges defaults with overrides. Non-null override fields replace the default values; null fields keep the default. This means the JSON file stays small and survives mod updates that add new templates.
Adding an Admin UI
An in-game admin page for managing templates makes the system accessible to server owners who don't want to edit JSON. MMO Skill Tree's Boost Templates admin page lets admins:
- Browse all templates filtered by scope (personal/global) and skill category
- View default vs. current values side by side
- Edit multiplier, duration, and cooldown for any template
- Disable or re-enable individual templates
- Copy the permission node string to paste into LuckPerms/HyperPerms commands
- Trim redundant overrides (overrides that match the default)
The permission string copy field is especially important — admins can select a template in the UI, copy the permission node, and paste it directly into a permission mod command:
/lp group vip permission set mmoskilltree.xpboosts.all.self.1_5.30.120 trueWildcard Support
Permission mods support wildcard nodes. Document which wildcards are useful so server owners can grant permissions in bulk:
# All boost permissions (personal + global)
mmoskilltree.xpboosts.*
# All personal boosts
mmoskilltree.xpboosts.*.self.*
# All global boosts
mmoskilltree.xpboosts.*.all.*
# All skill permissions
mmoskilltree.skill.*Your mod doesn't need to implement wildcard matching itself — the permission mod handles it. When you call player.hasPermission("mmoskilltree.xpboosts.mining.self.1_5.30.60"), LuckPerms will match it against mmoskilltree.xpboosts.* if the player has that wildcard granted.
No Hard Dependency
The entire integration works without importing any permission mod classes. Your mod only uses the Hytale-provided Player.hasPermission() method. This means:
- Your mod works without any permission mod installed (permissions default to the server's built-in behavior)
- Your mod works with any permission mod that hooks into Hytale's native permission system
- No compile-time dependency, no version conflicts, no class-not-found errors
- If a new permission mod is released tomorrow, it works automatically
Implementation Checklist
| Step | What to do |
|---|---|
| 1 | Pick a permission node prefix based on your mod ID (yourmod.category.name) |
| 2 | Define all valid permission nodes as string constants or generated templates |
| 3 | Gate features with player.hasPermission(node) — check at both UI render and action time |
| 4 | For complex features, encode parameters in the node string and write a parser |
| 5 | Make templates configurable with an override-based config so server owners can customize |
| 6 | Add an admin UI with a copyable permission string field for easy setup |
| 7 | Document every permission node and provide LuckPerms/HyperPerms command examples |
Reference Implementation
MMO Skill Tree implements this pattern with 124 boost permission nodes. The full source serves as a working reference:
- Permission checking —
PermissionUtil.javawraps allplayer.hasPermission()calls - Node parsing —
BoostPermission.javaparses permission strings into typed objects - Template defaults —
BoostTemplateDefaults.javagenerates the 124 default nodes - Override config —
BoostTemplateConfig.javamerges defaults with user overrides - Runtime filtering —
XpBoostService.getAvailableBoostsForPlayer()checks permissions live - Admin UI —
BoostTemplateOverridesPage.javawith copyable permission string field