Atheryx
Войти
Документация

Скрипты на Lua.

Свои модули с настройками, команды чата, HUD и ESP — прямо из файла .lua. Скрипт перезагружается сам при каждом сохранении, а его модули живут в меню и пресетах наравне со встроенными.

Быстрый старт

Откройте меню клиента → Tools → Scripts и нажмите «Новый скрипт»: в папке .minecraft/atheryx/scripts появится файл из шаблона и откроется в редакторе. Сохраните его — скрипт загрузится, а его модуль появится в своём разделе меню.

-- @name Привет
-- @author вы
-- @version 1.0
-- @description Мой первый модуль

local m = module.create{
    name = "Hello",
    description = "Здоровается при включении",
    category = "player",
}

local text = m:text("Текст", "Привет из Lua!")

m:on("enable", function()
    chat.print(text:get())
end)

m:on("tick", function()
    if player.health() < 6 then
        client.notify("Hello", "Мало здоровья!")
    end
end)
  • Шапка из комментариев -- @name, @author, @version, @description — то, что видно в разделе Scripts.
  • Правка файла подхватывается за секунду: скрипт выгружается и грузится заново, а включённость и настройки его модулей сохраняются.
  • Готовые примеры клиент кладёт в scripts/examples — скопируйте любой в scripts, и он заработает.
  • Проверить что-то на лету — команда .lua player.health() прямо в чате.

Как устроено

.minecraft/atheryx/scripts/ ├── myscript.lua ← скрипт: каждый .lua в этой папке грузится сам ├── lib/ │ └── colors.lua ← библиотека: только через require("colors") ├── examples/ ← примеры от клиента (сами не грузятся) └── .data/ ← storage скриптов и состояние раздела

Жизненный цикл

  • При загрузке выполняется весь файл (основной код). Модули, их настройки и команды заводятся именно здесь — из обработчиков module.create не работает.
  • Модули скрипта — полноценные модули клиента: карточка в меню, клавиша, поиск, уведомления, сохранение в пресет. Выключенный или упавший скрипт не стирает их настройки из пресета.
  • Скрипт можно выключить переключателем в разделе Scripts или командой .script off имя — выбор помнится между запусками.
  • Перед выгрузкой (правка файла, выключение) модули скрипта выключаются, затем зовётся events.on("unload").

Ошибки

Ошибка при загрузке показывается на карточке скрипта красным. Ошибка в обработчике модуля выключает модуль, в events.on — снимает обработчик, в таймере — снимает таймер. Каждая ошибка пишется в консоль раздела Scripts (там же вывод print) и в чат — не чаще раза в 5 секунд на одно место.

Команды в чате

.script listСкрипты и их состояние.
.script reload [имя]Перезагрузить один скрипт или все.
.script on|off <имя>Включить или выключить скрипт.
.script newНовый скрипт из шаблона — сразу в редакторе.
.script folderОткрыть папку скриптов.
.script logПоследние 10 строк консоли.
.lua <код>Выполнить строку Lua; выражение печатает значение: .lua world.tps(). Переменные живут до .lua reset.

Модули

module.create{name, description, category, bind, …} → модульНовый модуль. name — до 32 символов, уникальное. category: combat, movement, render, player (по умолчанию), world. bind — клавиша: "R", "F6", "LSHIFT", "MOUSE4". Обработчики можно передать полями: tick = function() … end.
module.create(name, [description], [category]) → модульТо же, короче.
module.get(name) → модуль | nilЛюбой модуль клиента по имени — встроенный ("Aura") или из скрипта.
module.list([category]) → {имена}Имена модулей, можно по разделу.
module.is_enabled(name) → booleanВключён ли модуль.

Методы модуля

m:on(event, fn)Обработчик события; работает, пока модуль включён. Повторный вызов заменяет обработчик. Только для своих модулей.
m:off(event)Снять обработчик.
m:enabled() → booleanВключён ли.
m:toggle(), m:set_enabled(on)Переключить / включить или выключить.
m:name(), m:description(), m:category()Имя, описание, раздел.
m:bind() → "R" | nil, m:set_bind(key)Клавиша модуля; nil или "none" — без клавиши.
m:setting(name) → настройка | nilНастройка по имени — в том числе у встроенных модулей: module.get("Aura"):setting("Дистанция"):set(3.2).
m:settings() → {имена}Имена всех настроек.
m:is_script() → booleanМодуль из скрипта или встроенный.

