Skip to content

Getting Started

frosxt edited this page Apr 14, 2026 · 1 revision

Getting started

This page walks through a minimal external module from an empty Gradle project to a jar the kernel will load. If you've already written one for PrisonCore, you can skip to the subsystem pages.

What a module is

A module is a jar that:

  1. Contains a bootstrap class annotated with @ModuleDefinition.
  2. Declares PrisonCore-Bootstrap: <fully.qualified.Bootstrap> in its manifest so the kernel can find the entry point without scanning every class.
  3. Lives under plugins/PrisonCore/modules/.

The kernel does not use Bukkit's plugin loader for modules. Modules are loaded by PrisonCore's own discoverer, into an isolated classloader, and driven through a lifecycle the platform controls.

Project layout

PrisonCore is published through JitPack. Add the JitPack repository, then declare a compileOnly dependency on each platform module you use. Replace <version> with a Git tag, branch name, or commit hash from the PrisonCore repository.

Gradle (Kotlin DSL)

plugins {
    java
    id("com.gradleup.shadow") version "8.3.6"
}

group = "com.example"
version = "1.0.0"

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
    maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
    maven("https://repo.papermc.io/repository/maven-public/")
    maven("https://jitpack.io")
}

dependencies {
    compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT")

    compileOnly("com.github.frosxt.Prisons:platform-api:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-spi:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-commons:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-command:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-menu:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-message:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-placeholder:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-scheduler:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-storage:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-kernel:<version>")
    compileOnly("com.github.frosxt.Prisons:platform-config:<version>")
}

tasks.shadowJar {
    archiveClassifier.set("")
    manifest {
        attributes["PrisonCore-Bootstrap"] = "com.example.hello.HelloBootstrap"
    }
}

Gradle (Groovy DSL)

repositories {
    mavenCentral()
    maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
    maven { url 'https://repo.papermc.io/repository/maven-public/' }
    maven { url 'https://jitpack.io' }
}

dependencies {
    compileOnly 'org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT'

    compileOnly 'com.github.frosxt.Prisons:platform-api:<version>'
    compileOnly 'com.github.frosxt.Prisons:platform-spi:<version>'
    compileOnly 'com.github.frosxt.Prisons:platform-commons:<version>'
    // ... and any other platform modules you use
}

Maven

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.github.frosxt.Prisons</groupId>
        <artifactId>platform-api</artifactId>
        <version>VERSION</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.github.frosxt.Prisons</groupId>
        <artifactId>platform-spi</artifactId>
        <version>VERSION</version>
        <scope>provided</scope>
    </dependency>
    <!-- ... and any other platform modules you use -->
</dependencies>

Notes

  • Always use compileOnly (Gradle) or <scope>provided</scope> (Maven). The platform jars are loaded at runtime by the kernel, so shading them into your jar would duplicate every class and break the isolated classloader.
  • Only pull in the subsystem jars you actually use. If your module never opens a menu, you don't need platform-menu.
  • For <version>, prefer a tagged release (for example 1.0.0).

The bootstrap class

package com.example.hello;

import com.github.frosxt.prisoncore.api.module.ModuleBootstrap;
import com.github.frosxt.prisoncore.api.module.ModuleContext;
import com.github.frosxt.prisoncore.api.module.PlatformModule;
import com.github.frosxt.prisoncore.api.module.annotation.ModuleDefinition;

@ModuleDefinition(
        id = "hello",
        name = "Hello",
        version = "1.0.0",
        apiVersion = "1.0"
)
public final class HelloBootstrap implements ModuleBootstrap {

    @Override
    public PlatformModule create(final ModuleContext context) {
        return new HelloModule();
    }
}

The @ModuleDefinition annotation is the only place module identity lives. You do not put this in a YAML file. The kernel reads these fields at discovery time to build a ModuleDescriptor, resolve dependencies, and order module loading.

Fields on the annotation:

  • id — globally unique module id. Lowercase, hyphen-separated by convention.
  • name — human-readable name shown in logs and admin commands.
  • version — your module's version string.
  • apiVersion — the PrisonCore API version you built against. Defaults to 1.0.
  • loadPhasePRE_INFRASTRUCTURE, POST_INFRASTRUCTURE (the default), or LATE. See Module Lifecycle.
  • requiredDependencies — ids of other modules that must be present. Fails startup if missing.
  • optionalDependencies — ids of other modules loaded before this one if they exist.
  • providesCapabilities — capability names this module publishes for others to consume.
  • requiresCapabilities — capability names this module needs. Fails startup if unsatisfied.

The module class

package com.example.hello;

import com.github.frosxt.prisoncore.api.module.ModuleContext;
import com.github.frosxt.prisoncore.api.module.support.AbstractPlatformModule;

public final class HelloModule extends AbstractPlatformModule {

    @Override
    protected void onPrepare(final ModuleContext context) {
        context.logger().info("Hello module preparing.");
    }

    @Override
    protected void onEnable(final ModuleContext context) {
        context.logger().info("Hello module enabled.");
    }

    @Override
    protected void onDisable(final ModuleContext context) {
        context.logger().info("Hello module disabled.");
    }
}

Three hooks and that's it. The ModuleContext gives you a logger scoped to your module, the service container, a capability registry, and your data folder under plugins/PrisonCore/modules/<id>/. You resolve everything else through the service container.

Building and installing

Gradle:

./gradlew shadowJar

The shaded jar lands in build/libs/.

Maven:

mvn clean package

The jar lands in target/. If you're using Maven you need the Shade plugin configured to produce a shaded jar and to write the PrisonCore-Bootstrap manifest attribute through <archive><manifestEntries>.

Drop the resulting jar into plugins/PrisonCore/modules/ and restart the server. You should see your module in the startup log.

If the kernel can't find your bootstrap class, double-check the PrisonCore-Bootstrap manifest attribute. If the module loads but nothing happens, make sure you didn't silently catch an exception in onPrepare.

Next steps

Clone this wiki locally