Bots emulate button presses instead of calling operations #155
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bots synthesize client button presses to reach behaviour that already exists
as a function. They should call the function.
The guideline
A bot never emulates a button press, an item op, or any other client
packet. It calls the operation directly.
A bot has no socket and no client. Nothing renders an interface for it, so
nothing can observe the click — and the in-game effect is identical
whether the press was synthesized on the backend or not. A synthesized click
is therefore pure cost: it is a second, hand-written client that nothing
compares against the real one, so it is free to drift.
That drift has already shipped once.
Goals.Restocksent the sell-side packclick without the child index a real client carries,
Button.authorise/1refused it as
{:op_disabled, 1}, and the two clicks behind it ran against anoffer holding no item — the goal reported success and listed nothing on
every trip it ever made, with a green suite behind it. It was found by
watching a live world and diffing against the operator's own client.
So: put the rules in
Contract.*or in the operation, and give the operationtwo callers — the client's click handler, and the bot.
Realism survives this, because realism is what an observer can see. The
bot still pays every observable cost — the level gate, the runes, the
animation, the delay, the wilderness ceiling — because all of that lives
inside the operation. What it skips is only the part nobody could ever have
seen.
Where a request tuple is still right
When the behaviour genuinely is the click: a walk, a loc action, an NPC
action, a player action. Those are world interactions with routes,
approaches and reach behind them, not interface state.
Bot.Actshould keepemitting request tuples for exactly those and nothing else.
What is already done
Bot.Act.arm_autocast/2was fixed onfeat/ancient-and-lunar-magic. It usedto send the two clicks a person makes — the combat tab's Choose spell, then
the cell inside the picker it opens — and the first of those was pure
theatre: it opened interface
201on a screen that does not exist, for areader that does not exist, so that a later click could write a varbit.
It now emits
{:bot, {:arm_autocast, slot}}and the session callsWorld.Player.Combat.arm_autocast/3, which is where the gates now live. Thesame branch added the operations the two new spellbooks need —
Bot.Act.spellbook/2,Bot.Act.teleport/2andBot.Act.lunar/3— each a{:bot, op}onto an operation that already existed.Extracting the operation found a bug that the click path had: nothing
gated the picked slot against the player's spellbook. Standard slots run
1–20 and ancient 31–46, so they do not collide and nothing would have raised
— a standard-book player could arm Ice Barrage, the varbit would take it, and
the cast would then read it back as nothing on every swing. A spell armed but
never cast is the worst of the three outcomes, because it looks like the
picker worked.
What is left
Four in
Bot.Act, all synthesizing packets:equip/4,use_item/4{:item_op, …}on interface 149World.Content.Item.interact/4— already existsdeposit_all/2button/6Care needed, per row
use_item/4is how a bot eats and drinks, and that path deliberatelyruns the whole of
World.Content.Consume— the three clocks and the attackdelay included.
Item.interact/4is the operation behind it, so calling itdirectly keeps all of that; this is simply the row where "skip the click" is
most likely to quietly skip a rule too, so it wants a test that asserts the
clocks, not just the item moving.
deposit_all/2has no operation yet. Op7on interface15component
3is the cache's Deposit-All, and its semantics — deposit everycopy of this id, leave anything unnamed alone — are what keeps a
gatherer's tool in the pack without a withdraw round trip. That behaviour
needs lifting out of the click handler before the bot can call it, and it is
the one item here that is real work rather than a re-point.
button/6should be deleted, not kept as a fallback. A genericclick-builder is how the next offender gets written.
Acceptance
Bot.Actemits{:bot, op}for everything that is interface state, andrequest tuples only for walks, loc/NPC/player actions.
grep -rn 'if_button\|item_op' lib/revenant/bot/returns nothing.a test asserting a refusal, not only the happy path — a refusal is what
a bot silently skips when the rule stays in the handler.
actually happens.
Moved to https://forge.home.arpa/Revenant/Server/issues/50