Настройки

Настройки заводятся у своего модуля при загрузке, рисуются в его карточке и сохраняются в пресет. Каждый вызов возвращает объект настройки.

m:boolean(name, [default=false])Галочка. get() → boolean.
m:slider(name, default, min, max, [step=1], [suffix])Ползунок: m:slider("Дистанция", 3, 1, 6, 0.1, " бл"). get() → число.
m:range(name, from, to, min, max, [step=1], [suffix])Отрезок с двумя ручками. get() → from, to.
m:mode(name, {варианты}, [default])Один из вариантов. get() → строка.
m:multi(name, {варианты}, [{включённые}])Несколько вариантов. get() → список включённых, s:is(v), s:toggle(v).
m:color(name, [default])Цвет с пикером. Без значения — следует теме клиента. get() → число ARGB.
m:text(name, [default=""], [max=64])Строка. get() → string.
m:keybind(name, [default])Своя клавиша. get() → имя или nil, s:down() — зажата ли сейчас.
m:button(name, [label], fn)Кнопка-действие в карточке.

Методы настройки

s:get(), s:set(value), s:reset()Значение, запись, сброс к умолчанию. Поля s.name и s.type (boolean, slider, range, mode, multi, color, text, keybind, button).
s:describe(text)Подсказка под названием в меню.
s:visible(fn | boolean)Показывать ли настройку: speed:visible(function() return mode:get() == "Быстрый" end).
s:modes(), s:options(), s:min(), s:max(), s:press()Варианты режима и набора, границы ползунка, нажать кнопку.
Методы с двоеточием (s:get()) — обычный стиль Lua; вызов через точку (s.get()) тоже работает.

События

У модуля — m:on(name, fn), работают, пока модуль включён. У скрипта — events.on(name, fn) / events.off(name), работают, пока скрипт загружен. Таблицы событий с e:cancel() отменяют действие игры.

enable, disableМодуль включили / выключили (только у модуля).
tickТик игрока, 20 раз в секунду, только в мире.
tick_endКонец тика клиента (идёт и в меню).
frameКаждый кадр в мире, между тиками.
move(input)Ввод движения на тик: forward, back, left, right, jump, sneak, sprint, moving. Что поменяете в таблице — то и уйдёт в игру.
render2d(frame)Рисование поверх интерфейса: width, height, mouse_x, mouse_y, partial.
render_world(frame)То же, но под интерфейсом — для меток над игроками и блоками.
render3d(frame)Отрисовка в мире: partial, camera_x/y/z.
key(e), mouse(e)Клавиша / кнопка мыши без открытого экрана: e.key/e.button, e.name, e.action (press, release, repeat), e.pressed, e:cancel().
chat(e)Сообщение в чате: e.text, e.sender (nil у системных), e:cancel() — скрыть.
chat_send(e)Своё сообщение перед отправкой: e.text, e:cancel().
attack(e)Удар: e.target (сущность), e.entity_id, e:cancel().
packet_send(e), packet_receive(e)Пакеты: e.name, e.id, e.class, e.direction, e:cancel(). У движения — x, y, z, yaw, pitch, on_ground; у отбрасывания — entity_id, motion_x/y/z, self.
join(e), leaveВход в мир (и смена измерения): e.dimension; выход.
unloadСкрипт выгружается (только events.on).
chat и packet_receive приходят из потока сети. Действия (chat.send, player.attack, m:toggle()) сами уходят в игровой поток, а вот рисовать там нельзя.

Игрок

Таблица player. Без мира всё возвращает nil, а действия ничего не делают.

