In-server Java API · 2.0.0

Control every bot. Extend every fight.

The compile-only Paper API for creating and managing bots, observing their full lifecycle and building custom combat modes or complete AI implementations inside the server.

BotPlugin.java
UltimateBotAPI api = UltimateBotAPI.get();

BotOperationResult result = api
    .getBotManager()
    .spawn(request);

if (!result.success()) {
    getLogger().warning(result.message());
}
01Paper 1.21.4+
02Java 21+
03compileOnly integration
04Bukkit-backed EventBus

Choose the right integration

A direct contract with the running server.

Use the API when your code is a Paper plugin loaded on the same server as UltimateBot. Calls are direct, Bukkit entities and ItemStacks are available, and events use the normal server event pipeline.

01 / Manage

Create and control bots

Spawn all supported bot types, query immutable snapshots and update combat, equipment, targets, modes or ownership at runtime.

IBotManager reference
02 / Observe

React to typed events

Use standard Bukkit listeners or functional subscriptions. Both receive the same cancellable event objects and metadata.

BotEventBus reference
03 / Extend

Provide modes and full AI

Register a complete mode, per-bot stateful combat sessions or a brain that replaces UltimateBot’s built-in decision tick.

Extension guide

API or SDK?

The API is the recommended dependency for Paper plugins and must be compileOnly. Use the SDK only for remote Java applications communicating through HTTP and Server-Sent Events.

Installation

Add the API without bundling it.

UltimateBot supplies the implementation at runtime. Your plugin compiles against the public artifact and declares UltimateBot as a server dependency.

build.gradle.kts
repositories {
    maven("https://repo.monkeymoon104.it/releases")
    maven("https://repo.papermc.io/repository/maven-public/")
}

dependencies {
    compileOnly("com.monkey.ultimatebot:api:2.0.0")
    compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
}
plugin.yml
name: MyUltimateBotIntegration
version: 1.0.0
main: com.example.MyPlugin
api-version: '1.21'
depend: [UltimateBot]
Runtime access

One stable entry point

UltimateBotAPI.get() returns the registered API or fails fast when called too early. Use isAvailable() or listen for UltimateBotReadyEvent when UltimateBot is optional.

UltimateBotAPI Javadocs

Never shade API or common into your jar

Bundling public UltimateBot classes creates duplicate class identities and breaks provider casting. Keep the dependency compile-only; UltimateBot provides both API and shared models on the server.

Bot construction

Validated settings from identity to combat.

BotSettings uses a staged builder: required values are supplied in a safe order, invalid combinations fail immediately, and optional runtime behavior remains fluent after the required profile is complete.

Complete single-bot spawn
BotSettings settings = BotSettings.builder()
    .setBotName("Trainer-%owner%")
    .setBotSkinOwner()
    .follow(true)
    .setChangeableFollow(true)
    .combat(true)
    .setChangeableCombat(true)
    .blastProtection(false, false, false, false)
    .setChangeableBlast(true)
    .armorValue(BotArmorTier.LEATHER, BotArmorTier.NETHERITE)
    .armor(BotArmorTier.NETHERITE)
    .setChangeableArmor(true)
    .totemValue(-1, 20)
    .totemCount(5)
    .setChangeableTotem(true)
    .difficultyValue(DifficultyTier.EASY, DifficultyTier.GOD)
    .difficulty(DifficultyTier.MEDIUM)
    .setChangeableDifficulty(true)
    .targetMode(BotTargetMode.PLAYERS)
    .combatMode(CombatMode.SWORD)
    .autoTarget(true)
    .autoTargetRange(24.0D)
    .healing(true)
    .build();

BotSpawnRequest request = BotSpawnRequest.builder(BotMode.SINGLE)
    .owner(player.getUniqueId())
    .settings(settings)
    .build();

BotOperationResult result = UltimateBotAPI.get()
    .getBotManager()
    .spawn(request);
SINGLE

Player opponent

Requires an owner. The owner is automatically used as the target.

EVENT

Independent bot

Supports explicit target sets and server-controlled event scenarios.

ALLY

Player ally

Requires an owner and follows the configured ally behavior.

TEAM_ALLY

Shared team ally

Uses a primary owner or a set of team-owner UUIDs.

Everything available in a bot profile

  • Name templates and random, owner, player, texture or URL skins
  • Fixed or changeable follow, combat, armor, blast protection, totems and difficulty
  • Built-in or namespaced combat modes and optional custom brain assignment
  • Player, mob or combined targeting with automatic range selection
  • Custom UUID, spawn location, explicit targets and team owners
  • Healing, explosions, terrain damage, Crystal PvP and Ender Pearls
  • Idle wandering, return distance, delay and owner-death persistence
  • Armor, trims, inventory contents and persistent empty/custom equipment slots
  • Kill-message control, WorldGuard PvP respect and bot-vs-bot attacks
  • Per-bot combat tuning overrides with server-profile reset support
