Руководство разработчика MagmaCore
Сгенерированный справочник Java содержит классы, методы и сигнатуры с поиском, а также версию исходников и коммит каждого модуля.
MagmaCore встраивается в использующие её плагины посредством shading. Это не отдельный серверный плагин; не указывайте её в depend, как будто игроки могут установить самостоятельный JAR MagmaCore.
Зависимость и упаковка
Текущая координата разработки — com.magmaguy:MagmaCore:2.2.0-SNAPSHOT. Она опубликована в репозитории выпусков MagmaGuy, а не в репозитории снимков, где хранятся только старые снимки 1.x. Содержимое снимка может измениться без смены строки версии, а опубликованная сборка обновляется не с каждым выпуском плагина, поэтому может быть старше MagmaCore, встроенной в текущие плагины. Сборка, опубликованная 5 октября 2026 года, включает описанные ниже API обновлений без перезапуска и матчей. Чтобы компилировать против более новых неопубликованных изменений, соберите MagmaCore из исходников и опубликуйте её в Maven Local, как описано в разделе Пересборка потребителя после изменения библиотеки. Для воспроизводимой сборки фиксируйте полученный артефакт.
repositories {
maven("https://repo.magmaguy.com/releases")
}
dependencies {
implementation("com.magmaguy:MagmaCore:2.2.0-SNAPSHOT")
}
<repositories>
<repository>
<id>magmaguy-releases</id>
<url>https://repo.magmaguy.com/releases</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>MagmaCore</artifactId>
<version>2.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
Эти объявления подключают зависимость. Настройте задачу shading, чтобы включить её в итоговый JAR плагина. Следуйте правилам перемещения пакетов существующего потребителя с аналогичной интеграцией и проверяйте рефлексивные обращения по строковым именам при переименовании пакетов. Дистрибутив перемещает org.luaj, org.reflections и javassist в com.magmaguy.shaded и не включает классы javax.annotation, нужные только при компиляции.
Каждый плагин может загрузить собственную копию библиотеки. Одноимённые Java-классы из разных загрузчиков плагинов являются разными типами. Используйте явные межплагинные контракты, например сервис Lua-способностей EliteMobs и адаптеры реестра местоположений. Не приводите внутренний объект MagmaCore другого плагина к типу из своей копии.
Модули и ответственность
| Модуль | Ответственность |
|---|---|
core | Жизненный цикл плагина, конфигурация, команды, меню, матчи, запросы местоположения, Lua, контент Nightbreak и общие утилиты |
nms:core | NMSManager, NMSAdapter и независимые от версии интерфейсы EasyMinecraftGoals |
nms:v* | Реализации контракта NMS для версий сервера |
dist | Встроенный дистрибутив с ядром и активными адаптерами |
Общие зачарования, действия предметов, учётные записи, меню настройки, каталоги и обновления принадлежат сервисам ядра. При добавлении поведения потребителю используйте компонент, уже отвечающий за него.
Жизненный цикл плагина
Минимальный жизненный цикл ядра повторяет существующий шаблон потребителей:
package example;
import com.magmaguy.magmacore.MagmaCore;
import org.bukkit.plugin.java.JavaPlugin;
public final class CoreConsumer extends JavaPlugin {
@Override
public void onLoad() {
MagmaCore.createInstance(this);
}
@Override
public void onEnable() {
MagmaCore.onEnable(this);
}
@Override
public void onDisable() {
MagmaCore.shutdown(this);
}
}
Эта инициализация не ограничивается получением служебного объекта. Она запускает работу с учётной записью, общие команды, слушатели и поддержку временных блоков. Перегрузка createInstance(plugin, NightbreakPluginSpec) задаёт тексты общих команд для конкретного плагина.
Предпочитайте методы с явным параметром плагина-владельца. getInstance() относится к одиночному экземпляру загруженной копии библиотеки; запросивший плагин определяется при создании этого экземпляра. Не определяйте по нему владельца для каждого потребителя.
shutdown(plugin) очищает регистрации загрузчика, обновления контента, инициализации и обновления плагина, затем также останавливает общую среду загруженной копии библиотеки. Действие не ограничивается удалением одной записи реестра. Вызывайте его для собственной встроенной библиотеки при отключении своего плагина; не останавливайте библиотеку другого плагина ради сброса интеграции.
Вызывайте createInstance в onLoad, чтобы владелец архива конфигураций зарегистрировался до импорта контента другим плагином. Архивирование выполняется собственной встроенной реализацией целевого плагина; не интерпретируйте чужие правила устаревания своей копией MagmaCore.
Для поэтапного запуска startInitialization принимает асинхронную и синхронную работу, а также обработчики успеха и ошибки. Перед асинхронной инициализацией он архивирует подходящие устаревшие конфигурации. Операции Bukkit с мирами и сущностями выполняйте в синхронной фазе. Длительная асинхронная работа должна проверять isShutdownRequested(plugin) между этапами. getInitializationState и isPluginReady показывают состояние менеджера инициализации.
Обновления плагина без перезапуска
NightbreakPluginBootstrap.registerStandardCommands регистрирует applypluginupdate вместе с остальными общими подкомандами. Она подставляет загруженное обновление: отключает ваш плагин, заменяет его jar и снова включает его в том же сеансе сервера, поэтому onDisable должен отменять задачи, снимать регистрацию слушателей и освобождать все ссылки, которые удерживали бы старый загрузчик классов. Включённые плагины, главный класс которых находится в com.magmaguy. и которые объявляют ваш плагин в depend или softdepend, перезагружаются вместе с ним. Любой другой плагин, зависящий от вашего, заставляет замену отказать и запросить перезапуск. Сторона владельца сервера описана в разделе Применение обновлений без перезапуска.
Если часть вашего плагина не может перезагрузиться на месте, вызовите NightbreakPluginHotSwap.requireRestartForUpdates(plugin, reason) до начала проверок обновлений и передайте false вторым аргументом в NightbreakPluginUpdater.setAutoDownloadConfigDefault, чтобы config.yml не предлагал applyPluginUpdatesWithoutRestart. Плагин всё равно перезагружается со своим текущим jar, когда заменяется плагин, от которого он зависит. NightbreakPluginUpdater.onPluginUpdateDownloaded(plugin, listener) запускает слушатель в потоке загрузки после того, как проверенное обновление попадает в папку update.
NMS и пакетные сущности
Инициализируйте NMS только при необходимости через NMSManager.initializeAdapter(plugin) из com.magmaguy.easyminecraftgoals. Проверяйте NMSManager.isEnabled() перед использованием зависимых от адаптера возможностей. Инициализация может завершиться ошибкой или обнаружить неподдерживаемую версию сервера.
Дистрибутив включает следующие семейства адаптеров:
| Адаптер | Версии Minecraft |
|---|---|
v1_21_R3 | 1.21.4 |
v1_21_R4 | 1.21.5 |
v1_21_R5 | 1.21.6, 1.21.7, 1.21.8 |
v1_21_R6 | 1.21.9, 1.21.10 |
v1_21_R7_spigot, v1_21_R7_paper | 1.21.11, отдельные реализации Spigot и Paper |
v26 | 26.1 и текущее семейство адаптеров 26.x |
Выбор адаптера не гарантирует совместимость со всеми будущими выпусками сервера. Возможность загрузки определяет переключатель в NMSManager во время выполнения. Версии до 1.21.4 не входят в текущий набор адаптеров.
EasyMinecraftGoals управляет сущностями, существующими только в пакетах, их видимостью и маршрутизацией взаимодействий, а также средствами движения и поиска пути. Это не обычные сущности мира. Используйте их собственный API и освобождайте созданные потребителем объекты, пока адаптер ещё доступен.
Запросы местоположения и защиты
com.magmaguy.magmacore.location.LocationQueryRegistry предоставляет запросы подземелий и защиты регионов, включая isInAnyDungeon, isInAnyProtectedRegion и canBuild.
Регистрируйте собственных поставщиков через registerDungeonLocator или registerProtectionProvider; удаляйте регистрацию того же поставщика при отключении владельца. Реестр включает адаптеры существующих плагинов и обнаруживает межплагинных поставщиков подземелий, не требуя общего загрузчика классов MagmaCore.
Выбирайте запрос, соответствующий действию. Нахождение вне подземелья не равнозначно разрешению строить в этой точке. Запросы, обращающиеся к Bukkit или плагинам защиты, выполняйте в серверном потоке.
Матчи
Жизненный цикл матчей находится в com.magmaguy.magmacore.match. Вызовите MatchCore.enable(plugin) один раз при включении, затем унаследуйте Match, передайте в его конструктор MatchSettings из MatchSettings.builder() и вызовите open() после завершения конструктора подкласса. Игровая логика размещается в защищённых хуках, таких как onJoin, onStart, onDeath и onLeave. MagmaCore.shutdown(plugin) уничтожает оставшиеся матчи плагина.
Ядро не вызывает собственных событий Bukkit. Оно вызывает MatchApi, заданный в настройках, поэтому ваш плагин сам решает, какие события предоставлять. Отменяемый обратный вызов запрещает шаг, возвращая false или выбрасывая исключение. Копия библиотеки в каждом плагине отслеживает только свои матчи; метка в метаданных игрока, magmacore_match, сообщает другим копиям, что игрок уже участвует в матче.
MatchSettings.builder().permission(...) задаёт право, которое нужно игроку для входа. Переопределите hasJoinPermission(player), чтобы решать для каждого игрока отдельно, например пускать персонал без этого права. Участник, который выходит из-за смерти (LeaveReason.DIED), перед выводом из матча полностью исцеляется, поэтому снятый при выходе бонус максимального здоровья сохраняет полное соотношение. Игрок, покинувший матч по любой другой причине, сохраняет текущее здоровье, а игроки, всё ещё находящиеся в матче к его завершению, исцеляются. Оба поведения новее сборки, опубликованной 5 октября 2026 года.
Старые классы матчей в com.magmaguy.magmacore.instance, включая MatchInstance, удалены. InstanceProtector остался там и регистрируется через MagmaCore.enableWorldProtections(plugin).
Хосты Lua Mind
MagmaCore компилирует написанные на Lua программы Mind для плагинов-хостов. Формат скрипта описан в разделе Программы поведения. Хост создаёт собственный LuaMindModuleRegistry, открывает владельца для своего пространства имён через openOwner(namespace), регистрирует модули методом владельца registerModule и получает LuaMindDefinition из validateProgram владельца. Каждый вызов instantiate у определения строит новую программу со своей средой Lua для одной сущности. Перечисленные ниже хуки новее сборки, опубликованной 5 октября 2026 года.
- Просмотр модуля.
LuaMindModuleRegistry.inspectModule(sourceName, source)читает id модуля, ревизию, зависимости и значения по умолчаниюsettings, не регистрируя его.LuaMindModuleDescriptor.settings()содержит значенияDouble,Boolean,StringилиList<String>. MagmaCore не передаёт настройки скриптам. Хост, которому нужны значения для каждого существа, накладывает свои значения поверх этих значений по умолчанию и предоставляет их сам, как питомцы FreeMinecraftModels делают сc.settings. - Расширение контекстов коллбэков.
LuaMindDefinition.instantiate(LuaMindContextExtension)добавляет ваши поля в таблицу контекста каждого коллбэка.extend(table, context, contribution)получает таблицу до того, как её увидит Lua,MindContextколлбэка и id модуля, объявившего коллбэк, либо id самой программы. Метод выполняется в основном потоке сервера внутри бюджета выполнения коллбэка, поэтому его процессорное время засчитывается вcpu_microsпрограммы, а исключение приводит к сбою коллбэка. Добавляйте поля черезrawsetилиLuaTableSupport.lazyField, который сохраняет существующий__indexтаблицы для всех остальных ключей. Не заменяйте метатаблицу таблицы или её__index, потому что встроенные разделы читаются через них, и не перезаписывайтеtick,generation,entity,memory,perception,actuatorиactions. Чтение встроенного раздела изextendстроит его для этого коллбэка. Передавайте отдельное расширение каждому вызовуinstantiate, если оно хранит состояние отдельной сущности. - Интервал проверки. Java-поведение может переопределить
MindBehavior.probeInterval(), эквивалент Luaprobe_interval, чтобы вызыватьcanStartкаждые N тиков, пока оно остановлено. Значение должно быть от 1 доMindBehavior.MAX_PROBE_INTERVAL(200);MindProgramотклоняет другие значения. По умолчанию 1 означает вызов на каждом тике.MindSensorопрашивает на первом тике, когда обрабатывается его тело, а затем каждыеintervalTicks()тиков на фазе, своей для каждой сущности. - Полёт.
MindActuator.steerFlight(Vector), который уже был в той сборке, ведёт телоFLYINGв полёте с этой скоростью в течение одного тика и требует аренды MOVE и LOOK. Новое здесь — его предел и Luasteer_flight:MindActuator.MAX_FLIGHT_SPEEDравен 4 блокам за тик, а более высокая скорость уменьшается до него.RouteFlightтоже ограничивает свою скорость этим значением, поэтому маршрут, заданный быстрее 80 блоков в секунду, летит со скоростью 80.
Пересборка потребителя после изменения библиотеки
Используйте JDK 21 и публикуйте MagmaCore в Maven Local командой ./gradlew publishToMavenLocal, а в Windows .\gradlew.bat publishToMavenLocal. Убедитесь, что потребитель получает нужную версию из этого репозитория, затем пересоберите его JAR со встроенной библиотекой. Замена библиотеки в Maven Local не обновляет уже собранный плагин.
API установленных плагинов перечислены в указателе разработчика. Такие интеграции обычно используют provided или compileOnly; для встроенной MagmaCore действует другой контракт упаковки.