Для тех, кто не знаком, Minecraft — это Javaпесочница, ориентированная на разрушение и построение блоков, а Redux — глобальная библиотека управления состоянием для JavaScript, обычно используется в качестве инструмента для решения проблем в веб-приложении.Короче говоря, Redux и Minecraft созданы на двух совершенно разных языках, так как они вообще могут работать вместе?

Java может поддерживать движок JavaScript во время выполнения, например Nashorn, Rhino, GraavlVM и другие. Эти механизмы эффективно позволяют вам писать код JavaScript для приложения Java. Это становится привлекательным, поскольку позволяет существующим разработчикам JavaScript создавать что-то на Java, не зная Java.

Minecraft имеет довольно большую сцену моддинга, которую можно разбить на разные области, такие как серверные плагины, моды, пакеты данных, пакеты ресурсов и т. д. Плагин, пакет данных и пакет ресурсов — это тип мода, который может поддерживать ваниль. клиенты, в то время как мод (например, использование Forge) требует модифицированного клиента. В мире плагинов существует множество различных плагинов, таких как Bukkit, Spigot, Paper, Purpor, Bungeecord и многие другие.

Имея все это в виду, я использовал серверный плагин, предоставляющий движок JavaScript (GraalVM) под названием Grakkit. Grakkit — это непредвзятая реализация подключаемого модуля сервера JavaScript Engine, которая предоставляет библиотеку определения типов, связанную с основными классами, объектами и типами Java и Paper. Это позволяет вам писать код на JavaScript, получая доступ к реализациям Java с помощью intellisense.

Примечание. JavaScript не будет иметь такого же интеллекта, как Java, поскольку Grakkit генерирует собственные определения типов, используя смесь JavaDocs и отражения. Доступ к различным API и плагинам может иметь 0 intellisense, пока кто-то не создаст для них определения типов.

Приключение

В течение последних двух лет я размещал свой собственный сервер Survival Minecraft под названием Super GoatLand и хотел предоставить какой-то уникальный контент. Первоначально я использовал Denizen, серверный плагин, позволяющий программировать на основе YML для Minecraft. Хотя это работало хорошо, это была очень нишевая вещь, и когда вышел Minecraft 1.17, в Denizen все сломалось. В тот момент я начал искать новые варианты и открыл для себя Grakkit, который был около 7 месяцев назад.

В течение первого месяца использования Grakkit я смог провести рефакторинг значительной части функций TypeScript от Denizen. Используя TypeScript и другие инструменты, я смог легко расширять каждую функцию с гораздо большей скоростью. Забавная особенность, которую я создал, — это механика Rotten Flesh. Гнилая плоть — это съедобный предмет, который выпадает из зомби, у которого на самом деле нет никакой цели, кроме загрязнения инвентаря. Однако с этой новой механикой, когда игрок ест гнилую плоть, теперь есть шанс вызвать событие случайной рулетки, в результате чего случайный игрок выбирается, а затем случайным образом награждается или наказывается в зависимости от события.

В это время я изучал Redux в Grakkit. По опыту я оценил преимущества Redux, особенно Redux Toolkit, и хотел реализовать его здесь для своих случаев использования. К сожалению, первое внедрение библиотеки не удалось из-за immer. Первоначально я думал, что это несовместимо, однако недавно со второй попытки я обнаружил, что это так.

В течение первых нескольких месяцев периодической разработки я не смог очень хорошо решить некоторые проблемы, такие как настойчивость. Варианты использования, которые у меня были, просто не требовали базы данных, поскольку большая часть была связана с кулдаунами и флагами игрока (например, запись пользовательских достижений игрока). Я создал свой собственный уровень хранения, но он всегда казался ограничивающим и сложным для использования новых функций.

Хорошая часть

Когда недавно вышел Minecraft 1.18, я снова начал заниматься разработкой. Была дискуссия о внутриигровой валюте и отсутствии «поглотителей денег», что привело к блестящей идее разработать новые предметы, которые игроки могли бы покупать на свои с трудом заработанные в игре деньги. Одной из идей был предмет, который может замаскировать любую сущность (монстров/животных/вагонетки/стойки для брони) с помощью костюма. Это позволит игроку замаскировать зомби под жителей или наоборот. Чтобы этот элемент работал, ему потребуется другая зависимость под названием LibsDisguises. Во время разработки я планировал, что LibsDisguises будет обрабатывать сохраняемость данных для маскировки, но, к сожалению, я обнаружил, что они не сохраняются и не восстанавливаются при сбое сервера. Это было нехорошо, тем более что версия 1.18 вызывала больше сбоев, чем раньше.

В этот момент я начал изучать свои варианты и решил еще раз попробовать Redux Toolkit. После нескольких проб и ошибок у меня наконец-то что-то заработало. Когда игрок надевал костюм на объект, он отправлял действие и обновлял состояние. С помощью быстрого кода я даже смог заставить его сохраняться и увлажнять магазин без проблем. Таким образом, всякий раз, когда сервер перезагружался, падал и т. д., он всегда восстанавливал костюмы. Миссия выполнена.

Работа Redux в Minecraft — это здорово, но можно ли было сделать еще один шаг и подключить Redux DevTools? Моей первой мыслью было создать поддельное веб-приложение Redux, синхронизировать состояние и действия, а затем использовать DevTools в поддельном веб-приложении. После дальнейших исследований я обнаружил другой метод, использующий для связи WebSockets. К сожалению, некоторые проблемы в Grakkit не были полностью решены, например, Fetch и WebSockets. Еще один разработчик Grakkit смог создать однопоточную базовую реализацию WebSocket, которую я в конечном итоге использовал, что было первым шагом.

Поскольку эта реализация WebSocket не могла поддерживать каналы (для SocketCluster), мне нужно было создать уровень посредника, который включал соединение двух разных потоков WebSocket вместе. Вы можете увидеть такой пример в https://github.com/MercerK/grakkit-redux-showcase/blob/main/scripts/reduxDevTools/index.ts. Последним шагом был запуск CLI-сервера Redux DevTools и его подключение. Я был одновременно поражен и удивлен, когда это наконец заработало, особенно когда было около полуночи.

После некоторых исправлений ошибок и расширения Redux я смог интегрировать кулдауны игроков, флаги игроков и создать слой постоянства/гидратации специально для игроков. Когда игрок присоединялся, он загружал его состояние. Когда игрок уходил, он сохранял и удалял его состояние. Благодаря DevTools у нас появился визуальный способ увидеть состояние.

Открытый источник

С тех пор, как я продемонстрировал эту возможность, я усердно работал над тем, чтобы открыть исходный код некоторых из этих работ. Первый проект, https://github.com/MercerK/grakkit-boilerplate, позволяет разработчикам быстро запустить новый проект для Minecraft, используя Grakkit, без необходимости возиться с процессами сборки. Как только это было завершено, родилась Grakkit Redux Showcase (https://github.com/MercerK/grakkit-redux-showcase). Это проект, который демонстрирует Redux в Minecraft вместе с Redux DevTools. Когда игрок копает, убивает, умирает, присоединяется или выходит, он отправляет действие. Когда что-то происходит, вы можете наблюдать за каждым действием и видеть состояние.

Последние мысли

Это было веселое приключение, и я очень рад начать работать над новыми функциями для своего сервера, чтобы увидеть, как далеко я могу зайти в Redux. Я не считаю, что решил вышеуказанные проблемы наиболее эффективным способом, и всегда есть возможности для улучшения во многих областях, но для меня это отправная точка, и она работает достаточно хорошо для моих вариантов использования. Спасибо за чтение!

Я рекомендую вам ознакомиться со следующими проектами: