Create and control bots
Spawn all supported bot types, query immutable snapshots and update combat, equipment, targets, modes or ownership at runtime.
IBotManager referenceIn-server Java API · 2.0.0
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.
UltimateBotAPI api = UltimateBotAPI.get();
BotOperationResult result = api
.getBotManager()
.spawn(request);
if (!result.success()) {
getLogger().warning(result.message());
}
Choose the right integration
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.
Spawn all supported bot types, query immutable snapshots and update combat, equipment, targets, modes or ownership at runtime.
IBotManager referenceUse standard Bukkit listeners or functional subscriptions. Both receive the same cancellable event objects and metadata.
BotEventBus referenceRegister a complete mode, per-bot stateful combat sessions or a brain that replaces UltimateBot’s built-in decision tick.
Extension guideThe 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
UltimateBot supplies the implementation at runtime. Your plugin compiles against the public artifact and declares UltimateBot as a server dependency.
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")
}
<dependency>
<groupId>com.monkey.ultimatebot</groupId>
<artifactId>api</artifactId>
<version>2.0.0</version>
<scope>provided</scope>
</dependency>
name: MyUltimateBotIntegration
version: 1.0.0
main: com.example.MyPlugin
api-version: '1.21'
depend: [UltimateBot]
UltimateBotAPI.get() returns the registered API or fails fast when called too early. Use isAvailable() or listen for UltimateBotReadyEvent when UltimateBot is optional.
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
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.
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);
Requires an owner. The owner is automatically used as the target.
Supports explicit target sets and server-controlled event scenarios.
Requires an owner and follows the configured ally behavior.
Uses a primary owner or a set of team-owner UUIDs.
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
Mutation lives in IBotManager; monitoring lives in the read-only IBotRegistry. Snapshots are immutable views and do not expose internal bot state.
Spawn, update, resolve player references, remove bots and enumerate available combat modes or registered brains.
Complete method referenceRead snapshots by owner or bot UUID, translate identities and inspect all currently active bots.
Complete method reference| Operation family | Available controls |
|---|---|
| Identity and lifecycle | Get by owner/bot UUID, count, remove one, remove all or remove only bots from a specific BotSource. |
| Core behavior | Follow, combat, difficulty, armor, totems, healing, target mode, target sets, team owners and auto-target range. |
| Combat platform | Change combat mode or brain, override/reset tuning, toggle Crystal PvP, explosions, terrain damage, Ender Pearls and bot-vs-bot combat. |
| Equipment | Replace armor or inventory maps, update individual inventory indexes, or persist DEFAULT, EMPTY and ITEM policies per equipment slot. |
| World behavior | WorldGuard PvP respect, idle wandering, return timing, owner-death persistence, spawn location and kill messages. |
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
Every API event is a Bukkit event. Use familiar @EventHandler methods or retain a closeable functional subscription from BotEventBus.
@EventHandler(ignoreCancelled = true)
public void onBotAttack(BotAttackEvent event) {
if (event.getAttackType() == BotAttackType.MELEE) {
rewardCombo(event.getOwnerUUID(), event.getBotUUID());
}
}
BotEventSubscription attacks = UltimateBotAPI.get()
.getEventBus()
.subscribeForOwner(
this,
ownerUuid,
BotAttackEvent.class,
event -> rewardCombo(event.getOwnerUUID(), event.getBotUUID()));
// Retain the handle and call attacks.close() during shutdown.
Ready, spawn preparation/completion, despawn preparation/completion, death and explicit despawn reasons.
Attack, damage, player/entity kills, explosions, explosion type and terrain policy, plus totem usage.
Observe or control individual bot actions before their runtime effect is committed.
Track target transitions and every supported runtime setting mutation through structured keys.
Observe hosted addon discovery, loading, enablement, failure and shutdown states.
Event ID, timestamp, source, owner UUID, bot UUID, per-bot sequence and immutable snapshot travel together.
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
Paper plugins and hosted addon jars use the same provider contracts. Registrations are namespaced, owner-scoped and removable without touching UltimateBot internals.
Supply GUI metadata, permission, ordering, capabilities, kit, every difficulty profile and an optional stateful runtime session per bot.
Mode provider contractOwn targeting reactions, movement, rotation, attacks and inventory decisions while UltimateBot retains entity lifecycle and cleanup.
Brain provider contractpublic 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();
}
}
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 surface | Contract |
|---|---|
| BotControl | Look, move, strafe, jump, stop, attack, swing, use items and manipulate bot equipment through controlled operations. |
| BrainTick | Current tick, selected target and state supplied to one isolated brain session. |
| BrainDamage / TargetChange | Typed signals delivered to the session without requiring global listener maps. |
| CombatModeRuntime | Per-bot mode context for kit-aware, stateful mode behavior with enter, tick, suspend, resume, exit and close lifecycle. |
| NativeBotAccess | An intentionally unstable, typed escape hatch for exact-version NMS bot, level and target handles. |
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
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.
Unique IDs, API version, required and soft dependencies, entrypoints and optional native mappings are checked before code loads.
Bundled UltimateBot classes are rejected, dependency cycles fail clearly and only the matching native entrypoint is selected.
Registrations, listeners, Paper/Folia tasks, closeable resources, bot sessions and ClassLoaders are released in safe reverse order.
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
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()));
}
}
Runtime contracts
The public surface is designed for fail-fast integration. Read the annotations and lifecycle contracts rather than retaining mutable Bukkit state indefinitely.
Nullable parameters and returns are explicit. Required public inputs reject null immediately with descriptive failures.
Call entity/world operations from the correct Paper or Folia context. Hosted addons should schedule through their scoped resource API.
Functional event subscriptions and direct extension registrations are AutoCloseable. Close them when the owning plugin disables.
Registry and operation results expose immutable data. Resolve the bot again instead of retaining internal entity assumptions across despawn.
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
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.