Написание Paper/Bukkit плагина LiteSMT #1 — Основа понятий и окружение
Всем привет! Это серия постов будет иметь много различных тем, но и я так-же не забыл о написании ядра на Rust, скоро будут продолжения).
Немного понятий
Я думаю, что стоит начать с некоторой основной информацией по созданию плагинов, а именно:
- Все плагины основываются на Bukkit — API для плагинов, которая может немного отличаться в зависимости от версий.
- Плагины пишутся в основном на Java или иногда на Kotlin .
- Некоторая информация плагина исключительно для ядра храниться в plugin.yml, где можно найти версию плагина, главный класс плагина и многое другое.
- В стандартных случаях плагинам хватает обычного, но существуют моменты, где могут понадобится NMS — net.minecraft.server или же API к самому Minecraft.
- Плагины без труда могут использовать API других плагинов, если имеется такая возможность, например PlaceholderAPI и Vault.
- Почти всегда, когда ядро обращается к плагину — выполняется в синхронном потоке сервера.
Думаю этой малой информации может хватить для того, чтобы мы могли подготовить основу нашего плагина и небольшое окружение для работы со своим плагином.
Подготавливаем наш тестовый сервер
Всё-таки я думаю нам сначала стоит именно тестовый сервер так-как тема конкретно написания плагина уже гораздо больше.
Для начала нам стоит выбрать основную версию и ядро, я выбрал 1.16.5 версию так-как сейчас она как основа для версий выше.

Из статистики выше видно, что большинство серверов на 1.16.5 и выше, а ядро Paper и следовательно как изначально планировалось было выбрано ядро Paper. Скачать его версии 1.16.5 можно по этой ссылке.
Скачанный файл по ссылке выше я помещаю в отдельную директорию рядом со своим Start.sh файлом:
java -Xms512M -Xmx1G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:InitiatingHeapOccupancyPercent=15 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -jar paper-1.16.5-794.jar nogui
После первого запуска будет скачан кеш и создан eula.txt( в котором надо будет установить true вместо false ):

После изменения eula.txt будет такой вывод с полным запуском:

Как я настроил некоторые файлы при разработке
settings: allow-end: false warn-on-overload: true permissions-file: permissions.yml update-folder: update plugin-profiling: false connection-throttle: 0 query-plugins: false deprecated-verbose: default shutdown-message: Server closed minimum-api: none spawn-limits: monsters: 10 animals: 10 water-animals: 5 water-ambient: 10 ambient: 5 chunk-gc: period-in-ticks: 900 ticks-per: animal-spawns: 1 monster-spawns: 1 water-spawns: 1 water-ambient-spawns: 1 ambient-spawns: 1 autosave: 12000 aliases: now-in-commands.yml
enable-jmx-monitoring=false rcon.port=25575 level-seed= gamemode=survival enable-command-block=false enable-query=false generator-settings= level-name=world motd=Test Server query.port=25565 pvp=true generate-structures=false difficulty=easy network-compression-threshold=256 max-tick-time=60000 max-players=20 use-native-transport=true online-mode=false enable-status=true allow-flight=false broadcast-rcon-to-ops=true view-distance=6 max-build-height=256 server-ip= allow-nether=false server-port=25565 enable-rcon=false sync-chunk-writes=true op-permission-level=4 prevent-proxy-connections=false resource-pack= entity-broadcast-range-percentage=100 rcon.password= player-idle-timeout=0 debug=false force-gamemode=false rate-limit=0 hardcore=false white-list=false broadcast-console-to-ops=true spawn-npcs=true spawn-animals=true snooper-enabled=true function-permission-level=2 level-type=flat text-filtering-config= spawn-monsters=true enforce-whitelist=false resource-pack-sha1= spawn-protection=16 max-world-size=500
После изменений конфигурации я удалил все миры, чтобы был создан только world с плоской генерацией. И теперь консоль после запуска выглядит так:

