Quickstart¶
The recommended path is bootstrap-first: use the platform bootstrap helper when it exists, keep the returned runtime handle, and close it when the platform shuts down.
If most of your logic lives directly in magicutils-core, keep the platform
entrypoint thin and move the shared services behind MagicRuntime.
That does not mean common should call forPlugin(...) or forMod(...).
Those bootstrap helpers stay in the platform module, which then hands the
runtime into shared code.
Bukkit/Paper¶
public final class MyPlugin extends JavaPlugin {
private BukkitBootstrap.RuntimeResult magic;
@Override
public void onEnable() {
magic = BukkitBootstrap.forPlugin(this)
.enableCommands()
.configureCommands(registry -> registry.registerCommand(new ExampleCommand()))
.buildRuntime();
magic.logger().info("Ready.");
}
@Override
public void onDisable() {
if (magic != null) {
magic.runtime().close();
magic = null;
}
}
}
BukkitBootstrap wires Platform, ConfigManager, Logger,
LanguageManager, Messages, and an optional CommandRegistry.
Fabric¶
public final class MyMod implements ModInitializer {
private static final String MOD_ID = "mymod";
private MinecraftServer server;
private FabricBootstrap.RuntimeResult magic;
@Override
public void onInitialize() {
magic = FabricBootstrap.forMod(MOD_ID, () -> server)
.enableCommands()
.buildRuntime();
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
if (magic.commandRegistry() != null) {
magic.commandRegistry().registerCommand(dispatcher, new ExampleCommand());
}
});
ServerLifecycleEvents.SERVER_STARTED.register(server -> this.server = server);
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
this.server = null;
if (magic != null) {
magic.runtime().close();
magic = null;
}
});
}
}
FabricBootstrap sets up the shared services early, while actual command
registration still happens inside Fabric's Brigadier callback.
Velocity¶
@Plugin(id = "myplugin", name = "MyPlugin", version = "1.0.0")
public final class MyPlugin {
private final ProxyServer proxy;
private final org.slf4j.Logger slf4j;
private final Path dataDirectory;
private VelocityBootstrap.RuntimeResult magic;
@Inject
public MyPlugin(ProxyServer proxy,
org.slf4j.Logger slf4j,
@DataDirectory Path dataDirectory) {
this.proxy = proxy;
this.slf4j = slf4j;
this.dataDirectory = dataDirectory;
}
@Subscribe
public void onProxyInitialize(ProxyInitializeEvent event) {
magic = VelocityBootstrap.forPlugin(proxy, this, "MyPlugin", dataDirectory)
.slf4j(slf4j)
.enableCommands()
.configureCommands(registry -> registry.registerCommand(new ExampleCommand()))
.buildRuntime();
magic.logger().info("Ready.");
}
@Subscribe
public void onProxyShutdown(ProxyShutdownEvent event) {
if (magic != null) {
magic.runtime().close();
magic = null;
}
}
}
VelocityBootstrap creates a managed LoggerCore, registers shutdown cleanup,
and can wire the Velocity command registry for you.
NeoForge¶
NeoForge currently uses the manual wiring path.
public final class MyMod {
private static final String MOD_ID = "mymod";
private final Platform platform;
private final ConfigManager configManager;
private final LoggerCore logger;
private final CommandRegistry commands;
public MyMod() {
platform = new NeoForgePlatformProvider();
configManager = new ConfigManager(platform);
logger = new LoggerCore(platform, configManager, this, "MyMod");
commands = CommandRegistry.create(MOD_ID, MOD_ID, logger);
logger.info("Ready.");
}
@SubscribeEvent
public void onRegisterCommands(RegisterCommandsEvent event) {
commands.registerCommand(event.getDispatcher(), new ExampleCommand());
}
}
Using The Runtime Handle¶
Every buildRuntime() call returns MagicRuntime, which exposes the shared
services as typed components:
MagicRuntime runtime = magic.runtime();
ConfigManager configManager = runtime.requireComponent(ConfigManager.class);
LoggerCore logger = runtime.requireComponent(LoggerCore.class);
LanguageManager languages = runtime.findComponent(LanguageManager.class).orElse(null);
Use named resources and config bindings when you want runtime-managed clients or other reloadable services.
Core / Common Logic¶
If your plugin or mod is mostly shared logic plus a thin platform bootstrap,
keep the common layer built around MagicRuntime and platform-agnostic
services.
See Core / Common Logic for the recommended split between platform glue and shared code.
Next Steps¶
- Pick the modules you need from the Modules section.
- Use the platform pages for more detailed bootstrap notes.
- Use the Core / Common Logic page for shared/common module structure.
- Read the Runtime guide for
MagicRuntime, managed resources, and config bindings. - Use the Migration guide if you are moving from older manual wiring examples.
- See the HTTP client page for
MagicRuntime-bound profiles.