API объекта bot
Все свойства и методы L2Bot: что делает, какие параметры и что означают true и false.
На этой странице
Полный список того, что доступно скрипту через объект bot (тип L2Bot).
- Свойства читают мир и возвращают модели —
bot.userдаётPlayer,bot.npcsдаётList<Npc>. Поля этих классов описаны на странице Модели. - Команды —
suspend-функции, все возвращаютBoolean. Что именно означаютtrueиfalse, написано для каждой команды отдельно. log— единственный метод, который неsuspendи ничего не возвращает.
Команды выполняются последовательно: вызов возвращает управление, когда команда отработала, — отдельно ждать после неё не нужно. Автоповтора нет: false — это ответ, а не ошибка, повторять или нет решает скрипт.
Оглавление
Про то, чем id отличается от oid и почему у многих команд по три формы, — в разделе «id или oid».
Чтение мира
Свойства, не функции: suspend не нужен, обращаться можно сколько угодно раз. Каждое обращение отдаёт свежую картину мира, но полученный объект — снимок: сам он не обновляется, поэтому перечитывай свойство на каждой итерации цикла.
| Свойство | Тип | Что возвращает |
|---|---|---|
bot.id | String | Идентификатор персонажа, которым управляет скрипт. |
bot.user | Player | Свой персонаж: HP/MP/CP, координаты, уровень, вес, адена, каст, инвентарь, умения. |
bot.target | LiveEntity? | Текущая цель. null — цели нет. Конкретный тип — Npc, Char, Player или Pet. |
bot.npcs | List<Npc> | Все видимые NPC и мобы. Пустой список — рядом никого. |
bot.chars | List<Char> | Все видимые другие игроки. |
bot.drops | List<Drop> | Весь видимый дроп на земле. |
bot.pets | List<Pet> | Свои петы и саммоны. Сейчас 0 или 1 элемент. |
bot.skills | List<Skill> | Свои умения. То же самое, что bot.user.skills. |
bot.inventory | List<InventoryItem> | Свой инвентарь. То же самое, что bot.user.inventory. |
bot.party | List<PartyMember> | Участники группы. Пустой список — группы нет. |
bot.dialogText | String | HTML текущего или последнего диалога NPC. Пустая строка — диалога не было. |
bot.storeItems | List<StoreItem> | Товары последней открытой частной лавки. Пусто — лавку не открывали. |
bot.storeSellerOid | Int | Чья лавка лежит в bot.storeItems. 0 — лавку не открывали. |
bot.boardText | String | HTML текущей или последней комьюнити-борды (кастомной панели). Пустая строка — борду не открывали. |
bot.automationRunning | Boolean | Работает ли встроенная автоматизация бота. Нужна, чтобы скрипт вернул её в исходное состояние, а не включил вслепую тому, у кого она не работала. |
bot.events | Flow<ScriptEvent> | Поток игровых событий. |
val me = bot.user // Player
bot.log("${me.name}: ${me.hp}/${me.maxHp} hp, ${me.adena} адены")
val mob = bot.npcs.nearest { it.attackable && !it.dead } // Npc?
if (mob != null) bot.log("${mob.name}, ур. ${mob.level}, ${mob.distToSelf} ед.")Цель и бой
| Метод | Что делает | Что возвращает |
|---|---|---|
setTarget(id: Int): Boolean | Выбирает цель. id — template-id моба (берётся ближайший живой такого типа) либо object id. | true — цель выбрана. false — объекта нет либо сервер цель не подтвердил. |
setTarget(entity: LiveEntity): Boolean | Выбирает цель по сущности. | true — цель выбрана. false — объекта уже нет в мире. |
setTargetByOid(oid: Int): Boolean | Выбирает цель строго по object id. | true — цель выбрана. false — объекта нет. |
setTargetByType(npcId: Int): Boolean | Выбирает ближайшего живого моба указанного типа. | true — цель выбрана. false — моба такого типа рядом нет. |
cancelTarget(): Boolean | Снимает текущую цель. | true — цель снята. false — снять не удалось. |
attack(ctrl: Boolean = false): Boolean | Атакует текущую цель. ctrl — атака с зажатым Ctrl (форс). | Всегда true — атака отправлена. Попала ли она, смотри по событиям AttackStarted/Died или по HP цели. |
attack(target: LiveEntity, ctrl: Boolean = false): Boolean | Выбирает цель, затем атакует. | Всегда true. Результат выбора цели не проверяется — см. заметку ниже. |
attack(id: Int, ctrl: Boolean = false): Boolean | То же, цель — template-id либо object id. | Всегда true. |
forceAttack(target: LiveEntity, ctrl: Boolean = false): Boolean | Форс-атака по сущности. | Всегда true — атака отправлена. |
forceAttack(id: Int, ctrl: Boolean = false): Boolean | Форс-атака по template-id (ближайший живой) либо object id. | Всегда true. |
forceAttackByOid(oid: Int, ctrl: Boolean = false): Boolean | Форс-атака строго по object id. | Всегда true. |
assist(other: LiveEntity): Boolean | Берёт цель указанного персонажа. | true — цель взята. false — персонажа не видно либо у него нет цели. |
assistByOid(oid: Int): Boolean | То же строго по object id. | true — цель взята. false — объекта с таким oid не видно. |
assist(name: String): Boolean | Берёт цель персонажа с указанным именем. | true — цель взята. false — персонажа с таким именем не видно. |
autoTarget(range: Int = 2500, zRange: Int = 500): Boolean | Сам находит и берёт в цель ближайшего врага: в радиусе range и в пределах zRange по высоте. | true — враг найден и взят в цель. false — подходящих врагов нет. |
ignore(id: Int): Boolean | Добавляет в игнор-лист. id — template-id (добавляются все видимые сейчас мобы этого типа) либо object id. | Всегда true — записи добавлены. |
ignore(entity: LiveEntity): Boolean | Добавляет в игнор-лист конкретную сущность. | Всегда true. |
ignoreByOid(oid: Int): Boolean | То же строго по object id. | Всегда true. |
clearIgnore(): Boolean | Очищает игнор-лист. | Всегда true. |
stopCasting(): Boolean | Прерывает собственный каст. | true — прерывание отправлено и принято. false — прервать не удалось. |
Игнор-лист держится по объектам, а не по типам. ignore(templateId) добавит всех мобов этого типа, которые видны в момент вызова; те, что заспавнятся позже, в игнор не попадут — вызывай снова.
У форм с целью результат выбора цели не проверяется. attack(mob) — это «выбрать цель, затем атаковать», и true относится только к отправке атаки. Если важно убедиться, что цель выбралась:
if (bot.setTarget(mob)) bot.attack()Умения
| Метод | Что делает | Что возвращает |
|---|---|---|
castSkill(skillId: Int, target: LiveEntity? = null, ctrl: Boolean = false, shift: Boolean = false): Boolean | Кастует умение. target = null — по текущей цели. ctrl — форс-каст (Ctrl), shift — каст без подхода к цели (Shift). | true — каст начался. false — умения нет, оно на перезарядке, не хватает MP, персонаж сидит или сервер каст отклонил. |
castSkill(skillId: Int, targetId: Int, ctrl: Boolean = false, shift: Boolean = false): Boolean | То же; цель — template-id моба (ближайший живой) либо object id. | Как выше. |
castSkillByOid(skillId: Int, targetOid: Int? = null, ctrl: Boolean = false, shift: Boolean = false): Boolean | То же; цель строго по object id, null — текущая цель. | Как выше. |
castAttackSkill(skillId: Int, target: LiveEntity? = null, ctrl: Boolean = false, shift: Boolean = false): Boolean | Кастует атакующее умение. Для боевых скиллов бери этот метод, для остальных — castSkill. | true — каст начался. false — те же причины, что у castSkill. |
castAttackSkill(skillId: Int, targetId: Int, ctrl: Boolean = false, shift: Boolean = false): Boolean | То же; цель — template-id либо object id. | Как выше. |
castAttackSkillByOid(skillId: Int, targetOid: Int? = null, ctrl: Boolean = false, shift: Boolean = false): Boolean | То же; цель строго по object id. | Как выше. |
castSkillAt(skillId: Int, x: Int, y: Int, z: Int, ctrl: Boolean = false, shift: Boolean = false): Boolean | Кастует умение по точке на земле (для скиллов с выбором места). | true — каст начался. false — умение недоступно либо сервер отклонил. |
dispel(skillId: Int): Boolean | Снимает с себя указанный бафф — как клик по его иконке. | true — бафф снят. false — такого баффа нет либо снять не удалось. |
Если цель передана явно, она сначала выбирается, и только потом идёт каст.
Проверить умение перед кастом можно по Skill — skill.ready означает «не на перезарядке, не пассивное, не заблокировано», но MP не учитывает:
val nuke = bot.user.skill(1177)
if (nuke != null && nuke.ready && bot.user.mp > 100) bot.castAttackSkill(nuke.id, mob)Сидящий персонаж не кастует — сначала stand().
Предметы
pet = true означает «работать с инвентарём пета».
| Метод | Что делает | Что возвращает |
|---|---|---|
useItem(id: Int, pet: Boolean = false): Boolean | Использует вещь. id — template-id вещи либо object id конкретной вещи. | true — вещь использована. false — вещи нет в инвентаре либо использовать её нельзя. |
useItem(item: InventoryItem, pet: Boolean = false): Boolean | Использует конкретную вещь из инвентаря. | Как выше. |
useItemByType(itemId: Int, pet: Boolean = false): Boolean | Строго по template-id. | Как выше. |
useItemByOid(oid: Int, pet: Boolean = false): Boolean | Строго по object id. | Как выше. |
dropItem(id: Int, count: Long): Boolean | Выбрасывает вещь на землю. id — template-id либо object id. | true — вещь выброшена. false — вещи нет в инвентаре либо её нельзя выбросить. |
dropItem(item: InventoryItem, count: Long): Boolean | То же для конкретной вещи. | Как выше. |
dropItemByOid(oid: Int, count: Long): Boolean | Строго по object id. | true — вещь выброшена. false — вещи с таким oid в инвентаре нет. |
destroyItem(id: Int, count: Long): Boolean | Уничтожает вещь. id — template-id либо object id. | true — вещь уничтожена. false — вещи нет либо её нельзя уничтожить. |
destroyItem(item: InventoryItem, count: Long): Boolean | То же для конкретной вещи. | Как выше. |
destroyItemByType(itemId: Int, count: Long): Boolean | Строго по template-id. | true — вещь уничтожена. false — вещи этого типа в инвентаре нет. |
destroyItemByOid(oid: Int, count: Long): Boolean | Строго по object id. | true — вещь уничтожена. false — вещи с таким oid в инвентаре нет. |
crystallizeItem(id: Int): Boolean | Кристаллизует вещь. id — template-id либо object id. | true — кристаллизация запущена. false — вещи нет либо персонаж не умеет кристаллизовать (user.canCrystallize). |
crystallizeItem(item: InventoryItem): Boolean | То же для конкретной вещи. | Как выше. |
crystallizeItemByOid(oid: Int): Boolean | Строго по object id. | Как выше. |
transferItem(itemId: Int, count: Long, toPet: Boolean): Boolean | Передаёт вещь между персонажем и петом. toPet = true — персонаж → пет, false — пет → персонаж. | true — передача выполнена. false — вещи нет, пета нет либо передавать её нельзя. |
transferItem(item: InventoryItem, count: Long, toPet: Boolean): Boolean | То же для конкретной вещи. | Как выше. |
craftItem(recipeId: Int): Boolean | Изготавливает предмет по рецепту. | true — крафт запущен. false — нет рецепта, материалов или MP. |
setAutoShots(itemId: Int, enabled: Boolean, pet: Boolean = false): Boolean | Включает или выключает автоматические шоты указанного типа. pet = true — шоты пета. | true — настройка применена. false — шотов этого типа нет в инвентаре. |
setAutoShots(item: InventoryItem, enabled: Boolean, pet: Boolean = false): Boolean | То же по вещи из инвентаря. | Как выше. |
count во всех операциях с количеством — Long.
Движение
У скрипта два способа перемещения, и они очень разные.
| Метод | Что делает | Что возвращает |
|---|---|---|
moveToByGeo(x: Int, y: Int, z: Int, timeoutMs: Long = 15_000): Boolean | Ведёт персонажа в точку по проходимой геодате сервера, огибая препятствия. Блокирует скрипт до конца ходьбы. | true — персонаж дошёл. false — пути нет, встал намертво, сработал stopMove(), истёк таймаут либо двигаться нельзя (мёртв, сидит). |
moveToByGeo(target: Positioned, timeoutMs: Long = 15_000): Boolean | То же, но цель — сущность или дроп (берутся их координаты). | Как выше. |
stopMove(): Boolean | Прерывает идущую ходьбу — выполняющийся moveToByGeo немедленно вернёт false. | Всегда true — команда отмены отправлена. |
moveTo(x: Int, y: Int, z: Int, timeoutMs: Long = 8000): Boolean | Отправляет одно прямое перемещение в точку и ждёт прибытия. Препятствия не огибает. | true — персонаж оказался в точке (≈80 единиц по X/Y) до истечения таймаута. false — не успел: упёрся, слишком далеко либо не двинулся вовсе. |
moveTo(target: Positioned, timeoutMs: Long = 8000): Boolean | То же к сущности или дропу. | Как выше. |
moveToNoWait(x: Int, y: Int, z: Int): Boolean | Прямое перемещение без ожидания прибытия. | Всегда true — перемещение отправлено. Дошёл ли персонаж, проверяй сам по bot.user.x/y. |
moveToNoWait(target: Positioned): Boolean | То же к сущности или дропу. | Всегда true. |
moveToByGeo — рабочий способ ходить по миру
Команда блокирующая: управление вернулось — значит персонаж уже пришёл (true) либо уже никуда не идёт (false).
timeoutMs— верхний предел ожидания, по умолчанию 15 секунд. Для длинного маршрута ставь больше или0— без дедлайна.- Зависнуть навсегда даже без таймаута нельзя: если персонаж перестал двигаться, маршрут перестраивается, а когда попытки исчерпаны — команда возвращает
false. - Каст и обездвиживание пережидаются внутри команды — прерывать её из-за них не нужно.
- Ограничения зон персонажа (рабочая область, запретные области) на маршрут не влияют: сказано «иди туда» — идём.
- Новый вызов вытесняет предыдущую ходьбу, а не встаёт за ней в очередь.
moveTo / moveToNoWait — один шаг напрямую
Отправляют одно перемещение по прямой. На открытом месте или для короткого шага — быстро и достаточно; в стену персонаж упрётся и moveTo вернёт false по таймауту. Прибытие в moveTo проверяется по X/Y, высота не учитывается.
// дойти до дальней точки: автоматизацию лучше выключить, дедлайн снять
bot.disableAutomation()
val ok = bot.moveToByGeo(82000, 148000, -3470, timeoutMs = 0)
bot.log(if (ok) "пришёл" else "не дошёл")Состояние персонажа
| Метод | Что делает | Что возвращает |
|---|---|---|
sit(): Boolean | Садится. | true — персонаж сел. false — сесть нельзя (в бою, мёртв) либо сервер отказал. |
stand(): Boolean | Встаёт. | true — персонаж встал. false — встать не удалось. |
dismissPet(): Boolean | Отзывает пета. | true — пет отозван. false — пета нет либо отозвать не удалось. |
dismissSummon(): Boolean | Распускает саммона или сервитора. | true — саммон распущен. false — саммона нет либо распустить не удалось. |
restart(): Boolean | Выходит на экран выбора персонажа и дожидается его. | true — экран выбора появился. false — не дождались либо выйти нельзя. |
restartNoWait(): Boolean | То же, но без ожидания экрана. | true — команда отправлена. false — отправить не удалось. |
selectCharacter(slot: Int): Boolean | Входит в мир персонажем из слота slot (нумерация с нуля). Только с экрана выбора — из игры сперва restart(). | true — вход состоялся. false — клиент не на экране выбора, слота нет либо ответа не дождались. |
goHome(restartType: RestartType = RestartType.TOWN): Boolean | Воскрешает персонажа или возвращает его в выбранную точку. | true — возрождение выполнено. false — точка недоступна либо персонаж жив. |
Значения RestartType: TOWN · CLAN_HALL · CASTLE · FORTRESS · FLAG.
Смена персонажа — это restart() и следом selectCharacter(n):
if (bot.restart() && bot.selectCharacter(2)) {
bot.log("Теперь играем за ${bot.user.name}")
}После успешной смены мир — другой персонаж: user, инвентарь, скиллы и окружение не имеют ничего общего с прежними. Перечитай bot.* целиком, а всё, что запомнил до смены (oid-ы, цели, дропы), выбрось.
Сидя персонаж не кастует умения — если скрипт сажает его на реген, не забудь stand() перед боем.
Диалоги NPC
| Метод | Что делает | Что возвращает |
|---|---|---|
openDialog(): Boolean | Открывает диалог с текущей целью. Цель не перевыбирается — она уже должна быть выбрана. | true — NPC ответил диалогом. false — цели нет либо диалога не последовало. |
openDialog(id: Int): Boolean | Выбирает NPC и открывает диалог. id — template-id (ближайший живой такого типа) либо object id. | true — NPC ответил диалогом. false — NPC не найден либо диалога не последовало. |
openDialog(npc: Npc): Boolean | То же для конкретного NPC. | Как выше. |
openDialogByOid(npcOid: Int): Boolean | Строго по object id. | Как выше. |
selectDialog(option: String): Boolean | Выбирает пункт диалога по подписи — по тексту, который виден в окне. Регистр не важен; сперва ищется точное совпадение, потом вхождение. Ждёт ответа сервера примерно до 2,5 секунд. | true — пункт выбран, пришёл новый диалог. false — пункта с такой подписью нет либо ответа не дождались. |
selectDialog(number: Int): Boolean | Выбирает пункт по порядковому номеру: первый пункт — 1, второй — 2 и так далее. Считаются все кликабельные пункты диалога, сверху вниз. | true — пункт выбран. false — такого номера в диалоге нет. |
sendBypass(cmd: String): Boolean | Отправляет команду диалога напрямую, без поиска пункта. | Всегда true — команда отправлена. Ответ придёт событием DialogReceived. |
selectBoard(option: String): Boolean | Нажимает кнопку комьюнити-борды (кастомной панели: бафер, телепорт, шоп) по её подписи. Регистр не важен: сперва точное совпадение, потом вхождение. | true — кнопка нажата, панель прислала новую страницу. false — кнопки с такой подписью нет либо ответа не дождались. |
selectBoard(number: Int): Boolean | То же по порядковому номеру: первая кнопка — 1. Считаются все кликабельные пункты страницы, сверху вниз. | true — кнопка нажата. false — такого номера на странице нет. |
confirmDialog(msgId: Int, requestId: Int, accept: Boolean): Boolean | Отвечает на окно-вопрос. msgId и requestId берутся из события ConfirmDialogReceived. | Всегда true — ответ отправлен. |
HTML текущего (или последнего) диалога лежит в bot.dialogText; пустая строка — диалога не было.
if (bot.openDialog(30080)) {
bot.selectDialog("Teleport")
delay(300)
bot.selectDialog(1) // первый пункт открывшегося списка
}Частные лавки
Лавка игрока — не диалог: сервер отдаёт её содержимое только по запросу, поэтому есть одна команда, которая делает всю дорогу целиком.
| Метод | Что делает | Что возвращает |
|---|---|---|
openStore(seller: Char): Boolean | Подходит к продавцу и открывает его лавку. Идёт по геодате, тем же каналом, что moveByGeo. | true — товары пришли и лежат в bot.storeItems. false — продавца нет, не дошли либо ответа не было. |
openStoreByOid(sellerOid: Int): Boolean | То же строго по object id. | Как выше. |
У обоих есть walkTimeoutMs (по умолчанию 15 с) на дорогу и timeoutMs (5 с) на ответ.
Товары не приходят возвращаемым значением — читай их из bot.storeItems сразу после true. Этот список — снимок на момент открытия, а не живые цены: когда кто-то выкупит позицию, сервер об этом молчит.
val seller = bot.chars.nearest { it.storeType == 1 } ?: return
if (bot.openStore(seller)) {
bot.storeItems
.filter { it.price < it.basePrice } // дешевле базовой
.forEach { bot.log("${it.itemId}: ${it.price} против ${it.basePrice}") }
}Комьюнити-борда
Кастомные панели (бафер, телепорт, донат) — это не диалог NPC: у них своё окно, своя разметка в bot.boardText и свои команды selectBoard. Смешивать нельзя, selectDialog панель не видит.
Кнопки панели ищутся по подписи. Внутренний код кнопки сервер выдаёт заново при каждом открытии страницы, поэтому запоминать его в скрипте бесполезно — через минуту он уже чужой.
bot.sendBypass("_bbshome") // открыть борду; эта команда постоянная
delay(500)
bot.selectBoard("Buffer") // раздел бафов
delay(500)
bot.selectBoard("Might")Длинная страница приезжает несколькими пакетами; selectBoard дожидается её целиком, так что следующая команда уже видит полную разметку. Если кнопка требует ввода в поле (в разметке это $name в конце команды) — selectBoard её не заполнит, тут нужен sendBypass("<код> значение") вручную.
Группа
| Метод | Что делает | Что возвращает |
|---|---|---|
inviteParty(name: String, lootMode: LootMode = LootMode.FINDERS_KEEPERS): Boolean | Приглашает игрока в группу с выбранным режимом дележа лута. | Всегда true — приглашение отправлено. Принял ли игрок, видно по событию PartyMemberJoined или по bot.party. |
leaveParty(): Boolean | Выходит из группы. | true — группа покинута. false — персонаж не в группе. |
setPartyLeader(member: PartyMember): Boolean | Передаёт лидерство участнику группы. | true — передача отправлена. false — участника с таким oid не видно. |
setPartyLeader(oid: Int): Boolean | То же по object id участника. | Как выше. |
setPartyLeaderByOid(oid: Int): Boolean | То же, явная форма. | Как выше. |
setPartyLeader(name: String): Boolean | Передаёт лидерство по имени игрока. | Всегда true — передача отправлена. |
У участников группы нет template-id — число в setPartyLeader(oid) всегда трактуется как object id (member.oid).
Значения LootMode: FINDERS_KEEPERS · RANDOM · RANDOM_SPOIL · BY_TURN · BY_TURN_SPOIL.
Приглашение к себе в группу приходит событием PartyInviteReceived, ответ на него — confirmDialog.
Чат
| Метод | Что делает | Что возвращает |
|---|---|---|
say(text: String, channel: Int = 0, target: String = ""): Boolean | Отправляет сообщение в чат. target — имя адресата, нужен только для привата. | Всегда true — сообщение отправлено. |
Коды каналов:
| Код | Канал | Код | Канал |
|---|---|---|---|
0 | обычный (вокруг) | 8 | торговый |
1 | крик | 9 | альянс |
2 | приват (нужен target) | 10 | объявление |
3 | группа | 11 | лодка |
4 | клан | 13 | поле битвы |
5 | GM | 14 | командный канал |
6 | петиция (игрок) | 25 | друзья |
7 | петиция (GM) |
bot.say("готов") // вокруг
bot.say("иду к вам", channel = 3) // в группу
bot.say("привет", channel = 2, target = "Friend") // в приватЛут
| Метод | Что делает | Что возвращает |
|---|---|---|
pickup(id: Int): Boolean | Подбирает дроп. id — itemId (берётся ближайший такой дроп на земле) либо object id дропа. | true — вещь подобрана. false — дропа нет, он чужой, персонаж слишком далеко либо инвентарь переполнен. |
pickup(drop: Drop): Boolean | Подбирает конкретный дроп. | Как выше. |
pickupByOid(oid: Int): Boolean | Строго по object id дропа. | Как выше. |
Команда не подводит персонажа к дропу — подойти нужно самому. Сервер разрешает подбор только вплотную (порядка 50–80 единиц):
val drop = bot.drops.nearest { it.isMine } ?: return
if (drop.distToSelf > 60) bot.moveToByGeo(drop)
bot.pickup(drop)Сырой пакет
Крайняя мера — на случай, когда типизированной команды для действия нет. Обычные методы этого раздела не заменяет и не дублирует: там пакет собирает сам игровой клиент, и он корректен по определению.
| Метод | Что делает | Что возвращает |
|---|---|---|
sendPacket(hex: String, active: Boolean = false): Boolean | Отправляет готовый игровой пакет — байты уходят на сервер как есть. | true — клиент подтвердил отправку. false — пакет не ушёл либо исход неизвестен. |
sendPacket(bytes: ByteArray, active: Boolean = false): Boolean | То же для пакета, собранного в коде. | Как выше. |
hex — тело пакета: опкод первым байтом, без префикса длины (длину и шифрование клиент допишет сам). Extended-пакет пишется целиком, вместе с D0 и подкомандой. Пробелы и запятые игнорируются, регистр любой.
bot.sendPacket("11 01") // снять цель
bot.sendPacket("D0 0D 00 …") // extended: D0 + подкоманда + телоactive = true — действию нужно активное окно клиента: окно будет выведено на передний план. Про доставку это не говорит ничего — сама отправка работает и в фоне.
Три вещи, которые стоит знать до того, как это использовать:
- Содержимое не проверяет никто. Сервер на неверные байты обычно разрывает соединение.
true— это про клиента, не про сервер. Он значит «байты ушли на провод», а не «действие принято». Принял ли сервер — видно по событиям и по состоянию мира.- Повтор — на твоей совести. При
falseприложение сырой пакет не переотправляет: для неидемпотентной команды (купить, использовать вещь) второй заход означает второе выполнение.
Сырой трафик
Сниффер: пакеты как они есть на проводе, без разбора. Нужен для разведки — посмотреть, что клиент шлёт по кнопке, или поймать серверный пакет, которого нет среди событий.
| Метод / поле | Что делает | Что возвращает |
|---|---|---|
capturePackets(incoming: Boolean = false, outgoing: Boolean = false): Boolean | Включает или выключает захват. Заменяет прежнюю настройку целиком; вызов без аргументов выключает оба направления. | true — применено. false — персонаж не найден. |
packetsIn: Flow<Packet> | Пакеты сервер→клиент. | Поток; молчит, пока не включён захват. |
packetsOut: Flow<Packet> | Пакеты клиент→сервер — и команды бота, и то, что игрок сделал руками. | Поток; молчит, пока не включён захват исходящих. |
По умолчанию захват выключен, и это не забывчивость: в бою через провод идут десятки пакетов в секунду, и гнать их в скрипт без спроса незачем.
bot.capturePackets(incoming = true)
bot.packetsIn
.filter { it.opcode == 0x0B }
.collect { bot.log("${it.size} байт: $it") }Захват снимается сам, когда скрипт заканчивается — забыть выключить не страшно.
Что в Packet
| Поле | Что это |
|---|---|
hex: String | Байты пакета в hex, верхним регистром, без разделителей. |
bytes: ByteArray | Те же байты. |
opcode: Int | Первый байт — опкод. |
subOpcode: Int | Подкоманда extended-пакета (после D0). -1, если пакет не extended. |
size: Int | Длина тела в байтах. |
byteAt(index: Int): Int | Байт по номеру, или -1 за пределами пакета. |
Тело идёт целиком, опкод первым байтом и без префикса длины — ровно в том виде, в каком его принимает sendPacket.
Исходящие требуют перехвата
packetsOut устроен иначе, чем packetsIn: по умолчанию клиент вообще не отдаёт приложению то, что отправляет на сервер. capturePackets(outgoing = true) этот перехват поднимает, и он же поднимает его для записи профилей (game_buff, возврат на спот).
Перехват общий, поэтому он арендуется, а не переключается: выключение твоего захвата не оборвёт идущую параллельно запись, а её окончание не оборвёт твой поток.
Автоматизация и профили
Скрипт может управлять встроенной автоматизацией — той, что настраивается в приложении.
| Метод | Что делает | Что возвращает |
|---|---|---|
enableAutomation(): Boolean | Включает встроенную автоматизацию. | Всегда true — переключение выполнено (если она уже включена, ничего не меняется). |
disableAutomation(): Boolean | Выключает встроенную автоматизацию. | Всегда true. |
loadZone(path: String): Boolean | Читает файл зон .iz (такой сохраняет приложение) и применяет его к персонажу. | true — файл прочитан и зоны применены. false — файла нет, он не читается либо формат битый. |
clearZone(): Boolean | Очищает зоны персонажа. | Всегда true — зоны очищены. |
loadConfig(path: String): Boolean | Читает файл профиля настроек .json (такой сохраняет приложение) и применяет его к персонажу. Имя профиля берётся из имени файла. | true — файл прочитан и отправлен на применение. false — файл не удалось прочитать. |
path — обычный путь в файловой системе, абсолютный или относительно рабочего каталога приложения.
Вывод
| Метод | Что делает | Что возвращает |
|---|---|---|
log(text: String) | Пишет строку в лог скрипта. Не suspend, вызывается откуда угодно. | Ничего (Unit). |