player.exists(), player.name(), player.entity()Есть ли игрок, ник, сам игрок как сущность.
player.position([partial]) → x, y, zПозиция; с partial из кадра — плавная, для рисования.
player.eye(), player.velocity(), player.rotation() → yaw, pitchГлаза, скорость за тик, углы камеры.
player.speed() → блоков/сГоризонтальная скорость.
player.health(), max_health(), absorption(), food(), saturation(), armor(), xp_level()Здоровье, золотые сердца, голод, насыщение, броня, уровень.
on_ground(), sprinting(), sneaking(), in_water(), in_lava(), gliding(), using_item(), blocking(), on_fire(), riding()Состояние игрока (все — player.…()).
fall_distance(), hurt_time(), attack_cooldown() → 0..1Высота падения, тики после урона, заряд удара.
player.slot() → 1..9, player.set_slot(n)Слот хотбара.
held_item(), offhand_item(), item(slot), inventory(), find_item(id) → слот | nilПредметы — таблицы {id, name, count, empty, damage, max_damage}. Слоты с 1: 1–9 хотбар, 10–36 рюкзак, 37–40 броня, 41 вторая рука. find_item("totem_of_undying").
player.effects(), player.has_effect(id)Эффекты {id, level, duration} (длительность в тиках, -1 — бесконечно).
gamemode(), ping(), dimension()Режим игры, пинг, измерение ("minecraft:overworld").
player.target() → сущность | nilСущность под прицелом.
player.looking_at() → {type, …}Что под прицелом: type = block / entity / miss, x, y, z, у блока — block, block_x/y/z, face, у сущности — entity.
player.jump(), player.swing([hand]), player.set_sprinting(on)Прыжок (с земли), взмах рукой ("main"/"off"), бег.
player.attack(entity), player.use_item([hand]), player.release_item()Ударить, использовать предмет, отпустить (лук, еда).
player.set_rotation(yaw, pitch), player.look_at(x, y, z)Повернуть камеру. Тихий поворот только для сервера — rotation.set.
player.set_velocity(x, y, z)Задать скорость.

Мир и сущности

world.exists()Загружен ли мир.
world.players() → {сущности}Игроки вокруг, включая вас (e:is_self()).
world.entities([radius]) → {сущности}Все сущности, по желанию — в радиусе от игрока.
world.entity(id)Сущность по id.
world.block(x, y, z) → "minecraft:stone", world.is_air(x, y, z), world.is_solid(x, y, z)Блок в точке.
world.time() → 0..23999, world.ticks()Время суток и счётчик тиков мира.
world.dimension(), world.raining(), world.thundering()Измерение и погода.
world.tps(), world.server() → адрес | nilTPS сервера, адрес (nil в одиночной игре).
world.online() → {{name, ping, gamemode}}Список игроков из таба.

Методы сущности

Сущность — лёгкая ссылка по id: если она ушла из мира, e:valid() вернёт false, остальные методы — nil. Сравнение a == b работает.

e:id(), e:uuid(), e:name(), e:type() → "minecraft:zombie", e:valid()Кто это.
e:position([partial]), e:eye(), e:velocity(), e:rotation()Где и куда смотрит.
e:distance([x, y, z])До игрока или до точки.
e:box() → minX, minY, minZ, maxX, maxY, maxZ, e:width(), e:height(), e:age()Хитбокс и возраст в тиках.
e:alive(), on_ground(), sneaking(), sprinting(), invisible(), on_fire(), in_water(), riding()Состояние.
e:is_player(), is_living(), is_item(), is_self(), is_friend()Что это за сущность и друг ли.
e:health(), max_health(), absorption(), armor(), hurt_time()Для живых существ.
e:held_item(), offhand_item(), armor_items(), effects(), using_item(), blocking(), gliding()Снаряжение и действия.
e:ping(), e:gamemode(), e:item()Пинг и режим игрока, предмет на земле.

Рендер 2D

Таблица render — только в обработчиках render2d и render_world. Тот же движок, что у меню клиента: скругления, тени, размытие, чёткий текст. Координаты — в единицах интерфейса. Цвет — число 0xAARRGGBB или строка "#RRGGBB", "#AARRGGBB", "#RGB".

