Настройка это сразу две вещи: то, что игрок видит и крутит в меню, и коробка, в которой лежит выбранное значение. Рисует её клиент, сохраняет тоже клиент. Твоё дело только прочитать значение, когда оно понадобится.
Создают настройки там же, где модуль: в файле, без отступа. Первым аргументом всегда идёт модуль, к которому настройка прицепится в меню.
mod = Module("Demo", "Visuals")
outline = Checkbox(mod, "Обводка")
speed = Slider(mod, "Скорость").min(1).max(10).step(0.5).set(5).suffix(" м/с")
target = Mode(mod, "Цель").add("Голова").add("Тело")Методы, которые что-то задают, возвращают саму настройку. Поэтому их и пишут цепочкой, как в строке со Slider. Порядок в цепочке обычно не важен, но есть одно исключение, о которое спотыкаются все.
Типов пятнадцать. Первые семь закрывают почти всё, остальные нужны реже: клавиша, строка ввода, время, градиент, точка, кривая плавности, сетка блоков и заголовок секции.
| Тип | Что это | Что отдаёт get() |
|---|---|---|
Checkbox | Галочка: включено или нет | True или False |
Slider | Ползунок: число в заданных границах | Число |
Mode | Выбор одного варианта из списка | Название варианта строкой |
Select | Выбор сразу нескольких вариантов | Проверяется через isSelected("имя") |
Range | Ползунок с двумя ручками: от и до | Пара чисел |
ColorSetting | Цвет, при желании с прозрачностью | Цвет, его можно сразу отдать в рисование |
Button | Кнопка: зовёт твою функцию по клику | Ничего, у неё нет значения |
Bind | Клавиша, которую игрок назначает в меню | Код клавиши числом, имя строкой |
TextSetting | Поле ввода: игрок пишет туда что хочет | Строка |
TimeSetting | Время крутилками: часы, минуты, секунды | Число секунд |
Gradient | Пара цветов: переход от одного к другому | Два цвета, и цвет в любой точке перехода |
PositionSetting | Точка, которую игрок таскает по площадке | Пара чисел |
Bezier | Кривая плавности: игрок тянет две ручки | Значение кривой в точке от 0 до 1 |
Blocks | Сетка блоков с поиском, отмечают галочками | Список отмеченных блоков |
Info | Заголовок секции, делит список настроек на группы | Ничего, читать нечего |
Вот все семь в одном скрипте, с настройкой каждого.
mod = Module("Kitchen", "Other")
# галочка, по умолчанию включена
silent = Checkbox(mod, "Тихий режим").set(True)
# ползунок: сначала границы и шаг, только потом значение
reach = Slider(mod, "Дистанция").min(3).max(6).step(0.1).set(3.5).suffix(" м")
# один вариант из списка. Первый добавленный выбран сразу
sort = Mode(mod, "Сортировка").add("Ближний").add("Здоровье")
# несколько вариантов сразу
targets = (Select(mod, "Цели")
.add("Игроки").add("Мобы").add("Животные")
.select("Игроки")
.min(1) # не даёт снять последнюю галочку
.draggable()) # порядок можно менять мышью
# диапазон: две ручки на одном ползунке
delay = Range(mod, "Задержка").min(0).max(500).step(10).first(50).second(200)
# цвет с прозрачностью
accent = ColorSetting(mod, "Цвет").color(120, 120, 255).alpha(True)
# кнопка: сначала функция, потом сама настройка
def reset():
reach.set(3.5)
client.msg("Сброшено")
Button(mod, "Сбросить").action(reset)Если ничего не задавать, клиент возьмёт значения по умолчанию: у ползунка это от 1 до 10 с шагом 1 и значением 5, галочка выключена, цвет белый. У Mode сразу выбран первый добавленный вариант, поэтому select() нужен, только если ты хочешь другой.
Остальные восемь в том же виде.
mod = Module("Kitchen", "Other")
# клавиша: игрок назначает её в меню, клиент запоминает
hotkey = Bind(mod, "Клавиша").set("G")
# поле ввода
nick = TextSetting(mod, "Ник").maxLength(16).set("Steve")
# время: колонки выбираешь сам, значение всегда в секундах
pause = TimeSetting(mod, "Пауза").units("minutes", "seconds").set(90)
# пара цветов
grad = Gradient(mod, "Градиент").set(Color(255, 0, 90), Color(90, 0, 255))
# точка на площадке, поле по умолчанию от -1 до 1
offset = PositionSetting(mod, "Смещение").bounds(-1, -1, 1, 1).set(0, 0)
# кривая плавности: две ручки безье
curve = Bezier(mod, "Плавность").start(0.2, 0.0).end(0.8, 1.0)
# сетка блоков с поиском
targets = Blocks(mod, "Блоки").select("obsidian").select("ender_chest")
# заголовок секции: делит настройки на группы, значения у него нет
Info(mod, "Отрисовка")Читают их так же, вызовом в тот момент, когда значение нужно.
@events.tick
def on_tick(event):
if not mod.isEnabled():
return
if pause.get() < 30: # секунды
return
if "minecraft:obsidian" in targets.getSelected():
client.overlay("обсидиан отмечен")
x, y = offset.get()
client.overlay("%s, смещение %.2f %.2f, плавность %.2f"
% (nick.get(), x, y, curve.ease(0.5)))
@events.key
def on_key(event):
if not event.isPress(): # иначе сработает ещё и на отпускании
return
if hotkey.isKey(event.getKey()): # сравниваем с назначенной клавишей
client.msg("нажали " + hotkey.name())Значение читают через .get() и делают это в тот момент, когда оно нужно, прямо внутри функции. Складывать его заранее в переменную нельзя: игрок подвинет ползунок, а твоя переменная об этом не узнает. Вызов дешёвый, зови сколько нужно.
@events.tick
def on_tick(event):
if not mod.isEnabled() or silent.get():
return
lo, hi = delay.get() # диапазон приходит парой чисел
if not targets.isSelected("Игроки"): # мультивыбор спрашивают по имени
return
if sort.get() == "Здоровье": # режим сравнивают со строкой
pass
client.overlay("дистанция %.1f, задержка %d-%d мс" % (reach.get(), lo, hi))Бинд это клавиша, которая включает модуль. Он живёт на самом модуле, и назначает его обычно игрок мышкой в меню. Клиент бинд запоминает.
Если клавиша нужна не для включения модуля, а для отдельного действия, заведи настройку Bind: она рисуется в меню такой же строкой, что и бинд модуля, и игрок назначает её мышью. В скрипте её сравнивают с клавишей из события.
Бинд бывает и сочетанием: игрок в меню держит Ctrl и нажимает G, клиент запоминает CTRL + G. Скрипту менять ничего не нужно, isKey() сам проверит, что модификаторы зажаты. Из скрипта сочетание задают строкой: .set("CTRL+G").
mod = Module("Shout", "Other")
hotkey = Bind(mod, "Клавиша крика").set("H")
@events.key
def on_key(event):
if not mod.isEnabled() or not event.isPress():
return
if hotkey.isKey(event.getKey()):
client.msg("Ааа!")Отсюда и приём: модуль-кнопка. Он срабатывает по бинду и сразу выключается сам.
mod = Module("Ping", "Other")
mod.setDesc("Написать в чат по бинду")
@events.module_toggled
def on_toggle(event):
if event.getModule().getName() != "Ping":
return
if not event.isState():
return # реагируем только на включение
client.msg("Пинг!")
mod.setEnabled(False) # сразу гасим, модуль работает как кнопкаЕсли действие вообще не надо вешать на клавишу, бери настройку-кнопку: она рисуется в меню под модулем и зовёт твою функцию по клику.
mod = Module("Greeter", "Other")
def say_hi():
client.msg("Привет!")
Button(mod, "Поздороваться").action(say_hi)Настройки чужих, встроенных модулей тоже можно читать и менять, но там свои правила. Про это страница Модули и настройки клиента.