Разработка Java-серверов на Paper · 6 мин чтения

Первый Paper-плагин: соберите JAR и подтвердите загрузку

Соберите плагин, который печатает TrailNotes загружен в консоль. Ниже есть все обязательные файлы Gradle-проекта для Paper 1.21.1/JDK 21, команда сборки и проверка JAR; это ограниченный учебный пример.

Редакция LonelyCraft · Обновлено

Схема: Проект → Загрузка → Проверка
Сборка против API, совпадение главного класса с manifest и наблюдаемая проверка. Авторская схема LonelyCraft.

Создайте Gradle-проект и два файла сборки

Скачайте IntelliJ IDEA и Temurin JDK 21. В IDEA выберите New Project → Java, Build system: Gradle, Gradle DSL: Kotlin, JDK 21 и имя TrailNotes. После создания дождитесь синхронизации Gradle. Структуру проверьте по Paper Project setup.

В корне проекта файл settings.gradle.kts содержит rootProject.name = "TrailNotes". Полностью замените build.gradle.kts следующим содержимым. API используется как compileOnly: сервер предоставляет его во время запуска. Версия 1.21.1 выбрана для воспроизводимого примера, а не как текущий выпуск публичного сервера.

plugins { java }

group = "ru.example"
version = "1.0.0"

repositories {
    mavenCentral()
    maven("https://repo.papermc.io/repository/maven-public/")
}

dependencies {
    compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
}

java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}

tasks.withType<JavaCompile>().configureEach {
    options.encoding = "UTF-8"
}

Создайте главный класс

В дереве IDEA создайте src/main/java/ru/example/trailnotes/TrailNotesPlugin.java, затем вставьте класс ниже. Если каталог src/main/java уже есть, создавайте только пакет и файл через New → Package / Java Class. Имя public-класса совпадает с именем .java.

При включении метод onEnable записывает одну строку. Это наблюдаемая проверка загрузки, без изменения инвентарей и мира. Если IDE не распознаёт JavaPlugin, сначала синхронизируйте Gradle и проверьте доступ к репозиторию; создание собственной пустой версии этого класса ошибку зависимости не исправляет.

package ru.example.trailnotes;

import org.bukkit.plugin.java.JavaPlugin;

public final class TrailNotesPlugin extends JavaPlugin {
    @Override
    public void onEnable() {
        getLogger().info("TrailNotes загружен");
    }
}

Добавьте manifest в resources

Создайте src/main/resources/plugin.yml и вставьте текст ниже. main — полное имя только что созданного класса, включая регистр. api-version ограничен нашим примером 1.21.1; не заменяйте его номером Java. Назначения полей есть в Paper plugin.yml.

Файл должен оказаться в корне JAR. На Windows включите показ расширений в Проводнике и убедитесь, что имя не стало plugin.yml.txt. Для этой минимальной проверки команды и permissions в manifest не нужны: они появятся при добавлении обработчика.

name: TrailNotes
version: 1.0.0
main: ru.example.trailnotes.TrailNotesPlugin
api-version: "1.21"

Соберите и проверьте JAR на тестовом Paper

В Terminal IDEA из корня проекта выполните в Linux/macOS ./gradlew clean build, в Windows PowerShell ./gradlew.bat clean build. Wrapper создан Gradle-проектом; если его нет, используйте Gradle-панель IDEA → Tasks → build → build либо создайте wrapper через установленный Gradle по документации Gradle.

Выполните jar tf build/libs/TrailNotes-1.0.0.jar: нужны plugin.yml и ru/example/trailnotes/TrailNotesPlugin.class. Остановите отдельный Paper 1.21.1, скопируйте JAR в его plugins, запустите с Java 21 и найдите TrailNotes загружен в logs/latest.log. После stop и нового запуска сообщение появляется снова один раз.

Настройте сборку так, чтобы API не попал внутрь JAR

Создайте Java-проект с Gradle или Maven и документированным репозиторием Paper. Зависимость paper-api подключайте как compileOnly в Gradle либо provided в Maven: сервер предоставляет API при запуске. Встраивание полного API в свой плагин создаёт лишний размер и риск конфликтующих классов. Сам код вашего проекта и необходимые собственные ресурсы при этом должны попасть в итоговый артефакт.