render.rect(x, y, w, h, color, [radius])Прямоугольник.
render.outline(x, y, w, h, color, [thickness=1], [radius])Рамка.
render.gradient(x, y, w, h, from, to, [vertical=true], [radius])Градиент.
render.circle(x, y, r, color), render.ring(x, y, r, thickness, color)Круг и кольцо.
render.arc(x, y, r, thickness, start, sweep, color)Дуга, углы в градусах.
render.line(x1, y1, x2, y2, color, [width=1])Линия.
render.shadow(x, y, w, h, sigma, [color])Мягкая тень или свечение.
render.blur(x, y, w, h, [strength=12], [radius], [tint])Размытие того, что под областью.
render.text(text, x, y, [size=10], [color], [align], [font]) → ширинаТекст. Вместо хвоста аргументов можно таблицу: {size, color, align, valign, font, shadow}. align: left/center/right, valign: top/center/bottom, font: regular/medium/semi/bold.
render.text_width(text, [size], [font]), render.text_height([size], [font])Размеры строки.
render.item(item, x, y, [size=16], [alpha])Иконка предмета: таблица из player.held_item() или id ("diamond_sword").
render.scissor(x, y, w, h) / render.pop_scissor()Обрезка области.
render.push(dx, dy, [scale], [ox], [oy]) / render.pop()Сдвиг и масштаб вокруг точки (ox, oy).
render.alpha(a)Прозрачность всего дальнейшего, 0..1.
render.project(x, y, z) → sx, sy | nilТочка мира на экране (nil — за камерой).
render.width(), render.height(), render.partial()Размер кадра и доля тика.

Ножницы и сдвиги, которые вы забыли снять, снимаются сами в конце обработчика.

Рендер 3D

Таблица render3d — в обработчике render3d. Фигуры видно сквозь стены; за обработчик — до 4096 штук.

render3d.box(x1, y1, z1, x2, y2, z2, fill, [outline])Бокс: заливка и рёбра (nil — без них).
render3d.block(x, y, z, fill, [outline])Блок, в котором лежит точка.
render3d.entity(e, fill, [outline], [grow])Хитбокс сущности, плавно за моделью.
render3d.line(x1, y1, z1, x2, y2, z2, color)Линия.
render3d.camera() → x, y, z, render3d.partial()Позиция камеры и доля тика.

Чат и команды

chat.print(text)Сообщение себе с префиксом Atheryx; §-коды работают.
chat.raw(text)То же без префикса.
chat.send(text)Отправить в чат; со / — как команду, с . — команду клиента.
chat.command(cmd)Серверная команда: chat.command("home").
command.register(name, [description], fn(args, raw))Своя команда .name: args — слова после имени, raw — вся строка. Имена встроенных команд заняты.
command.unregister(name)Снять команду.
command.register("coords", "Мои координаты", function(args, raw)
    local x, y, z = player.position()
    chat.print(string.format("§fXYZ §7%.0f %.0f %.0f", x, y, z))
end)

Таймеры и хранилище

timer.after(ms, fn) → idВызвать один раз через ms миллисекунд.
timer.every(ms, fn) → idВызывать каждые ms.
timer.cancel(id) → booleanСнять таймер.
storage.get(key, [default])Значение, сохранённое между запусками игры.
storage.set(key, value), storage.remove(key)Записать: числа, строки, boolean и таблицы из них.
storage.keys(), storage.clear()Все ключи, очистить.

Хранилище у каждого скрипта своё — файл scripts/.data/имя.json, пишется раз в секунду и при выгрузке.

Утилиты

print(...), script.log/warn/error(...)Строка в консоль раздела Scripts.
script.id, script.name, script.author, script.version, script.reload()О себе и перезагрузка.
require(name)Библиотека из scripts/lib/name.lua (require("utils.math") → lib/utils/math.lua). Правка библиотеки перезагружает скрипт.
client.fps(), client.time(), client.in_game(), client.screen()FPS, время в мс, в мире ли, открытый экран: chat, container, pause, clickgui, other или nil.
client.notify(title, [text]), client.theme(), client.name, client.versionУведомление клиента, цвет темы.
color.rgb(r, g, b, [a]), color.hsv(h, s, v, [a]), color.hex(str)Цвет: каналы 0..255, оттенок в градусах, s и v 0..1.
color.alpha(c, a), color.fade(c, f), color.mix(a, b, t), color.unpack(c) → r, g, b, a, color.theme()Прозрачность 0..255, множитель прозрачности 0..1, смешивание.
math.clamp(x, min, max), math.lerp(a, b, t), math.round(x, [digits]), math.sign(x)В дополнение к обычному math.
rotation.to(x, y, z) → yaw, pitchУглы от глаз на точку.
rotation.set(yaw, pitch)Тихий поворот для сервера на этот тик (камера не двигается) — звать каждый тик, пока нужен.
rotation.active(), rotation.yaw(), rotation.pitch(), rotation.wrap(deg)Идёт ли тихий поворот, его углы, нормализация угла.
friends.is(name), friends.add(name), friends.remove(name), friends.list()Друзья клиента.
input.key(name), input.mouse(button)Зажата ли клавиша ("LSHIFT", "R") или кнопка ("LEFT", "MOUSE4").
input.key_code(name), input.key_name(code), input.cursor() → x, yКоды клавиш и позиция курсора.
os.clock(), os.time(), os.date([format])Часы и дата; остального os нет.

Ограничения

Скрипты работают в песочнице: им нельзя навредить компьютеру и повесить игру.

  • Нет io, debug, luajava, dofile, loadfile и os кроме часов — ни файлов, ни процессов, ни Java. load принимает только текст.
  • Обработчик события — до 60 мс, загрузка файла — до 2 с. Застрявший цикл обрывается, даже внутри pcall и корутин.
  • Файл скрипта — до 1 МБ, string.rep — до 4 млн символов, таймеров — до 512, хранилище — до 4096 ключей.
  • Рисовать можно только в обработчиках отрисовки и только из игрового потока.
  • Каждый скрипт — в своём окружении: переменные и подмены string одного не видны другим.

Примеры

Все примеры лежат в scripts/examples: hello, autogg, hud, esp, commands, automessage.

Мини-HUD

local m = module.create{ name = "MiniHud", category = "render" }
local accent = m:color("Акцент")              -- цвет темы
local size = m:slider("Размер", 10, 7, 16, 0.5)

m:on("render2d", function(frame)
    local x, y, z = player.position(frame.partial)
    local text = string.format("XYZ %.1f %.1f %.1f  •  %d FPS", x, y, z, client.fps())
    local w = render.text_width(text, size:get(), "medium") + 16
    render.blur(6, 6, w, 22, 10, 6)
    render.rect(6, 6, w, 22, "#B0141820", 6)
    render.rect(10, 11, 2, 12, accent:get(), 1)
    render.text(text, 16, 17, { size = size:get(), font = "medium", valign = "center" })
end)

Подсветка игроков

local m = module.create{ name = "SimpleESP", category = "render" }
local fill = m:color("Заливка", "#28FFFFFF")
local edge = m:color("Рёбра")

m:on("render3d", function(frame)
    for _, p in ipairs(world.players()) do
        if not p:is_self() then
            render3d.entity(p, fill:get(), p:is_friend() and "#63FF8E" or edge:get())
        end
    end
end)

Автоответ и тихий поворот

local m = module.create{ name = "LookAtNearest", category = "combat", bind = "G" }
local range = m:slider("Дальность", 4, 1, 6, 0.1, " бл")

m:on("tick", function()
    local best, bestDistance
    for _, p in ipairs(world.players()) do
        local d = p:distance()
        if not p:is_self() and not p:is_friend() and d <= range:get() and (not best or d < bestDistance) then
            best, bestDistance = p, d
        end
    end
    if best then
        local x, y, z = best:eye()
        rotation.set(rotation.to(x, y - 0.3, z))
    end
end)

m:on("chat", function(e)
    if e.sender and e.text:find("ping", 1, true) then
        timer.after(500, function() chat.send("pong!") end)
    end
end)
Ничего не нашлось — попробуйте другое слово.