Иконка ресурса

Руководство [Bukkit API] - написание плагина, эвенты и команды

Поддерживаемые версии
  1. 1.12
Доброго времени суток. Я в прошлый раз обещал написать второй туториал насчет плагинов на следующий день, но к сожалению, этот день затянулся РОВНО НА ДВА МЕСЯЦА. Прошу прощения.
Итак, снова всем привет. В прошлый раз мы научились создавать плагин, но все-же он не имел функционала. В этот раз мы сделаем следующее:
1) Сделаем свое сообщение при входе
2) Попробуем выключить TAB (автодополнение)
3) Будем проигрывать звук ui.toast.challenge_complete (звук выполнения испытания) когда на сервер заходит администратор или игрок с OP
4) Добавим свою команду
5) Добавим аргументы для команды

Туториалы:
1) Написание плагинов
2) Написание плагинов - Эвенты и команды
3) Bukkit API - Сущности

И снова хочу сказать "извините". Дело в том, что я поменял жесткий диск, и потерял старый проект.
Сейчас мне нужно написать один плагин для себя, и по мере написания плагина я буду писать туториалы. Трудностей возникнуть не должно - поменялись только названия классов и пакетов.

P.S. В конце я напишу весь код целиком, чтобы не возникло банальных вопросов.

1) Создаем свое сообщение при входе

Для начала, напишем в главный класс код для регистрации класса эвента:
в тело onEnable() запишем getServer().getPluginManager().registerEvents(new EventsListener(), this);
Что значат эти слова? Я не буду разбирать все досконально, расскажу только об аргументах, чтобы не возникло путаницы. new EventsListener() - это "новый слушатель эвентов". В этом месте вместо EventsListener можно написать что угодно, но лучше было бы чтобы слово содержало смысл. this - главный класс, в котором импортируется JavaPlugin.
IDE загорится ошибкой, и предложит создать класс EventsListener. Создаем его, и открываем.
Там где public class EventsListener дописываем implements Listener. implements - это реализация интерфейса. Это может быть непонятным, поэтому советую почитать про интерфейсы, классы и абстрактные классы.
В тело пишем аннотацию @EventHandler, она указывает что это эвент.
Сразу после аннотации пишем public void название_эвента(Эвент e)
Где "название_эвента" можно написать что угодно, где "Эвент" - именно тот эвент, который нам нужен.
Итак, вернемся к идее. Что нам нужно? Свое сообщение при входе. Значит эвент будет PlayerJoinEvent.
Cписок эвентов можно посмотреть тут. Это не все эвенты, а только связанные с игроком.
Продолжим писать код.
У нас получилось public void onPlayerJoin(PlayerJoinEvent e)
IDE предложит импорт этого эвента, импортируем.
Теперь в тело пишем e.setJoinMessage(e.getPlayer().getName()+"§a зашел на сервер!");
Разберем. e.setJoinMessage - дословно, это установка сообщения при входе. e.getPlayer().getName() - это получение имени игрока. При входе, у нас будет примерно такое:
Admin зашел на сервер!
Готово.

2) Звук при входе, если игрок администратор
Теперь, все в том же эвенте, пишем следующие строки:

Java:
        if (e.getPlayer().isOp() || e.getPlayer().hasPermission("plugin.admin")) { // проверка игрока на OP или право                                                                               // "plugin.admin", где plugin -
                                                                                         // название плагина
            for (Player pp : Bukkit.getOnlinePlayers()) {
                pp.playSound(pp.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 100.0F, 100.0F);
            }

            /*
             * проигрывание звука
             *
             * .getLocation - локация игрока,
             *
             * Sound.UI_TOAST_CHALLENGE_COMPLETE - звук выполненного испытания,
             *
             * 100.0F и 100.0F я честно не помню что значат, вроде тональность и дальность
             * звука.
             *
             * Попробуйте поменять эти два значения.
             */

            e.setJoinMessage("§cАдминистратор §e" + e.getPlayer.getName() + "§c зашел на сервер!");
        }
Я написал в комментариях к коду, что и как тут происходит.
3) Отмена использования TAB'а
В том же самом классе (EventListener) напишите этот код:

Java:
@EventHandler
    public void onPlayerUseTab(TabCompleteEvent e) {
        if (!e.getSender().hasPermission("plugin.admin") || !e.getSender().isOp()) {
            e.setCancelled(true);
        }
}
Если тот кто использовал TAB - не имеет ОП или права "plugin.admin", то эвент отменяется. Все легко и просто. Должно работать.

4) Добавление команды
В большинстве туториалов предлагают создание команды в главном классе, но мы как тру-кодеры будем делать все отдельно.
Вернемся к onEnable() главного класса, допишем в конец тела следующую строку:
getServer().getPluginCommand("команда").setExecutor(new название_класса_команды());
где вместо "команда" может быть все что угодно, и... вместо "название_класса_команды" тоже все что угодно. Но придерживайтесь правила - это "все что угодно" должно иметь смысл. У меня будет называться команда "player" и класс "PlayerCMD".