Теперь для начала нам надо загрузить важны плагины:
- PlaceholderAPI — API для плейсхолдеров.
- PlugManX — форк оригинального PlugMan для работы с плагинами(перезагрузка, загрузка, выгрузка и тд).
- Auto Reload — автоматическая перезагрузка плагинов в случае изменений.
После загрузки можно перезагрузить частично сервер используя reload confirm. И потом плагины загрузятся и некоторые создадут конфигурации.
plugins/PlugManX/config.yml
ignored-plugins: [PlugManX] notify-on-broken-command-removal: true auto-load: enabled: true check-every-seconds: 2 auto-unload: enabled: true check-every-seconds: 2 auto-reload: enabled: false check-every-seconds: 2
plugins/PlaceholderAPI/config.yml
# PlaceholderAPI # Version: 2.11.1 # Created by: extended_clip # Contributors: https://github.com/PlaceholderAPI/PlaceholderAPI/graphs/contributors # Issues: https://github.com/PlaceholderAPI/PlaceholderAPI/issues # Expansions: https://api.extendedclip.com/all/ # Wiki: https://github.com/PlaceholderAPI/PlaceholderAPI/wiki # Discord: https://helpch.at/discord # No placeholders are provided with this plugin by default. # Download placeholders: /papi ecloud check_updates: true cloud_enabled: true cloud_sorting: "name" cloud_allow_unverified_expansions: true boolean: 'true': 'yes' 'false': 'no' date_format: MM/dd/yy HH:mm:ss debug: true
plugins/bStats/config.yml
enabled: false serverUuid: 00000-00000 logFailedRequests: false
После сделанных изменений надо снова перезагрузить сервер, а после полной перезагрузки мы можем спокойно зайти на наш тестовый сервер с любого клиента, который поддерживает версию 1.16.5, так-же стоит выдать себе все права используя op .
Подготовка нашего плагина
Так-как плагин будет написан на стандартном Java, то нам надо подумать о сборщике нашего плагина, есть несколько вариантов: IDE компилятор, Maven и Gradle. Давайте посмотрим основные плюсы и минусы, которые я выделил как основные:
- Компилятор IDE(IDEA, Eclipse и др)
Плюсы:
1) Все зависимости и компиляция настроены прямо в настройках редактора.
2) Может быть быстрым но зависит от настроек компиляции.
Минусы:
1) Для редактирования может потребоваться конкретный редактор или его поддержка в другом редакторе.
2) Часто ограничен возможностями самого редактора.
3) Компиляция часто может идти тяжелее нежели на Maven или Gradle. - Maven
Плюсы:
1) Возможно настроить и форматирование файлов , все зависимости и репозитори, а так-же плагины компиляции.
2) Не зависит от конкретного редактора.
3) Быстро компилирует, но хуже Gradle.
Минусы:
1) Для компиляции каждый раз запускается новый процесс, который каждый раз заново читает и собирает информацию. - Gradle
Плюсы:
1) Есть настройки форматирования файлов, зависимостей, репозиторий и различных дополнений(например Lombok).
2) Запускает компиляцию в фоновом процессе, который считывает конфиги и другое после изменений или при другой нужде.
3) Не зависит от редактора как и Maven.
4) Можно писать конфигурацию компиляции на языке Groovy или Kotlin DSL
5) Запуск компиляции проходит с помощью запуска фонового процесса(если не запущен) или обращение к нему.
Минусы:
1) Фоновый процесс постоянно требует некоторое количество ОЗУ.
Вы конечно можете сами выбрать сборщик под себя, но я выбрал Gradle и из-за чего дальше будет информация связанная с ним. Так-же выбрал редактор Intellij IDEA от JetBrains так-как он очень замечательно работает с Java.
Первым делом нужно инициализировать Gradle проект:

После создания проекта я в первую очередь удалил папку test и изменил build.gradle под проект:
plugins < id 'java' >group 'xyz.distemi' version '1.0-SNAPSHOT' repositories < mavenCentral() maven < name = "PaperMC" url = "https://repo.papermc.io/repository/maven-public/" >maven < name = "PlaceholderAPI" url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/' >> dependencies < compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT' // PaperMC compileOnly 'me.clip:placeholderapi:2.11.1' // API плагина PlaceholderAPI compileOnly 'org.projectlombok:lombok:1.18.24' // Lombok API annotationProcessor 'org.projectlombok:lombok:1.18.24' // Lombok процессор >
И следом я нажал на кнопку синхронизации в своей IDEA.
Теперь нам надо сделать главный класс плагина, который у меня будет xyz.distemi.litesmt.LiteSMT:
Базовый код главного класса плагина LiteSMT
package xyz.distemi.litesmt; // Объявляем наш пакет // Импортируем Getter из ломбок, абстрактный класс JavaPlugin и // интерфейс логгера. import lombok.Getter; import org.bukkit.plugin.java.JavaPlugin; import java.util.logging.Logger; public class LiteSMT extends JavaPlugin < // Создаём две статичные переменные: @Getter private static LiteSMT instance; // Класс плагина. @Getter private static Logger jlogger; // Логгер. @Override public void onEnable() < // Устанавливаем наши статичные переменные: instance = this; jlogger = super.getLogger(); // Выводим в консоль сообщение Hello from LiteSMT // от имени плагина. jlogger.info("Hello from LiteSMT!"); >>
Для людей, которые не знают Java или хотящие подробное объяснение
В классе выше мы создали файл в папке src/main/xyz/distemi/litesmt файл LiteSMT.java с содержанием выше.
Импорты передают компилятору информацию о использованных классах и другого, без импорта ему неизвестно какой именно класс/интерфейс или другое вы используете.
public class позволяет нам показать класс как главный в этом файле, а это значит, что никто не мешает создать рядом просто class без public.
private является областью видимости поля, которая может быть применена как на метод, так и на переменную.
static — модификатор, говорящий, что данное поле может быть использовано, инициализировано и тд без конструирования самого класса( new Class() ).
Аннотация @Override позволяет нам перезаписать метод из класса-предка(у нас это абстрактный класс JavaPlugin)
Аннотация @Getter из Lombok указывает, что должен будет сгенерироваться дополнительный код, используя процессор аннотаций Lombok-а.
Метод onEnable работает как конструктор, но только вот он исключительно для нашего плагина. Метод возвращает тип void, а именно ничего.
Внутри перезаписанного метода onEnable мы устанавливаем глобальные переменные instance и jlogger, но если с первым случаем ясно, что ссылаемся на сконструированный класс, то во втором случае используем super уже для обращению к «предку», а именно JavaPlugin.
Следом выводим в консоль сообщение из аргумента.
Чтож, главный класс у нас имеется, но для работы плагина этого недостаточно!
Серверу нужно знать какой же класс главный и другую информацию, для этого нам нужно создать файл plugin.yml, но уже не в качестве кода, а файл-ресурса, в Gradle такие файлы можно создать в директории проекта src/main/resources/, где файлы внутри не могут быть скомпилированы, а копируются в наш jar «сырыми», но есть например возможность некоторого форматирования, однако пока думаю можно будет обойтись и без него.
В папке ресурсов я создаю файл plugin.yml, который по умолчанию не имеет ничего я записываю содержимое ниже:
name: LiteSMT main: xyz.distemi.litesmt.LiteSMT version: 1.0 author: Distemi prefix: LSMT depend: - PlaceholderAPI
Как вы можете заметить, то мы устанавливаем всего шесть значений, однако некоторые необязательные.
name (Обязательно) — даёт знать ядру о «имени» плагина, которое может использоваться как в некоторых командах сервера, так и других плагинах по типу того же PlugManX.
main (Обязательно) — указывает класс в нашем jar, который становиться главным в работе плагина, 1 jar = 1 плагин.
version (Обязательно) — атрибут, означающий версию нашего плагина, может быть как 1.0 так и 1.0.0.
author — указывает автора плагина.
prefix — префикс в логе вместо названия плагина.
depend — обязательные зависимости для плагина, если каких-то нету, то плагин не будет загружен, в списке указываются «имена» плагинов.
Если интересно почитать о других атрибутах и тд для plugin.yml, то можете почитать по этой ссылке.
Всё почти готово, однако теперь нам нужно собрать плагин и перекинуть в папку с сервером, можно конечно это делать руками, но я больше предпочитаю делать это автоматически, используя свои задачи в Gradle, для чего нам нужно в build.gradle добавить следующее:
task copyToDevEnv_1_16_5() < doLast < copy < from "build/libs/LiteSMT-1.0-SNAPSHOT.jar" into "../test-server1.16.5/plugins/" >> > build.finalizedBy copyToDevEnv_1_16_5
Тут мы объявляем задачу, которая копирует готовый jar плагина в папку указанную из into, а build.finalizedBy означает, что задачу build мы всегда заканчиваем с copyToDevEnv_1_16_5. Давайте теперь мы впишем ./gradlew build —offline -x test, где мы запускаем компиляцию без доступа к интернету (—offline) и исключаем задачу(-x) тестов(test). Теперь смотрим в нашу папку с плагинами и видим:

Ура! Наш плагин успешно собрался и сам был помещён в директорию с плагинами. Теперь пробуем запустить наш сервер и видим.

Да! Плагин наш был успешно запущен и при запуске вывел в консоль наше сообщение, однако для проверки автоматической перезагрузки плагина в случае изменений я могу чуть изменить сообщение в коде и заново собрать плагин прошлой командой в консоль/терминал и увидеть уже в консоли сервера:

