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

Стартап [ПЕРЕВОД] NMS на разных версиях без рефлексии

Тема в разделе "Разработка плагинов для новичков", создана пользователем Dexel, 14 фев 2018.

  1. Автор темы
    Dexel

    Dexel Активный участник Пользователь

    Баллы:
    76
    Оригинал (EN)

    Я видел много людей, которые делают плагины, которые зависят от версии. Они, например, отправляют сообщения в title или actionbar. Многие используют код NMS (net.minecraft.server), чтобы использовать эти возможности, так как это единственный способ. Так как NMS представляет конкретную версию, я видел немало плагинов, которые зависят от версии, и когда выходит обновление, они больше не работают с предыдущими версиями.

    Недавно я искал лучший способ предложить поддержку нескольких версий, в зависимости от версии сервера, на котором работал мой плагин. Я остановился на Рефлексии.
    Пока я думал, что это - классная вещь (т.к. мой плагин теперь поддерживает предыдущие версии), @DarkSeraphim в теме, где я разместил способ с рефлексией, что он очень сильно нагружает сервер, и правильнее было бы использовать интерфейс, который позволит мне всего лишь проверять, какую совместимость мне нужно предложить, когда мой плагин запущен.

    Использование интерфейса позволяет моему коду с NMS находиться в различных классах, при этом будет загружен и использован только соответствующий с версией сервера. Это избавляет от необходимости использовать рефлексию!

    Несмотря на то, что этот гайд не избавляет от необходимости использовать рефлексию где бы вы ни захотели (бывают причины, когда вам НУЖНО использовать её), для таких вещей, как отправка сообщений в title или actionbar он отлично подходит!

    В этом примере мы будем отправлять сообщение в actionbar игроку, зашедшему на сервер. Этот плагин будет работать на версиях 1.8.x.

    Итак, начнём:

    В своём плагине создайте отдельный пакет для вашего интерфейса и NMS-классов:
    [​IMG]
    Внутри этого пакета мы создадим интерфейс под названием Actionbar.
    Этот интерфейс будет хранить абстрактный метод, который будут использовать наши NMS-классы для отправки в actionbar.

    Любой класс, который реализует наш интерфейс, должен содержать его абстрактный метод.
    Таким образом, мы сможем хранить Actionbar в нашем главном классе, но при этом можем присваивать туда любой из наших NMS-классов, который реализуют интерфейс.
    Код:
    package me.clip.actionbarplugin.actionbar;
    
    import org.bukkit.entity.Player;
    
    public interface Actionbar {
    
        public void sendActionbar(Player p, String message);
    }
    Довольно просто, правда? Здесь всего лишь одна строка кода.
    Это абстрактный метод, который будут использовать наши классы, что реализуют Actionbar, для вызова методов конкретной версии NMS.
    Если вы использовали это для того, чтобы сделать что-то помимо отправки сообщения, вы можете добавить столько методов, сколько вам необходимо для каждого NMS-класса. Учтите, что каждый класс, который реализует этот интерфейс, должен содержать каждый метод, описанный вами здесь.

    Теперь у нас есть наш интерфейс, давайте создадим наши классы, которые реализуют его и отправляют текст в actionbar игроков при помощи NMS!

    Класс 1.8.1, реализующий наш интерфейс Actionbar:
    Код:
    package me.clip.actionbarplugin.actionbar;
    
    import net.minecraft.server.v1_8_R1.ChatSerializer;
    import net.minecraft.server.v1_8_R1.IChatBaseComponent;
    import net.minecraft.server.v1_8_R1.PacketPlayOutChat;
    import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer;
    
    import org.bukkit.entity.Player;
    
    public class Actionbar_1_8_R1 implements Actionbar {
    
        @Override
        public void sendActionbar(Player p, String message) {
    
            IChatBaseComponent icbc = ChatSerializer.a("{\"text\": \"" + message + "\"}");
    
            PacketPlayOutChat bar = new PacketPlayOutChat(icbc, (byte) 2);
    
            ((CraftPlayer) p).getHandle().playerConnection.sendPacket(bar);
        }
    }
    Класс 1.8.3, реализующий наш интерфейс Actionbar:
    Код:
    package me.clip.actionbarplugin.actionbar;
    
    import net.minecraft.server.v1_8_R2.IChatBaseComponent;
    import net.minecraft.server.v1_8_R2.PacketPlayOutChat;
    import net.minecraft.server.v1_8_R2.IChatBaseComponent.ChatSerializer;
    import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer;
    
    import org.bukkit.entity.Player;
    
    public class Actionbar_1_8_R2 implements Actionbar {
    
        @Override
        public void sendActionbar(Player p, String message) {
    
            IChatBaseComponent icbc = ChatSerializer.a("{\"text\": \"" + message + "\"}");
    
            PacketPlayOutChat bar = new PacketPlayOutChat(icbc, (byte) 2);
    
            ((CraftPlayer) p).getHandle().playerConnection.sendPacket(bar);
        }
    }
    Теперь нам осталось лишь создать наш главный класс!
    Код:
    package me.clip.actionbarplugin;
    
    import me.clip.actionbarplugin.actionbar.Actionbar;
    import me.clip.actionbarplugin.actionbar.Actionbar_1_8_R1;
    import me.clip.actionbarplugin.actionbar.Actionbar_1_8_R2;
    
    import org.bukkit.Bukkit;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class ActionbarPlugin extends JavaPlugin implements Listener {
    
        // наш интерфейс! Любой класс, что реализует Actionbar, может быть присвоен сюда!
        // когда нам понадобится отправить текст в actionbar, нам всего лишь нужно будет вызвать actionbar.sendActionbar(player, message);
        // когда соответствующий NMS-класс будет присвоен в методе onEnable, мы будем совместимы с предыдущими версиями!
        private Actionbar actionbar;
    
        @Override
        public void onEnable() {
    
            if (setupActionbar()) {
    
                Bukkit.getPluginManager().registerEvents(this, this);
    
                getLogger().info("Установка Actionbar успешна!");
                getLogger().info("Процесс установки плагина завершён!");
    
            } else {
    
                getLogger().severe("Не удалось установить Actionbar!");
                getLogger().severe("Ваш сервер несовместим с этим плагином!");
    
                Bukkit.getPluginManager().disablePlugin(this);
            }
        }
        // этот метод установит наш actionbar и вернёт true, если сервер работает на
        // совместимой с нашими NMS-классами версии.
        // Если сервер несовместим, вернётся false!
        private boolean setupActionbar() {
    
            String version;
    
            try {
    
                version = Bukkit.getServer().getClass().getPackage().getName().replace(".",  ",").split(",")[3];
    
            } catch (ArrayIndexOutOfBoundsException whatVersionAreYouUsingException) {
                return false;
            }
    
            getLogger().info("Ваш сервер использует версию " + version);
    
            if (version.equals("v1_8_R1")) {
                //сервер работает на 1.8-1.8.1, поэтому нам нужно использовать NMS-класс 1.8 R1
                actionbar = new Actionbar_1_8_R1();
    
            } else if (version.equals("v1_8_R2")) {
                //сервер работает на 1.8.3, поэтому нам нужно использовать NMS-класс 1.8 R2
                actionbar = new Actionbar_1_8_R2();
            }
            // Вернётся true, если версия сервера оказалось совместимой с версией одного из наших NMS-классов,
            // потому что если так и есть, наш actionbar не будет null
            return actionbar != null;
        }
    
        @EventHandler
        public void onJoin(PlayerJoinEvent event) {
            actionbar.sendActionbar(event.getPlayer(), "Welcome to the server!");
        }
    }
    
    В этот туториале я хранил всё в главном классе плагина.
    Если у вас большой плагин, и вы используете несколько классов (класс для слушателей, например)
    вам следует создать геттер для Actionbar в своём главном классе, таким образом другие ваши классы смогут обращаться к нему.

    Создать геттер - очень просто, и вы должны уже знать, как, если вы смотрите этот туториал.
    Код:
    public Actionbar getActionbar() {
        return actionbar;
    }
    Теперь все ваши классы имеют доступ к отправке сообщения в actionbar!

    Есть ещё много способов проверить версию сервера. Я использовал название пакета сервера bukkit, но вы также можете использовать Bukkit.getBukkitVersion() и проверять/присваивать ваш NMS-класс в зависимости от этого.

    Если вы инициализируете один из ваших NMS-классов, который не подходит версии сервера, ваш плагин выбросит ClassNotFoundException.
    Убедитесь, что вы инициализируете только класс для конкретной версии сервера, на котором работает плагин!

    [​IMG]
     
  2. hyndorik

    hyndorik Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    hyndo
    Ты какого года вообще статью переводил? 12? Юзать нмс чтоб экшн бар отправить, бог...
     
  3. Автор темы
    Dexel

    Dexel Активный участник Пользователь

    Баллы:
    76
    Отправка actionbar'ов здесь является примером использования мультиверсионной поддержки NMS. Или, в твоём понимании, NMS только для этого существует?
     
  4. hyndorik

    hyndorik Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    hyndo
    Ты поехавший какой-то, можно было бы еще нмсом игрока телепортировать, че апи то юзать. Пример с экшн баром уже года 2 как не актуален
     
  5. alexandrage

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

    Баллы:
    173
    Капец ты ньюфак 80лвл :D. Иди спи дальше со своим екшен баром и тайтлом.
     
  6. AtomicScience

    AtomicScience Активный участник Пользователь

    Баллы:
    76
    Имя в Minecraft:
    AtomicScience
    А какой пример гораздо круче и информативнее?
     
  7. hyndorik

    hyndorik Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    hyndo
    Да любой, смысл делать нмсом то, что можно сделать через апи
     
  8. Ission

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

    Баллы:
    173
    Skype:
    lokivava
    Статья, как я понял по первой строчке -- перевод. И по второй тоже.
    По поводу статьи. Мне кажется, или человек хотел показать один из вариантов, когда нужен NMS и как это сделать не через механизм рефлексий, а через более понятный (хотя можно было и как некоторые кадры байткодогенератором это всё на*****ть). Можно было использовать и установку блока, не важно на чём пример показывать. Я думаю, что стоило вообще это сделать на примере отправки сообщения в чат, чтобы не возникло даже желания бездумно копировать.
    Ну и ещё раз: это перевод, что было в оригинале, то тут и есть.
     
  9. hyndorik

    hyndorik Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    hyndo
    Сделать сто писот интерфейсов или заюзать player.sendActionBar?
     
  10. Cool_boy

    Cool_boy Активный участник Пользователь

    Баллы:
    96
    Имя в Minecraft:
    prettydude
    Мсье, подскажите где ваша машина времени, тоже хочу в будущее.

    В интерфейсе игрока не нашёл такого метода, но можно через player.spigot().sendMessage().
     
  11. hyndorik

    hyndorik Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    hyndo
    Paper spigot 1 12 2
     
  12. Ission

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

    Баллы:
    173
    Skype:
    lokivava
    Помните, я написал выше сообщение о том, что это перевод, а так же, что пример было бы вообще хорошо сделать абстрактным, чтобы не копировали код бездумно? Так вот, прочитайте моё сообщение 87 раз, потом ещё столько же, потом можете перечитать перевод, а затем подумать, имел ли смысл ваш комментарий.
     
  13. alexandrage

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

    Баллы:
    173
    Еслиб ТС не тырил контекст из прошлого, никто бы и не придрался.
     

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