OpenMU

This project aims to create an easy to use, extendable and customizable server for a MMORPG called "MU Online".

View on GitHub

Server-side AI Bots

Bots are persistent, autonomous characters which populate a server like real players: they hunt with the skills of their class, level up, spend their points, keep their buffs up, pick up and wear better gear, restock in town, group up, defend themselves, and come and go over the day. A player who meets one should not be able to tell it apart from a quiet human player.

They are driven entirely by the server. No game client is involved and no packets are exchanged: a bot is a connection-less OfflinePlayer — the same class which keeps a character playing after its owner logs out — with a navigator on top which gives it a life of its own.

The feature is disabled by default. Enabling it is always a deliberate act of the server admin.

How it works

Bots are ordinary accounts. Each one is a regular Account with the IsBot flag, holding up to five characters with generated names, levels, classes, stats, skills and starter gear. They are created once, saved like any other character, and reloaded on every start — a bot’s progress belongs to the server’s data, not to a process. Every bot animates one character in its own persistence context, so the characters of one account can play at the same time.

Two ticks make up the mind of a bot. The offline MU Helper AI runs twice a second and does what it does for a human’s offline session: attack, heal, buff, pick items up. On top of it, a bot navigator runs every second and decides the things an offline session never had to: where to hunt, when to travel or warp, when to go shopping, whom to follow. Everything a bot changes about itself — equipping, jewels, resets, master points — is queued into the AI tick, so it never runs while the combat handler is working on the same character.

Bots act through the regular player actions. Moving an item, talking to a merchant, consuming a jewel, entering an event: a bot goes through the same actions with the same validations a client’s packet would trigger. It cannot do anything a player could not do, and rule changes apply to bots for free.

The population is split over the game servers. Bots count towards the player count of their server exactly like players do, and a server which reached its maximum player count turns new clients away — so a population large enough to fill a server would lock the players out of it. Bot capacity % (60 by default) is the share of a server’s player limit its bots may occupy; the rest stays reserved for the players. Which accounts a server animates is a pure function of the account index and the set of configured game servers, so every server computes the same split without asking the others — which also holds when each game server runs as its own process. Exactly one server generates the population, so accounts and character names are never created twice. Accounts which do not fit stay offline until the deployment offers the room for them.

Configuration

The Bots feature plugin, in the “Feature Plugins” section of the admin panel:

What a bot does

Hunting and travelling

A bot hunts where the monsters actually are: it scans its surroundings for live monsters instead of walking to a spawn point which may be empty. Long distances are covered with a cached route over the whole map, walked a few steps at a time, so the bot can stop and fight on the way.

It only engages what it can survive. The decision is made against the monster’s real damage, defense and attack rate versus the bot’s own defense, health and chance to be hit — a monster’s nominal level says little about its punch on the high-end maps. An agility build’s dodge therefore counts as the defense it really is, and better gear opens tougher maps, exactly like for a player.

Map access follows the game’s warp list, and a bot travels on a player’s terms: it enters a map only if its level may legally warp there, it meets the map’s own requirements, and it pays the warp’s fare out of its own Zen. A bot which finds itself on a map it may not be on (after a reset, for instance) leaves for the best map it may use. The map it reached is persisted, so a restarted bot wakes up where it stopped.

Which map it goes to is drawn rather than maximized. The maps of a level band differ by a few monster levels, so always taking the strongest one made it every bot’s answer and left the rest of the band deserted. The best map still wins about a third of the picks and the runners-up split the rest, so the population spreads over the maps a player of that band would choose between. Every map in the draw is one the bot may legally reach, can afford, and which is better than where it stands - the draw only decides between improvements.

A map can pass every check and still pay nothing: the monsters the bot may fight are a rare kind among ones it must refuse, or other hunters empty the grounds first. The bot notices the way a player would, by having landed no hit in minutes, and steps down to easier ground one notch at a time until it finds something it can farm; the regular map choice carries it back up as its level and gear recover. A bot which cannot afford any trip at all walks home to its class town for free, so it is never stranded on ground it cannot earn on.

Fighting and progressing

A bot fights with the strongest skill of its class it has learned and can pay for; casters keep their distance and drink mana. Between skills worth about the same it takes the one with the longer reach - the flat bonus of a spell is a rounding error next to a high-level character’s own damage, while three tiles of range are three tiles at any level. Skills the game only activates during a castle siege are left out, and so are a pet’s skills unless the pet is actually equipped: Plasma Storm draws its damage from the Fenrir, but the attribute behind it is derived from the character’s own stats, so nothing but the pet slot tells a mounted character from one riding nothing. Skills are learned against the game’s own requirements — total energy, leadership, character level — at generation and again on every level-up, and the class buffs are kept up on their own.

A skill the character cannot currently cast is passed over, in the attack rotation and in the buffs alike. That is not the same as not having learned it: a reset keeps every skill but takes back the level which unlocked it, so a veteran back at level 12 still owns Swell Life, which asks for level 120. The game refuses such a cast silently, so a character which kept trying would simply stand there — buffing something that never takes effect, and never getting as far as attacking.

Level-up points follow a per-class build modelled on what players actually play: an agility/shield meta on reset servers, guide-style builds on classic ones, chosen automatically by whether the reset feature is configured. Classes with two viable archetypes (a warrior or a wizard Magic Gladiator, a pure or an energy Blade Knight) roll one per bot, and a stat which hits a server’s maximum overflows into the rest of the build.

Bots evolve like players do. The second-generation class change happens at level 200 — the same assignment the class-change quest performs — and the master class at the game’s maximum level, followed by a relog, because the master attributes only mount when a character enters the world. Master points go into the master skill tree through the regular action, with its rank gates and skill requirements, preferring passives which boost a stat and strengtheners of skills the bot actually uses; a bonus tied to a weapon type the bot does not fight with is never bought. On a server with the reset feature, a bot only masters once its reset limit is exhausted — while resets remain, resetting is what players do, so the bots do it too.

A mastered bot changes what it hunts. Master experience is only granted for monsters of at least Minimum monster level for master experience (95 in the default configuration), and a character at the maximum level earns nothing else — so below that line a kill pays a mastered bot nothing at all. It therefore looks for maps which hold such monsters, and takes the weakest ones above the line rather than the strongest: master experience hardly grows with the monster’s level, so the cheapest kill above it is the best one. Those monsters carry 40.000+ health, well beyond the hit budget a bot’s usual gear affords, so the budget is stretched for them — a slow fight it survives beats a quick one worth nothing. What is not stretched is its survivability: a monster whose hits the bot cannot take is refused, mastered or not.

Items and money

Dropped gear is judged before it is picked up: a bot collects what it can wear and what is worth money, and leaves the rest lying. An upgrade is put on through the regular move-item action, with the whole swap planned first — which slot, and which pieces have to come off, including the other hand for a two-handed weapon. If the engine refuses the equip after all, the old gear goes straight back on. The replaced piece stays in the backpack and is sold on the next trip to town, rather than being dropped where the next bot would pick it up again.

A merchant trip is the only moment a bot can turn loot into anything, so it goes whenever it has something to gain there: the backpack is filling with junk, the potions are running low, a jewel is waiting to be used, or a surplus is waiting to be sold. Restocking needs the means to pay for it, though - Zen, or loot to sell once it is there. A broke bot buys nothing, so the trip would leave it just as short as it set out, and it would set out again instead of hunting, which is the only way it could have earned the money. It picks the merchant which sells what it needs right now, and on a map whose merchants sell no potions while it needs some, it warps home to a real town instead. While the shop dialog visibly occupies it, the bot sells its junk, repairs its gear — which is what earns the NPC’s discount — and buys potions and, where a shop offers them, jewels.

Only Jewels of Bless, Soul and Life are collected, and only up to the configured stock: a bot cannot trade or craft, so any other kind would be a backpack slot it never gets back. They are spent on its own equipment through the regular consume action, with the same success rates and failure penalties a player faces, and with the caution a player shows: a Soul is only risked where a failure cannot destroy the item’s level.

