Skip to content

Releases: HyperSystemsDev/HyperPerms

HyperPerms v2.9.0

28 Feb 17:42

Choose a tag to compare

Hotfix: Web Editor Session Create

Fixed

  • Web editor returning 500 on /hp editor — The gzip compression introduced in 2.8.9 was applied to all session create requests, but the Cloudflare Worker API does not support Content-Encoding: gzip on incoming request bodies. This caused every /hp editor command to fail with "Server returned status 500". Compression is now only applied to payloads exceeding 500KB, keeping normal requests uncompressed while still protecting very large servers from HTTP 413 errors.

If you are on 2.8.9, update immediately.

HyperPerms v2.8.9

28 Feb 16:26

Choose a tag to compare

Architecture Rehaul & MMOSkillTree Integration

First-Class MMOSkillTree Support

HyperPerms now has full, first-class integration with MMOSkillTree — one of the biggest plugins on Hytale.

  • 200+ permission nodes registered across admin, command, skill, boost, and alternate prefix categories
  • All 23 skill nodesmmoskilltree.skill.mining, .woodcutting, .excavation, .harvesting, .fishing, .swords, .daggers, .polearms, .staves, .axes, .blunt, .archery, .unarmed, .defense, .taming, .acrobatics, .crafting, .repair, .alchemy, .enchanting, .cooking, .smithing, .building
  • All 140 XP boost permission nodes covering personal and global boosts for all skills, skill categories, and all-skills targets with varying multipliers, durations, and cooldowns
  • ziggfreed.* alternate prefix support — MMOSkillTree checks permissions through both mmoskilltree.* and ziggfreed.mmoskilltree.* prefixes. HyperPerms now correctly resolves both via bidirectional aliases
  • Hytale command path aliasescom.ziggfreed.mmoskilltree.command.* paths resolve to their mmoskilltree.command.* equivalents
  • Wildcard expansion for all MMST permission categories
  • Tab completion & web editor now show all MMST permission nodes
  • Updated RPG & Survival templates with appropriate MMST permissions at each rank tier (XP boosts scale with rank progression)

Staged Plugin Lifecycle

The plugin initialization system has been completely rewritten with a clean, modular architecture:

  • 11 ordered stages: Config → Storage → CoreManager → Resolver → Registry → Chat → Integration → Web → Scheduler → Analytics → DefaultGroups
  • PluginLifecycle orchestrator initializes stages in order and shuts them down in reverse — if any stage fails, previously initialized stages are safely torn down
  • ServiceContainer provides typed dependency injection across all stages
  • HyperPerms.java reduced from ~400 lines of monolithic init to ~25 lines — all setup logic now lives in dedicated Stage implementations

Annotation-Based Command Framework

The entire command system has been rebuilt using a declarative annotation-driven approach:

  • New annotations: @CommandGroup, @Command, @Arg, @OptionalArg, @Permission, @Confirm
  • CommandScanner automatically discovers and registers annotated command methods at startup
  • CommandDispatcher handles argument parsing, permission checks, and confirmation flows
  • 5 annotated command groups replace 42 individual command classes: GroupCommands, UserCommands, DebugCommands, RootCommands, PermsCommands, BackupCommands
  • Net reduction of ~1,500 lines with significantly better maintainability

Web Editor Improvements

  • Gzip compressed session requests — Session create payloads are now gzip compressed before sending to the API, preventing HTTP 413 errors on servers with many groups and permissions

Bug Fixes

  • Fixed config being null during early stage initialization
  • Fixed default groups being created before storage was fully ready
  • Integrated 2.8.8's centralized sync and diff-based permission logic into the new lifecycle system

HyperPerms v2.8.8

24 Feb 00:47

Choose a tag to compare

[2.8.8] - 2026-02-23

Server Version: 2026.02.19-1a311a592

