All notable changes to HyperPerms will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
No changes yet
Server Version: 2026.02.19-1a311a592
- Web editor session create returning 500 - The gzip compression added in 2.8.9 was applied to all session create requests, but the Cloudflare Worker API does not support
Content-Encoding: gzipon incoming request bodies. All/hp editorcommands failed with "Server returned status 500". Compression is now only applied to payloads exceeding 500KB to protect very large servers from HTTP 413 errors while keeping normal requests uncompressed.
Server Version: 2026.02.19-1a311a592
- First-Class MMOSkillTree Integration - Full permission support for MMOSkillTree, one of the biggest plugins on Hytale
- 200+ permission nodes registered across admin, command, skill, boost, and alternate prefix categories
- All 23 individual skill nodes (
mmoskilltree.skill.mining,.woodcutting,.excavation, etc.) - All 140 XP boost permission nodes with the encoded format
mmoskilltree.xpboosts.<target>.<scope>.<multiplier>.<duration>.<cooldown> - Full alias support for MMOSkillTree's
ziggfreed.*alternate prefix pattern — grantingmmoskilltree.skill.miningalso resolvesziggfreed.mmoskilltree.skill.miningchecks - Hytale command path aliases (
com.ziggfreed.mmoskilltree.command.*→mmoskilltree.command.*) - Wildcard expansion for all MMST permission categories
- Tab completion and web editor support for all MMST permissions
- Updated RPG and Survival permission templates with appropriate MMST permissions per rank tier
- Annotation-Based Command Framework - New declarative command system replacing the old individual command class pattern
@CommandGroup,@Command,@Arg,@OptionalArg,@Permission,@ConfirmannotationsCommandScannerautomatically discovers and registers annotated command methodsCommandDispatcherhandles argument parsing, permission checks, and confirmation flows- 5 annotated command groups:
GroupCommands,UserCommands,DebugCommands,RootCommands,PermsCommands,BackupCommands
- Staged Plugin Lifecycle - New
PluginLifecycleorchestrator withServiceContainerdependency injection- 11 ordered stages: Config, Storage, CoreManager, Resolver, Registry, Chat, Integration, Web, Scheduler, Analytics, DefaultGroups
- Stages initialize in order and shut down in reverse — if any stage fails, previously initialized stages are safely torn down
ServiceContainerprovides typed service registration and retrieval across stages
- Gzip Compressed Web Editor Sessions - Session create requests are now gzip compressed before sending to the API, preventing HTTP 413 errors on servers with many groups/permissions
- Plugin Initialization -
HyperPerms.javareduced from ~400 lines of monolithic initialization to a clean staged lifecycle (~25 lines). All setup logic moved to dedicatedStageimplementations incom.hyperperms.lifecycle.stages - Command System - Removed 42 old individual command classes (3,500+ lines). Replaced with 5 annotated command group classes (~2,000 lines) — net reduction of ~1,500 lines with better maintainability
- Config null during stage initialization - Resolved a race condition where config was not yet available when stages attempted to read it during early lifecycle setup
- Default groups created before storage ready - Moved
loadDefaultGroups()into its ownDefaultGroupsStagethat runs after storage and managers are fully initialized
Server Version: 2026.02.19-1a311a592
- Permission pollution in Hytale's permissions.json -
syncPermissionsToHytale()previously pushed all resolved permissions on every change, causing hundreds of permissions to accumulate. Now uses diff-based sync that computes the delta between Hytale's current state and HyperPerms' resolved set, only adding missing and removing stale permissions - Race condition in concurrent permission syncs - Multiple threads (command thread, scheduler, CF pool, web editor) could call
syncPermissionsToHytale()simultaneously for the same user, racing on Hytale's non-thread-safeHashSetview fromgetUserPermissions(). Added per-UUID synchronization locks and defensive copying of the live view - Scattered manual sync calls - Six user commands and
HyperPermsPermissionProvidereach had their own inlinesyncPermissionsToHytale()call via bootstrap reflection. Centralized all sync logic into aCacheInvalidator.setSyncListener()hook — every cache invalidation now automatically triggers Hytale sync for affected online users - Group commands invalidated entire cache - Group permission/property changes (
setperm,unsetperm,setprefix,setsuffix,setweight,setexpiry,parent add/remove) calledinvalidateAll()instead of targetedinvalidateGroup(), causing unnecessary cache churn for unrelated users - Expired permissions not synced to Hytale -
ExpiryCleanupTaskremoved expired nodes but didn't invalidate the cache or trigger Hytale sync, so expired permissions remained active until the player reconnected - Inconsistent cache invalidation API - Some commands used
getCache().invalidate()(bypassing sync) while others usedgetCacheInvalidator().invalidate()(with sync). Unified all commands to usegetCacheInvalidator()
- Permissions not applied after permissions.json wipe -
syncPermissionsToHytale()only removed negated permissions from Hytale's internal storage but never added granted permissions. After an OOM crash wiped Hytale'spermissions.json, third-party plugins (OrbisGuard, etc.) usingPermissionsModule.hasPermission()saw an empty permission set. Now pushes all expanded granted permissions (with wildcard and alias resolution) to other providers, then removes denied permissions — ensuring negations still override grants - JSON storage data loss on JVM crash -
saveUser(),saveGroup(), andsaveTrack()usedFiles.writeString()withTRUNCATE_EXISTING, which could leave files empty or corrupt if the JVM crashed mid-write. Now writes to a.tmpfile first, then atomically renames to the target path - Corrupt JSON file crashes entire load -
loadAllUsers(),loadAllGroups(), andloadAllTracks()only caughtIOException, notJsonParseException(aRuntimeException). A single corrupt file would crash the entire load and prevent all other files from loading. Now catches all exceptions, logs a warning with the filename and error, and continues loading remaining files
- MariaDB/MySQL Storage Backend - Full database storage provider as an alternative to JSON file-based storage, designed for multi-server deployments sharing a central database
MariaDBStorageProvider(~1,050 lines) with HikariCP connection pooling- Complete async CRUD for users, groups, tracks, and permission nodes
- JSON dump backup/restore strategy for networked databases
- 5-table schema:
users,groups,user_nodes,group_nodes,tracks(InnoDB, utf8mb4) - Configure via
storage.type: "mariadb"or"mysql"in config.json with full connection options (host, port, database, username, password, poolSize, useSSL) useSSLconfig option with automatic config migration from older versions- HikariCP 6.2.1 and MariaDB JDBC 3.5.1 bundled in shadow JAR
- Category-based debug logging - New
Logger.DebugCategoryenum with 10 categories (RESOLUTION,CACHE,STORAGE,CONTEXT,INHERITANCE,INTEGRATION,CHAT,WEB,MIGRATION,EXPIRY) — each toggleable individually via/hp debug toggle <category>- Debug traces throughout chat pipeline (
ChatListener,ChatManager,ChatFormatter,PrefixSuffixResolver) - Debug traces for integration setup (Factions, WerChat, PlaceholderAPI, MysticNameTags, VaultUnlocked)
- Debug traces throughout chat pipeline (
- Missing
hytale.mods.outdated.notifypermission - Registered in PermissionRegistry and PermissionAliases, matching the constant defined in Hytale'sHytalePermissionsclass - Vanilla OP/Default overwrite warning - Startup check warns server operators if custom permissions are detected in vanilla's OP or Default groups, which are forcibly reset on every server restart by
HytalePermissionsProvider.read() - JitPack publishing - Other developers can now depend on HyperPerms via
com.github.HyperSystemsDev:HyperPerms:<version>from JitPack - CONTRIBUTING.md - New contributor guide with build setup, soft dependency instructions, code style, and branch strategy
- Update permission constants - Added
UPDATES_ALL,UPDATES_TOGGLE,UPDATES_NOTIFYtoPermissionsutility class
- Permissions not syncing to Hytale after group commands - User group commands (
/hp user addgroup,removegroup,promote,demote,setprimarygroup,clone) only invalidated the Caffeine permission cache but missed ChatAPI/TabListAPI cache invalidation and Hytale permission sync. Negated permissions weren't being removed from Hytale's internal storage after command-based group changes. Now calls full cache invalidation andsyncPermissionsToHytale() - Tab list not sorting by group weight -
TabListListenernever actually sorted entries by group weight — players were sent in arbitrary order and the client sorted alphabetically. Now sorts theServerPlayerListPlayer[]array by group weight (descending) before sending packets - Web editor resetting prefix/suffix priority to 0 -
SessionData.GroupDtowas missingprefixPriorityandsuffixPriorityfields, so saving from the web editor silently reset priorities to 0 - Prefix priority using stale data -
PrefixSuffixResolverloaded groups from raw storage instead of the GroupManager cache, meaning prefix priority changes via commands could be ignored until the async storage save completed. Now usesGroupManager.loadGroup()for all group lookups - Primary group excluded from prefix priority -
PrefixSuffixResolveronly useduser.getInheritedGroups(), not the user's primary group field. If the primary group wasn't also an inherited group node, it wouldn't participate in prefix priority comparison. Now includes the primary group consistently withPermissionResolver - Web editor HTTP/2 connection failures - Java HttpClient defaults to HTTP/2, causing "HTTP/1.1 header parser received no bytes" errors when ALPN negotiation fails. Forced HTTP/1.1 for web editor client connections
- Noisy gamemode group warnings - Hytale calls
addUserToGroupwith virtual gamemode groups (Creative, Adventure) on every player login. Downgraded from warning to debug level - MariaDB resource leak - Fixed unclosed connection in backup/restore, missing backups directory initialization, and redundant
setAutoCommitcall - Duplicate javadoc - Fixed
setPlayerContextProvider()javadoc accidentally duplicated onto the getter
- Build system overhaul - Hytale Server API now resolved automatically from
maven.hytale.cominstead of local JAR files. Use-Phytale_channel=pre-releaseto build against the pre-release server. VaultUnlocked upgraded to 2.19.0 via Maven coordinate fromrepo.codemc.io - Hytale permissions alignment - Aligned with
hytale-permissions-docsv1.1.0: documented multi-provider group aggregation, nondeterministic iteration avoidance via virtual user group, wildcard restrictions matching vanilla behavior, and vanillapermissions.jsoninitialization semantics
- Command system extraction - Decomposed monolithic
HyperPermsCommand(3,000 lines) into 48 focused command classes undercom.hyperperms.command.*organized by domain (user/,group/,debug/,util/). Root command class is now 90 lines — registration and help only - ConfigManager system - New
com.hyperperms.configpackage withConfigManagerorchestrating typed config files (CoreConfig,CacheConfig,ChatConfig,DebugConfig,IntegrationConfig,WebEditorConfig) with validation viaValidationResult - PermissionHolderBase - Extracted shared node storage, listener, and
PermissionHolderAPI fromGroupandUserinto abstract base class — removes ~200 lines of duplicated code - AbstractStorageProvider - Extracted shared executor lifecycle, health tracking, and
runAsync()helper fromJsonStorageProviderandSQLiteStorageProviderinto a common base class - AbstractSqlLuckPermsReader - Extracted shared SQL migration logic from
H2StorageReaderandSqlStorageReader— eliminates ~300 lines of duplicated JDBC code - SimpleContextCalculator - Extracted shared boilerplate from 5 context calculators (
Biome,GameMode,Region,Time,World) into a generic base class withcomputeValue()template method - CommandUtil shared utilities - Extracted common message colors,
join()helper, and confirmation tracking — eliminates duplicated constants across all commands - ReflectionUtil - Centralized reflection helpers used by integration classes
Server Version: 2026.02.17-255364b8e
- Server compatibility: Compile against latest Hytale server JAR to resolve
NoSuchMethodErroronPacketHandler.write()(TabListListener crash) - User load race condition:
UserManagerImpl.loadUser()now uses first-writer-wins to prevent concurrent loads from replacing a user whose username was already set byonPlayerConnect - Server version warning: Manifest now specifies target server version (prevents PluginManager "does not specify a target server version" warning)
- Offline player resolution:
resolveUser()now falls back to storage lookup and PlayerDB API when in-memory search fails, enabling commands like/hp user <name> infoto work for offline players - PlayerDB integration: New
PlayerDBServiceutility for looking up any Hytale player by username via the playerdb.co API (5-minute TTL cache) - Online player safety net: New
findOnlineUuidByName()onPlayerContextProviderresolves players who are connected but whose async user load hasn't completed yet
- PlayerResolver extraction: Moved inline
resolveUser()logic fromHyperPermsCommandto dedicatedPlayerResolverutility with 5-step resolution chain (UUID parse → loaded users → online players → storage → PlayerDB) - Improved logging: Player connect/disconnect, user loading, and permission sync now use info level for better server diagnostics
- Target-aware build: Compile against release or prerelease server JAR via
-PhytaleTargetGradle flag
- HyperFactions permission registry overhaul: Reorganized all HyperFactions permissions into a proper hierarchical structure with category wildcards (
hyperfactions.faction.*,hyperfactions.member.*,hyperfactions.territory.*, etc.) and better descriptions - Runtime discovery namespace filtering: Only keeps permissions whose namespace matches the plugin's JAR filename, manifest Name, or manifest Group — eliminates false positives from bundled/relocated dependencies
- Web editor showing
com.*command path permissions: Hytale command path format permissions (e.g.,com.hyperfactions.hyperfactions.command.faction) are now filtered from the web UI plugin permission scanner (still used internally for wildcard resolution) - Runtime discovery no longer skips HyperSystems plugins: Removed hardcoded exclusion of
hyperhomes,hyperwarps,hyperfactionsfrom discovery — these plugins register their own permissions via the built-in registry and discovery should not interfere
- EssentialsPlus Compatibility - Fixed parameterized permission queries failing silently
- Plugins like EssentialsPlus use
getFirstPermissionProvider().getGroupPermissions()to enumerate permissions for prefix scanning (e.g.essentialsplus.sethome.limit.[n],essentialsplus.home.reduce.cooldown.30s) - HyperPerms was being registered last in the provider chain, so the native Hytale provider (which doesn't understand HyperPerms' virtual user groups) was returned first, yielding empty results
- Provider registration now reorders the chain to ensure HyperPerms is the primary (first) provider
- Plugins like EssentialsPlus use
- Permission Enumeration API -
HyperPermsAPI.getResolvedPermissions(UUID)returns all granted permission strings for a user- Includes permissions from direct nodes and group inheritance, resolved against current contexts
- Enables any plugin to scan permissions by prefix without depending on the native provider chain
- Temporary Permissions - Duration/expiry support for permissions and group membership
/hp user setperm <player> <perm> [value] [duration]- Set permissions with optional expiry (e.g.1d,2h30m,1w)/hp group setperm <group> <perm> [value] [duration]- Same for groups/hp user setexpiry <player> <perm> <duration|permanent>- Modify expiry on existing permissions/hp group setexpiry <group> <perm> <duration|permanent>- Same for groups/hp group parent add <group> <parent> [duration]- Temporary group inheritance/hp user addgroup <player> <group> [duration]- Temporary group membership- All duration arguments are optional, defaulting to permanent (backwards compatible)
/hp user infoand/hp group infonow display expiry in amber for temporary permissions- Uses existing
TimeUtilduration parsing (30s,5m,2h,1d,1w, combos,permanent)
- Web Editor Expiry Pipeline - Fixed web editor silently dropping expiry data when applying changes
Change.javanow carries expiry field through the DTO pipelineWebEditorServicereads expiry from JSON in all parsing pathsChangeApplier.buildNode()applies expiry when building permission nodes- Web editor UI already supported expiry — only the Java-side pipeline was broken
- Permission Negation Bug - Fixed critical bug where negated permissions set via web editor were granted instead of denied
- Web editor sent conflicting data (
-permissionprefix withvalue: false), causing double negation in the permission resolver - Backend
ChangeAppliernow normalizes-prefix permissions to always usevalue: true - Frontend
toBackendNodenow sends correct value for negated permissions
- Web editor sent conflicting data (
- Permission Display - Fixed
/hp group infoand/hp user infoshowing raw internal format for negated permissions- Was showing
+ -hytale.command.spawnor- -hytale.command.spawn - Now correctly shows
- hytale.command.spawnwith red color - Also fixed in
/hp user treeinheritance display
- Was showing
- Command Feedback - Fixed setperm commands showing "Granted" for denied permissions
/hp group setperm group perm falsenow correctly says "Denied perm on group"/hp group setperm group -permnow correctly says "Denied perm on group"
- Permission List Sorting - Group and user info commands now display permissions in alphabetical order
- Build System - Fixed Shadow JAR clobbering in multi-project Gradle builds
- Added
jar { archiveClassifier = 'plain' }to prevent the plain JAR task from overwriting the fat JAR
- Added
- HyperPerms API v2 Foundation - Completely overhauled developer API
- New event system: GroupCreateEvent, GroupDeleteEvent, GroupModifyEvent, UserGroupChangeEvent, UserLoadEvent, UserUnloadEvent, DataReloadEvent, TrackPromotionEvent, TrackDemotionEvent
- Cancellable events with EventPriority (LOWEST through MONITOR)
- Async permission methods:
hasPermissionAsync(),getPermissionValueAsync(), fluentcheckAsync()builder - Permission query API for bulk operations and complex permission lookups
- Metrics tracking for permission operations
- PlaceholderAPI Integration - Native support for PlaceholderAPI on Hytale
- Faction placeholders, group/rank placeholders, and prefix/suffix placeholders
- Works with PlaceholderAPI and WiFlow PlaceholderAPI
- Permission Templates System - 11 pre-built server configurations
- Templates: factions, survival, creative, minigames, smp, skyblock, prison, rpg, towny, vanilla, staff
/hp template list,/hp template preview,/hp template apply,/hp template export- Custom templates via JSON files in
templates/folder
- Analytics & Auditing System - Track permission usage (requires SQLite)
/hp analytics summary- Overview of permission health/hp analytics hotspots- Most frequently checked permissions- Change history audit trail
- Cloudflare Workers API - Split architecture for better performance and cost
- Game server API routed through
api.hyperperms.com(Cloudflare Workers) - Web editor UI served from
www.hyperperms.com(Vercel) - New
apiUrlconfig option with automatic migration
- Game server API routed through
- LuckPerms H2 Migration - Complete H2 database reader support
- Dynamically loads H2 driver from LuckPerms
libs/folder - Handles locked databases by creating temporary copies
- Support for various LuckPerms folder naming conventions
- Dynamically loads H2 driver from LuckPerms
- Console Improvements - Clickable hyperlinks in supported terminals
- Expanded HyperFactions Integration - Improved faction permission interop
- Optional SQLite Driver - JAR size reduced from ~15MB to ~2.4MB
- SQLite JDBC driver no longer bundled; users download separately if needed
- H2 driver fallback removed for CurseForge compliance
- Async Threading - Fixed threading issue in permission checks
- Permission Cache Bypass - Fixed
HyperPermsPermissionSet.contains()bypassing Caffeine cache, reducing CPU usage by 90%+ - Group Weight Priority - Group weight now used as default prefix/suffix priority
- Web Editor Error Messaging - Improved error messaging for empty web editor changes
- Windows H2 File Lock - Better error message for Windows H2 file lock issue
- Track-Based Promote/Demote Commands - Easily manage user progression through rank tracks
/hp user promote <player> <track>- Promotes user to next rank on track/hp user demote <player> <track>- Demotes user to previous rank on track- Handles edge cases gracefully (already at top/bottom, not on track)
/hp update confirmCommand - Fixed "expected 0, given 1" argument error by refactoring to nested subcommand pattern
- HyperFactions Integration - Built-in support for HyperFactions permission integration
- Seamless permission checking between HyperPerms and HyperFactions
- Automatic permission provider registration when HyperFactions is detected
- Permission Set Checks - Fixed user data not being properly loaded during permission set validation
- Permission Resolution Order - Aligned with Hytale's native implementation
- Global wildcard (
*) now checked first - Prefix wildcards resolve shortest-first (
a.*beforea.b.*)
- Global wildcard (
- User Loading - Fixed user not being loaded during permission set checks
- Runtime Permission Discovery - Fixed plugins directory not being found
-
Runtime Permission Discovery - Automatically discovers and registers permissions from all installed plugins
- JAR scanning at startup for permission strings in bytecode
- Intelligent filtering with blacklist of code-related words
- Results cached in
jar-scan-cache.jsonfor performance - Web editor displays discovered permissions with "Installed" badges
-
Operator Update Notification System - Never miss an update
/hp update- Check for available updates/hp update confirm- Download update to mods folder/hp updates on|off- Toggle join notifications- Preferences persist in
notification-preferences.json
-
LuckPerms Migration Tool - Migrate with a single command
/hp migrate luckperms- Preview migration (dry-run)/hp migrate luckperms --confirm- Execute migration- Supports YAML, JSON, H2, MySQL/MariaDB backends
- Migrates groups, users, tracks, temporary permissions, contexts
- Hex Color Support - Added hex color parsing (
§x§R§R§G§G§B§Bformat) - Werchat Compatibility - HyperPerms defers chat handling when Werchat is installed
- HyperPerms + HyFactions Chat - Resolved chat prefix conflict
- Player List Formatting - Complete rewrite using Hytale's packet system
- Universal Permission Negation - Restructured
WildcardMatcher.check()to properly evaluate negations before grants - User Permission Leak - Fixed
PermissionProvider.addUserPermissions()incorrectly persisting every permission check
-
VaultUnlocked Integration - First Hytale permission plugin with full VaultUnlocked support
- Automatic registration as VaultUnlocked permission provider
- Supports permission checks, group operations, context-aware resolution
- Zero configuration required
-
Dynamic Permission Support - Web editor shows "Installed" badges for server plugins
-
HyperFactions & HyperHomes Permission Registry - 31+ pre-registered permissions
- Optional dependency format for Hytale's plugin loader
- Transient permission handling with graceful fallback
- Hytale Permission Discovery - Discovered actual permission nodes Hytale checks
.self/.othersuffix pattern for player-targeted commands- ~100+ new permission mappings between web UI and actual Hytale nodes
- New Command Support - Warp commands, inventory commands, teleport sub-commands
- Documentation - Added
HYTALE_PERMISSIONS.mdreference
- Command System Overhaul - Centralized formatting, flag syntax for optional arguments
- Confirmation steps for destructive commands
- Per-entity locking for concurrent modifications
- Alias expansion in
getUserDirectPermissions() - Case-insensitive permission checking for Hytale compatibility
/hp checkcommand argument handlingclearNodes()avoidingUnsupportedOperationException
- Critical: Player Group Assignments Preserved on Restart - Fixed user data not being loaded during server startup
- Added
userManager.loadAll().join()during initialization - Modified
loadUser()to use atomiccompute()operations - Changed critical
saveUser()calls to await completion
- Added
- HyperHomes Integration - Permission aliasing for HyperHomes plugin
hyperhomes.guimaps to actual Hytale permission nodes- Wildcard
hyperhomes.*expands to all HyperHomes permissions
- User permissions not being recognized by Hytale's built-in system
- Added virtual user group mechanism for direct user permissions
- ChatAPI Race Condition - Fixed prefixes returning empty strings for external plugins
- Single atomic preload operation instead of separate async operations
- ChatAPI cache preloaded when players connect
- Player data invalidated from cache on disconnect
- ChatAPI.getPrefix() Returning Empty - Increased cache TTL and sync timeout
- Web Editor Null Pointer Exceptions - Added comprehensive null-safety checks to JSON parsing
- JSON Parsing Robustness - Handle multiple field name variations gracefully
/hp resetgroups --confirmcommand to reset all groups to plugin defaults
- Faction placeholders (
%faction%,%faction_rank%,%faction_tag%) not resolving in chat - Permission inheritance - inherited permissions from parent groups now work correctly
- Default group permission nodes changed from
hytale.command.*tohytale.system.command.*
- Faction placeholders not resolving properly in chat
- Permission inheritance for Hytale commands
-
Tab List Formatting - Native prefix/suffix display in server tab list
- New
tabListconfig section with customizable format - Automatic cache invalidation when permissions change
- TabListAPI for external plugin integration
- New
-
Tebex/Donation System Support - Commands now support offline players via UUID
/hp user addgroup {uuid} <group>creates user if needed- Works with Tebex
{id}placeholder
- Web editor "type field is null" crash when fetching changes
- Non-OP players couldn't use commands even with correct permissions
HyperPermsPermissionProvidernow properly creates users with default group
- Auto-updater exception on Windows when backing up old JAR (Windows locks loaded JAR files)
- Auto-Update System - Check for updates with
/hp versionand install with/hp update - Compatibility with latest Hytale Server JAR
- Chat prefixes now update instantly when permissions change
- Group prefix display when adding player to groups
- Faction tags and group prefixes display together properly
- Various caching issues causing outdated info