Итак, IDE скажет что у нас нет такого класса, создаем его.
После public class PlayerCMD добавим implements CommandExecutor.
IDE предлагает добавить недобавленные методы, добавляем.
Класс принял такой вид:

Java:
public class PlayerCMD implements CommandExecutor {

    @Override //переопределяем метод
    public boolean onCommand(CommandSender sender, Command cmd, String str, String[] args) {
         //CommandSender - отправляющий команду, Command - команда, String str я никогда не использовал, мне хватало cmd, String[] args - массив аргументов.
        return false; //вернем "ложь" если команда выполнена неправильно (настраивается в plugin.yml)
    }

}
По сути, мы добавили команду.
Но она ничего не делает, а это не интересно, поэтому перейдем к аргументам...
5) Аргументы и факты
Java:
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String str, String[] args) {
            Player target = sender.getServer().getPlayer(args[0]); //аргумент 1 (отсчет идет с нуля, поэтому в массивах число=число+1)
            if (sender.hasPermission("grief.playerinfo") && (args.length < 1 || args.length > 1)) { //если игрок имеет правo "плагин.playerinfo"
                sender.sendMessage("§eИмя игрока: §c"+target.getName());
                sender.sendMessage("§eКоординаты: §c"+target.getLocation());
                sender.sendMessage("§eРежим: §c"+target.getGameMode());
                sender.sendMessage("§eИмеет ОП: §c"+target.isOp());
                if (sender.hasPermission("grief.playerinfo.adv")) { //если игрок имеет право "плагин.playerinfo.adv" (adv - advanced, улучшенный)
                sender.sendMessage("§eIP: §c"+target.getAddress());
                sender.sendMessage("§eUUID: §c"+target.getUniqueId());
                }
                return true; //вернем правду, команда выполнена верно
            }
        return false;
    }

Как сделать объявления (аналог /bc в Essentials):
Java:
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String str, String[] args) {
            if (sender.hasPermission("grief.broadcast")) {
                if (args.length!=0) {
                    String message = ""; //инициализация переменной
                    for (int i = 0; i < args.length; i++) { //цикл, который проходит по массиву аргументов
                    message = String.valueOf(message)+args[i]+""; //сбор всех аргументов в одно целое
                    }
                    message = ChatColor.translateAlternateColorCodes('&', message); //перевод & (цветовые коды)
                    Bukkit.broadcastMessage("§7[§a"+sender.getName()+"§7] "+message); // показываем всем свое сообщение
                } else {
                    sender.sendMessage("§fИспользуйте /broadcast <сообщение>"); //можно настроить в plugin.yml сообщение, а можно и так)
                }
         
            }
            sender.sendMessage("§cУ Вас нет прав!"); //нет прав!
        return true;
    }
Этот код показывает примерную работу с большим количеством аргументов. Вывод должен быть примерно таким:
Мы вводим: /broadcast 1 2 3 4 4 5 6 7
Все видят:
1566678266922.png


В прошлом уроке мы использовали plugin.yml. Он был довольно маленького содержания, но сейчас оно пополниться.
Нам нужно заполнить plugin.yml командами и правами, тут нет ничего сложного, и можно понять по шаблону

Целиком файл выглядит так:
YAML:
name: Grief
main: me.mycompanyname.grief.Grief
version: 1.0

commands: #команды
   player: #команда
      description: Описание, отображается в /help
      permission: grief.playerinfo #право
      usage: /<command> [player]
    broadcast:
      description: Возможность писать объявления
      permission: grief.broadcast
      usage: /<command> [сообщение]

permissions: #права
    grief.playerinfo.adv: #право
        description: Описание
        children: #"дети" права. кажется, это нужно чтобы не вводить в файл с правами -grief.playerinfo.adv
                       #и -grief.playerinfo, и использовать -grief.playerinfo.* . Если у Вас одно "детское" право как у                        #меня, то можно не использовать
            grief.playerinfo: true #является
    grief.playerinfo:
        description: Дает право на просмотр базовой информации об игроке
    grief.admin:
        description: Обход некоторых запретов и уникальное сообщение при входе
Вроде бы, это все. Экспортируем в Jar и идем проверять.
Задаем вопросы, указываем на ошибки, ожидаем третью часть - она будет совсем скоро, ну а теперь - до встречи!
Автор
q20w26a
Просмотры
23,793
Первый выпуск
Обновление
Оценка
5.00 звёзд 2 оценок

Другие ресурсы пользователя q20w26a

Поделиться ресурсом

Последние обновления

  1. Обновление

    Исправлены некоторые фактические ошибки; добавлена закрывающая скобочка во втором разделе.
  2. Отредактирован код

    Добавлена проверка на аргументы в пятом пункте, поправлено проигрывание звука всем игрокам во...

Последние рецензии

Очень доходчиво и с подробными комментами. Годный контент. Спасибо за вклад в развитие русскоязычного сообщества
Спасибо за туториал полезная инфа еще бы туториал по BungeeCord было б норм. Не видел еще норм туториалов по BungeeCord плагинах в русскоязычных сообществах или форумах
Назад
Сверху Снизу