MetaCore
A shared Trigger Engine platform for Paper plugins — MetaCore provides the Trigger Engine, its Paper integration layer, and a Kotlin DSL as a centralized library that other plugins (MetaJobs and your own) can depend on without bundling duplicate engine code.
Overview
MetaCore is a utility library plugin that hosts a single, shared instance of the Trigger Engine on your Paper/Folia server. Instead of every plugin embedding its own copy of the engine — wasting memory, duplicating configuration logic, and complicating cross-plugin triggers — plugins register their trigger configurations as modules against MetaCore's shared engine.
Think of it as "Trigger Engine as a Service" for your server.
Why MetaCore?
| Problem | MetaCore Solution |
|---|---|
| Multiple plugins each bundle the Trigger Engine → memory bloat, version conflicts | Single shared engine instance loaded once |
| Plugins can't easily reference each other's triggers | Cross-module trigger references via shared TriggerHolder IDs |
| Each plugin reimplements Paper integrations (parsers, elements, properties) | Registered once at startup by MetaCore |
| Configuration reload requires plugin restart | Hot-reload individual modules via /metacore reload <module> |
| Kotlin DSL setup is boilerplate-heavy | LoadScope DSL + PaperTriggers.load { } helpers that work on the shared engine |
Features
- Shared Trigger Engine — One
DefaultTriggerEngineinstance, one event bridge, one placeholder registry - Paper Integration Layer — All Paper-specific parsers, elements, properties, lookups, and trigger types registered once
- External Item Support — Built-in providers for ItemsAdder, Oraxen, Nexo, CraftEngine (auto-detected)
- PlaceholderAPI Integration — Optional, auto-enabled when PlaceholderAPI is present
- Persistent Placeholder Storage — SQLite (default) or MySQL with async flush
- Kotlin DSL —
LoadScopeDSL +PaperTriggers.load { }/yaml()helpers inio.github.neoramm.triggerengine.kotlin.paper, usable on the shared engine - Brigadier Commands — Modern command API with tab completion for module management
- Folia Compatible — Region-aware, thread-safe engine operation
- Hot Module Reload — Reload a single plugin's triggers without touching others
Installation
For Server Administrators
- Download the latest
MetaCore-<version>.jar - Place in
plugins/ - Start the server — MetaCore creates
plugins/MetaCore/config.yml - Configure storage (optional): SQLite (default) or MySQL
- Install dependent plugins (MetaJobs, MetaEnchants, or your own)
For Plugin Developers (Gradle)
// build.gradle.kts of your plugin
dependencies {
compileOnly("io.papermc.paper:paper-api:26.2.build.+")
compileOnly(files("libs/MetaCore.jar"))
}
paper-plugin.yml (Dependent Plugin)
name: YourPlugin
version: 1.0.0
main: com.your.YourPlugin
api-version: '26.2'
depend: [MetaCore] # Hard dependency — MetaCore loads first
# Or soft dependency:
# load: BEFORE
# required: false
Quick Start (Plugin Developer)
1. Access the Shared Engine
import io.github.neoramm.metacore.MetaCore;
import io.github.neoramm.triggerengine.paper.PaperTriggers;
public class YourPlugin extends JavaPlugin {
private PaperTriggers triggers;
@Override
public void onEnable() {
// Get the shared engine (initialized by MetaCore)
triggers = MetaCore.triggers();
// Register your plugin as a module for reload support
MetaCore.registerModule("yourplugin", session -> {
loadTriggers(session);
});
}
private void loadTriggers(LoadSession session) {
// Load YAML, Kotlin DSL, or programmatic triggers
ConfigNode root = triggers.read(dataFolder.toPath().resolve("triggers.yml"), session);
if (root != null) {
session.add(root.get("triggers"), root.get("placeholders"), TriggerHolder.of("yourplugin", "1.0"));
}
}
}
2. Using the Kotlin DSL on the shared engine (Recommended)
The Kotlin DSL does not create an engine. It provides LoadScope builders
(paper.load { }, yaml()) that run on any PaperTriggers — including the
global instance started by MetaCore:
// In your plugin's Kotlin code
import io.github.neoramm.metacore.MetaCore
import io.github.neoramm.triggerengine.kotlin.holder
import io.github.neoramm.triggerengine.kotlin.paper.load
import io.github.neoramm.triggerengine.kotlin.paper.yaml
class YourPlugin : JavaPlugin() {
override fun onEnable() {
// Shared singleton, already initialized + started by MetaCore.
// Paper elements/parsers/properties were registered once by MetaCore.
val paper = MetaCore.triggers()
val holder = holder("yourplugin")
fun loadAll() = paper.load {
yaml(dataFolder.toPath().resolve("triggers.yml"), holder)
// or programmatic triggers in the same session:
// add(holder, "in-code") { trigger("welcome") { on("player-join") /* ... */ } }
}
loadAll()
// Reuse the same loader for hot-reload (same pattern as MetaJobs).
// The LoadSession passed by MetaCore is unused here because
// paper.load{} manages its own session internally.
MetaCore.registerModule("yourplugin") { loadAll() }
}
}
Do not call
Plugin.triggerEngine()here — that helper creates a new, standalone engine (see below), not the shared one.
3. Shared vs. standalone engine
| Mode | How | Who owns lifecycle | When to use |
|---|---|---|---|
| Shared (default with MetaCore) | MetaCore.triggers() |
MetaCore (createShared() + start() / shutdown() once) |
MetaJobs, MetaEnchants, any plugin with depend: [MetaCore]. Enables cross-module run_trigger and /metacore reload <module>. |
| Standalone (opt-in, no MetaCore) | Plugin.triggerEngine() (kotlin-dsl) or PaperTriggers.create(plugin, ...) (paper module) |
Your plugin (start() / shutdown() yourself, own EventBridge) |
You explicitly don't want the shared instance: isolated tests, separate server, forked behavior. Full Paper defaults (properties, parsers, elements, types) are registered on the new engine. |
Creating your own engine while also depending on MetaCore is allowed but discouraged: you pay for two engines, two event bridges, and triggers on the private engine are invisible to other modules.
// Standalone only — no MetaCore dependency:
val isolated: PaperTriggers = triggerEngine {
// optional DefaultTriggerEngine.Builder customization
}
isolated.start()
// ... isolated.load { ... } ...
// onDisable: isolated.shutdown()
4. Hot Reload Support
Players/ops can reload just your plugin's triggers:
/metacore reload yourplugin
Or programmatically:
MetaCore.reloadModule("yourplugin");
Configuration (config.yml)
storage:
# sqlite -> file inside plugins/MetaCore (zero setup)
# mysql -> external database for multi-server sync
type: sqlite
sqlite:
file: data.db
mysql:
host: localhost
port: 3306
database: minecraft
user: root
password: ""
properties:
useSSL: false
characterEncoding: utf8
# Flush interval in seconds (min 5). Also saves on shutdown/player quit.
flush-seconds: 30
Commands
| Command | Permission | Description |
|---|---|---|
/metacore |
metacore.base |
Show version and loaded modules |
/metacore modules |
metacore.base |
List registered module IDs |
/metacore reload |
metacore.admin |
Reload all modules |
/metacore reload <module> |
metacore.admin |
Reload a specific module |
Tab completion works for module names in
/metacore reload <module>.
API Reference
MetaCore (Main Entry Point)
| Method | Description |
|---|---|
static PaperTriggers triggers() |
Get the shared PaperTriggers instance |
static CompositeExternalItemRegistry externalItems() |
Access the combined external item registry |
static ModuleHandle registerModule(String id, ModuleInitializer init) |
Register a module for hot-reload |
static ModuleHandle getModule(String id) |
Retrieve a module handle |
static Set<String> getModuleIds() |
List all registered module IDs |
static void reloadModule(String id) |
Hot-reload a single module |
static void reloadAllModules() |
Reload all modules |
static void unregisterModule(String id) |
Unregister a module (on plugin disable) |
ModuleInitializer (Functional Interface)
@FunctionalInterface
public interface ModuleInitializer {
void accept(LoadSession session);
}
Receives a fresh LoadSession — add your triggers, placeholders, and configs here.
PaperTriggers (Engine Access)
Key methods you'll use:
// Engine & registries
DefaultTriggerEngine engine();
PaperKeys keys();
PaperTriggerTypes types();
CompositeExternalItemRegistry externalItemRegistry();
// Loading
LoadSession engine().beginLoad();
ConfigNode read(Path file, LoadSession session);
CompileResult loadFile(Path file, String section, TriggerHolder holder);
CompileResult report(CompileResult result); // Logs diagnostics
// Lifecycle
void start(); // Owner calls once: MetaCore for the shared instance,
// your plugin for a standalone PaperTriggers.create() engine
void shutdown(); // Same owner rule as start()
External Item Providers
MetaCore auto-registers providers for these plugins (if present):
| Provider | Items | Requires |
|---|---|---|
| ItemsAdder | itemsadder: namespace |
ItemsAdder |
| Nexo | nexo: namespace |
Nexo |
| CraftEngine | craftengine: namespace |
CraftEngine |
Use in triggers like any vanilla item:
# triggers.yml
triggers:
give_custom_sword:
type: player-join
actions:
- give_item:
item: "itemsadder:my_custom_sword"
amount: 1
Cross-Module Triggers
Since all modules share one engine, triggers can reference each other:
# MetaJobs triggers.yml
triggers:
miner_level_up:
type: job-level-up
conditions:
- job_id: "miner"
actions:
- run_trigger: "namespace:apply_mining_bonus" # References other plugin trigger
# Other plugin triggers.yml
triggers:
apply_mining_bonus:
type: manual # Only run via run_trigger
actions:
- add-enchantment:
enchantment: "fortune"
level: 1
Compatibility
| Platform | Version |
|---|---|
| Paper | 26.2+ (API 26.2+) |
| Folia | Supported (region-aware) |
| Java | 25+ |
| Trigger Engine | Bundled (core/paper modules) |
License
MIT License — Free for any use, including commercial servers and plugins.
Links
- Trigger Engine Docs: trigger-engine-docs
- Discord: discord.gg/sapphire
For Plugin Authors: Publishing Your Plugin
When publishing a plugin that depends on MetaCore:
-
Declare dependency in
paper-plugin.yml:depend: [MetaCore] # Or soft dependency: # load: BEFORE # required: false -
Document requirement in your plugin's README:
Requires MetaCore (provides shared Trigger Engine). Download from releases.
-
Use
MetaCore.registerModule()so server admins can hot-reload your triggers via/metacore reload yourplugin. -
Don't shade Trigger Engine classes — use
compileOnly/providedscope. -
Don't call
Plugin.triggerEngine()when you target the shared engine — useMetaCore.triggers()+paper.load { }. ReservePlugin.triggerEngine()/PaperTriggers.create()for the opt-in standalone mode with no MetaCore dependency.
No gallery available for this project.
| Version | Minecraft | Loader | Download |
|---|---|---|---|
|
MetaCore 1.0.0 1.0.0 |
26.2, 26.3
|
folia, paper
|
Download |