The same plugin, three protection levels. Download. Decompile. Compare.
Reading marketing copy is fine. Holding the artifacts in your decompiler is better.
We took one real Bukkit plugin (CWelcomer 1.0.1) and protected it twice:
once on the free tier with every dial maxed, once on Citadel with the full pipeline.
The original is here too. Pull all three, run them through your tool of choice,
and form your own opinion.
Untouched build
The plugin as it ships from the developer compile.
- readable
- yes, fully
- strings
- plaintext
- control flow
- structured
- native helpers
- none
What every other JAR you ever downloaded looks like before protection. Decompile it, diff it, see the readable control flow and string table. This is the baseline.
CWelcomer-1.0.1.jar
e74ccd365335bb0a
Free tier, every dial maxed
No card. No trial timer. Just the free pass with everything on.
- renames
- full
- strings
- encrypted
- control flow
- flattened
- native helpers
- none
Same source plugin, run through the free tier with every transform we ship turned up. Renames, string concealment, control-flow flattening, decoy classes, watermark, layout scramble. The decompile is no longer pleasant reading.
CWelcomer-1.0.1-free-max.jar
3900ad208a651c7c
Citadel, the full stack
Native-bound, license-gated, the whole pipeline.
- renames
- full
- strings
- encrypted
- control flow
- flattened + VM
- native helpers
- linux + windows
The same plugin run through the paid Citadel pipeline. Native-bound key derivation, runtime integrity heartbeat, virtualized control flow, native method emission, synthetic helper extraction, and the license client. The full deployment shape.
CWelcomer-1.0.1-paid-max.jar
21dc427abd9e2d64
Compatibility and overhead, with the version numbers attached.
Most obfuscators promise the moon and ship a JAR that does not load. JavaObf is booted against real platforms on every release. Below: the exact versions we test on, and the actual overhead a protected build adds. No hand-waving, no synthetic benchmarks dressed up as production data.
Booted, not just compiled.
For each platform below we run the obfuscated plugin against a real server and confirm it loads, enables, and runs without errors. The exact tested versions are listed on every card.
Paper / Bukkit / Spigot
runtime golden- Tested build
- Paper 1.21.11-130
- Minecraft
- 1.21.11
- Java
- 21 (Temurin)
- Loader
- plugin.yml + paper-plugin.yml
Boot validation runs against this version on every Pro+ build. The cwelcomer reference plugin asserts plugin enable, command dispatch, listener registration, and license activation against a live Paper instance.
BungeeCord
runtime golden- Tested build
- BungeeCord 1.26.1-R0.1-SNAPSHOT
- Build number
- #2064
- Java
- 21 (Temurin)
- Loader
- bungee.yml
Listener annotation strip + companion EventExecutor regen verified booting against the real BungeeCord proxy. Zero VerifyError, zero NoSuchMethodException across 5 listener shapes.
Velocity
runtime golden- Tested build
- Velocity 3.4.0-SNAPSHOT
- Build hash
- git-b1dd26fb-b541
- Java
- 21 (Temurin)
- Loader
- velocity-plugin.json
Guice DI wiring preserved. @Subscribe consolidation routes through a synthetic companion class with @Subscribe-annotated dispatch slots. EventManager is a Velocity interface, so the engine emits INVOKEINTERFACE rather than INVOKEVIRTUAL.
Sponge
scanner golden- API target
- SpongeAPI 11+
- Java
- 21 / 25 supported
- Loader
- sponge_plugins.json
- Harness
- plugin-loader simulator
Real SpongeVanilla install needs Java 25 + FART + Mojang server jar (~500 MB), so CI runs a Sponge-shaped plugin loader that reaches the same enabled() semantics short of world generation. @Listener stripping + companion regen verified.
Forge
scanner golden- API
- net/minecraftforge/* (Forge 47+)
- Java
- 17 / 21
- Descriptor
- mods.toml
- Event bus
- IEventBus.register(Object)
2-arg IEventBus.register descriptor verified against the per-slot register stub emitter (not the legacy 3-arg shape that broke with VerifyError). @Mod entry resolution + @SubscribeEvent companion regen pass the static contract test.
NeoForge
scanner golden- API
- net/neoforged/* (NeoForge 21+)
- Java
- 21
- Descriptor
- neoforge.mods.toml
- Event bus
- IEventBus.register(Object)
NeoForge fork (2024) shares architecture with Forge. Same per-slot register-stub emitter. NeoForge descriptor is matched first (more specific) so a mod that ships both files routes correctly.
Fabric
scanner golden- API
- Fabric Loader 0.15+
- Java
- 21
- Descriptor
- fabric.mod.json
- Events
- functional Event<T>.register
Fabric has no annotation-driven event consolidation. ModInitializer.onInitialize is body-extracted; functional Event.register lambdas are captured and emitted as nested synthetic SAM classes.
Built for plugins that ship for money.
One protected JAR survives Paper boot, Velocity event subscribe, Bungee handler register, Fabric ModInitializer, Sponge listener scan, and the Forge / NeoForge mod bus, without you maintaining seven different build configurations. The engine reads the descriptor, picks the right consolidation pass, and emits bytecode that the loader you actually ship to recognizes.
Try it on your pluginOverhead, measured. Not promised.
Numbers below come from the cwelcomer reference plugin (a real licensing-gated Bukkit plugin used as our boot golden) on Paper 1.21.11-130, Java 21 Temurin, baseline OpenJDK G1GC defaults. Source: the same CI logs we ship with every release.
Plugin enable cost added by the full Citadel stack (native key derivation, anti-tamper interlocks, license client boot). Pro profile is closer to +4 ms. Within OS-scheduler noise on most runs.
Renames, string concealment, and control-flow flattening are static one-time transforms with zero hot-path cost. The native key stub is consulted at boot, not per tick. Selective virtualization only fires on methods you opt in.
Decoy classes, watermark metadata, and the fingerprinted runtime helper. Citadel adds the native key stub binaries (linux-x86_64, linux-aarch64, windows-x86_64) for an additional ~280 KB depending on platform set.
Includes analyze, transform, and validate against a live Paper boot. Citadel adds ~6 s for the native compile step (per platform target). Larger plugins scale linearly with class count.
The numbers above are not curated marketing. They are a checkbox in the build report.
Want to verify the numbers on your own plugin?
The free tier includes the build report. Run a Pro trial against your real JAR, read the receipts, then decide.