Skip to content

Core Services

DarkBladeDev edited this page May 10, 2026 · 4 revisions

Core Services (Registration and Consumption)

This page documents how to register and consume core services (and public services) from MultiBlockEngine addons.

The services API is centered around the AddonContext.java contract and relies on the engine’s internal service registry and, optionally, on Bukkit’s services manager for public exposure.

Quick map

  • Consume core services: context.getService(Service.class).
  • Register a service for other addons to consume: context.registerService(Service.class, impl).
  • Expose a service as a Bukkit Service (visible outside the MBE ecosystem): context.exposeService(Service.class, impl, priority).
  • Key rule: the service type (the interface) must exist in the engine API.
flowchart TD
  A[Addon onLoad/onEnable] --> B{"context.getService(X)"}
  B -->|provider ENABLED| C[X available]
  B -->|provider NOT ENABLED or not registered| D[null]
  A --> E{"context.registerService(X, impl)"}
  E -->|already registered by another addon| F[IllegalStateException]
  A --> G{"context.exposeService(X, impl)"}
  G -->|exposure happens at end of onEnable| H[Bukkit Services]
  G -->|fails| I[Addon fails in ENABLE]
Loading

1) Registration process

1.1 Prerequisites and dependencies

Requirement: the service type must live in the api module

MultiBlockEngine validates that the service type belongs to the engine's API.

Practical implication:

  • You can register/consume only interfaces that are in the engine API.
  • If you need a “new service” between addons, that interface must be added to the api module and published with the engine.

Typical addon dependencies

  • compileOnly for Paper (for the Bukkit/Paper API).
  • compileOnly for the engine’s api dependency via JitPack.

1.2 Register a new service (engine internal registry)

Use: when you want other addons (loaded by MBE) to resolve your implementation via getService.

API:

  • context.registerService(Class<T> serviceType, T service)

Rules:

  • A serviceType can have only one provider.
  • If another addon already registered that type, IllegalStateException is thrown.

Example:

import dev.darkblade.mbe.api.addon.AddonContext;
import dev.darkblade.mbe.api.addon.AddonException;
import dev.darkblade.mbe.api.addon.MultiblockAddon;

public final class MyAddon implements MultiblockAddon {
    @Override
    public void onLoad(AddonContext context) throws AddonException {
        // ... registration logic
    }
}

1.3 Expose a service as a “public service” (Bukkit Services)

Use: when you want external plugins (not necessarily addons) to consume it via Bukkit.getServicesManager().

API:

  • context.exposeService(Class<T> api, T implementation, ServicePriority priority)

Important details:

  • Exposure happens after your onEnable() finishes, during the engine enable process.
  • If exposure fails, the addon is marked as failed in ENABLE.

Example:

import dev.darkblade.mbe.api.addon.AddonContext;
import dev.darkblade.mbe.api.addon.AddonException;
import dev.darkblade.mbe.api.addon.MultiblockAddon;
import org.bukkit.plugin.ServicePriority;

public final class MyAddon implements MultiblockAddon {
    @Override
    public void onLoad(AddonContext context) throws AddonException {
        context.exposeService(MyCoreApiService.class, new MyCoreApiServiceImpl(context), ServicePriority.High);
    }
}

2) Service consumption

2.1 Available methods

a) Resolve from the addon context

API:

  • <T> T context.getService(Class<T> serviceType)

Return:

  • T if it exists and the provider is ENABLED.
  • null if it does not exist or is blocked by state.

b) Resolve “public” services from Bukkit

If an addon exposes a service, another plugin (or addon) can use Bukkit.getServicesManager() like any other Bukkit service.

2.2 Required and optional parameters

getService

  • Required: serviceType.

exposeService

  • Required: api (service type), implementation.
  • Optional: priority (defaults to ServicePriority.Normal).

2.3 Error handling and exceptions

Common errors

  • IllegalArgumentException when registering/resolving a service type that does not belong to the API.
  • IllegalStateException when registering a type already registered by another provider.
  • null when consuming services whose provider is not yet ENABLED.

Recommended consumption pattern

import dev.darkblade.mbe.api.addon.AddonContext;
import dev.darkblade.mbe.api.addon.AddonException;
import dev.darkblade.mbe.api.addon.MultiblockAddon;
import dev.darkblade.mbe.api.i18n.I18nService;

public final class MyAddon implements MultiblockAddon {
    @Override
    public void onEnable() throws AddonException {
        // ...
    }

    public void doSomething(AddonContext context) {
        I18nService i18n = context.getService(I18nService.class);
        if (i18n == null) {
            context.getLogger().warn("I18nService not available");
            return;
        }

        // use i18n...
    }
}

2.4 Best practices and recommendations

  • Resolve services in onEnable() if they depend on other addons; onLoad() is valid for core services.
  • Treat getService(...) as nullable; avoid assuming availability.
  • Do not register services with types outside the engine API.
  • Avoid coupling to engine-internal classes (package dev.darkblade.mbe.core.*).

3) Built-in core services

These services are registered by the plugin at startup (before loading addons).

3.1 Complete list (Highlights)

  1. MultiblockRuntimeService
  2. EnergyService
  3. NetworkService
  4. PanelViewService
  5. HologramService
  6. PersistenceService
  7. I18nService

Refer to the Service Registry for the full technical list.

Clone this wiki locally