Files
AdamuSw/docs/Bots.md
nolt ebf6958068 bots: accept party invitations regardless of level gap
The reset-aware level gate in BotPartyHandler rejected nearly every party
invitation on servers with resets, because it folded reset count into the level
scale (one reset ~= 400 points against a 500 cap). A veteran player inviting a
freshly generated bot was always over the limit, so the invitation was silently
declined. Remove the gate so a bot accepts any inviter who is alive and in the
world, matching OpenMU's own party action; the situational safeguards (shopping,
revenge, mini game, pending invite, human companion) stay in place.
2026-08-13 08:45:29 +03:00

328 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:
- **`Enabled`** — spawns the bots after the server has started. Off by default.
- **`Number of accounts`** — how many bot accounts to maintain.
- **`Characters per account`** — how many characters each account animates at
once (at most five).
- **`Bot capacity %`** — the share of a game server's maximum player count its
bots may occupy; the rest is reserved for the players.
- **`Presence rotation`** — bots log in and out over the day instead of all
being online around the clock.
- **`Min. online share %`** — how much of the population stays online at the
quietest hour.
- **`Bots pay reset costs`** — whether bots pay the configured zen and item
costs for their resets. Off by default: they take no part in the economy those
costs are balanced for.
- **`Jewel stock per kind`** — how many Jewels of Bless, Soul and Life a bot
keeps of each kind. Above it, it stops picking them up and sells what it
already carries. Depends on the server's drop rates: on high rates a small
stock keeps the backpack free, on low rates a larger one is never reached
anyway.
- **`Potion stock charges`** — how many charges of healing and of mana potions a
bot restocks to at a merchant. Depends on what the shops sell: a server whose
potions come in stacks of 255 fills the target in a single purchase.
- **`Reset bots`** — deletes the whole population and generates it again, then
clears itself. With the number of accounts set to zero it deletes without
generating anything.
- **`Purge bots`** — deletes the whole population WITHOUT generating a new one,
and switches the feature off. It works with the feature enabled or disabled;
the switch-off is what makes it a purge, since the same pass would otherwise
create the population again right after deleting it. Clears itself afterwards.
## 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
400. 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
- **The engine's races are hit more often.** Neither `MagicEffectsList` nor
`ComposableAttribute` is thread-safe, and a thousand bots run into them more
often than human players do: a few caught exceptions per minute. A bot whose
attribute graph gets corrupted restarts itself (see above); a real fix belongs
into the engine, not into the bots.
- **Master skills which cost ten points at once are never learned.** A bot
invests every point as it earns it, so it never holds ten of them, and the
branches of the tree behind such a skill stay untouched.
- **The Summoner's enemy debuffs (Sleep, Weakness, Innovation) are unused.**
Deliberate: they would be cast through the buff rotation, which would have the
bot put itself to sleep. A cast-on-enemy path in the combat handler would be
needed.
- **Bots never buy equipment.** They wear what they find, so their gear lags
behind their level, and a bot at the maximum level is weaker than a player of
the same level would be. It is the reason a mastered bot needs a stretched hit
budget to reach the monsters which pay master experience at all. Letting bots
spend their money on gear would close the loop; they earn plenty of it.
- **Bots do no quests and do not trade with players.** Deliberate scope. The
quests which matter for progression (the class changes) are performed
directly, and trading would be an abuse surface.
- **Adding a game server to a running deployment does not spread the bots onto
it before a restart.** Deliberate: moving a bot between two running servers
would animate one account from two persistence contexts, which corrupts the
character.
## 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.