Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MinecraftPluginBlueprint

A clean, reusable Paper/Java plugin blueprint you can copy whenever you start a new Minecraft plugin.

This project is intentionally built as a strong base, not as a finished gameplay plugin. It gives you the structure most of your plugins will need: commands, permissions, config, messages, listeners, scheduled services, and simple YAML storage.


What this blueprint includes

  • Gradle Kotlin DSL project setup
  • Paper API dependency
  • Modern plugin.yml
  • Clean package structure
  • Main plugin lifecycle class
  • Reloadable config.yml
  • Reloadable messages.yml
  • MiniMessage support for nice gradients/colors
  • Main /blueprint command
  • Tab completion
  • Permissions
  • Listener example
  • Scheduled task/service example
  • Simple YAML storage helper
  • Utility class for text components
  • README instructions for renaming and extending the project

Project structure

MinecraftPluginBlueprint/
├── build.gradle.kts
├── settings.gradle.kts
├── README.md
├── LICENSE
├── .gitignore
├── .editorconfig
└── src/
    └── main/
        ├── java/
        │   └── me/subzerofrezer/blueprint/
        │       ├── BlueprintPlugin.java
        │       ├── Permissions.java
        │       ├── command/
        │       │   └── BlueprintCommand.java
        │       ├── config/
        │       │   ├── ConfigManager.java
        │       │   └── MessageService.java
        │       ├── listener/
        │       │   └── PlayerJoinListener.java
        │       ├── service/
        │       │   └── ExampleFeatureService.java
        │       ├── storage/
        │       │   └── YamlStorage.java
        │       └── util/
        │           └── Text.java
        └── resources/
            ├── plugin.yml
            ├── config.yml
            └── messages.yml

Requirements

This blueprint is configured for the current Paper API style shown in the Paper docs:

compileOnly("io.papermc.paper:paper-api:26.1.2.build.+")

and Java toolchain:

toolchain.languageVersion.set(JavaLanguageVersion.of(25))

If your Minecraft/Paper server is older, change both of these together.

Examples:

compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
toolchain.languageVersion.set(JavaLanguageVersion.of(21))

or for older Java 17 servers:

compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
toolchain.languageVersion.set(JavaLanguageVersion.of(17))

Always match your plugin API version to the server version you are actually running.


How to build

From the project folder:

./gradlew build

On Windows:

gradlew.bat build

If you do not have the Gradle wrapper yet, either import the project in IntelliJ and let it use Gradle, or run:

gradle wrapper

Then build again.

The compiled plugin JAR will be here:

build/libs/MinecraftPluginBlueprint-1.0.0.jar

Copy that JAR into your Paper server's plugins folder and restart the server.


Current commands

Command Permission Description
/blueprint help blueprint.use Shows the help menu
/blueprint version blueprint.use Shows the plugin version
/blueprint reload blueprint.reload Reloads config/messages/storage and restarts services

Alias:

/bp

Current permissions

Permission Default Description
blueprint.use true Allows basic command usage
blueprint.reload op Allows /blueprint reload
blueprint.admin op Parent admin permission

Config file

src/main/resources/config.yml

settings:
  debug: false
  example-feature-enabled: true
  example-broadcast-interval-seconds: 300

storage:
  type: YAML

Use ConfigManager to read values cleanly instead of calling getConfig() everywhere.

Example:

if (plugin.configManager().isExampleFeatureEnabled()) {
    // start your feature
}

Messages file

src/main/resources/messages.yml supports MiniMessage formatting.

Example:

prefix: "<gradient:#4FC3F7:#7E57C2><bold>Blueprint</bold></gradient> <dark_gray>»</dark_gray> "

messages:
  reload-success: "<green>Configuration and messages reloaded successfully."

Send a message like this:

messages.send(sender, "reload-success");

With placeholders:

messages.send(sender, "version", Map.of("version", plugin.getPluginMeta().getVersion()));

Message path:

messages.version

Placeholder format:

{version}

How to rename this into your own plugin

Suppose you want to create a plugin called FrostGems.

1. Rename the project

In settings.gradle.kts:

rootProject.name = "FrostGems"

In build.gradle.kts:

group = "me.subzerofrezer"
version = "1.0.0"

Change the JAR name:

jar {
    archiveBaseName.set("FrostGems")
}

2. Rename the package

Current package:

me.subzerofrezer.blueprint

Example new package:

me.subzerofrezer.frostgems

In IntelliJ, right-click the blueprint package and use:

Refactor > Rename

3. Rename the main class

Current:

BlueprintPlugin.java

Example:

FrostGemsPlugin.java

4. Update plugin.yml

name: FrostGems
main: me.subzerofrezer.frostgems.FrostGemsPlugin
api-version: '26.1.2'

5. Update command names

In plugin.yml:

commands:
  frostgems:
    description: Main command for FrostGems.
    usage: /frostgems <help|reload|version>
    aliases: [fgems]
    permission: frostgems.use

Then update your Java command registration:

PluginCommand command = getCommand("frostgems");

How to add a new command