Fixed

  • 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-safe HashSet view from getUserPermissions(). Added per-UUID synchronization locks and defensive copying of the live view
  • Scattered manual sync calls - Six user commands and HyperPermsPermissionProvider each had their own inline syncPermissionsToHytale() call via bootstrap reflection. Centralized all sync logic into a CacheInvalidator.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) called invalidateAll() instead of targeted invalidateGroup(), causing unnecessary cache churn for unrelated users
  • Expired permissions not synced to Hytale - ExpiryCleanupTask removed 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 used getCacheInvalidator().invalidate() (with sync). Unified all commands to use getCacheInvalidator()

v2.8.7

22 Feb 20:57

Choose a tag to compare

Fixed

  • 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's permissions.json, third-party plugins (OrbisGuard, etc.) using PermissionsModule.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(), and saveTrack() used Files.writeString() with TRUNCATE_EXISTING, which could leave files empty or corrupt if the JVM crashed mid-write. Now writes to a .tmp file first, then atomically renames to the target path
  • Corrupt JSON file crashes entire load - loadAllUsers(), loadAllGroups(), and loadAllTracks() only caught IOException, not JsonParseException (a RuntimeException). 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

v2.8.6 — MariaDB/MySQL Storage, Command Refactor & Bug Fixes

22 Feb 15:08

Choose a tag to compare

Highlights

MariaDB/MySQL Storage Backend — HyperPerms now supports database-backed storage for multi-server deployments. Connect all your servers to a shared MariaDB or MySQL database with a single config change.

Massive Command Refactor — The monolithic 3,000-line command handler has been decomposed into 48 focused command classes organized by domain, making the codebase significantly more maintainable.

Critical Bug Fixes — Permissions now properly sync to Hytale after group commands, tab list sorts by weight, and prefix/suffix priorities no longer reset to 0 from the web editor.


Added

MariaDB/MySQL Storage Backend

  • Full 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
  • Full connection options: host, port, database, username, password, poolSize, useSSL
  • useSSL config option with automatic migration from older config versions
  • HikariCP 6.2.1 and MariaDB JDBC 3.5.1 bundled in shadow JAR

Category-Based Debug Logging

  • New Logger.DebugCategory enum with 10 categories: RESOLUTION, CACHE, STORAGE, CONTEXT, INHERITANCE, INTEGRATION, CHAT, WEB, MIGRATION, EXPIRY
  • Each toggleable individually via /hp debug toggle <category>
  • Debug traces throughout the chat pipeline (ChatListener, ChatManager, ChatFormatter, PrefixSuffixResolver)
  • Debug traces for integration setup (Factions, WerChat, PlaceholderAPI, MysticNameTags, VaultUnlocked)

Permissions & Documentation

  • Registered missing hytale.mods.outdated.notify permission node matching Hytale's HytalePermissions class
  • Startup warning when vanilla OP/Default groups contain custom permissions that will be silently lost on restart
  • Added UPDATES_ALL, UPDATES_TOGGLE, UPDATES_NOTIFY permission constants

Developer Experience

  • JitPack publishing — depend on HyperPerms via com.github.HyperSystemsDev:HyperPerms:<version>
  • CONTRIBUTING.md — contributor guide with build setup, code style, and branch strategy
  • Standalone build support for JitPack/CI environments

Fixed

Critical: Permissions Not Syncing 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 and syncPermissionsToHytale().

Tab List Not Sorting by Group Weight

TabListListener never actually sorted entries by group weight — players were sent in arbitrary order and the client sorted alphabetically. Now sorts the ServerPlayerListPlayer[] array by group weight (descending) before sending packets.

Web Editor Resetting Prefix/Suffix Priority to 0

SessionData.GroupDto was missing prefixPriority and suffixPriority fields, so saving from the web editor silently reset priorities to 0.

Prefix Priority Using Stale Data

PrefixSuffixResolver loaded 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 uses GroupManager.loadGroup() for all group lookups.

Primary Group Excluded from Prefix Priority

PrefixSuffixResolver only used user.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 with PermissionResolver.

Other Fixes

  • Web editor HTTP/2 connection failures — Forced HTTP/1.1 to prevent "header parser received no bytes" errors when ALPN negotiation fails
  • Noisy gamemode group warnings — Hytale calls addUserToGroup with virtual gamemode groups on every login; downgraded from warning to debug level
  • MariaDB resource leak — Fixed unclosed connection in backup/restore, missing backups directory initialization, and redundant setAutoCommit call

