Skip to content

Add experimental Velocity plugin reload support - #95

Merged
Test-Account666 merged 93 commits into
Test-Account666:dev/velocityfrom
MrSimpleJS:Velocity
Sep 16, 2026
Merged

Test-Account666 merged 93 commits into
Test-Account666:dev/velocityfrom
MrSimpleJS:Velocity

Conversation

@MrSimpleJS

@MrSimpleJS MrSimpleJS commented Jul 14, 2026 •

Copy link
Copy Markdown

This PR adds experimental runtime plugin management for Velocity 3.4.0 through 4.1.0. Newer versions use the Velocity 4.x adapter after runtime capability checks.

PlugManX can now load, unload, enable, disable, restart, and reload compatible Velocity plugins without restarting the proxy.

Java 25 or newer is required. Velocity has no official runtime reload API, so this development build uses capability-checked internal APIs that may require updates when Velocity changes.

Features:

  • Runtime loading, unloading, enabling, disabling, restarting, and reloading
  • Support for Velocity 3.4.0 through 4.1.0
  • Version-specific adapters for Velocity 3.4+ and 4.x
  • Startup validation of required internal classes, fields, methods, and registries
  • Automatic capability checks for newer Velocity builds
  • Reload is disabled safely when required runtime internals are incompatible
  • Serialized operations to prevent concurrent registry and classloader changes
  • Dependency validation and dependency-aware bulk operation ordering
  • Plugin initialization and shutdown lifecycle event handling
  • Fault-tolerant cleanup that continues when individual steps fail
  • Cleanup of listeners, scheduled tasks, commands, messaging channels, registries, and classloaders
  • Classloader-aware packet registry cleanup
  • Packet registry snapshots and per-plugin registration delta tracking
  • Safe removal of exactly the packet mappings added during plugin initialization
  • Fallback cleanup for late or asynchronously registered packet mappings
  • Runtime validation of Velocity StateRegistry and packet registry layouts
  • Protection against duplicate packet registrations after reload
  • Tracking of plugin-owned messaging channels
  • Detection of remaining threads, registrations, classloaders, and other unload leaks
  • Detailed reporting of failed cleanup steps
  • Automatic rollback to the previous JAR when loading or reloading fails
  • Recovery from partial unload and cleanup failures
  • Protection for critical plugins with Velocity-only --force support
  • Console-only Velocity commands to prevent conflicts with backend PlugManX installations
  • Velocity-specific configuration, messages, help output, and plugin lists
  • Colored console output and development-build startup diagnostics
  • Reload timings and detailed diagnostics with velocityReloadDebug: true
  • Crash dumps with unique IDs for runtime and cleanup failures

Showcase:
https://www.youtube.com/watch?v=X3AOtK3jhPo

Download for Velocity:
PlugManX-3.1.0.Velocity.zip

This build adds runtime reload support for Paper plugins using paper-plugin.yml, including Paper provider loading, Paper plugin cleanup, command/listener cleanup, and compatibility fixes for newer Paper versions. It also includes a configurable paperReloadDebug option for troubleshooting Paper reload issues.
Features:
Supports loading/reloading Paper plugins with paper-plugin.yml
Uses Paper runtime provider loading instead of Bukkit-only loading
Cleans up Paper plugin manager/provider storage on unload
Handles modern Paper classloader differences
Skips unsupported runtime bootstrap/loader entrypoints safely
Optional debug logging via paperReloadDebug: true
Built for modern Paper/Spigot 1.20+ / 1.21.x / 26.x servers
Addressed the review comments:
- Reverted the local Windows-only licenseResolver path back to the project-relative one.
- Restored Lombok @requiredargsconstructor in PaperInitializer.
- Added defensive handling for optional dependency linkage errors during Paper command cleanup.
Paper plugins now reload through Paper's provider/entrypoint system and re-run the COMMANDS lifecycle after enabling, fixing missing Brigadier commands after reload.
… enable handling, better diagnostics, and more robust shutdown cleanup.

Changes
Added a plugin load preflight check before /plugman load:
verifies the plugin jar exists
verifies plugin.yml or paper-plugin.yml is readable
prevents loading a plugin that is already loaded
checks obvious required dependencies before loading