A bot which reaches the server’s maximum inventory money can no longer sell anything — the money simply does not fit. What it cannot sell it keeps, and destroys only what has no other way out: jewels beyond its stock, and, while the backpack is genuinely full, junk gear. The repair bill is what normally keeps it away from that limit in the first place.

Wings do not drop, so bots earn them at the classic milestones instead — the first pair at level 180, the second at 280 and the third, master-only pair at

  1. Which class wears which pair comes from the item data, and the outgrown pair is destroyed rather than dropped.

Mini game events

A bot never enters Blood Castle, Devil Square or Chaos Castle on its own — it has no ticket and does not farm for one. It enters when a player who leads a party with bots enters with their own ticket: the leader’s entry legitimizes the visit for the whole group.

Each bot is checked against the entry restrictions a player faces (the level bracket, including the separate one for the special characters, the master-class requirement, the player-killer rule). A bot which does not qualify leaves the party and goes back to its own life instead of blocking the entry.

Inside, its open-world routine is suspended: no shopping, no map changes, no boredom, no grudges. It fights what the event throws at it and keeps up with the leader. Chaos Castle is a free-for-all, so there the other participants are targets like everyone else — and a fight inside leaves no grudge outside. A bot which dies respawns in the safezone like a player, which takes it out of the event; the survivors are warped out when the event ends.

Company and rhythm

Bots hunt in parties of two to five, grouped by level so the whole party can hunt the leader’s maps. The elf heals, the buffs are shared, the party experience bonus applies. Parties re-form every hour.

A player may invite a bot into their own party: it accepts after a human-like pause of a few seconds, as long as it is not in the middle of an errand. There is no level gate — just like OpenMU’s own party action, a bot accepts an inviter of any level, since it is the player who invites and the bot leaves once it gets bored. A living player takes precedence over the bot’s own company — a bot hunting with other bots leaves them for the inviter, and breaks that bot party up if it was leading it, so a player never has to guess which bot happens to be free. In a party the bot follows its leader, defers a due reset, and eventually leaves politely: when the leader enters a map it may not access, before its own logout, or simply when it gets bored.

A bot fights back when a player attacks it, but only as far as the game’s own PvP rules allow: inside the active self-defense window, or against a player already flagged as a killer. It can therefore never be provoked into becoming an outlaw that players could farm for free. It remembers who hit it, and a killed bot walks back to its killer — waiting for a legal opening rather than taking one.

Over the day, the presence rotation logs bots in and out: fewest in the early morning, most in the evening, and never more than one at a time, so the population ebbs and flows instead of appearing and vanishing in blocks.

Keeping itself alive

The engine’s attribute system is not thread-safe, and a lost race can corrupt a character’s attribute graph for good. A bot which hits it stops playing and throws on every following tick. Rather than leave it lying there, a bot counts the ticks which fail in a row and, after twenty of them, has itself restarted: a fresh login rebuilds the attribute graph and heals it — the same thing a player would do. A single failing tick is skipped, as before.

What it costs

Measured on a 12-core host, as a rough guide for capacity planning:

Population CPU Memory
250 bots ~0.35 core ~760 MB
1100 bots ~1.7 cores ~1.2 GiB

Generating a fresh population costs about a second per account (the password hash dominates); starting an existing one of 1100 bots takes some 15 seconds.

Known limitations

Enabling it on a server

  1. Enable the Bots plugin and set the number of accounts. Each account animates up to five characters, so 50 accounts × 5 = 250 bots.
  2. Check that the population fits. The bots of a game server may occupy Bot capacity % of its player limit — with the default of 60 %, a server for 1000 players hosts up to 600 bots. What does not fit stays offline, and the plugin says so in the log: raise the player limit, raise the share, or add a game server, over which the population then spreads by itself.
  3. Restart the server. The population is generated on the first start and reloaded afterwards.
  4. To build a fresh population, set Reset bots: it deletes the old one, generates a new one, and clears the flag again.
  5. To stop the bots without losing them, uncheck Enabled: they log out within a few seconds and nothing is deleted, so checking it again brings the same characters back. To get rid of them for good, set Purge bots — it deletes every bot account with its characters, items and storages, and leaves the feature switched off.