1. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

Туториал Пишем простой плагин для bukkit (v1.2.5+)

Тема в разделе "Руководства, инструкции, утилиты", создана пользователем DmitriyMX, 13 июн 2012.

?

Продолжать выкладывать туториалы по написанию плагинов?

  1. Да

    157 голосов
    95,7%
  2. Нет

    7 голосов
    4,3%
  1. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
    Подготовка
    Для написания своих плагинов нам понадобятся:
    Так же понадобятся базовые знания по Java. Если таковых нет, то вот ссылки по “поднятию скила”:
    Установка и настройка Eclipse

    Если вы уже знакомы с Eclipse или увас другая IDE, то пропускайте этот раздел.
    Проблем с установкой эклипса возниктуть не должно: его нужно просто распаковать в любоую папку и запустить. Сразу после этого, эклипс попросит указать, какое рабочее пространство(workspace) сейчас открыть. Это папка, в которой будут сохранятся все созданные проекты и где ее располагать – лично ваше решение. Если вам всеранво, то оставляйте все как есть. Если вдруг захотите изменить рабочее пространстро, то не переживайте: при каждом следующем запуске, эклипс сново спросит вас о рабочем пространстве. Таких пространств можно наделать сколько угодно и каждое может быть настроено по разному, под какие-то определенные цели. К примеру у меня есть 2 рабочих пространства: для написания обычных java-приложений и для написания плагинов под “ведро”. Если вдруг вам надоест это сообщение, там есть галочка «Use this as the default and do not ask again», что позволяет задать workspace по-умолчанию.

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

    [​IMG][​IMG]
    Теперь же мы видим рабочее пространство самого эклипса. Из всего этого, нам понадобится только следующие панели:

    • Package Explorer
      Здесь будут отображаться ваши проекты, пакеты(о них позже) и всевозможные файлы наших будующих плагинов.
    • Problems
      Этой панелькой мы будем редко пользоваться(если вообще до нее дело дойдет), но сказать о ней стоит. Здесь будут показываться ошибки, допущенные в коде, а так же предупреждающие сообщения о возможных ошибках или неточностях.
    • Outline
      Тут будет отображаться навигация непосредственно по коду открытого java исходника.
    Последние 2 описанные панели можно вообще свернуть, т.к. пользоваться ими будем редко.
    Рабочее место почти готово. Осталось только поставить еще 2 галочки в настройках.

    Переходим в меню Window -> Preferences, далее по древу General -> Editor -> Text Editors и выставляем галочку «Show line numbers», чтобы включить отображение нумерации строк. Теперь переходим в General -> Workspace и в группе «Text file encoding» выставляем кодировку UTF-8, тем самым установив кодировку по-умолчанию.
    [​IMG][​IMG]
    С установкой и настройкой покончено. Теперь поясню, как создавать новый проект для плагина. Это можно сделать одим из 3-х способов:
    • Меню File -> New -> Java Project
    • Кнопка на панели инструментов
    • Правый клик в Package Explorer
    [​IMG]
    Перед нами откроется окно New Java Project. В Project name указываем название нашему проекту.
    [​IMG]
    Нажимаем Next.
    В появившемся окне, переходим на вкладку Libraries, нажимаем кнопку Add External JARs и выбираем скаченный Bukkit API.
    [​IMG]
    Жмем Finish.
    Слева, в Package Explorer, показался наш проект с папкой src, в которой будут храниться наши исходные коды. Теперь созданим новый класс. Делается это точно так же, как и с Java Project.
    [​IMG]
    В окне New Java Class нам понадобятся только следующие графы:
    • Package
      указывается пакет, в котором будет хранится наш класс. Формат имени должен быть примерно такой: ru.dmitriymx.bukkit.tutorial.
      Если в двух словах и на пальцах, то пакеты в ява – это пространство имен(namespace) или «виртуальные папки», в которые помещаются классы. Подробнее про это можно прочитать здесь: [1], [2], [3].
    • Name
      указываем название класса (у меня это DmxFirstPlugin)
    Все остальные пункты оставляем как есть и жмем Finish.
    Вот теперь переходим непосредственно к коду.

    Пишем простой плагин
    Как только мы создали новый класс, нашему взору предстает уже готовый пустой шаблон:
    Код:
    package ru.dmitriymx.bukkit.tutorial;
     
    public class DmxFirstPlugin {
     
    }
    Пока это всего лишь пустой класс, который абсолютно бесполезен в быту. Будем это исправлять. Изменяем вот это:
    Код:
    public class DmxFirstPlugin
    на это
    Код:
    public class DmxFirstPlugin extends JavaPlugin
    Эклипс подчеркнет нам JavaPlugin, указывая на ошибку в коде. Если подвести мышь к такому подчеркнутому коду, то откроется окошко с описанием ошибки и способы ее решения. В данном случае нам нужно импортировать класс из Bukkit API, для чего выбираем пункт «Import ‘JavaPlugin’(org.bukkit.plugin.java)».
    [​IMG]
    Сразу же замечаем, как над всем нашим кодом вписалась строчка
    Код:
    import org.bukkit.plugin.java.JavaPlugin;
    Немного теоретического материала. У плагинов есть 3 основных метода: onEnable(), onDisable() и onLoad(). Первые два отвечают за включение и отключение плагина, а последний срабатывает когда плагин непосредственно подгружается в память сервера. Из этого следует, что onLoad выполняется самым первым, но сам плагин начинает работать только после вызова onEnable со стороны сервера. По выключению или перезагрузки сервера, вызывается метод onDisable.
    С “точками входа-выхода” разобрались. Давайте теперь напишем что-нибудь более-менее работоспособное. Приведем общий код класса к следующему виду:
    Код:
    package ru.dmitriymx.bukkit.tutorial;
     
    import java.util.logging.Logger;
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.plugin.java.JavaPlugin;
     
    public class DmxFirstPlugin extends JavaPlugin implements Listener {
      public static final Logger _log = Logger.getLogger("Minecraft");
     
      @Override
      public void onEnable() {
          _log.info("[DMX PLG] onEnable()"); //вывод произвольного текста в консоль сервера
          Bukkit.getPluginManager().registerEvents(this, this);
      }
     
      @EventHandler
      public void onJoin(PlayerJoinEvent event){
          event.getPlayer().sendMessage(ChatColor.GREEN + "Добро подаловать на сервер, " + ChatColor.GOLD + event.getPlayer().getName());
          event.setJoinMessage(ChatColor.GRAY + "Игрок " + ChatColor.GOLD + event.getPlayer().getName() + " зашел на сервер");
      }
     
      @EventHandler
      public void onQuit(PlayerQuitEvent event){
          event.setQuitMessage("");
          getServer().broadcastMessage(ChatColor.GRAY + "Игрок " + ChatColor.GOLD + event.getPlayer().getName() + " покинул сервер");
      }
    }
    То что мы сейчас написали – готовый плагин. Все что он делает – это пишет в чат о приходе и уходе игрока на сервер. Разбираться в его работе будем по порядку(а как иначе?).
    Сперва обращу внимание на строку объявления класса. Как видно, к нашему классу добавилось расширение Listener. Не углубляясь в дебри явы, скажу проще: указывая данное расширение, мы тем самым расширяем область применения класса не только как плагина(JavaPlugin), но и как обработчика событий(Listener). А вот как раз в методе onEnable() мы регистрируем наш класс на сервере как обработчик событий(this – это указание «на самого себя», если кто забыл).
    В этом и есть координальное отличие от старой системы обработки событий, которые были мною описаны ранее. Теперь, вместо того, чтобы лепить кучу классов, и запоминатьточные названия методов событий, нам достаточно расширить класс до листенера и указать с помощью «@EventHandler», какие функции будут являтся обработчиками событий. Просто? Да не то слово как просто!!
    Далее следует 2 наших обработчика событий onJoin() и onQuit(). Первый отвечает а событие входа игрока на сервер, а второй – за уход. С помощью метода event.getPlayer().sendMessage(), мы можем отправить сообщение тому игроку, которое вызвал данное событие(в нашем случае игроку, который зашел). Статический класс ChatColor хранит в себе константы цветов для окраски. Думаю как им пользоваться уже видно из примера. Так же, оба наших обработчка оповещают других игроков на сервере о произошетших событиях, но делают это по разному. В onJoin() с помощью метода event.setJoinMessage() мы меняем привычное сообщение «Player joined the game» на любое другое. А в onQuit() мы поступили инача(в целях примера): убрали вывод сообщения о выходе и сообщаем об этом через метод getServer().broadcastMessage(), который просто посылает всем игрокам на сервере указанное сообщение.
    Дело осталось за малым: написание важного файлика plugin.yml и упаковка всего этого в jar-файл.
    plugin.yml – это файл описания плагина. В нем задается название плагина, главный класс, описание и какие комманды зарегестрировать за плагинов(об этом позже) и т.д. В нашем случае, файлик должен выглядеть так:
    Код:
    name: Dmx First Plugin
    main: ru.dmitriymx.bukkit.tutorial.DmxFirstPlugin
    description: Простой плагин с сайта dmitriymx.ru
    version: 1.0
    Ой, забфл сказать, где этот файлик должен находится. Жмем правой кнопкой мыши в PackageExplorer по папке src и через меню New выбираем File. В поле File name пишем plugin.yml и жмем Finish. В открывшемся текстовом редакторе, пишем то, что я указывал выше. Всё сохраняем и переходим к последней фазе: упаковке.
    Правый тык по папке src -> Export. В древе папок, открываем Java и выбираем JAR file и жмем Next. Из голочек оставляем только «Export generated class files and resources» и «Compress the contents of the JAR file». В поле JAR file указываем, куда будем сохранять полученный плагин. После нажатия на Finish, плагин можно класть в папку plugins, запускать сервер и проверять его работу.

    [​IMG][​IMG][​IMG]
    Видите? Это совсем просто. С практикой вы наберетесь больше опыта и сможете делать более крутые плагины, даже такие легендарные как WorldEdit и WorldGuard.

    Ссылки
    Следующая статья:
    Документация:
    Полезности:
    ________________________________________​
     
    SaMEC, DavidShabaev, zuma2 и 11 другим нравится это.
  2. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
    UPD: починил картинки/скриншоты
     
  3. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
    Кстати, не стесняйтесь и пишите в комментариях вопросы, ответы на которые хотели бы увидеть в следующих уроках.
     
  4. DanteS

    DanteS Старожил Девелопер Пользователь

    Баллы:
    103
    Отличная работа!
    Крайне полезно для новичков.
     
  5. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
  6. ensirius

    ensirius Старожил Пользователь

    Баллы:
    123
    Listener в main классе это нечто.
     
  7. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
    :confused: это замечание? Если да, то объясните почему
     
    Earstorm нравится это.
  8. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    Вы не правы. В отдельных случаях, если плагин компактный и обрабатывается одно-единственное событие, то для чего городить целый класс?

    Аналогично с обработчиком команд. Для небольшого плагина удобнее его организовывать внутри осного класса. А если у Вас обработчики команд здоровенные - то можно на каждую команду отдельный класс делать.
     
  9. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    DmitriyMX, Вы молодец! Жалко такого туториала не было когда я пытался чему-то научиться.
     
  10. Ission

    Ission Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    lokivava
    Когда лепишь до лесу обработчиков событий, обработчики событий одного пакета(например player или block) нужно делить события по разным классам, иначе они начинают материться и частично не работать. Также помимо этого желательно указывать приоритет обработки классов.
     
    DmitriyMX нравится это.
  11. Ission

    Ission Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    lokivava
    На счёт Вас не знаю, но с версии 1.7.3 точно был(на английском).
     
    caNek нравится это.
  12. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    Они начинают материться и частично неработотать вовсе не из-за этого, уверяю Вас ;)

    Деление listener'ов на разные типы player - block -- это наследие старой системы обработчиков событий. Просто тогда можно было ТОЛЬКО так. Сейчас с этим проще. Если у меня 3 небольших обработчика, то зачем мне создавать три разных класса?! Но раньше можно было приоритет задавать при иницилизации, теперь этого уже нельзя (для настраиваемого приоритета сейчас нужно делать два обработчика одного события и уже в зависимости от необходиомого выполнять код в одном или в другом).
    Приоритет можно опускать - будет NORMAL.
     
  13. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    Ну я совем не знал Java, никогда в жизни не видел Eclipse, не программировал лет восемь или семь - для меня статьи на bukkit wiki были слишком продвинутые. Я первый плагин сделал по какому-то туториалу с youtube :)
     
  14. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    DmitriyMX, если Вы пользовались github'ом, то не могли бы рассказать о нём?
    Я его не понимаю. Один плагин смог выложить, а второй - какая-то путаница, не то с ключами не то с чем-то ещё. Не могу разобраться.
     
  15. Ission

    Ission Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    lokivava
    Я, когда первый раз писал плагин, ничего не знал о Java, были основные знания в C++(мог написать hello world и пару циклов). Первый плагин - я разобрал чужой плагин и собрал что-то нечто своё. Eclipse - до сих пор без-понятия-что-это-такое, ни с чем, кроме жвачки не ассоциируется. Далее пришлось читать статьи на bukkit'е)
     
  16. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
    На счет приоритетов, то они до сих пор могут выставляться(правда, я пока не нашел им применение... да и плохо понимаю). Делается это теперь так:
    Код:
    @EventHandler(priority=EventPriority.HIGH)
    Про GitHub, то пользоваться стал им совсем не давно и только начинаю в нем разбираться. Как станет более-менее понятно, напишу статью про него (точнее связку Eclipse + EGit). Если не терпится, можете написать мне в скайп, расскажу что знаю :)

    :) Вот потому, что не было туториалов на русском, я и начал всё это писать
     
  17. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    DmitriyMX, с приоритетами все просто. Жирную точку в обработке события ставить событие с наивысшим приоритетом, зато к раздаче прибывает событие с низшим.

    Т.е. если у события приоритет LOWEST оно выполняется первым, если MONITOR - последним. C приоритетом MONITOR выполнять события не рекомендуется, если выполянется - то не рекомендуется тут производить тут какие-то "активные действия". С наивысшим приоритетом должны выполняться обработчики плагинов типа LogBlock и прочие антигриферско-античетерские. Которым важно отследить результат события, а не установить где-то блока или заспавнить моба (примеры с потолка).
    В большинстве случаев достаточно приоритета NORMAL, у меня в Lockpick&Rent событие на PlayerInteractEvent выполняется с приоритетом HIGHEST (т.е. до MONITOR'а). Это дает возможность открыть сундук или дверь ("запертый" посредством LWC, например) и в тоже время не перебить у LogBlock'а информацию о том, кто в этот сундук или дверь влез.
     
    DmitriyMX нравится это.
  18. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    Я имел в виду, что раньше можно было создать переменную типа Priority (или EventPriority) и инициализировать её в соответствии с конфигурацией. А сейчас если ты в коде написал priority=EventPriority.NORMAL, то всё. Этот обработчик без правки кода и перекомпиляции как HIGH не запустишь.
    Т.е. если по каким-то причинам Вы выносите в конфиг приоритет события, то нужно создавать количество обработчиков для каждого приоритета и уже в обработчиках проверять - в котором из них код выполнять, в каком нет. Громоздко, но увы больше никак.
     
  19. Автор темы
    DmitriyMX

    DmitriyMX Старожил Пользователь

    Баллы:
    153
    Skype:
    dmn550
    Я не уверен, но может для таких случаев нужно использовать void registerEvent(Class<? extends Event> event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin) ?

    Код:
    void registerEvent(Class<? extends Event> event,
                    Listener listener,
                    EventPriority priority,
                    EventExecutor executor,
                    Plugin plugin)
    Регистрирует указанный исполнителем в данном классе событий
    (Registers the specified executor to the given event class)
    Параметры:
    event - Тип события для регистрации (Event type to register)
    listener - Приемник для регистрации (Listener to register)
    priority - Приоритетными для регистрации этого события в (Priority to register this event at)
    executor - EventExecutor зарегистрироваться (EventExecutor to register)
    plugin - Плагин для регистрации (Plugin to register)
    Спонсор перевода: Google Translate.
     
  20. fromgate

    fromgate Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    fromgate
    DmitriyMX, Возможно. Надо будет попробовать.
     
    GJEvolution нравится это.

Поделиться этой страницей