Improved load failure messages:
missing required dependencies now show a clear message
invalid plugin files fail before Paper reflection logic runs where possible

Improved Paper /plugman enable behavior:
Paper no longer re-enables a disabled plugin through the old classloader
/plugman enable <plugin> now uses a safer restart-style flow internally:unload the disabled plugin
load it fresh from disk
return the normal enable success message

Added support for operation-specific message arguments through PluginResult.

Improved shutdown cleanup:
reflection caches are cleared before the service registry is cleared
cleanup is protected against late shutdown classloader/linkage issues

Improved Paper warning output:
Paper warning now includes version information
detailed Paper reload diagnostics are only shown when paperReloadDebug is enabled
warning output uses the console sender so colors render correctly on Paper

Reduced noisy Paper load stacktraces:
full Paper load stacktraces are only logged when paperReloadDebug is enabled
otherwise PlugManX logs a short warning
Improve the Paper startup warning to display the detected server software and version instead of always reporting Paper.
This PR improves Paper plugin reload support by setting the Paper command lifecycle owner context during plugin enable, preventing `No lifecycle owner context is set` errors for plugins registering Paper commands in `onEnable`. (see issue Test-Account666#76)

It also updates `/plugman list` to show Paper and Bukkit plugins in separate groups, adds the new message keys to all bundled message files, and extends the v4 config migration to backfill missing message entries without overwriting existing custom messages.
- Added `MessageMigrationService` to keep message migration logic out of `PlugManConfigurationManager`
- Automatically adds missing v4 message keys to existing message files without overwriting custom values
- Adds missing `list.paper`, `list.bukkit`, `enable.failed`, and `load.missing-dependencies` messages
- Added fallback to bundled default messages when old `messages.yml` files are missing newer keys
- Prevents `Error: '<key>' not found in messages.yml` for keys that exist in the bundled defaults
- Hardened reflection cache cleanup during plugin shutdown
- Avoids `NoClassDefFoundError` during server stop by resolving cache classes lazily
Reload/restart now unloads dependent plugins first, reloads the target, then restores dependents in order.

Command syncing is deferred until the chain finishes to avoid Paper async command-map errors.

Example: this prevents classloader issues when reloading CMI while CMIEInjector still references the old CMI instance.
…plugin description"

I also added a confirmation notification for “Restart All” and “Reload All”.

Translations will be added later.
Added new keys: all-failed, blocked-dependents, confirm-all, missing-dependencies
Adds /plugman deps <plugin> to show dependencies and dependent plugins, including tab completion and translated messages.

I think everything is done ^^
Adds safer Paper plugin loading/reloading, dependency-aware reload/restart handling, /plugman deps, /plugman reloadmode
The Paper plugin loader now only registers Maven libraries on supported newer Paper versions (`1.21` through `26.2`). On Paper 1.20 it skips library loading, preventing startup failures like missing `com.fasterxml.jackson.core.Versioned` or invalid relocated Maven coordinates.

Also keeps the shaded dependencies relocated inside the jar, so PlugManX can start even when Paper library resolution is unavailable or unreliable.
Also keeps the cleanup scoped to the unloaded plugin only, so recipes from other plugins or Minecraft itself are not touched.
Added COMPILE_SCOPE = "compile"
…lugin path directly when `FileProviderSource#prepareContext` is not available.

Paper 1.20 does not expose a compatible `FileProviderSource#prepareContext(...)` method, which caused runtime reloads of Paper plugins to fail during provider setup. This change falls back to passing the plugin path directly into provider registration when `prepareContext` is unavailable, allowing Paper plugin reloads to continue on 1.20 while keeping the existing prepareContext path for newer Paper builds.
Fixes Paper plugin reloads by keeping existing provider dependency context while only loading the target plugin provider. This prevents missing dependency errors and duplicate provider reloads during runtime reload.
… plugins.

Paper 1.20 uses `getDependencyTree()` instead of `createDependencyTree()` and exposes multiple `MetaDependencyTree.add(...)` overloads. This update supports both dependency tree methods and selects the correct `add(PluginProvider)` overload, preventing Paper reload failures for plugins like EconomyShopGUI on 1.20.
@Zoriot

Zoriot commented Sep 6, 2026

Copy link
Copy Markdown

What's left needed for merging?

@Test-Account666

Test-Account666 commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

What's left needed for merging?

I don't see any immediate issues.

The main delay was to not introduce too many big changes at once.
I'll merge this PR today (Just gotta get to my PC)

@Test-Account666

Copy link
Copy Markdown
Owner

Hmmm, I just tested this on Velocity 4.1.2-SNAPSHOT-27:

PMX-VEL-20260906-161357-168-F262CEFA.log
log1
log2

@Test-Account666

Copy link
Copy Markdown
Owner

Not sure if this is an issue specific to the plugin I tested though

Fix Velocity plugin reloads by recovering plugin registrations during cleanup and preventing duplicate Guice container bindings.
@MrSimpleJS

Copy link
Copy Markdown
Author

should be fixed now.
try it please.

@Test-Account666

Copy link
Copy Markdown
Owner

latest.log
Commands are still leaking. At least with this plugin

@Test-Account666

Copy link
Copy Markdown
Owner

@MrSimpleJS

MrSimpleJS commented Sep 6, 2026 •

Copy link
Copy Markdown
Author

It works for me?

cmds too:
image

see:
latest (4).log

@Test-Account666

Copy link
Copy Markdown
Owner

It works for me?

cmds too: image

see: latest (4).log

Commands can still be executed even after the plugin has been unloaded

@Test-Account666

Test-Account666 commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner
image

As expected, this is an issue specific to SkinRestorer. Unsure if it's worth it to fix

@MrSimpleJS

Copy link
Copy Markdown
Author

@Zoriot

Zoriot commented Sep 7, 2026

Copy link
Copy Markdown

@MrSimpleJS can you resolve the merge conflicts?

# Conflicts:
#	README.md
#	plugman-assembly/pom.xml
#	plugman-core/src/main/java/core/com/rylinaux/plugman/commands/executables/ListCommand.java
#	plugman-paper/src/main/java/paper/com/rylinaux/plugman/pluginmanager/ModernPaperPluginManager.java
#	plugman-paper/src/main/java/paper/com/rylinaux/plugman/pluginmanager/PaperPluginManager.java
@sonarqubecloud

sonarqubecloud Bot commented Sep 8, 2026

Copy link
Copy Markdown

@Test-Account666

Copy link
Copy Markdown
Owner

Seems to be working. Will be merging this now

@Test-Account666
Test-Account666 changed the base branch from master to dev/velocity September 16, 2026 08:04
@Test-Account666
Test-Account666 merged commit a16a6af into Test-Account666:dev/velocity Sep 16, 2026
2 checks passed
@Test-Account666 Test-Account666 mentioned this pull request Sep 16, 2026
Test-Account666 added a commit that referenced this pull request Sep 16, 2026
* Add experimental Velocity plugin reload support (#95)

* 26.2 support - Implemented support for Paper plugin reloads

This build adds runtime reload support for Paper plugins using paper-plugin.yml, including Paper provider loading, Paper plugin cleanup, command/listener cleanup, and compatibility fixes for newer Paper versions. It also includes a configurable paperReloadDebug option for troubleshooting Paper reload issues.
Features:
Supports loading/reloading Paper plugins with paper-plugin.yml
Uses Paper runtime provider loading instead of Bukkit-only loading
Cleans up Paper plugin manager/provider storage on unload
Handles modern Paper classloader differences
Skips unsupported runtime bootstrap/loader entrypoints safely
Optional debug logging via paperReloadDebug: true
Built for modern Paper/Spigot 1.20+ / 1.21.x / 26.x servers

* 3.0.5 pom

* 8 SonarCloud-Issue fix

* Revert local path and restore Lombok constructor

Addressed the review comments:
- Reverted the local Windows-only licenseResolver path back to the project-relative one.
- Restored Lombok @requiredargsconstructor in PaperInitializer.
- Added defensive handling for optional dependency linkage errors during Paper command cleanup.

* Fix Paper plugin reload command registration

Paper plugins now reload through Paper's provider/entrypoint system and re-run the COMMANDS lifecycle after enabling, fixing missing Brigadier commands after reload.

* Improves Paper plugin reload safety with preflight load checks, safer enable handling, better diagnostics, and more robust shutdown cleanup.

Changes
Added a plugin load preflight check before /plugman load:
verifies the plugin jar exists
verifies plugin.yml or paper-plugin.yml is readable
prevents loading a plugin that is already loaded
checks obvious required dependencies before loading

Improved load failure messages:
missing required dependencies now show a clear message
invalid plugin files fail before Paper reflection logic runs where possible

Improved Paper /plugman enable behavior:
Paper no longer re-enables a disabled plugin through the old classloader
/plugman enable <plugin> now uses a safer restart-style flow internally:unload the disabled plugin
load it fresh from disk
return the normal enable success message

Added support for operation-specific message arguments through PluginResult.

Improved shutdown cleanup:
reflection caches are cleared before the service registry is cleared
cleanup is protected against late shutdown classloader/linkage issues

Improved Paper warning output:
Paper warning now includes version information
detailed Paper reload diagnostics are only shown when paperReloadDebug is enabled
warning output uses the console sender so colors render correctly on Paper

Reduced noisy Paper load stacktraces:
full Paper load stacktraces are only logged when paperReloadDebug is enabled
otherwise PlugManX logs a short warning

* Issue SonarCLoud

* 1 Issue sonarcloud :(

* Show detected server software in Paper warning

Improve the Paper startup warning to display the detected server software and version instead of always reporting Paper.

* proper German

* found another one "ue"

* Improve Paper reload handling and grouped plugin list

This PR improves Paper plugin reload support by setting the Paper command lifecycle owner context during plugin enable, preventing `No lifecycle owner context is set` errors for plugins registering Paper commands in `onEnable`. (see issue #76)

It also updates `/plugman list` to show Paper and Bukkit plugins in separate groups, adds the new message keys to all bundled message files, and extends the v4 config migration to backfill missing message entries without overwriting existing custom messages.

* sonarqubecloud issues

* Fixed a shutdown issue NoClassDefFoundError

- Added `MessageMigrationService` to keep message migration logic out of `PlugManConfigurationManager`
- Automatically adds missing v4 message keys to existing message files without overwriting custom values
- Adds missing `list.paper`, `list.bukkit`, `enable.failed`, and `load.missing-dependencies` messages
- Added fallback to bundled default messages when old `messages.yml` files are missing newer keys
- Prevents `Error: '<key>' not found in messages.yml` for keys that exist in the bundled defaults
- Hardened reflection cache cleanup during plugin shutdown
- Avoids `NoClassDefFoundError` during server stop by resolving cache classes lazily

* Add cascading reload support for dependent plugins

Reload/restart now unloads dependent plugins first, reloads the target, then restores dependents in order.

Command syncing is deferred until the chain finishes to avoid Paper async command-map errors.

Example: this prevents classloader issues when reloading CMI while CMIEInjector still references the old CMI instance.

* removed Duplications

* fixed MSG MigrationService + added better logging for "Error reading plugin description"

I also added a confirmation notification for “Restart All” and “Reload All”.

Translations will be added later.

* added new keys to all messages

Added new keys: all-failed, blocked-dependents, confirm-all, missing-dependencies

* Fixed SonarCloud issues

* Add /plugman deps

Adds /plugman deps <plugin> to show dependencies and dependent plugins, including tab completion and translated messages.

I think everything is done ^^

* public -> protected "array"

* dependency handling

Adds safer Paper plugin loading/reloading, dependency-aware reload/restart handling, /plugman deps, /plugman reloadmode

* Sonar-Issue

* Fixes Paper 1.20 startup?

The Paper plugin loader now only registers Maven libraries on supported newer Paper versions (`1.21` through `26.2`). On Paper 1.20 it skips library loading, preventing startup failures like missing `com.fasterxml.jackson.core.Versioned` or invalid relocated Maven coordinates.

Also keeps the shaded dependencies relocated inside the jar, so PlugManX can start even when Paper library resolution is unavailable or unreliable.

* Adds recipe cleanup during Paper plugin unloads.

Also keeps the cleanup scoped to the unloaded plugin only, so recipes from other plugins or Minecraft itself are not touched.

* Sonar-Issue

Added COMPILE_SCOPE = "compile"

* Adds a Paper 1.20 fallback for plugin provider loading by using the plugin path directly when `FileProviderSource#prepareContext` is not available.

Paper 1.20 does not expose a compatible `FileProviderSource#prepareContext(...)` method, which caused runtime reloads of Paper plugins to fail during provider setup. This change falls back to passing the plugin path directly into provider registration when `prepareContext` is unavailable, allowing Paper plugin reloads to continue on 1.20 while keeping the existing prepareContext path for newer Paper builds.

* Fix Paper runtime reload dependencies for Enchantment Plugins

Fixes Paper plugin reloads by keeping existing provider dependency context while only loading the target plugin provider. This prevents missing dependency errors and duplicate provider reloads during runtime reload.

* sonar issues

* Fixes Paper 1.20 runtime loading compatibility for `paper-plugin.yml` plugins.

Paper 1.20 uses `getDependencyTree()` instead of `createDependencyTree()` and exposes multiple `MetaDependencyTree.add(...)` overloads. This update supports both dependency tree methods and selects the correct `add(PluginProvider)` overload, preventing Paper reload failures for plugins like EconomyShopGUI on 1.20.

* Fixes stale Paper commands after disabling a plugin.

* added CrashDumpWriter

When PlugManX logs severe failures or Paper reload failures, it now writes a detailed dump to `plugins/PlugManX/crash-dumps/`. The dump includes context, server version, Java/OS info, thread name, and the full throwable chain so developers can diagnose runtime reload issues more easily.

* sonar issue

* changed deprecated stuff

* better Thread, added Dump ID

* Update ThreadUtil.java

* added cleanupPermissions for reload

* Maybe Fix Paper recipe cleanup performance during plugin unload/reload.

Now detects at runtime whether the server supports removeRecipe(NamespacedKey, boolean) and updateRecipes(). When available, it removes plugin-owned recipes without forcing a recipe book update for every single recipe, then updates recipes once after cleanup.

* added /plugman reloadconfig cmd

* 2x Sonar-Issue-fixed

* Optimize reload performance by batching command syncs

Reduced command syncing during reloads by batching delayed and immediate syncCommands() calls so reload/restart operations only flush command updates once at the end.

* Optimize Paper recipe cleanup during reloads

I optimized recipe cleanup during Paper reloads by removing plugin-owned recipes through Paper’s internal RecipeMap in one batch, then triggering a single recipe update instead of calling removeRecipe for every recipe.

* make sonar happy ^^

* Optimize Bulk Reloads and Command Flag Parsing

Optimized bulk reloads and restarts by processing each plugin only once in dependency order, and replaced the old flag handling with clean argument parsing that no longer leaves `null` entries.

* Sonar issues

* Add Post-Unload Leak Detection for Bukkit and Paper

Added post-unload leak detection for Bukkit and Paper that reports remaining tasks, services, listeners, commands, and threads still referencing the unloaded plugin or its classloader.

* Add Developer Documentation for Messages and Paper Compatibility

Added a development guide covering message migrations, Paper API and runtime JAR inspection, reload compatibility updates, testing requirements, and linked it from the README.

* Add Linux to dev-docs

* Add Small API Adaptation Tutorial to Devnotes

* Add experimental Velocity plugin reload support

I added experimental Velocity plugin loading, unloading, and reloading with runtime cleanup, platform-specific configuration and messages, startup warnings, detailed diagnostics, reload timings, and a separate versioned Velocity build.

* Improve Velocity unload safety and compatibility

Velocity unload cleanup fault-tolerant, added version-specific runtime adapters, and introduced debug leak detection for remaining listeners, tasks, commands, and plugin threads.

* Sonar issue

* Clarify Velocity Enable and Disable Behavior

I clarified that Velocity’s `disable` command fully unloads a plugin and `enable` loads it again, updating the command handling, messages, help output, and documentation accordingly.

* Sonar issues

* Add Velocity Development Build Tools and Platform-Specific Force Handling

Renamed the experimental Velocity runtime to a Development Build.
Renamed ExperimentalVelocityRuntime to VelocityDevelopmentRuntime.
Updated startup warnings, diagnostics, documentation, and adapter messages.
Added velocityCrashDumps for automatic crash dumps with unique IDs.
Added velocityDevTestFunctions for protected development tools.
Added /plugman dev status and /plugman dev crashdump.
Added the plugman.dev permission.
Added Velocity version, Java version, context, thread, OS, and stacktrace details to crash dumps.
Restricted --force entirely to Velocity.
Added runtime capability checks before parsing --force.
Removed --force from Paper/Bukkit command help, usage text, messages, and documentation.
Added Velocity-specific help entries for commands supporting --force.
Added migration cleanup for old [--force] entries on non-Velocity platforms.

* Restrict Velocity Commands to Console and Expand Development Logging

I restricted PlugManX proxy commands to the Velocity console so player commands can reach backend Paper servers, and added verbose development-mode logging for startup details, runtime operations, command execution, and diagnostics.

* added startup guidance for enabling debug logs

* Add cleanup warning

* add more test options, rmvd useless stuff

* fix memory leaks on velocity

* Separate Velocity from Core and Restore Paper Reload Stability

I separated Velocity from the shared Core and Paper assembly to prevent Paper reload issues. Paper now uses the stable PR #90 implementation, while Velocity is built separately.

* Refactor Velocity integration using a platform SPI

I introduced a platform SPI for Velocity-specific behavior, removed the duplicated Core classes and Sonar exclusions, preserved the stable Paper behavior, and verified both builds with all tests passing.

* sonar

* Preserve Paper commands and tab completion behind Velocity

I separated the Velocity console command alias from /plugman, allowing player commands and tab completion to pass through to Paper while keeping Velocity plugin management console-only.

* i forgot to push: maven -> java 25

I aligned the Velocity Maven build with Java 25. Falling back to Java 21 would require dropping Velocity 4.0 support or publishing a separate Java 21 artifact for older Velocity versions.

* Add Velocity 4.0 packet registry cleanup

added classloader-aware packet registry cleanup during plugin unload and failed-load rollback to prevent duplicate packet registrations.

This currently works only on Velocity 4.0; I will test and add support for older Velocity versions later.

* enable older versions for packet registry cleanup

* Track Velocity packet registry deltas during plugin loading

* sonar

* add 4.1.0 velocity

* add capability check on plugman load

* fixed double Player#updateCommands() error

* sonar

* Fix Paper command synchronization batching

* Mark Velocity runtime as experimental

* Gate Velocity startup diagnostics behind debug mode

* Add temporary wrong-platform JAR detection

I added temporary wrong-platform detection for Paper/Bukkit and Velocity builds, providing a clear error when the incorrect JAR is installed. This will remain in place until I find a cleaner solution. :(

* Hide this public constructor

* v3.05 -> 3.1.0

* Improve Bungee PlugManX command handling, reload stability, and platform-specific output.

Fixes Bungee reloads and SnakeYAML conflicts. Adds a Bungee plugin list and sorted help.

* rmved replay join listeners

* sonar issues

* Fix SonarCloud issues and target Java 21 for Velocity

* Remove duplicated `reloadConfiguration` method

* Fix stale Velocity plugin state after unload

Fix Velocity plugin reloads by recovering plugin registrations during cleanup and preventing duplicate Guice container bindings.

* sonar issue

* fixed Commands xecuted even after the plugin has been unloaded

* add findCommandAliases for cloud cmds

* Fix Velocity scheduled-task cleanup by using an explicit task list type.

* i hate github but yes double reloadConfiguration

* Fix reflection cache cleanup during shutdown to prevent Velocity warning messages.

---------

Co-authored-by: Test-Account666 <36412486+Test-Account666@users.noreply.github.com>

* Fix JavaDoc for alternate color code parameter

* Add non-versioned/stable jar for testing purposes

* Update version to '3.2.0'

---------

Co-authored-by: MrSimpleJS <54013002+MrSimpleJS@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish Velocity Build to Modrinth

3 participants