Changed

  • Build system overhaul — Hytale Server API now resolved automatically from maven.hytale.com instead of local JAR files. VaultUnlocked upgraded to 2.19.0 via Maven
  • Hytale permissions alignment — Aligned with hytale-permissions-docs v1.1.0: documented multi-provider aggregation, nondeterministic iteration avoidance, wildcard restrictions, and permissions.json initialization semantics

Refactored

  • Command system — Decomposed monolithic HyperPermsCommand (3,000 lines) into 48 focused command classes under com.hyperperms.command.* organized by domain (user/, group/, debug/, util/). Root command is now 90 lines
  • ConfigManager — New com.hyperperms.config package with typed config files (CoreConfig, CacheConfig, ChatConfig, DebugConfig, IntegrationConfig, WebEditorConfig) and validation
  • PermissionHolderBase — Shared node storage and PermissionHolder API extracted from Group and User — removes ~200 lines of duplication
  • AbstractStorageProvider — Shared executor lifecycle, health tracking, and runAsync() extracted from JSON and SQLite providers
  • AbstractSqlLuckPermsReader — Shared SQL migration logic extracted from H2 and SQL readers — removes ~300 lines of duplication
  • SimpleContextCalculator — Generic base class for 5 context calculators with computeValue() template method
  • CommandUtil — Common message colors, join() helper, and confirmation tracking centralized
  • ReflectionUtil — Centralized reflection helpers for integration classes

Upgrade Notes

  • MariaDB setup: Set storage.type to "mariadb" or "mysql" in config.json and configure the mysql block with your connection details. Schema is created automatically on first run.
  • Config migration: The useSSL option is automatically added to existing configs on upgrade.
  • No breaking changes: All existing JSON and SQLite storage continues to work without modification.

Full Changelog: 2.8.5...2.8.6

HyperPerms v2.8.5

17 Feb 20:55

Choose a tag to compare

[2.8.5] - 2026-02-17

Server Version: 2026.02.17-255364b8e

Fixed

  • Server compatibility: Compile against latest Hytale server JAR to resolve NoSuchMethodError on PacketHandler.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 by onPlayerConnect
  • Server version warning: Manifest now specifies target server version (prevents PluginManager "does not specify a target server version" warning)

Added

  • Offline player resolution: resolveUser() now falls back to storage lookup and PlayerDB API when in-memory search fails, enabling commands like /hp user <name> info to work for offline players
  • PlayerDB integration: New PlayerDBService utility for looking up any Hytale player by username via the playerdb.co API (5-minute TTL cache)
  • Online player safety net: New findOnlineUuidByName() on PlayerContextProvider resolves players who are connected but whose async user load hasn't completed yet

Changed

  • PlayerResolver extraction: Moved inline resolveUser() logic from HyperPermsCommand to dedicated PlayerResolver utility 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 -PhytaleTarget Gradle flag

HyperPerms v2.8.4

15 Feb 04:35

Choose a tag to compare

Changed

  • 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

Fixed

  • 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, hyperfactions from discovery — these plugins register their own permissions via the built-in registry and discovery should not interfere

Full Changelog: https://github.com/HyperSystemsDev/HyperPerms/blob/main/CHANGELOG.md

HyperPerms v2.8.3

12 Feb 00:09

Choose a tag to compare