Specific UUID and empty equipment slots
BotSpawnRequest request = BotSpawnRequest.builder(BotMode.ALLY)
    .botUUID(UUID.fromString("5fbf64f4-c012-4f04-9cb6-f27f68f3bb80"))
    .owner(player.getUniqueId())
    .emptyEquipmentSlot(BotEquipmentSlot.MAIN_HAND)
    .emptyEquipmentSlot(BotEquipmentSlot.OFF_HAND)
    .equipmentItem(BotEquipmentSlot.HEAD, customHelmet)
    .settings(settings)
    .build();

Runtime management

Owner UUID or bot UUID. Your choice.

Mutation lives in IBotManager; monitoring lives in the read-only IBotRegistry. Snapshots are immutable views and do not expose internal bot state.

Mutation

IBotManager

Spawn, update, resolve player references, remove bots and enumerate available combat modes or registered brains.

Complete method reference
Inspection

IBotRegistry

Read snapshots by owner or bot UUID, translate identities and inspect all currently active bots.

Complete method reference
Operation familyAvailable controls
Identity and lifecycleGet by owner/bot UUID, count, remove one, remove all or remove only bots from a specific BotSource.
Core behaviorFollow, combat, difficulty, armor, totems, healing, target mode, target sets, team owners and auto-target range.
Combat platformChange combat mode or brain, override/reset tuning, toggle Crystal PvP, explosions, terrain damage, Ender Pearls and bot-vs-bot combat.
EquipmentReplace armor or inventory maps, update individual inventory indexes, or persist DEFAULT, EMPTY and ITEM policies per equipment slot.
World behaviorWorldGuard PvP respect, idle wandering, return timing, owner-death persistence, spawn location and kill messages.
Runtime updates and snapshots
IBotManager bots = UltimateBotAPI.get().getBotManager();

bots.updateCombatModeByBotUUID(botUuid, CombatMode.MACE);
bots.updateDifficultyByBotUUID(botUuid, DifficultyTier.HARD);
bots.updateTargetModeByBotUUID(botUuid, BotTargetMode.PLAYERS_AND_MOBS);

BotSnapshot snapshot = bots.getBotByBotUUID(botUuid)
    .orElseThrow(() -> new IllegalStateException("Bot is no longer active"));

getLogger().info(snapshot.botNameTemplate() + " uses " + snapshot.combatMode());

Typed EventBus

One event, two listening styles.

Every API event is a Bukkit event. Use familiar @EventHandler methods or retain a closeable functional subscription from BotEventBus.

Standard listener
@EventHandler(ignoreCancelled = true)
public void onBotAttack(BotAttackEvent event) {
    if (event.getAttackType() == BotAttackType.MELEE) {
        rewardCombo(event.getOwnerUUID(), event.getBotUUID());
    }
}
Lifecycle

Ready, spawn and removal

Ready, spawn preparation/completion, despawn preparation/completion, death and explicit despawn reasons.

Combat

Attacks and outcomes

Attack, damage, player/entity kills, explosions, explosion type and terrain policy, plus totem usage.

Action

Healing and teleport

Observe or control individual bot actions before their runtime effect is committed.

State

Target and settings

Track target transitions and every supported runtime setting mutation through structured keys.

Addon

Extension lifecycle

Observe hosted addon discovery, loading, enablement, failure and shutdown states.

Metadata

Trace every event

Event ID, timestamp, source, owner UUID, bot UUID, per-bot sequence and immutable snapshot travel together.

Cancellable means pre-action

Cancelling a supported event prevents the underlying action. Mutable properties such as explosion block damage change only that part of the operation; cancelling an explosion event cancels the complete explosion.

Combat extension platform

Custom mode, custom brain—or both.

Paper plugins and hosted addon jars use the same provider contracts. Registrations are namespaced, owner-scoped and removable without touching UltimateBot internals.

CombatModeProvider

Build a complete game mode

Supply GUI metadata, permission, ordering, capabilities, kit, every difficulty profile and an optional stateful runtime session per bot.

Mode provider contract
BotBrainProvider

Replace the complete AI tick

Own targeting reactions, movement, rotation, attacks and inventory decisions while UltimateBot retains entity lifecycle and cleanup.

Brain provider contract
Register from a Paper plugin
public final class CombatExtensionPlugin extends JavaPlugin {
    private final List<ExtensionRegistration> registrations = new ArrayList<>();

