Shading & relocation
paper-dispatch is a library, not a plugin — it is not on the server, so it must be bundled into your jar. And it must be relocated while you do so.
Every plugin on a server shares one classloader hierarchy. Two plugins that
shade the same unrelocated fr.robie.paperdispatch package can pick up each
other's classes.
This library has a concrete reason beyond version skew: OfflinePlayerCache's
global instance is static, so without relocation which plugin owns it
becomes classloader-dependent — and the symptom appears in the other plugin,
looking like someone else's bug.
Relocate into a package you own, e.g. com.yourplugin.libs.paperdispatch.
- Maven
- Gradle (Kotlin)
- Gradle (Groovy)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<relocations>
<relocation>
<pattern>fr.robie.paperdispatch</pattern>
<shadedPattern>com.yourplugin.libs.paperdispatch</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
plugins {
id("com.gradleup.shadow") version "8.3.5"
}
tasks.shadowJar {
relocate("fr.robie.paperdispatch", "com.yourplugin.libs.paperdispatch")
}
tasks.build {
dependsOn(tasks.shadowJar)
}
plugins {
id 'com.gradleup.shadow' version '8.3.5'
}
shadowJar {
relocate 'fr.robie.paperdispatch', 'com.yourplugin.libs.paperdispatch'
}
build.dependsOn shadowJar
Check it worked
Unzip the built jar and look at the package layout:
unzip -l target/yourplugin.jar | grep paperdispatch
Every entry should sit under your relocated package. If you still see
fr/robie/paperdispatch/, relocation did not apply — usually because you are
shipping the plain jar output instead of the shaded one.
Do not shade the Paper API
Never shade paper-api. It is provided / compileOnly for a reason: the
server supplies it. Shading it produces a jar tens of megabytes large that
breaks in confusing ways.
minimize()
Shadow's minimize() strips unused classes and cuts jar size, but it can also
strip classes only reached by reflection. If something works in your IDE and
throws ClassNotFoundException from the built jar, try without it first.