Using ProGuard to protect Minecraft server plugins

Since I’ve personally been using ProGuard to shrink and protect Bukkit/Spigot plugins for Minecraft servers, I figured sharing the information here can’t hurt.

First of all, you need to integrate ProGuard in your build process. If you have not done so already, I would highly recommend using Gradle for your builds as it can easily download the required dependencies for you. In the past I used Maven for building and got dependencies from Maven repositories, but Gradle can also download dependencies from those same Maven repositories and is more flexible.

I won’t include all the details on how to set up Gradle based builds (might be for another post if there is interest) but I do have a few tips:

  • Use the resource processing task to automatically replace your plugin version in plugin.yml
processResources {
    outputs.upToDateWhen { false }
    filesMatching('**/plugin.yml') {
        filter {
            it.replace('@version@', project.version.toString())
        }
    }
}
  • If you have a public API that you are keeping (more on this later) create a task that can export a library jar that can be used by other plugin devs.
task apiJar(type: Jar, dependsOn: compileJava) {
    from (sourceSets.main.output) {
        include 'my/package/api**'
    }
    includeEmptyDirs = false
    baseName = 'APIJAR'
}

Now for the ProGuard part, this is a partial config with the most essential rules:

# Keep your main class
-keep public class my.package.MainPluginClass {
    public void onEnable();
	public void onDisable();
}

# Keep the public API
-keep class my.package.api.** { *; }
-keepclassmembers class my.package.api.**

# Keep event handlers
-keep,allowobfuscation class * extends org.bukkit.event.Listener {
    @org.bukkit.event.EventHandler <methods>;
}

# If your goal is obfuscating and making things harder to read, repackage your classes with this rule
-repackageclasses 'my.package'

# Some attributes that you'll need to keep (to be honest I'm not sure which ones really need to be kept here, but this is what works for me)
-keepattributes !LocalVariableTable,!LocalVariableTypeTable,Exceptions,InnerClasses,Signature,Deprecated,LineNumberTable,*Annotation*,EnclosingMethod

With this information and some help from the ProGuard manual regarding the Gradle setup, you should be able to process your plugin!

3 Likes

Mojang themselves use ProGuard to optimize their Minecraft JARs. The maps are also made available so I assume they rely on it mostly for file size reduction and optimization. Do you also notice the impact on size/performace when processing your own Bukkit plugins?

They have been for quite a while, but the modding community didn’t like the terms that came with them, so they were actually not being used. Those terms were recently changed, in the hopes that modders will start to use the official mappings.
I assume that indeed Mojang uses it mostly for file size & performance at this point.

As for my own plugins: I don’t have any exact numbers, but it did make a big size difference, especially when shading large external dependencies. I have not noticed a big performance improvement, since most logic in plugins is pretty simple to begin with. Also, if you’re wanting to protect your code from copying, it does make things less readable…