For small plugins, you can add another case inside BlueprintCommand.

For bigger plugins, create a separate command class:

command/
├── BlueprintCommand.java
└── GemsCommand.java

Then register it inside BlueprintPlugin#registerCommands().

Example:

PluginCommand gemsCommand = getCommand("gems");
if (gemsCommand != null) {
    GemsCommand executor = new GemsCommand(this, messageService);
    gemsCommand.setExecutor(executor);
    gemsCommand.setTabCompleter(executor);
}

And add the command to plugin.yml.


How to add a new listener

Create a listener class:

public final class BlockBreakListener implements Listener {

    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        event.getPlayer().sendMessage("You broke a block!");
    }
}

Register it in BlueprintPlugin#registerListeners():

getServer().getPluginManager().registerEvents(new BlockBreakListener(), this);

How to add a new service

Services are good for systems that have their own logic, such as:

  • currency systems
  • minion systems
  • pet systems
  • crate systems
  • cooldown systems
  • shop systems
  • database sync systems
  • scheduled tasks

Example:

public final class GemsService {

    private final BlueprintPlugin plugin;

    public GemsService(BlueprintPlugin plugin) {
        this.plugin = plugin;
    }

    public void giveGems(UUID playerId, int amount) {
        // business logic here
    }
}

Create the service in your main plugin class and expose it with a getter.


How YAML storage works

The blueprint creates a data.yml file automatically.

Example write:

plugin.storage().data().set("players." + uuid + ".gems", 100);
plugin.storage().save();

Example read:

int gems = plugin.storage().data().getInt("players." + uuid + ".gems", 0);

This is fine for small plugins or prototypes.

For larger plugins, replace this with MySQL, MariaDB, PostgreSQL, SQLite, Redis, or MongoDB depending on the project.


Suggested architecture for your future plugins

For small plugins:

command/
listener/
config/
storage/
util/

For serious plugins:

api/
command/
config/
database/
dto/
event/
gui/
listener/
model/
repository/
service/
task/
util/

Example for a premium currency plugin:

frostpoints/
├── api/
│   └── FrostPointsApi.java
├── command/
│   └── PointsCommand.java
├── database/
│   └── MySqlConnectionProvider.java
├── gui/
│   └── PointsShopGui.java
├── listener/
│   └── PlayerJoinListener.java
├── model/
│   └── PlayerBalance.java
├── repository/
│   └── BalanceRepository.java
├── service/
│   └── PointsService.java
└── task/
    └── AutoSaveTask.java

Good development rules

  1. Keep your main plugin class small.
  2. Put business logic in services.
  3. Put config reading in config classes.
  4. Put database/storage logic in repositories or storage classes.
  5. Never do heavy database or web API work on the main server thread.
  6. Always validate command input.
  7. Always check permissions.
  8. Always cancel repeating tasks on disable.
  9. Keep messages in messages.yml, not hardcoded everywhere.
  10. Test one feature at a time before adding more.

Safe async rule

Most Bukkit/Paper API calls must run on the main server thread.

Safe async examples:

  • database queries
  • web API requests
  • file parsing
  • calculations

Unsafe async examples:

  • changing blocks
  • opening inventories
  • teleporting players
  • modifying entities
  • sending many direct Bukkit API calls

Pattern:

Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
    // slow database/web work here

    Bukkit.getScheduler().runTask(plugin, () -> {
        // Bukkit API work here
    });
});

Troubleshooting

org.bukkit.plugin.InvalidPluginException: Unsupported class file major version

Your plugin was compiled with a newer Java version than your server runs.

Fix:

  • Check your server Java version with java -version.
  • Lower options.release.set(...) and toolchain.languageVersion.set(...) if your Paper version supports it.
  • Or update the Java runtime used by your server.

Cannot execute command ... plugin is disabled

The plugin failed during startup.

Fix:

  • Check the first error in console, not only the command error.
  • Make sure plugin.yml has the correct main path.
  • Make sure your package/class names match exactly.
  • Make sure your dependency version matches your server version.

Command does nothing

Check:

  • Is the command inside plugin.yml?
  • Is it registered in registerCommands()?
  • Does the player have permission?
  • Did the plugin load green in /plugins?

Command 'blueprint' is missing from plugin.yml

Your command name in Java does not match the command name in plugin.yml.


Recommended next upgrades

Once the base is working, good upgrades are:

  • Add a proper subcommand framework
  • Add GUI base classes
  • Add cooldown manager
  • Add MySQL/SQLite repository layer
  • Add Vault economy hook
  • Add PlaceholderAPI expansion
  • Add LuckPerms integration
  • Add unit tests for pure Java service logic
  • Add GitHub Actions build workflow
  • Add release packaging

Useful commands while developing

Build:

./gradlew build

Clean build:

./gradlew clean build

Find output JAR:

build/libs/

License

MIT. You can copy, rename, modify, and use this as the base for your own private or public Minecraft plugins.

About

A clean, reusable Paper/Java plugin blueprint you can copy whenever you start a new Minecraft plugin.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages