Ты уже собрал рабочий модуль. Теперь разберёмся, по каким правилам вообще живёт файл скрипта: что и когда выполняется. Без этого дальше начнутся необъяснимые вещи.
Скрипт это не программа, которая крутится в цикле. Клиент выполняет твой файл целиком ровно один раз, в момент загрузки, и больше к нему не возвращается.
Считай, что файл это сборка. Пока он выполняется, ты создаёшь модуль, настройки, надписи на экране и говоришь, какие функции звать на какие события. Дальше сам текст файла никому не нужен: работает то, что ты успел создать.
Из этого следует главное правило. Всё, что стоит в файле слева, без отступа, случится один раз при загрузке. Всё, что лежит внутри функции, случится столько раз, сколько клиент эту функцию позовёт.
client.msg("Скрипт загрузился") # напишется один раз
@events.attack
def on_attack(event):
client.msg("Удар") # напишется на каждый ударРаз файл читается сверху вниз, порядок важен: нельзя пользоваться тем, что ещё не создано. Привычный скелет выглядит так.
# 1. постоянные значения, которые не меняются
ACCENT = Color(120, 120, 255)
# 2. модуль
mod = Module("Demo", "Visuals")
mod.setDesc("Скелет обычного скрипта")
# 3. настройки: им нужен уже созданный модуль
show_text = Checkbox(mod, "Показывать текст").set(True)
# 4. переменные скрипта
shown = 0
# 5. свои функции
def title():
return "Показано раз: %d" % shown
# 6. реакции на события
@events.tick
def on_tick(event):
global shown
if not mod.isEnabled() or not show_text.get():
return
shown += 1
client.overlay(title())
# 7. отметка в лог, что всё загрузилось
print("demo загружен")Жёстко соблюдать эти семь пунктов никто не заставляет, но настройки обязаны идти после модуля, а функция должна быть объявлена выше того места, где ты её зовёшь.
Ты не пишешь ни одного import, а Module и client при этом работают. Так и задумано: клиент кладёт свои имена в скрипт перед запуском. Вот те, что понадобятся чаще всего.
| Имя | Что это |
|---|---|
Module | Создаёт модуль |
Checkbox, Slider, Mode, ColorSetting и другие | Создают настройки модуля |
events | Реакции на игровые события |
client | Сообщения в чат, надписи над хотбаром, доступ к модулям клиента |
world | Мир вокруг: игроки, мобы, ты сам |
mc | Сама игра: FPS, настройки, текущий экран |
hud, island | Свои элементы на экране и статусы Dynamic Island |
render3d | Рисование прямо в мире: боксы, линии, маркеры |
Color, font, border | Цвета, шрифты, скругления углов |
storage | Сохранение данных на диск |
Timer | Секундомер |
Это не весь список, но с остальным ты познакомишься по ходу дела. Полный перечень всегда лежит в Справочнике API.
Ты сохраняешь файл, и клиент перезапускает скрипт. Выглядит это как одно действие, но шагов два: сначала старая версия скрипта полностью убирается, потом файл выполняется заново.
Убирается всё, что ты создал через клиентские имена: модули, их настройки, элементы на экране, реакции на события. Писать код очистки не нужно, дублей не будет. Именно поэтому модуль создают вызовом Module(...), а не регистрируют где-то руками.
Имена вроде client или world лежат в обычных переменных скрипта. Значит, если ты заведёшь свою переменную с таким же именем, настоящее API под этим именем исчезнет. Ошибка при этом вылезет позже и в другом месте, поэтому ловится тяжело.
color = Color(255, 0, 0) # затёрли имя color, которым создают цвета
another = color(0, 255, 0) # ошибка: цвет больше не функция
world = "overworld" # теперь world.players() не существуетСписок занятых имён длинный, запоминать его не надо. Достаточно правила: называй переменную по смыслу, а не по типу. accent вместо color, speed_slider вместо slider, my_world вместо world.
Переменные скрипта живут ровно столько, сколько он загружен. Перезапустил скрипт, и всё обнулилось. Поэтому у любых данных есть три места, и выбор зависит от того, как долго они должны жить.
Настройки игрока. Их не надо хранить вообще: сам ползунок или галочка и есть хранилище. Клиент запишет значение в конфиг и вернёт после перезахода в игру. Твоё дело только прочитать его через .get() в нужный момент.
Временные данные. Счётчики, последняя цель, время последнего действия. Это обычные переменные Python. Не забывай global, если записываешь в них из функции.
hits = 0
@events.attack
def on_attack(event):
global hits # без global Python создаст новую переменную внутри функции
hits += 1Данные, которые должны пережить всё. Например, счётчик за всё время игры. Такое кладут на диск через storage, про него есть отдельная страница Хранилище и утилиты.