Всё-таки я добавил «Changed from me!» в строку вывода и после сборки плагин AutoReload сам увидел изменение и перезагрузил плагин, ну не удобство ли, когда надо бывает частенько и главный класс изменить?)
Так-же как вы могли бы заметить, то наш префикс из plugin.yml тоже показывает результат так-как без того атрибута у нас выводился бы LiteSMT.
В плагине мы можем так-же допустим реализовать работу с конфигурацией, событиями и другим, но я в этой части покажу лишь работу с событиями так-как на конфигурацию у меня есть много интересного содержания)
Обработка событий в плагине или как можно приукрасить чат.
Сейчас мы будем работать лишь с тремя из большого количества событий, а именно вход игрока, выход и написание сообщений в чат. Наверное многим не нравиться стандартный формат чата из и игры из-за чего скачивают и устанавливают плагины по типу Chatty и другого, но сейчас мы сделаем некую свою мини альтернативу, правда не всё, но хоть что-то)
Для событий в плагинах используют отдельные классы, которые просто помимо своего существования должны наследовать один из интерфейсов от Bukkit и быть зарегистрированы в событиях Bukkit-а.
Для событий чата будет у меня отдельный пакет в моём jar, а именно xyz.distemi.litesmt.listeners.chat, который в IDEA создаётся в два клика:

В нашем новом пакете создадим класс с именем MainChatListener, который по началу имеет только публикацию класса и пакет . И после его имени мы должны прописать implements Listener, однако как я говорил раньше, то нужно и импортировать классы, чтобы сборщик мог знать какой класс нам нужен и JVM тоже, поэтому IDEA предлагает выбрать Listener из нескольких пакетов, но нам нужен именно с org.bukkit.event и следом появиться импорт org.bukkit.event.Listener. Теперь данный класс для ядра считается неким слушателем событий, однако он не зарегистрирован и пусть, а это значит, что от него нету толка, для этого в главном классе, в onEnable мы прописываем:
Bukkit.getPluginManager().registerEvents(new MainChatListener(), this);
И теперь для bukkit наш слушатель зарегистрирован на все типы событий, а в качестве второго аргумента мы передаём плагин, это означает, что этот слушатель принадлежит нашему плагин.
— Тогда получается возможно регистрировать слушатели и из других плагинов?
— Верно! Однако не стоит так делать.
Если мы и попробуем сейчас собрать плагин и протестировать его, то у нас не будет никаких отличий так-как слушатель хоть и существует, но он пустой. Давайте попробуем создать в нём функцию для форматирования сообщений из чата, а именно установка своего формата сообщений:
import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class MainChatListener implements Listener < @EventHandler public void onChat(AsyncChatEvent event) < event.renderer((source, sourceDisplayName, message, viewer) ->Component.text() .append(sourceDisplayName.color(TextColor.fromHexString("#a8a432"))) .append(Component.text(" : ")) .append(message) .build()); > >
Объяснение кода
Все методы событий обязательно должны иметь аннотацию EventHandler от org.bukkit, чтобы было ясно, что этот метод точно является слушателем событий, а именно AsyncChatEvent так-как именно он указан в аргументе. Далее для форматирования не используется устаревший метод formatter, а новый — renderer, который имеет больше возможностей. Для нашего renderer мы используем так называемый функциональные интерфейсы, в данном случае ChatRenderer и спасибо Java, что тут получилось так сокращённо, ведь иначе вышло бы на несколько строк больше.
Для форматирования мы создаём наш новый чат-компонент Component, но для всего связанного с чатом сейчас используется пакет net.kyori.adventure.text. Component.text() создаёт нам конструктор, который мы используем для связки трёх других компонентов: ник, разделитель для сообщения( : ) и самого сообщения.
Метод TextColor.fromHexString даёт возможность получить нам цвет для чат-компонента из HEX строки c нужным цветом, в моём случае #a8a432. Этот цвет я применяю на переменную компонента sourceDisplayName и добавляю получившейся компонент в конструктор.
Далее я добавляю в конструктор разделитель в сообщении » : «, который можно получить используя Component.text(» : «).
Последнее добавление в конструктор — само сообщение игрока.
Заканчивается создание форматированного компонента методом build.
Теперь если мы попробуем набрать в консоль любое сообщение, то увидим:
![]()
Далее я бы убрал сообщение выхода с сервера таким кодом:
@EventHandler public void onQuit(PlayerQuitEvent event)
Теперь при повторной сборке и следующей проверки выхода мы не увидим сообщения в консоли о выходе игрока, кроме того, что является от самого ядра.
Можно и приукрасить сообщение о входе:
@EventHandler public void onJoin(PlayerJoinEvent event)
И после сборки этого кода, то при заходе будет данное сообщение:

Итог
Вот и была сделана небольшая основа для плагина, которая дальше будет дополняться всё большим функционалом в следующих частях!
Готовый сходный код доступен по этой ссылке.
[Гайды][1.9.2] Создание плагина spigot, часть 1 — «Подготовка»
![[Гайды][1.9.2] Создание плагина spigot, часть 1 -](https://ru-minecraft.ru/uploads/posts/2016-04/1459585777_cooltext174827860809440.png)
И так, для того чтобы создать простейший плагин Вам понадобится Spigot сервер,
Spigot-api, eclipse (желательно luna) и хотя бы базовые знания java. Ссылки на
Eclipse luna, Spigot-api и Spigot сервер будут указаны в конце статьи.
![[Гайды][1.9.2] Создание плагина spigot, часть 1 -](https://ru-minecraft.ru/uploads/posts/2016-04/1459585818_cooltext174827957460659.png)
1.Запускаем elipse и (желательно) указываем пустую директорию.
2.Создаем новый java проект и называем его как хотим(я выбрал Test).
3.Нажимаем по проекту ПКМ и выбираем properties->java build path->libraries->add extrenal jars->OK
4.Указываем путь к spigot-api-1.9.2-R0.1-SNAPSHOT-latest-shaded
5.Переходим к созданию главного файла.
Шаги 3 и 4 в виде картинки:
![[Гайды][1.9.2] Создание плагина spigot, часть 1 -](https://ru-minecraft.ru/uploads/posts/2016-04/medium/1459586558_bezymyannyy.png)
![[Гайды][1.9.2] Создание плагина spigot, часть 1 -](https://ru-minecraft.ru/uploads/posts/2016-04/1459590382_cooltext174834919142796.png)
1.Создаем папку (package) и называем ее так *регион*.*автор*.*имя плагина*,
у меня получилось ru.stebbilust.test.
2.Создаем главный класс в этой папке, называем его как хотим.
3.Пишем в нем такой код:
// сюда пишем вашу папку
package ru.Stebbilust.test;
public class Main extends JavaPlugin < // расширяем класс JavaPlugin
public void onEnable() // что то, что происходит при включении
getLogger().info(«Hello. «); // выводим в консоль сообщение Hello.
>
public void onDisable() // что то, что происходит при выключении
getLogger().info(«Bye. «); // выводим в консоль сообщение Bye.
>
>
4.Создаем в src файл plugin.yml и пишем там:
name: test
main: ru.Stebbilust.test.Main
version: 0.1
authors:
description:
commands:
name — имя плагина
main — путь к главному файлу
5.Переходим к экспорту!
![[Гайды][1.9.2] Создание плагина spigot, часть 1 -](https://ru-minecraft.ru/uploads/posts/2016-04/1459588253_cooltext174831738885610.png)
![]()
1.Нажимаем File->export->jar file
2.Указываем путь сохранения
3.ОК
Если вдруг появляются ошибки, а предупреждений в коде нету,
то попробуйте экпортировать файл еще раз с заменой.
После этого устанавливаем плагин, запускаем сервер и видим:
[Урок][Глава 1] Учимся писать плагин для сервера
![[Урок][Глава 1] Учимся писать плагин для сервера](https://ru-minecraft.ru/uploads/posts/2017-07/1499969270_60901441.png)
Вводим там следующие пункты
1. name — Название вашего проекта
2. main — Название.main.Название — Будет использоваться чтобы использовать плагин на сервере
3. version — версия плагина.
Далее мы создаем Package в файле scr и в Package создаем Class. Все файлы называть как название плагина.
Когда вы создадите файл, вы должны добавить к 2 строке extends JavaPlugin, затем, навести на него курсор и нажать импорт. После чего, у вас появится строка с импортом для работы плагина
И так. Дабы не томить вас нудными скринами, составил вам сразу готовый код выдачи лога в консоль. Давайте же разберемся, а не тупо спишем.
private Logger Log — Создает лог плагина, после чего, идут сообщения в консоль.
public void onEnable () < - Данное действие при запуске консоли(сервера), будем информировать нас и включать плагин
getLogger().info(«Enabled!») — Благодаря этому, в консоль будет выводиться сообщение «Enabled», когда плагин будет включен
log.info(«MAIN LOGGER») — Включается когда запускается консоль
log.warning(«Warning») — Включается когда имеется баг
log.error(«Error») — Включается, когда идет фатальная ошибка (полностью отключается плагин)
Все это выше выводит всё в консоль
public void onDisable() < - Данное действие будет выключать всё при выключении сервера
getLogger().info(«Disabled») — Выключение плагина. Выводит сообщение в консоль
Вы наверное спросите, зачем мы пишем < и >> Несколько раз?
Дело в том, что эти скобочки, открывают взаимодействие с пабликом. Если после ввода public void onEnable() поставить Чтобы закрыть паблик, нужно ввести >. Чтобы полностью закончить код, нужно в самом конце и в самом начале строке, написать еще раз >. Это означает, что паблик и код завершены
В сегодняшнем уроке, мы научились выставлять сообщение в консоль о запуске/выключении консоли.
Если у вас есть вопросы, обращайтесь ко мне в ВК — vk.com/vovakostikov
Спасибо за просмотр новости
Как написать свой первый плагин — обновлённый гайд за 2023 год [Гайд]
Если вы играли в Minecraft на серверах, то наверняка вам доводилось сталкиваться с различными системами по типу китов, точек дома, префиксов, чатов и т.д. Эти все системы добавляются на сервера при помощи плагинов — неких дополнений к серверным ядрам.
Первое что нам нужно знать — ванильные сервера и одиночная игра не поддерживают плагины! Это связанно с тем, что в одиночной игре мы запускаем так называемый встроенный сервер, в котором нет поддержки API (программного интерфейса приложения), который нужен для запуска плагинов и выполнения их кода. Тоже самое касается и ванильного серверного ядра.
Ядра которые поддерживают плагины были разработаны сообществом, наиболее яркими примерами являются Bukkit, Spigot, Paper, Magma, CatServer, Purpur, Tuinity, kSpigot и т.д. Я могу продолжать этот список очень долго, т.к. по факту помимо оригинальных ядер существуют их форки — версии от других разработчиков с какими либо улучшениями и дополнениями. Некоторые из этих форков предоставляют доп. возможности именно для разработчиков. Например Spigot и Paper имеют доп. API.
Как же это всё работает? Очень просто! Когда вы запускаете серверное ядро с поддержкой плагинов, оно создаст в корне сервера папку plugins, куда мы и будем помещать наши плагины.
Все плагины для Minecraft Java Edition пишутся на языке программирования Java, без знания которого вы не сможете разрабатывать плагины от слова вообще. Так что перед ознакомлением с этим гайдом я советую ознакомиться с базовой логикой Java и хотя бы изучить структуру самого ЯП. Если вы считаете, что готовы, то можете смело переходить ко следующему пункту.
2.Загрузка и установка Java
Давайте начнём с подготовки вашего ПК к разработке плагинов. Как я уже сказал ранее, все плагины для Minecraft Java Edition написаны на ЯП Java, а это означает, что нам нужно установить JDK (Java Development Kit) на свой ПК. Так как мы будем разрабатывать плагин для новой версии Minecraft, а именно 1.19.4, то и JDK нам нужна свежая.
Если версия ядра ниже 1.17, то нужна Java 8.
Если версия ядра 1.17 — 1.17.1, то нужна Java 16.
Если версия ядра 1.18 и выше, то нужна Java 17.
Для загрузки той или иной версии Java достаточно вбить в поисковую строку JDK 17, JDK 16 и т.д.
Я рекомендую использовать JDK от Oracle. Допустим, если мы сделаем запрос JDK 17, то первый вебсайт, который нам выдаст это архивная страница для загрузки JDK 17 (Да, JDK 17 уже считается устаревшей)
![]()
Заходим на эту страницу и на ней видим вот такой список:
![]()
Здесь мы выбираем Java под свою ОС, вероятнее всего у вас Windows x64, поэтому мы загрузим именно Windows x64 Installer.
ВАЖНО Для загрузки некоторых архивных версий Java необходимо зарегистрироваться на сайте Oracle.
Открываем установщик и видим следующее:
![]()
Жмём Next >, и видим страницу, где можно указать куда именно будет установлена нужная вам версия JDK. Здесь я рекомендую изменить название папки на то, которое для вас будет самым удобным. После этого нажимаем Next > и ждём пока установка завершится. После установки мы увидим окно с кнопкой Next Steps и Close. Нажимаем Close и довольствуемся, ведь мы только что установили JDK на ваш ПК, подготовив его к разработке плагинов на 33,3%.
Проверить корректно ли установилась JDK можно следующим образом:
Запускаем cmd
![]()
Исполняем команду java -version
![]()
Если у вас такой же вывод как и на этом скриншоте, значит вы всё сделали правильно.
Можно переходить к следующему пункту, где мы разберём что такое IDE и зачем оно нам надо.
3.Загрузка и установка IDE
IDE (Среда Разработки) — программа, в которой мы и будем разрабатывать (кодить) наши плагины. Есть различные варианты, например Apache NetBeans, Eclipse и InteliJ Idea. Мы будем использовать именно InteliJ Idea Community Edition, т.к. на данный момент это самая продвинутая, функциональная и приятная IDE. Для того, чтобы её загрузить нам понадобится сделать следующий запрос в Google: InteliJ Idea. Вероятнее всего, вы увидите следующее:
![]()
Нажимаем на Download и видим вот такую картину:
![]()
Нам нужно загрузить именно InteliJ Idea Community Edition, т.к. Ultimate Edition является платной версией этой IDE и по факту нам не сильно нужен для Minecraft разработки. Нажимаем Download и ожидаем пока загрузится .exe установщик IDE.
В установщике просто нажимаем Next > и соглашаемся со стандартными настройками. По окончанию установки у нас должна появится InteliJ Idea на ПК. Если она установилась корректно, то переходите ко следующему пункту.
4.Загрузка серверного ядра и развертывание своего сервера
Для разработки плагинов нам также необходимо загрузить на свой пк серверное ядро той версии, для которой будем писать плагин. Делаем простой запрос в гугл: Название вашего ядра + версия. Допустим мне нужно ядро Paper 1.19.4, соответственно выглядеть это будет так:
![]()
Нажимаем на этот сайт и попадаем на страницу загрузок:
![]()
Здесь мы нажимаем на Paper и видим, что сайт предлагает загрузить ядро Paper для версии 1.20.2, но нам нужна именно версия 1.19.4, поэтому переходим в Build Explorer:
![]()
![]()
Здесь мы выбираем нужную версию и качаем последний билд ядра на нашу версию:
![]()
После загрузки мы должны переместить .jar файл в отдельную папку, допустим server:
![]()
Для удобства я переименовал ядро в core.jar, т.к. сейчас нам нужно будет создать загрузочный скрипт. Для этого мы создаём .txt файл и переименовываем его в start.bat:
![]()
Открываем файл при помощи текстового редактора по типу Notepad++ или же обычного блокнота и вписываем туда следующее:
@echo off title Test server java -jar core.jar -nogui pause
Сохраняем скрипт и запускаем его:
![]()
Если всё верно, то сервер загрузит библиотеки и выдаст ошибку, т.к. вам необходимо принять EULA (Политику конфиденциальности). Для этого заходим в eula.txt и изменяем eula=false на eula=true.
ВАЖНО Если у вас не лицензионный аккаунт Minecraft, вам так же следует октлючить online-mode в server.properties. Для этого открываем этот файл текстовым редактором и заменяем online-mode=true на online-mode=false.
Во время второго запуска сервер должен сгенерировать до конца все файлы и успешно запустится:
![]()
Если вы увидели надпись Done (xxx s)! For help, type «help», то сервер успешно запущен и готов к работе. Мы можем переходить к финальному подготовительному этапу.
5.Установка доп. плагинов для IDE
Итак, теперь нам нужно подготовить нашу IDE к разработке Minecraft плагинов. Для этого мы запускаем саму InteliJ Idea:
![]()
Переходим во вкладку Plugins и видим экран установки плагинов для IDE:
![]()
Пишем в поисковой строке Minecraft Development и нажимаем Install:
![]()
После этого IDE попросит вас перезагрузить её чтобы плагин начал работать и фактически на этом этапе мы готовы к разработке плагинов на все 100%! Теперь вы можете смело переходить к финальному и самому основному пункту данного гайда — разработка самого плагина.
6.Создание своего первого плагина
Если вы дошли сюда, значит у вас уже всё готово для начала разработки. Давайте приступим к этому интересному процессу. Для начала мы переходим на главную страницу InteliJ Idea и нажимаем New Project:
![Как написать свой первый плагин - обновлённый гайд за 2023 год [Гайд]](https://ru-minecraft.ru/uploads/posts/2023-10/1697397689_snimok-ekrana-2023-10-15-185546.png)
После нажатия на эту кнопку откроется вот такое меню:
![]()
Нажимаем на Minecraft и с этого момента мы действительно начинаем работу над плагином:
![]()
Итак, сейчас я подробно объясню вам что делает каждое из этих полей. Мой личный совет — заполняйте все поля, кроме Depend, Soft Depend и Load Before. Эти 3 поля заполняйте только по необходимости.
Начнём с первого поля, и это Name, где мы указываем название проекта, не плагина:
![]()
Далее идёт поле Location, где мы указываем в какой директории будут находится файлы нашего проекта:
![]()
Теперь мы видим переключалку под названием Platform Type, где есть два значения: Mod и Plugin. Выбираем Plugin, т.к. мы будем разрабатывать именно плагин.
![]()
После этого мы видим поле Platform, где выбираем для какого типа ядра будем писать плагин, в нашем случае это Bukkit, поэтому выбираем его:
![]()
Также мы видим переключалку Bukkit Platform, в которой можно выбрать какого типа наше ядро: Spigot или Paper. Т.К. Я загрузил ядро Paper, то я выбрал здесь Paper.
ВАЖНО Давайте немного углубимся в тему форков. Spigot — это форк Bukkit, поэтому Spigot включает в себя всё что есть в бакките + некоторые свои функции. Paper — это форк Spigot, поэтому он включает в себя всё что есть в бакките, спигете и некоторые свои функции. Это важно понимать при выборе значения в этой переключалке.
![]()
В поле Minecraft Version выбираем версию нашего ядра, в моём случае это 1.19.4:
![]()
В поле Plugin Name мы вводим название самого плагина:
![]()
В поле Main Class мы вводим путь к главному классу плагина:
![]()
Далее мы видим раздел Optional Settings, я рекомендую вам развернуть его и заполнить:
![]()
В поле Description вводим описание плагина, что он делает:
![]()
В поле Authors вбиваем свой никнейм:
![]()
В поле Website вводим ссылку на свой сайт, если он у вас есть:
![]()
В поле Log Prefix мы вводим префикс плагина который будет отображаться в консоли и логах:
![]()
Переключалка Load At предназначена для более продвинутых пользователей, которые понимают в какой именно момент им нужно чтобы плагин инициализировался, поэтому поставим значение Startup (До загрузки мира):
![]()
Поля Load Before, Soft Depend и Depend мы заполнять не будем, т.к. наш плагин не имеет никаких зависимостей или же несовместимостей.
После секции Optional Settings идёт поле Build System. Я очень настоятельно рекомендую оставить значение Maven, т.к. Gradle является менее распространённым в мире написания плагинов и вы врядли сможете найти нужные дополнения/зависимости/гайды и т.д. для Gradle:
![]()
В секции Build System Properties мы видим 3 поля:
Group ID — Ваш идентификатор разработчика, если нет веб-сайта то пишите me.nickname, если есть, то пишите domainzone.domain.
Artifact ID — Идентификатор самого плагина, обычно идентичен названию плагина.
Version — Версия плагина, можете оставить 1.0-SNAPSHOT, но я заменю на 0.1.
![]()
Ну и последнее поле — JDK. В нём вы указываете какую версию JDK вы будете использовать для проекта, в моём случае это JDK 17.
![]()
После этого нажимаем Create и видим, что проект был успешно создан:
![]()
Давайте разберёмся со структурой проекта:
.idea — системная папка InteliJ Idea, не трогаем её.
src — папка с исходниками нашего плагина, тобишь та папка, где мы будем писать весь код.
resources — папка с ассетами (ресурсами) плагина, например конфигурация, инфо об плагине и т.д.
pom.xml — схема для Maven, если вы не разбираетесь в этом, то вам это трогать уж точно не нужно.
Открываем папку src, в ней доходим до главного класса и открываем его:
![]()
Здесь за нас уже написали самую основу плагина, давайте разберёмся:
Вопервых, за нас уже правильно объявили главный класс который наследует все методы из класса JavaPlugin.
public final class Main extends JavaPlugin
Также за нас уже написали два метода: onEnable() (при включении) и onDisable() (при выключении). Фактически, большинство действий мы будем выполнять именно при включении сервера.
@Override public void onEnable() { // Plugin startup logic > @Override public void onDisable() { // Plugin shutdown logic >
В этом уроке мы разберём написание самого простейшего плагина для вывода надписи при включении и выключении сервера.
Первым делом нам нужно создать объект под названием Logger. Этот объект отвечает за вывод в консоль всевозможных ошибок, предупреждений, информации и т.д.:
![]()
Мы приравниваем Logger к Logger’у из Bukkit, т.к. нам нужен именно майнкрафтовский логгер.
Теперь в методы onEnable() и onDisable() мы впишем простую команду: log.info(«Информация»):
![]()
Отлично, мы написали простенький плагин, давайте же проверим работает ли он. Для начала нам нужно скомпилировать его. Вверху мы видим меню компилятора:
![]()
Нажимаем на зелёную стрелочку и наблюдаем за происходящим на экране, если всё правильно, то внизу у вас должна появится консоль с логом и также должна появится папка target, где и находится наш .jar файл плагина:
![]()
Копируем этот .jar файл в папку plugins своего сервера и запускаем сам сервер:
![]()
Как мы видим, плагин написан правильно и делает то что и должен. Мы можем выключить сервер дабы удостоверится в этом ещё раз:
![]()
Поздравляю вас, вы написали свой первый плагин для Minecraft!
Заключение
В этом гайде мы полностью разобрали как же делаются плагины. Важно понимать, что для полноценной разработки плагинов вам нужно знать не только Bukkit API, но и Java в целом. Я надеюсь, что этот гайд поможет вам в ваших начинаниях по созданию плагинов! Спасибо за прочтение.