1. База Java для плагинов: синтаксис, ООП, коллекции
База Java для плагинов: синтаксис, ООП, коллекции
Зачем база Java именно для Spigot/Paper
Плагины для Minecraft на Spigot/Paper — это обычные Java-приложения, которые запускаются внутри сервера. Сервер вызывает ваш код (например, при вводе команды или событии), а вы используете Java, чтобы:
В следующих статьях мы начнём писать реальный плагин, а здесь закладываем фундамент: синтаксис Java, ООП и коллекции — ровно то, что вы будете использовать каждый день.
> Практическое правило для плагинов: пишите код так, чтобы его было безопасно вызывать много раз и в непредсказуемом порядке (события приходят тогда, когда это делает игрок).
Версия Java и стиль кода
На современных версиях Paper обычно используется Java 17 и выше. Конкретные требования зависят от версии сервера.
Синтаксис Java, который постоянно встречается в плагинах
Переменные и типы
В Java тип указывается явно.
Часто в плагинах встречаются:
int, long для счётчиков, времени в миллисекундахboolean для флаговString для сообщений, имёнUUID для идентификации игроковМетоды
Метод — это именованный блок кода. В плагинах вы постоянно выносите повторяющиеся действия в методы.
Условия и циклы
События и команды обычно содержат ветвления.
Циклы часто используются для перебора коллекций.
null и проверки
В Java ссылочная переменная может быть null (то есть ничего не указывает). В плагинах null часто появляется при поиске сущности по имени/UUID или при чтении конфигов.
Если API возвращает Optional, это явный сигнал: значение может отсутствовать.
Классы и объекты: как устроен ваш код
Класс — это шаблон. Объект — экземпляр класса.
Поля, конструктор, инкапсуляция
Инкапсуляция — прячем внутреннее состояние и даём доступ через методы.
Ключевые моменты для плагинов:
private защищает поля от случайной порчи из других классовpublic) — это ваш контракт использованияstatic — когда это уместно
static принадлежит классу, а не объекту.
В плагинах static применяют для:
Но состояние плагина (Map с данными игроков и т. п.) обычно делают полями экземпляра главного класса/сервиса, а не static, чтобы проще управлять жизненным циклом.
Модификаторы доступа
public — доступно отовсюдуprotected — доступно в пакете и наследникамprivate — доступно только внутри классаООП в контексте плагинов
ООП нужно не ради терминов, а ради структуры: чтобы код не превращался в один огромный класс.
Наследование
Наследование — это is-a ("является").
Пример из Bukkit/Paper: ваш главный класс плагина наследуется от JavaPlugin.
Важно:
JavaPlugin)Интерфейсы
Интерфейс — это контракт: что объект умеет делать.
В плагинах интерфейсы встречаются постоянно, например обработчики событий реализуют Listener.
Полиморфизм
Полиморфизм — это когда код работает через общий тип (интерфейс/родительский класс), а конкретная реализация подставляется автоматически.
В плагинах это полезно для:
Композиция вместо наследования
Композиция — это has-a ("имеет"). Обычно так строят плагины: главный класс имеет сервисы.
Это делает код проще для тестирования и расширения.
Исключения: как не убить сервер ошибками
Исключение (exception) — это сигнал об ошибке выполнения.
try/catch и логирование
Практика для плагинов:
catchChecked и unchecked (коротко и по делу)
RuntimeException и наследники) — частые ошибки логики или данныхIOException и т. п.) — заставляют обработать/пробросить, часто встречаются при работе с файламиДженерики (Generics): типобезопасные коллекции
Дженерики позволяют коллекциям знать тип элементов.
Почему это критично для плагинов:
ClassCastException в рантаймеКоллекции: ваш основной инструмент хранения данных
Коллекции — это структуры данных из Java Collections Framework.
Официальные материалы:
List: упорядоченный список
Используйте, когда важен порядок и допускаются повторы.
Частые применения в плагинах:
Set: уникальные элементы
Используйте, когда важна уникальность.
Частые применения:
Map: ключ → значение
Самая полезная коллекция для плагинов: быстрый доступ к данным по ключу.
Типичные кейсы:
UUID -> PlayerDataUUID -> cooldownEndTimeString -> настройка/локализацияВыбор реализации: что брать по умолчанию
ArrayList — почти всегда базовый выбор для ListHashSet — базовый выбор для SetHashMap — базовый выбор для MapЕсли нужен порядок вставки:
LinkedHashMap, LinkedHashSetЕсли нужен отсортированный порядок:
TreeMap, TreeSetЕсли ключ — это enum:
EnumMap (быстро и экономно)Итерация по коллекциям
equals() и hashCode() — важно для HashMap и HashSet
HashMap и HashSet полагаются на:
equals() чтобы понять, равны ли два ключаhashCode() чтобы быстро находить "корзину" для ключаЕсли вы делаете свой класс ключом в HashMap или элементом в HashSet, обычно нужно переопределить оба.
Практическая рекомендация:
final поля, без сеттеров), иначе можно "сломать" поиск в HashMapПотоки выполнения и коллекции в плагинах
Большая часть Bukkit/Paper API должна вызываться из главного потока сервера. Это влияет на коллекции:
HashMap только в главном потоке, обычно всё нормальноБазовые правила:
ConcurrentHashMap) и проектируйте доступ аккуратноМини-практика: типичные фрагменты для плагина
Кулдаун на команду
Набор отключённых миров
Хранилище данных игрока
Итоги
В этой статье вы собрали базу, без которой плагин быстро превращается в хаос:
null)List, Set, Map) как основной способ хранить состояние плагинаВ следующей статье мы перейдём от базы к практике: создадим каркас плагина, разберём структуру проекта и жизненный цикл onEnable/onDisable, чтобы начать подключать команды и события.