Для первого примера удобно явно выбрать Paper 1.21.1 и Java 21. Это ограниченная учебная цель, а не рекомендация устаревшей версии для нового публичного сервера. При выборе современного ядра сверяйте текущие требования runtime и API. Условие api-version в manifest сообщает совместимость, но не переводит байткод, собранный новой Java, в старую.

Разделите исходники и ресурсы

В src/main/java хранится класс, а в src/main/resources — plugin.yml. Не помещайте manifest рядом с Java-файлом: обычная сборка не обязана перенести его оттуда в корень JAR. Проверьте пакет класса и main посимвольно. Имя файла, имя public-класса и пакет должны соответствовать структуре проекта, включая регистр.

После сборки просмотрите содержимое JAR командой jar tf с именем вашего файла. В списке должны быть TrailNotesPlugin.class по пути пакета и plugin.yml в корне. Файл исходного .java не заменяет скомпилированный класс. Если нужных записей нет, исправляйте структуру сборки до копирования на сервер: серия рестартов не добавит отсутствующий ресурс.

После проверки архива выполните обычный цикл установки с чтением журналов. Проверка JAR на тестовом сервере.

Проверяйте точку включения отдельно от функций

Скопируйте один собранный JAR в plugins тестового Paper и запустите сервер штатно. Найдите имя плагина и сообщение из onEnable. Если оно отсутствует, сначала читайте ошибку загрузки, а не добавляйте игровые слушатели. Неправильный main, несовместимая Java и отсутствующая зависимость проявляются до того, как ваше действие сможет работать.

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

  1. Выполните чистую сборку и найдите итоговый JAR.
  2. Проверьте класс и manifest внутри архива.
  3. Установите файл в отдельный тестовый сервер.
  4. Подтвердите одно сообщение включения.
  5. Добавьте одну функцию и её обработчик.
  6. Проверьте штатное отключение и повторный запуск.

Добавляйте конфигурацию без скрытой логики

Если нужен config.yml, разместите шаблон в resources и создайте пользовательскую копию поддерживаемым API. Читайте значения с явными единицами и диапазонами. Например, время ожидания должно называться wait-seconds или иметь такое же ясное описание. Отсутствующее значение и явно заданный ноль требуют разных решений, если ноль отключает функцию.

Главный класс собирает компоненты, но не должен содержать каждый клик, SQL-запрос и переход раунда. Выделите отдельный сервис для логики, слушатель для событий и хранилище для данных. Даже в маленьком проекте это позволяет проверить расчёт результата без запуска Minecraft и оставить работу с миром в нужном потоке.

Загруженный YAML ещё нужно проверить по смыслу до включения игровой механики. Проверка config.yml.

Типичные ошибки первого проекта

Если сервер пишет UnsupportedClassVersionError, сравните Java сборки и запуска. Если не найден главный класс, сопоставьте main с записью внутри JAR. Если plugin.yml отсутствует, проверьте каталог ресурсов. Если команда возвращает неизвестное имя, выясните, зарегистрирована ли она выбранным способом и успешно ли включился плагин.

Не подменяйте диагностику общим reload. После замены бинарника выполните штатную остановку и запуск. Сохраняйте номер своего выпуска и имя исходного коммита, чтобы тест относился к определённому файлу. Когда простая функция работает после рестарта с обычными правами, минимальная основа готова к расширению.

Частые вопросы

Почему paper-api используют compileOnly?

API предоставляет сервер при запуске. Ваш плагин компилируется против него, но не должен без необходимости включать его классы внутрь собственного JAR.

Где должен находиться plugin.yml?

В обычной структуре проекта он лежит в src/main/resources и попадает в корень итогового JAR. Проверьте архив перед установкой.

api-version исправит ошибку новой Java?

Нет. Она описывает требования API, а версия байткода определяется инструментом сборки. Согласуйте Java проекта и runtime сервера.

Почему сначала достаточно сообщения onEnable?

Оно проверяет минимальную загрузку класса и manifest. Затем каждую функцию можно добавлять отдельно, сохраняя известное рабочее состояние.

Просмотры: … · Один просмотр с браузера за день

Было полезно?Общий счёт: …

Одна реакция с браузера. Нажмите повторно, чтобы снять её, или выберите другую.

Источники и документация

Minecraftразработка плагиновPaper

Читайте дальше