Skip to content

Implementation Guide

DarkBladeDev edited this page Dec 27, 2025 · 1 revision

Step-by-step implementation guide

1) Initial environment setup

  1. Create a Java project (Gradle recommended).
  2. Copy the MultiBlockEngine JAR into your addon project (for example libs/MultiBlockEngine.jar).
  3. Compile with Java 21.

Minimal build.gradle example:

plugins {
  id 'java'
}

repositories {
  mavenCentral()
  maven { url = 'https://repo.papermc.io/repository/maven-public/' }
}

dependencies {
  compileOnly "io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT"
  compileOnly files('libs/MultiBlockEngine.jar')
}

java {
  toolchain { languageVersion = JavaLanguageVersion.of(21) }
}

2) Create the base files

addon.properties (required)

It must be located at src/main/resources/addon.properties and packaged inside the JAR:

id=energy
version=1.0.0
main=com.tuorg.energy.EnergyAddon
api=1
depends=
  • id: unique ID.
  • main: class implementing MultiblockAddon.
  • api: must match MultiBlockEngine.getApiVersion().
  • depends: optional, comma/space-separated list (machines,networks).

3) Implement MultiblockAddon

Contract: MultiblockAddon.java

Example (with commented code):

package com.tuorg.energy;

import com.darkbladedev.engine.api.addon.AddonContext;
import com.darkbladedev.engine.api.addon.AddonException;
import com.darkbladedev.engine.api.addon.MultiblockAddon;

public final class EnergyAddon implements MultiblockAddon {

    private AddonContext context;

    @Override
    public String getId() {
        return "energy";
    }

    @Override
    public String getVersion() {
        return "1.0.0";
    }

    @Override
    public void onLoad(AddonContext ctx) throws AddonException {
        // Called during the engine LOAD phase.
        // Ideal for registering actions/conditions/matchers and preparing code-defined multiblocks.
        this.context = ctx;

        if (ctx.getApiVersion() != 1) {
            throw new AddonException(getId(), "Incompatible API", true, AddonException.Phase.LOAD, "apiVersion");
        }

        // Register a namespaced action
        ctx.registerAction("energy:energy_transfer", map -> new EnergyTransferAction(map));

        // Register a namespaced condition
        ctx.registerCondition("energy:energy_greater_than", map -> new EnergyGreaterThanCondition(map));

        // Matchers: prefix must be EXACTLY the addonId
        ctx.registerMatcher("energy", token -> new EnergyWireMatcher(token));
    }

    @Override
    public void onEnable() throws AddonException {
        // Called after the engine loaded YAML and restored instances.
        // Recommended: register listeners and/or define multiblocks by code.
        context.registerListener(new EnergyListener());

        // Create and register a code-defined multiblock
        var type = context
            .createMultiblock("cell") // creates energy:cell
            .version("1.0")
            .controller(new EnergyControllerMatcher())
            .pattern(new org.bukkit.util.Vector(0, 1, 0), new EnergyCasingMatcher())
            .variable("energy", 0)
            .build();

        context.registerMultiblock(type);
    }

    @Override
    public void onDisable() {
        // Addon cleanup.
        // If you started your own async tasks, cancel them here.
    }
}

4) Integrating with the engine API

The addon should only use AddonContext:

  • actions/conditions/matchers registration
  • multiblock creation and registration
  • controlled scheduler (runTask, runTaskAsync)
  • prefixed logger

Do not access engine internals directly.

5) Handling dependencies between addons

addon.properties supports depends.

  • If an addon depends on another one, the engine will try to enable it afterward.
  • If a dependency is missing or failed, your addon will be marked as FAILED and will not be enabled.

Clone this wiki locally