New: see how many SpigotMC page viewers end up running your plugin →

Installation

The SDK is one Java class with no dependencies. You shade it into your plugin's jar and move it into your own package.

Coordinates

Repositoryhttps://pluginanalytics.dev/maven
Groupcom.gamepathics
Artifactpluginanalytics-bukkit
Version1.2.0
Package to relocatecom.gamepathics.pluginanalytics

The artifact also publishes sources and javadoc jars, so your IDE shows the documentation of every method.

Gradle (Kotlin DSL)

// build.gradle.kts
plugins {
    java
    id("com.gradleup.shadow") version "8.3.9"
}

repositories {
    mavenCentral()
    maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
    maven("https://pluginanalytics.dev/maven")
}

dependencies {
    compileOnly("org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT")
    implementation("com.gamepathics:pluginanalytics-bukkit:1.2.0")
}

tasks.shadowJar {
    archiveClassifier.set("")
    relocate("com.gamepathics.pluginanalytics", "me.you.arenaplus.libs.analytics")
}

tasks.build {
    dependsOn(tasks.shadowJar)
}

Gradle (Groovy DSL)

// build.gradle
plugins {
    id 'java'
    id 'com.gradleup.shadow' version '8.3.9'
}

repositories {
    mavenCentral()
    maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
    maven { url = 'https://pluginanalytics.dev/maven' }
}

dependencies {
    compileOnly 'org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT'
    implementation 'com.gamepathics:pluginanalytics-bukkit:1.2.0'
}

shadowJar {
    archiveClassifier.set('')
    relocate 'com.gamepathics.pluginanalytics', 'me.you.arenaplus.libs.analytics'
}

build.dependsOn shadowJar

Build with ./gradlew build (or shadowJar) and put the jar from build/libs on your server. The plain jar task doesn't include the SDK.

Maven

A complete pom.xml: the repository, the dependency, and maven-shade-plugin with the relocation.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>me.you</groupId>
  <artifactId>arenaplus</artifactId>
  <version>1.4.0</version>
  <packaging>jar</packaging>

  <properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <repositories>
    <repository>
      <id>spigotmc-repo</id>
      <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
    </repository>
    <repository>
      <id>pluginanalytics</id>
      <url>https://pluginanalytics.dev/maven</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>org.spigotmc</groupId>
      <artifactId>spigot-api</artifactId>
      <version>1.21.1-R0.1-SNAPSHOT</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.gamepathics</groupId>
      <artifactId>pluginanalytics-bukkit</artifactId>
      <version>1.2.0</version>
      <!-- compile scope (the default): it goes inside your jar -->
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.6.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <createDependencyReducedPom>false</createDependencyReducedPom>
              <relocations>
                <relocation>
                  <pattern>com.gamepathics.pluginanalytics</pattern>
                  <shadedPattern>me.you.arenaplus.libs.analytics</shadedPattern>
                </relocation>
              </relocations>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Build with mvn package. The jar in target/ contains your plugin and the relocated SDK.

Why relocation is required

Many plugins on one server can use PluginAnalytics, each with its own copy, possibly of different versions. Bukkit lets plugins see each other's classes, so two jars that both contain com.gamepathics.pluginanalytics.PluginAnalytics could end up sharing one copy: the wrong version, or another plugin's settings. Moving the SDK into your own package makes your copy yours alone.

The SDK checks this when it starts: it compares the package of its own class with the original one (built at runtime, so the shading tool can't rewrite the comparison). If it wasn't relocated, it turns itself off and your plugin keeps working:

[ArenaPlus] PluginAnalytics is disabled: relocate com.gamepathics.pluginanalytics into your plugin's package.

To check a build, list the jar: you should see the class under your package and nothing under com/gamepathics.

unzip -l build/libs/ArenaPlus.jar | grep PluginAnalytics
#   me/you/arenaplus/libs/analytics/PluginAnalytics.class
#   me/you/arenaplus/libs/analytics/PluginAnalytics$Span.class
#   ...

Relocating into a sub-package of your plugin (like me.you.arenaplus.libs.analytics) is the convention. The performance sampler leaves the SDK's own classes out either way.

Java and server versions

  • The SDK is compiled for Java 8 against the Bukkit 1.8.8 API, so it runs inside plugins built for any Java version from 8 up, on 1.8 through the latest releases.
  • It runs on Bukkit, Spigot, Paper, Purpur and Folia, and reports which one each server uses.
  • It has no dependencies. On servers that use log4j (Spigot and Paper), it reads errors from log4j too, through reflection.

plugin.yml and paper-plugin.yml

  • Nothing to add: there's no PluginAnalytics plugin to depend on. The SDK lives in your jar.
  • Commands are counted and timed automatically when they're declared in plugin.yml and run through your executor. Commands you register another way (for example through Paper's Brigadier lifecycle API in a paper-plugin.yml plugin) aren't wrapped: track them yourself.
  • Your depend and softdepend lists are read to report which of those plugins each server has installed.
  • The version in your plugin.yml is the version shown everywhere in the dashboard and compared for update notices, so keep it in a numeric form like 1.4.0.

Folia

The SDK detects Folia and skips everything that needs a single main thread. On Folia:

WorksDoesn't run
Servers, players, versions, retention · track events and properties · player first joins and funnels · config usage · errors and logs · spans (time) · update notices and feedback Main-thread sampling · automatic timing of event handlers and commands · automatic command events (they come from the same command wrapper) · server tick time (MSPT)

Declare folia-supported: true in your plugin.yml as usual if your plugin supports Folia; the SDK doesn't need anything else. Property suppliers run on the SDK's own thread, so on Folia only read values that don't belong to a region.