Getting started

  1. Set keystone-parent as your parent and name a relocation package

    <parent>
        <groupId>dev.bwmp</groupId>
        <artifactId>keystone-parent</artifactId>
        <version>1.1.0</version>
    </parent>
    
    <properties>
        <keystone.libs.package>dev.bwmp.yourplugin.libs</keystone.libs.package>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>dev.bwmp</groupId>
            <artifactId>keystone-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.spigotmc</groupId>
            <artifactId>spigot-api</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    Shading and relocation are then automatic.

  2. Add the Nexus repository to your settings.xml

    Maven resolves a parent before it reads the project's own <repositories>, so the repository has to come from ~/.m2/settings.xml:

    <profiles>
      <profile>
        <id>bwmp-nexus</id>
        <repositories>
          <repository>
            <id>bwmp-nexus</id>
            <url>https://nexus.bwmp.dev/repository/maven-public/</url>
          </repository>
        </repositories>
      </profile>
    </profiles>
    <activeProfiles><activeProfile>bwmp-nexus</activeProfile></activeProfiles>

    Building Keystone from source and mvn install-ing it locally also works, and is the way to test an unreleased change.

  3. Bootstrap the handle

    public final class YourPlugin extends JavaPlugin {
        private KeystoneHandle keystone;
    
        @Override public void onEnable()  { keystone = Keystone.bootstrap(this); }
        @Override public void onDisable() { if (keystone != null) keystone.shutdown(); }
    }

    Everything else hangs off keystone. Most subsystems are created on first use; the GUI protection listener is created at bootstrap so menus are safe even if a consumer forgets to request the service first.

  4. If you target Folia, say so

    # plugin.yml
    folia-supported: true

    Without it Folia will not load your plugin at all, no matter how correct your scheduling is.

The relocation package must be unique

The convention is your plugin's own package plus .libs, so dev.bwmp.sigil.libs or dev.bwmp.holopanels.libs. That is unique by construction as long as your plugin's package is.

What you get for it

One jar. No second plugin for a server owner to install, no version of the framework to keep in step with the version of your plugin, and no possibility of another plugin's copy of the framework being loaded instead of yours.

The cost is jar size and the relocation rule in publishing an API, which is the one thing that catches people out.

Verify the packaged jar

Run your normal Maven build, inspect the final plugin jar, and confirm Keystone classes live under your keystone.libs.package rather than dev/bwmp/keystone. Start a test server once and check the bootstrap log reports Keystone 1.1.0 without the unrelocated developer warning. This validates the artifact users will install, not only the IDE classpath.