    @Override
    public void onEnable() {
        UltimateBotExtensionRegistry extensions = UltimateBotAPI.get().getExtensions();
        registrations.add(extensions.registerBrain(this, new AdaptiveBrainProvider()));
        registrations.add(extensions.registerCombatMode(this, new AdaptiveModeProvider()));
    }

    @Override
    public void onDisable() {
        registrations.reversed().forEach(ExtensionRegistration::close);
        registrations.clear();
    }
}
Stateful full-control brain
public final class AdaptiveBrainProvider implements BotBrainProvider {
    private static final BrainKey KEY = BrainKey.of("myplugin", "adaptive-melee");

    @Override
    public BrainDescriptor descriptor() {
        return new BrainDescriptor(
            KEY,
            "Adaptive Melee",
            "Reads distance and controls the full combat tick",
            Set.of(BrainCapability.FULL_CONTROL),
            false);
    }

    @Override
    public BotBrainSession create(BotBrainContext context) {
        return tick -> tick.selectedTarget().ifPresent(target -> {
            context.control().lookAt(target);
            context.control().moveTowards(target, 2.7D);
            if (context.bot().getLocation().distanceSquared(target.getLocation()) <= 9.0D) {
                context.control().attack(target);
            }
        });
    }
}
Runtime surfaceContract
BotControlLook, move, strafe, jump, stop, attack, swing, use items and manipulate bot equipment through controlled operations.
BrainTickCurrent tick, selected target and state supplied to one isolated brain session.
BrainDamage / TargetChangeTyped signals delivered to the session without requiring global listener maps.
CombatModeRuntimePer-bot mode context for kit-aware, stateful mode behavior with enter, tick, suspend, resume, exit and close lifecycle.
NativeBotAccessAn intentionally unstable, typed escape hatch for exact-version NMS bot, level and target handles.

NMS is optional and version-specific

Most custom AI should use BotControl. If direct NMS is unavoidable, compile one implementation per supported Minecraft version and load it only through a matching native.<version> addon entrypoint.

Hosted addon engine

One jar, discovered automatically.

Developers who do not need a separate Paper plugin can ship an UltimateBot addon directly into plugins/UltimateBot/addon/. The engine validates, orders and isolates every addon at startup.

Discover

Validated descriptor

Unique IDs, API version, required and soft dependencies, entrypoints and optional native mappings are checked before code loads.

Isolate

Dedicated ClassLoader

Bundled UltimateBot classes are rejected, dependency cycles fail clearly and only the matching native entrypoint is selected.

Release

Owned lifecycle

Registrations, listeners, Paper/Folia tasks, closeable resources, bot sessions and ClassLoaders are released in safe reverse order.

META-INF/ultimatebot-addon.properties
id=adaptive-combat
name=Adaptive Combat
version=1.0.0
api-version=2
main=com.example.adaptive.AdaptiveAddon
authors=DeveloperName
dependencies=
soft-dependencies=
native.1.21.11=com.example.adaptive.nms.v1_21_11.NativeAddon
Hosted addon entrypoint
public final class AdaptiveAddon implements UltimateBotAddon {
    @Override
    public void onLoad(AddonContext context) {
        context.registerBrain(new AdaptiveBrainProvider());
        context.registerCombatMode(new AdaptiveModeProvider());

        context.resources().runAsyncTask(() -> loadReadOnlyModel(context.dataDirectory()));
    }
}
  • No manual API jar is installed on the server.
  • API and common remain compile-only and are never shaded.
  • Private third-party libraries may be relocated inside the addon jar.
  • Replacing addon jars through server reload is intentionally unsupported; restart after changes.
  • One addon jar may contain separate NMS implementations for every version it supports.

Runtime contracts

Predictable ownership, nullability and cleanup.

The public surface is designed for fail-fast integration. Read the annotations and lifecycle contracts rather than retaining mutable Bukkit state indefinitely.

Null safety

JSpecify contracts

Nullable parameters and returns are explicit. Required public inputs reject null immediately with descriptive failures.

Threading

Respect Bukkit ownership

Call entity/world operations from the correct Paper or Folia context. Hosted addons should schedule through their scoped resource API.

Resources

Close what you retain

Functional event subscriptions and direct extension registrations are AutoCloseable. Close them when the owning plugin disables.

State

Prefer snapshots

Registry and operation results expose immutable data. Resolve the bot again instead of retaining internal entity assumptions across despawn.

Built-in failure isolation

Custom brain and mode sessions are isolated per bot. Repeated provider failures close the faulty session and return the bot to a safe built-in fallback instead of continuously crashing the entity tick.

Generated from source

Complete API reference.

Search every public API type generated for version 2.0.0. Select a result to open its constructors, methods, parameters, return values, exceptions and nullability contract.

Loading public types…

Loading the generated Javadoc index…