Как использовать http внутри Minecraft?
Приветствую всех читателей Хабра!
Расскажу предысторию создания данного поста
Недавно, скучая после безумно нудного учебного дня и залипая в очередной раз на любимом видеохостинге, мне наткнулось интересное видео, сподвигшее к созданию невероятного (Внизу версия на Рутуб, выложенная мной, для читателей из России).
Как можно видеть с самого видео, человек, нажимая на кнопку в Майнкрафте, включает у себя лампу в реальной жизни.
Круто! Но как это работает?
Почитав комментарии (и ответ самого создателя видео) всё встало на свои места.
Комментарий создателя
Перевод:
Прежде чем я начну объяснять, как это работает, давайте назовем устройства, которые участвуют в процессе:
MCPC — компьютер ComputerCraft в Minecraft
MyServ — мой IRL-сервер
PowSwitch — интеллектуальный выключатель питания, подключенный к лампеLamp подключен к коммутатору питания Wi-Fi (PowSwitch). PowSwitch подключается к Интернету и имеет API для управления им.
Компьютеры ComputerCraft могут выполнять простые HTTP-веб-запросы. Они не способны выполнять запросы / вызовы API.
Вот тут-то и появляется MyServ — он реагирует на HTTP-веб-запрос MCPC и «переводит» его в вызов API PowSwitch.
Проще говоря — когда вы нажимаете кнопку в Minecraft, MCPC пытается загрузить случайные данные из MyServ. MyServ обнаруживает запрос MCPC и реагирует отправкой команды через API PowSwitch. Эта команда API заставляет PowSwitch переключать питание и, следовательно, включать лампу enitre.
»Ну ничего себе! » — подумал я — »Это сколько же возможностей даёт один единственный мод! ».
И… так оно и есть. Через модификацию и HTTP можно связаться с сервером и через него передавать данные!
Однако всё по порядку.
Сейчас я собираюсь рассказать о том, как конкретно можно это сделать на примере отправки сообщений через Telegram-бота через фреймворк Express.js (на базе Node).
Опишем все «инструменты» по порядку (Если вдруг чего-то из этого не знаете, не волнуйтесь! В процессе объяснения всё будет понятно, а вместо node.js Вы можете использовать любой инструмент, позволяющий прописывать API — в данном случае, это большой роли не играет):
Майнкрафт мод — «Computer Craft (CC) Tweaked».
Версия Майнкрафта — 1.20.1 (Forge).
Туннель («зеркало» нашего локального сервера под уникальным доменом + созданным с включенным SSL (https), откуда будут идти запросы) — ngrok.
Обращения к телеграм-боту — node-telegram-bot-api.
API на Node + Express.js.
Важно учитывать то, что подчёркнуто!
Возможно, у внимательных читателей возникнет вполне резонный вопрос
Почему создатель того видео использует Computer Craft, а мы используем именно CC Tweaked?
Вопрос хороший! На него есть ответы.
— Во-первых, CC Tweaked всё ещё развивается, дышит и поддерживается, о чём свидетельствует частое появление коммитов в его репозитории. У него простая официальная документация, описывающая всё лучше (особенно в моментах взаимодействия с сервером), чем оригинальная, а также живое коммьюнити, так что при наличии каких-то вопросов Вам, скорее всего, ответят достаточно быстро.
CC Tweaked — это форк оригинального Computer Craft.
Всё, что применимо к Computer Craft — применимо к CC Tweaked.
Репозиторий CC Tweaked на момент 14.12.2024
Увы, то же самое нельзя сказать про оригинальный Computer Craft — его последняя версия была выпущена в 2017 году на версию 1.12.2, а репозиторий обновляется раз в несколько лет ради каких-то совсем мелочных изменений.
Коммиты репозитория Computer Craft
Официальный веб-сайт и сам говорит, что, увы, жизнеспособности у него нет.
Скрин с официального сайта www.computercraft.info
— Во-вторых, протокол HTTP живёт своей жизнью на оригинальном моде.
Скрин с версии 1.8.9 (стабильной) Computer Craft при попытках обратиться по http к «www.google.com» (что используется в туториалах) и к собственному ngrok-туннелю.
При попытках взаимодействия с http постоянно вылазят ошибки, что «невозможно получить данные с сервера» — грубо говоря, nil. На оригинальном моде вообще В ПРИНЦИПЕ при обращении к любому эндпоинту будет возвращаться ниловое значение.
Забавно, что в поиске решений проблемы люди рекомендуют поменять значения в конфигах мода для работы с http. (Представили моё лицо, когда оказалось, что там уже прописано ровно то, что и предлагают при решении этой ошибки?)
Предложение решения на Computer Craft
Буквально тот же самый запрос без замен конфига, но уже на CC Tweaked (Правильный респонс)
Вероятно, CC Tweaked, в связи с рефакторингом, исправлением старых ошибок и превнисением нового функционала в мод (напомню, последняя версия оригинала — 2017 год), настроен на более новую отправку запросов по http, поэтому Computer Craft в этом плане выглядит проигрышно, нежели его форк.
Уяснив это, вопросов на этот счёт возникать не должно.
Ну и, вероятно, автор сразу имел в виду конкретно Tweaked, т.к. оригинальное видео вышло всего-лишь 4 года назад, но это лишь мелочи.
Приступим к созданию!
Для начала нужно подготовить всё нужное для мода:
Скачать мод;
Создать бота;
Зарегистрироваться и установить ngrok.
Создать наш node.js проект.
Включить ngrok и создать туннель между локалхостом.
Начнём с первого и самого простого пункта — мод
Переходим по ссылке (У вас сразу должна начаться загрузка на версию 1.20.1. У Вас уже на тот момент должен быть установлен Forge 1.20.1).
После скачивания копируем из папки загрузки и переходим в путь — »C:\Users\Пользователь\AppData\Roaming\.minecraft\mods» — куда и вставляем наш мод.
Конгратулатионс — мод у нас в кармане.
Двигаемся дальше — создание бота
Здесь всё тоже не очень сложно.
Заходим в Telegram и ищем BotFather.
Начинаем с ним диалог, после чего создаём нового бота:
Создание бота в BotFather
Любопытненько.
Не пытайтесь использовать этого бота.
На момент выкладки поста его уже не существует.
Далее просто начинаем переписку с ним:
/start у нашего бота
»HTTP API token», который он нам выдал, понадобится при создании нашего бота с помощью Ноды.
Третий пункт — ngrok.
Если Вы из России (как я), то просто так Вам на этой платформе не зарегистрироваться:
Your location was determined using your IP address
Однако это нас не остановит.
Качайте VPN (любой, который нравится и работает), используйте почту НЕ MAIL.RU и смело снова пытайтесь зарегистрироваться — нажимайте на кнопочку »Sign Up».
Я обычно захожу через GitHub, но можете зарегистрироваться прямо через почту или Гугл-аккаунт.
Далее нас встречает приветственная страничка.
Welcome!
Ngrok требует VPN только на этапе регистрации.
Далее он не понадобится — можете его отключить.
Windows окошко
Переходим вниз к пункту »Connect» — выбираем »Download» и качаем для своей системы (64\32 бита).
Нам скачался архив с exe-файлом. Просто перекидываем на своё рабочее место и открываем.
После открытия вставляем всю команду с нашим »add-authtoken» и нажимаем Enter.
Радуемся жизни!
Четвёртый пункт — создание проекта.
В моём случае, Express.js (Однако Вы можете писать, на чём душе будет угодно).
Всё как всегда.
Инициализируете проект (
npm init -y
);Скачиваете пакеты express, nodemon (для реал-тайм перезагрузок) и node-telegram-bot-api (
npm i express nodemon node-telegram-bot-api
).
Создание проекта
После чего создаёте index.js в той же директории и меняете скрипты запуска в package.json, вставляя туда обращение к nodemon при дев-сервере и к node при старте билда.
Не забываем также указать, что мы используем ES-модули, чтобы использовать импорты как в обычном проекте на js.
package.json
Инициализируем Express в нашем index.js файле:
Код express.js
И далее в терминале просто запускаем наш код через npm run dev
:
Запуск проекта
Мы запустили наш проект, однако этого недостаточно для Tweaked. Мод не может слушать localhost, поэтому мы должны, скажем, отзеркалить его на какой-то рабочий домен.
Последнее — туннель ngrok
Чувствую, что немного устали)
Не волнуйтесь, данный шаг станет последним, после чего зайдём в сам Майнкрафт.
Чтобы создать туннель с проектом нужно воспользоваться командой ngrok http 3000
. Где »3000» — это порт, который мы задали через Express (app.listen(3000)
).
Грубо говоря, мы говорим ngrok’у: «Чувак, создай нам туннель через http по порту, который мы дали локалхосту»:
Создаём туннель
После нажатия Enter у нас открывается окошко, в котором мы можем взять наш URL, по которому сможем обращаться в Майнкрафте (https://be84–95–106–165–71.ngrok-free.app):
Мы создали туннель!
Поздравляю! Мы готовы двигаться дальше! А дальше только интереснее
Мы подошли к тому, чтобы запустить наш Майнкрафт
Я НЕ буду углубляться в сам CC Tweaked, ровно как и в язык, на котором пишется код в нём — Lua.
Моя задача — лишь познакомить с ним и показать Вам, насколько просто использование HTTP через этот мод.
Если всё же интересно изучить конкретно мод, вот плейлист с уроками на все самые важные темы на русском языке:
https://www.youtube.com/watch? v=7HrWg_P7uKk&list=PL3A9AC22762B7829E
Запускаем на версии Forge 1.20.1 (Как было обговорено раньше) и создаём карту.
Инвентарь в творческом режиме
Можем обратить внимание, сколько предметов может предложить мод, однако нам интересна вещь, без которой мы не сможем обращаться к нашему серверу — компьютер.
Так как мы хотим, чтобы компьютер, как TabNine, предлагал нам автокомплит, а также в принципе имел больше возможностей, чем обычный компьютер, возьмём продвинутый (большой жёлтый блок в самом начале):
Продвинутый компьютер в инвентаре
Далее открываем его, после чего вводим команду edit (название файла).lua
.
Запоминаем, что »edit» в Computer Craft — это открытие файла для изменения.
edit index.lua
Нам открывается пустое окошко, которое является своего рода блокнотом, куда мы можем вводить наш код, а по нажатию ctrl, и выбрав »Run» стрелочками слева снизу, дополнительно нажав Enter, запустить (Выйти из этого режима можно также нажав ctrl):
Блокнот CC Tweaked
Переменные здесь создаются без объявления каких-либо типов или даже ключевых слов. Просто какому-то названию переменной присваиваем какое-то значение (Пайтонисты радуются).
Подобной переменной станет наш URL, который нам выплюнул ngrok. Просто выписываем как отдельную константу, чтобы затем воспользоваться:
NODE_ENPOINT
Теперь мы даже можем обратиться через http и сделать какой-то демо-запрос.
Для этого у нас есть глобальный класс »http», через который мы можем создать условный GET-запрос.
Вывести результат в консоль мы можем с помощью функции print()
(Пайтонисты радуются).
Наравне с GET мы также можем сделать POST-запрос. Хедеры для него указываются вторым аргументом после эндпоинта.
Ровно как и использовать вебсокеты прямо на базе мода, что, в хорошем смысле, не может не удивлять. (Это же было и в оригинальном моде).
Полная таблица методов для http в CC Tweaked выглядит так:
Таблица методов http
Переходим к написанию кода на JavaScript
Суть программы
Суть нашей программы будет заключаться в том, что у каждой переписки есть свой id (так называемый »chat id»). Мы будем следить за его наличием в боте. Если таковой имеется, будем отправлять туда сообщения до тех пор, пока пользователь нажимает на кнопку, которая подведена редстоуном. Если новый пользователь введёт сообщение в него, то бот переключится на нового пользователя, и при «накликивании» в Майнкрафте сообщения будут идти на него. Так будет до тех пор, пока новый пользователь не заблокирует нашего бота. Если всё же произойдёт блок, но в Майнкрафте произошёл ещё один клик на кнопку, то мы шлём ошибку, а затем снова (с нуля всего цикла) запрашиваем написать боту сообщение.
Мне подсказали, что подобного бота стоит назвать «Бот-ждун».
Ради бога, думаю, правда можно назвать так)
Подключаемся к боту
Сначала, чтобы наш бот работал, нам нужен его HTTP API token, который так к стати нам дал BotFather ещё в самом начале.
Далее нам нужно инициализировать бота через класс из библиотеки, указав также polling (Грубо говоря, мы будем следить за тем, что пришло к нашему боту в реальном времени).
Давайте для теста также укажем боту, чтобы на сообщение он нам отвечал тем же сообщением (Подобные боты называются »Эхо-ботами»).
Перед этим давайте выведем то, что бот даёт при ответе на то, что мы написали ему какое-то сообщение. Для этого воспользуемся методом ».on('message', () => {})
» и вызовем console.log()
с ответом на событие.
Ответ на событие отправки сообщение
Видим, что ответом является большой объект, из которого нам на данный момент нужно вытянуть текст — ключ »text», а также айди чата (ключ »chat.id»), по которому нужно отправить сообщение.
Чтобы создать «эхо» просто воспользуемся методом ».sendMessage(msg.chat.id, msg.text)
».
Результат работы
Как видим — всё работает!
Пишем Express.js
Далее мы напишем небольшое API.
В связи с тем, что приложение тестовое, небольшое, будем обращаться к обычному »/»
Для начала создадим обращение к нашему Экспресс'у через GET-запрос.
app.get("/", function (request, response) { response.send("Welcome") })
«Welcome»
На основе чего зададим следующую логику:
На глобальном уровне пропишем мутируемую переменную chatId, которой будет являться чат, на который в данный момент будут слаться сообщения.
В теле callback’а запроса будем смотреть, если наш чат не нулевой.
Если такое условие соблюдается, то мы выполняем отправку сообщения боту, а также обрабатываем этот промис на наличие reject’а (Коим и является проверкой на блок у пользователя. Как раз таки в.catch()
мы и будем его обнулять, ожидая нового айди).
Если условие не соблюдается, то мы просто возвращаем, что хотим от пользователя ввести какое-то сообщение.Дополним наше »
.on('message')
» присваиванием нового значения для chatId, а также отправкой его через бота.Также пропишем функцию »sendResponse», которая будет возвращать void — отправку на запрос (грубо говоря, вывод в консоль в Майнкрафте) функции со строкой, которая разделяется с помощью »\n», а также трёх сплошных линий и принимать два аргумента: саму функцию для отправки и строчку, которую мы должны отправить.
Важной частью всего колбэка является наличие хедера
ngrok-skip-browser-warning
.
Видите ли, когда Вы переходите по домену, который Вам дал ngrok, то вначале мы видим приветственное «Хеллоу!» от нашего дорогого туннеля.You are about to visit ngrok
В чём основная проблема — запрос тоже видит это приветственное сообщение, которое, словно кирпичная стена, не даёт получить нам тот ответ, который нужен, из-за чего мы будем получать nil вместо ответа.
Наш хедер, который мы поставим с помощью »
response.set('ngrok-skip-browser-warning', 'skip-browser-warning')
» будет важной частью правильной работы.Результат кода по итогу должен выглядеть так:
Код проекта
Или (для копирования):
import Express from 'express';
import TelegramBot from "node-telegram-bot-api";
const app = Express();
const TOKEN = "7876670462:AAHVTSEIoblDhauy1x0U2fQG9lT-LoqKLvI";
const bot = new TelegramBot (TOKEN, {polling: true});
let chatId = 0;
const sendResponse = (respFoo, str) => {
return respFoo.send (str + '\n ---');
}
app.get (»/», function (request, response) {
response.set ('ngrok-skip-browser-warning', 'skip-browser-warning');
if (chatId > 0) {
bot.sendMessage (chatId, `Minecraft program was launched. Message was sent on chat id — »${chatId}»`).then (() => {
sendResponse (response, `Message sent. Current chat id — »${chatId}»`);
}).catch (() => {
sendResponse (response, `Oops! Something went wrong with chat id »${chatId}». Check, if your bot is not blocked and type it any message to set new chat id!`);
chatId = 0;
})
} else {
sendResponse (response, `You need to pass a chat id to the bot. Pass it first and come back to send a message!`);
}
});
bot.on ('message', (msg) => {
bot.sendMessage (msg.chat.id, `Current chat id for sending messages is ${msg.chat.id}`);
chatId = msg.chat.id;
})
app.listen (3000);
Также необходимо указать ».readAll()
» при GET в CC Tweaked. Он позволяет прочитать всё содержимое файла правильно и показать нам именно строчку, а не таблицу (»table»).
readAll ()
Письмо счастья
И теперь, если при запуске программы (ctrl + Enter и выбрать »Run») Вам выдался текст в Майнкрафте, а при написании боту вернулся ответ «Message sent…» — поздравляю! Ваш код работает верно.
Для полноты картины давайте выведем наш результат в монитор
Мод позволяет нам использовать мониторы, чтобы смотреть результаты программы, не отходя от концепции блоков.
Давайте поставим справа четыре блока продвинутого монитора и выведем на него сообщение.
Вначале построим прямо справа от нашего компьютера 4 блока монитора (блоки расширяют друг друга, отчего превращаются в один большой монитор).
Затем нужно обратиться к монитору. Чтобы это сделать, нужно выйти из программы — (ctrl + Exit + Enter), после чего прописать ключевое слову »monitor», указать, в каком направлении от компьютера стоит монитор (»right» / »left» / »top» / т.д.) и написать название программы для вывода. Всё просто!
Прописываем обращение к монитору
Наш рабочий монитор
Осталось доделать совсем немного, чтобы назвать наши планы завершёнными ;)
Взаимодействие с кнопкой в Майнкрафте
Computer Craft из коробки позволяет взаимодействовать с редстоуном. Для этого у него на глобальном уровне прописан класс »rs» (Акроним — «RedStone»).
Красный камень должен взаимодействовать с компьютером. При подведении одного к другому, а также при последующем взаимодействии через команды »вкл.»/»выкл.» можно использовать большое количество методов.
Методы взаимодействия с красным камнем (Input / Output)
Одним из таких, который нужен для того, чтобы смотреть нажалась кнопка или нет, является ».getInput()
». Через него мы будем тыкать запросы, чтобы затем выводить их результаты.
В чём основная проблема?
»
.getInput()
» НЕ слушает ввод через редстоун постоянно. Его главная задача заключается в том, чтобы лишь один раз посмотреть наличие и вывести какой-то ответ.
Поэтому было решено сделать троттлинг на прослушивание событий кнопки.Что такое троттлинг?
Говоря грубо, мы раз в какое-то время будем смотреть изменение состояния чего-либо. В нашем случае, будет воспроизводиться функция »sleep()
» с цикломwhile
. Данная функция не даёт потоку программы двигаться, пока не пройдёт определённый промежуток времени, который был указан в параметры этой функции.
Давайте напишем этот цикл:
Троттлинг нажатия кнопки
Компьютер с красным камнем
И не забываем подвести строго слева (как прописано в направлении — »left») кнопку с красным камнем.
Далее делаем всё ту же процедуру:
»monitor right index.lua
» — затем нажимаете на кнопочку — Пишет ответ!
»
monitor right index.lua
»;Затем нажимаете на кнопочку;
Пишет ответ — вам приходит в Telegram уведомление!
Эпилог
Возможно, данное решение требует некоторой программной подготовки ради того, чтобы хотя бы что‑то написать, однако способ подобного взаимодействия сводит с ума. Сводит с ума также тот факт, сколько всего можно таким образом реализовать.
Попробуйте и Вы сделать что‑то интересное!
Буду очень рад узнать, что моё объяснение кому‑то хотя бы минимально в этом плане помогло).
Также буду очень рад услышать, что меня можно где‑то поправить.
Если есть какие‑то вопросы по коду, по содержанию — пишите, на всё постараюсь ответить.
Всем добра!