Твой персонаж это mc.player. Ровно тот же объект вернёт world.self(), бери что удобнее. Это настоящий игрок из игры, со всеми его методами: координаты, здоровье, углы взгляда.
Пока ты не в мире (в главном меню, на экране подключения) игрока нет, и mc.player вернёт None. Поэтому любой код, который лезет к игроку, начинается с проверки.
@events.tick
def on_tick(event):
if not world.ingame(): # мир и игрок вообще есть?
return
p = mc.player # он же world.self()
client.overlay("%.1f, %.1f, %.1f" % (p.getX(), p.getY(), p.getZ()))Вот то, что нужно почти в любом скрипте.
| Метод | Возвращает | Что делает |
|---|---|---|
getX() / getY() / getZ() | float | Координаты игрока |
getEyeY() | float | Высота глаз. Нужна для трассеров и лучей |
getYaw() / getPitch() | float | Куда смотрим: yaw это поворот вбок, pitch наклон вверх-вниз |
setYaw(v) / setPitch(v) | ничего | Резко выставить углы взгляда |
getHealth() / getMaxHealth() | float | Здоровье. 2.0 это одно сердечко |
isOnGround() | bool | Стоим на земле? |
isSprinting() / isSneaking() | bool | Бежим? Крадёмся? |
isTouchingWater() | bool | В воде? |
isUsingItem() | bool | Держим ПКМ: едим, натягиваем лук, блокируем щитом |
isAlive() | bool | Живы? |
distanceTo(entity) | float | Расстояние до другой сущности, в блоках |
setVelocity(x, y, z) | ничего | Задать скорость: куда и как быстро летим |
getId() | int | Номер сущности в сети, пригодится для пакетов |
Ник и FPS лежат не в игроке, а в самом клиенте: mc.getSession().getUsername() и mc.getCurrentFps(). Соберём из всего этого маленький монитор состояния:
mod = Module("LowHealth", "Player")
mod.setDesc("Кричит, когда здоровья мало")
warned = False
@events.tick
def on_tick(event):
global warned
if not mod.isEnabled() or not world.ingame():
return
p = mc.player
hp = float(p.getHealth())
# строка над хотбаром: ник, координаты, fps
client.overlay("%s | %d %d %d | %d fps" % (
mc.getSession().getUsername(),
int(p.getX()), int(p.getY()), int(p.getZ()),
mc.getCurrentFps(),
))
# пишем один раз, а не каждый тик
if hp <= 6.0 and not warned:
client.warn("Мало здоровья: %.1f" % hp)
warned = True
elif hp > 10.0:
warned = FalseТик это один ход игры, их 20 в секунду. Без флага warned чат бы залило двадцатью строчками в секунду. Хранить состояние можно в обычных глобальных переменных Python: они живут, пока живёт скрипт, и обнуляются при перезагрузке.
Yaw это поворот влево-вправо, pitch наклон вверх-вниз. Самый прямой способ повернуться, просто присвоить углы игроку. Камера дёрнется мгновенно, как будто ты сам рванул мышкой:
def look(delta_yaw, delta_pitch):
p = mc.player
if p is None:
return
p.setYaw(float(p.getYaw()) + float(delta_yaw))
# pitch зажат в рамки: -90 смотрим строго в небо, +90 строго в пол
p.setPitch(max(-90.0, min(90.0, float(p.getPitch()) + float(delta_pitch))))
turn = Module("TurnAround", "Player")
Button(turn, "Развернуться").action(lambda: look(180.0, 0.0))Второй способ это событие rotate_camera. Оно приходит на каждое движение мыши и даёт подправить, насколько сильно повернётся камера, ещё до того как игра это применит. Сделаем замедлитель мыши на время, пока натягиваешь лук:
mod = Module("BowAim", "Combat")
mod.setDesc("Снижает чувствительность мыши, пока натягиваешь лук")
factor = Slider(mod, "Sensitivity").min(0.1).max(1.0).step(0.05).set(0.4)
@events.rotate_camera
def on_rotate(event):
if not mod.isEnabled() or not world.ingame():
return
if not mc.player.isUsingItem(): # ничего не используем, не мешаем
return
k = float(factor.get())
event.setDeltaYaw(event.getDeltaYaw() * k) # delta это на сколько градусов повернуть
event.setDeltaPitch(event.getDeltaPitch() * k)Скрипт не нажимает клавиши на настоящей клавиатуре. Он дёргает биндинги самой игры: mc.options.forwardKey.setPressed(True). Игра будет считать клавишу зажатой, пока ты сам её не отпустишь.
| Поле mc.options | Что это |
|---|---|
forwardKey / backKey | Вперёд и назад (W, S) |
leftKey / rightKey | Вбок влево и вправо (A, D) |
jumpKey | Прыжок (пробел) |
sneakKey | Присед (Shift) |
sprintKey | Спринт (Ctrl) |
attackKey | Удар и ломание блока (ЛКМ) |
useKey | Использовать и поставить блок (ПКМ) |
У каждого биндинга есть setPressed(bool), isPressed() и wasPressed(). Напишем автобег. Главное правило: трогай клавиши только пока модуль включён, иначе ты будешь каждый тик отжимать W и обычная ходьба сломается. А когда модуль выключают, отпусти клавиши руками, иначе персонаж убежит в закат.
mod = Module("AutoWalk", "Movement")
mod.setDesc("Держит W и спринт, пока включён")
def press(key_name, state):
getattr(mc.options, key_name).setPressed(bool(state))
@events.tick
def on_tick(event):
if not mod.isEnabled() or not world.ingame():
return # выключены, вообще не лезем к клавишам
press("forwardKey", True)
press("sprintKey", True)
@events.module_toggled
def on_toggle(event):
# обработчика "модуль выключили" нет, ловим это событием
if event.getModule().getName() == "AutoWalk" and not event.isState():
press("forwardKey", False)
press("sprintKey", False)Есть путь поаккуратнее, событие input. Оно срабатывает, когда игра уже собрала весь ввод за тик, и позволяет переписать его. Движение тут не нажатия, а числа от -1.0 до 1.0.
| Метод события | Что делает |
|---|---|
getForward() / setForward(v) | Вперёд-назад: 1.0 вперёд, -1.0 назад, 0.0 стоим |
getStrafe() / setStrafe(v) | Влево-вправо, те же числа |
isJump() / setJump(b) | Прыжок |
isSneak() / setSneak(b) | Присед |
isSprint() / setSprint(b) | Спринт |
setYaw(yaw) | Пересчитать ввод под другой yaw, чтобы идти по камере при тихой ротации |
setYawSmooth(yaw) | То же, но плавно |
mod = Module("WaterJump", "Movement")
mod.setDesc("Сам всплывает в воде плюс вечный спринт")
@events.input
def on_input(event):
if not mod.isEnabled() or not world.ingame():
return
if mc.player.isTouchingWater():
event.setJump(True) # всплываем, пробел зажимать не надо
if event.getForward() != 0.0: # спринт только когда реально идём вперёд
event.setSprint(True)