B
BlackSpigot Guides
Guest
What you will build
A small Java plugin with one command, a permission and a configurable greeting. This exercise deliberately targets Spigot API 1.21.1 and Java 21; match the API and Java requirements to your actual server before adapting it. It is a complete starter project, not a downloadable third-party plugin.
1. Create the project
Install a JDK 21 and Maven, then check
Put this in
2. Describe the plugin
Save this as
See the plugin.yml reference for metadata and permission defaults.
3. Implement the command
Put the following in
The default configuration is copied on first enable; an existing administrator-edited configuration is preserved. Returning false for extra arguments asks Bukkit to show the usage from plugin.yml. Console senders work too because this command does not cast the sender to Player. Read Spigot’s command tutorial for the handler contract.
4. Build and verify
Run
Test with a non-operator account as well. This example intentionally grants workshop.hello to everyone; set default to op in plugin.yml if that is your intended policy. Test an explicit denial using your permission manager when adapting this for restricted actions.
When it fails
Unknown command: inspect startup logs and confirm the JAR contains plugin.yml at its root. Invalid main class: compare package, filename and main exactly. Unsupported class version: check the Java actually starting the server. Do not copy the Spigot API JAR into plugins. Make one change at a time and use a clean restart of the development server.
Validation: example Java compiled against the stated Spigot API. Server behavior is a verification procedure for you to run; no in-game execution is claimed.
A small Java plugin with one command, a permission and a configurable greeting. This exercise deliberately targets Spigot API 1.21.1 and Java 21; match the API and Java requirements to your actual server before adapting it. It is a complete starter project, not a downloadable third-party plugin.
1. Create the project
Install a JDK 21 and Maven, then check
java -version and mvn -version in the same terminal. Maven must report the intended JDK. Create this layout; names and capitalization matter:
Code:
pom.xml
src/main/java/com/example/workshop/WorkshopPlugin.java
src/main/resources/plugin.yml
src/main/resources/config.yml
pom.xml. The provided scope keeps the server API out of your plugin JAR; the running server supplies it.
XML:
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId><artifactId>workshop-hello</artifactId><version>1.0.0</version>
<properties><maven.compiler.release>21</maven.compiler.release><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
<repositories><repository><id>spigot</id><url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</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></dependencies>
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.13.0</version></plugin></plugins></build>
</project>
2. Describe the plugin
Save this as
src/main/resources/plugin.yml. The main value is the full Java class name, not the file path. Declaring the command allows the server to route it to JavaPlugin's command handler.
YAML:
name: WorkshopHello
version: 1.0.0
main: com.example.workshop.WorkshopPlugin
api-version: '1.21'
commands:
workshop:
description: Show the workshop greeting
usage: /workshop
permission: workshop.hello
permissions:
workshop.hello:
description: Use the workshop command
default: true
3. Implement the command
Java:
package com.example.workshop;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
public final class WorkshopPlugin extends JavaPlugin {
@Override public void onEnable() { saveDefaultConfig(); }
@Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length != 0) return false;
sender.sendMessage(getConfig().getString("message", "Welcome, {player}!")
.replace("{player}", sender.getName()));
return true;
}
}
src/main/resources/config.yml:
YAML:
message: 'Welcome, {player}! Build something small today.'
4. Build and verify
Run
mvn clean package beside pom.xml. Stop a development server, put target/workshop-hello-1.0.0.jar in its plugins folder, then start it. Use /workshop: your player name should replace the placeholder. Run workshop in the console and /workshop extra in game; the latter should show usage. Edit plugins/WorkshopHello/config.yml while stopped, restart, and confirm the new message.Test with a non-operator account as well. This example intentionally grants workshop.hello to everyone; set default to op in plugin.yml if that is your intended policy. Test an explicit denial using your permission manager when adapting this for restricted actions.
When it fails
Unknown command: inspect startup logs and confirm the JAR contains plugin.yml at its root. Invalid main class: compare package, filename and main exactly. Unsupported class version: check the Java actually starting the server. Do not copy the Spigot API JAR into plugins. Make one change at a time and use a clean restart of the development server.
Validation: example Java compiled against the stated Spigot API. Server behavior is a verification procedure for you to run; no in-game execution is claimed.