Added

  • MysticNameTags Integration - First-class soft dependency with reflection-based detection
    • Event-driven cache invalidation on permission/group changes via HyperPerms EventBus
    • Calls TagManager.clearCanUseCache() and MysticNameTagsAPI.refreshNameplate() on changes so tags update without relog
    • Group-level permission changes invalidate all online players who may inherit from the affected group
    • LuckPerms conflict detection with warning log
    • Local CachedTagData with 5-second TTL for API method results
    • Public API: getActiveTagDisplay, getActiveTagId, getAvailableTagCount, hasTagPermission, refreshPlayerTags, etc.
    • Configurable via config.json mysticnametags section (enabled, refresh toggles, tag permission prefix)
    • Auto-migration adds config section to existing configs
  • PlaceholderAPI Expansion - 5 new MysticNameTags placeholders
    • %hyperperms_tag% - Active tag ID
    • %hyperperms_tag_display% - Active tag display text (colored)
    • %hyperperms_tag_count% - Number of available tags
    • %hyperperms_tags% - All available tag IDs (comma-separated)
    • %hyperperms_has_tag_<name>% - Check tag permission (true/false)
  • Temporary Permissions Developer API - Full public API for managing timed permissions programmatically
    • New TemporaryPermissionInfo record DTO with getRemaining() and isExpired() methods
    • PermissionHolder interface: 12 new methods for setting, querying, and modifying temporary permissions
      • setPermission(perm, value, Duration/Instant) - Set permissions with expiry
      • isTemporaryPermission(perm) / getPermissionExpiry(perm) / getPermissionRemaining(perm) - Query expiry state
      • setPermissionExpiry(perm, Instant) / adjustPermissionExpiry(perm, Duration) - Modify or remove expiry
      • getTemporaryPermissions() - Enumerate all active temporary permissions
      • addGroup(name, Duration/Instant) - Temporary group membership via interface
    • HyperPermsAPI top-level convenience methods: setTemporaryPermission(), getTemporaryPermissions(), isTemporaryPermission(), getPermissionRemaining()
    • All methods are backward-compatible default methods — no breaking changes
  • Permission Enumeration API - getResolvedPermissions(UUID) on HyperPermsAPI
    • Returns all granted permission strings for a user including inherited permissions from group hierarchy
    • Enables plugins to scan permissions by prefix without depending on the native provider chain

Fixed

  • EssentialsPlus Compatibility - Fixed provider ordering causing parameterized permission queries to fail silently
    • Hytale's native provider was first in the chain and couldn't resolve HyperPerms virtual groups
    • ensureFirstProvider() now reorders the provider chain so HyperPerms is always first
    • Fixes essentialsplus.sethome.limit.[n], essentialsplus.home.reduce.cooldown.*, and similar queries
  • Compilation Warnings - Resolved all 63 compiler warnings for a completely clean build
    • Fixed 56 dangling-doc-comments warnings in migration record types
    • Fixed 4 unchecked/rawtypes warnings in AsyncPermissionCheckBuilder
    • Fixed 3 text-blocks trailing whitespace warnings in SQLiteAnalyticsStorage

HyperPerms v2.8.2

09 Feb 05:46

Choose a tag to compare

Added

  • 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 info and /hp group info now display expiry in amber for temporary permissions
    • Uses existing TimeUtil duration parsing (30s, 5m, 2h, 1d, 1w, combos, permanent)

Fixed

  • Web Editor Expiry Pipeline - Fixed web editor silently dropping expiry data when applying changes
    • Change.java now carries expiry field through the DTO pipeline
    • WebEditorService reads expiry from JSON in all parsing paths
    • ChangeApplier.buildNode() applies expiry when building permission nodes
    • Web editor UI already supported expiry — only the Java-side pipeline was broken

HyperPerms v2.8.1

08 Feb 21:55

Choose a tag to compare

Fixed

  • Permission Negation Bug - Fixed critical bug where negated permissions set via web editor were granted instead of denied
    • Web editor sent conflicting data (-permission prefix with value: false), causing double negation in the permission resolver
    • Backend ChangeApplier now normalizes - prefix permissions to always use value: true
    • Frontend toBackendNode now sends correct value for negated permissions
  • Permission Display - Fixed /hp group info and /hp user info showing raw internal format for negated permissions
    • Was showing + -hytale.command.spawn or - -hytale.command.spawn
    • Now correctly shows - hytale.command.spawn with red color
    • Also fixed in /hp user tree inheritance display
  • Command Feedback - Fixed setperm commands showing "Granted" for denied permissions
    • /hp group setperm group perm false now correctly says "Denied perm on group"
    • /hp group setperm group -perm now correctly says "Denied perm on group"
  • Permission List Sorting - Group and user info commands now display permissions in alphabetical order

Changed

  • Build System - Fixed Shadow JAR clobbering in multi-project Gradle builds