Skip to content

Getting started

Prerequisites

  • Java 17 or newer
  • A Bukkit API on your compile classpath (Spigot or Paper) for your server version
  • Gradle (the examples use the Kotlin DSL)

Installation

weftkit is published to Maven Central. Add it to your plugin's Gradle build. The spigot-api dependency comes from the Spigot repository.

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

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

    implementation("org.weftkit:weftkit-bukkit:0.6.0")
    annotationProcessor("org.weftkit:weftkit-processor:0.6.0")
    annotationProcessor("org.weftkit:weftkit-bukkit-processor:0.6.0")
}

weftkit-bukkit brings the runtime and the wiring API. The processor path stays out of your jar: weftkit-processor validates the graph and generates the registry during compilation, and weftkit-bukkit-processor weaves in the bundled Bukkit modules and checks listeners and commands.

A minimal plugin

Three classes make a plugin that welcomes joining players. The plugin main carries @Registry, extends WeftPlugin, and contains no other code:

@Registry
public final class HelloPlugin extends WeftPlugin {

    @Override
    protected ComponentRegistry registry() {
        return WeftWiring.INSTANCE;
    }
}

A component holds the logic:

@Wired
@Singleton
final class Greeter {

    public String greet(Player player) {
        return "Welcome, " + player.getName();
    }
}

A listener uses it:

@Wired
@Singleton
final class JoinListener implements Listener {

    private final Greeter greeter;

    JoinListener(Greeter greeter) {
        this.greeter = greeter;
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        event.getPlayer().sendMessage(greeter.greet(event.getPlayer()));
    }
}

Build, drop the jar on a server, join, and the message appears. WeftPlugin loaded the graph, injected Greeter into JoinListener, registered the listener, and tears everything down on disable. Startup work goes into an onWeftEnable(WeftLoader) override when you need one.

Neither component class is public. weftkit wires package-private classes, so nothing goes public just to become injectable, see internal components.

WeftWiring is generated

WeftWiring is produced by the annotation processor during compilation, in your plugin main's package. It does not exist until you build once, so a fresh checkout shows it unresolved in the IDE until the first compile. Enable annotation processing in your IDE so it regenerates as you edit.

plugin.yml

weftkit does not change how Bukkit finds your plugin, so declare the main class as usual.

name: HelloPlugin
version: 1.0.0
main: com.example.hello.HelloPlugin
api-version: "1.20"

Build

./gradlew build

The processor validates the whole graph as it compiles, so a missing dependency, a cycle, or a malformed listener stops the build.

Next steps

  • The examples are complete runnable plugins, from the smallest wired listener to a module with feature flags, each documented class by class.
  • Components covers injection, singletons, products, and reaching your objects.
  • Lifecycle covers startup, shutdown, and load order.
  • Listeners and commands covers Bukkit event and command wiring.