Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.

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

Dexel

Активный участник
Пользователь
Баллы
76
Имя в Minecraft
SiRiuS_OSiRiuS
Оригинал (EN)

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

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

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

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

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

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

В своём плагине создайте отдельный пакет для вашего интерфейса и NMS-классов:
8673f49dd0a8623b690dceba9edd7af64e4eb19f

Внутри этого пакета мы создадим интерфейс под названием 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.
Убедитесь, что вы инициализируете только класс для конкретной версии сервера, на котором работает плагин!

2d04869897b2fd973933c773156865d886b3a46f
 
Ты какого года вообще статью переводил? 12? Юзать нмс чтоб экшн бар отправить, бог...
 
Ты какого года вообще статью переводил? 12? Юзать нмс чтоб экшн бар отправить, бог...
Отправка actionbar'ов здесь является примером использования мультиверсионной поддержки NMS. Или, в твоём понимании, NMS только для этого существует?
 
Отправка actionbar'ов здесь является примером использования мультиверсионной поддержки NMS. Или, в твоём понимании, NMS только для этого существует?
Ты поехавший какой-то, можно было бы еще нмсом игрока телепортировать, че апи то юзать. Пример с экшн баром уже года 2 как не актуален
 
Капец ты ньюфак 80лвл :D. Иди спи дальше со своим екшен баром и тайтлом.
 
Ты поехавший какой-то, можно было бы еще нмсом игрока телепортировать, че апи то юзать. Пример с экшн баром уже года 2 как не актуален

А какой пример гораздо круче и информативнее?
 
Ты поехавший какой-то, можно было бы еще нмсом игрока телепортировать, че апи то юзать. Пример с экшн баром уже года 2 как не актуален
Статья, как я понял по первой строчке -- перевод. И по второй тоже.
По поводу статьи. Мне кажется, или человек хотел показать один из вариантов, когда нужен NMS и как это сделать не через механизм рефлексий, а через более понятный (хотя можно было и как некоторые кадры байткодогенератором это всё на*****ть). Можно было использовать и установку блока, не важно на чём пример показывать. Я думаю, что стоило вообще это сделать на примере отправки сообщения в чат, чтобы не возникло даже желания бездумно копировать.
Ну и ещё раз: это перевод, что было в оригинале, то тут и есть.
 
Статья, как я понял по первой строчке -- перевод. И по второй тоже.
По поводу статьи. Мне кажется, или человек хотел показать один из вариантов, когда нужен NMS и как это сделать не через механизм рефлексий, а через более понятный (хотя можно было и как некоторые кадры байткодогенератором это всё на*****ть). Можно было использовать и установку блока, не важно на чём пример показывать. Я думаю, что стоило вообще это сделать на примере отправки сообщения в чат, чтобы не возникло даже желания бездумно копировать.
Ну и ещё раз: это перевод, что было в оригинале, то тут и есть.
Сделать сто писот интерфейсов или заюзать player.sendActionBar?
 
Сделать сто писот интерфейсов или заюзать player.sendActionBar?
Мсье, подскажите где ваша машина времени, тоже хочу в будущее.

В интерфейсе игрока не нашёл такого метода, но можно через player.spigot().sendMessage().
 
Сделать сто писот интерфейсов или заюзать player.sendActionBar?
Помните, я написал выше сообщение о том, что это перевод, а так же, что пример было бы вообще хорошо сделать абстрактным, чтобы не копировали код бездумно? Так вот, прочитайте моё сообщение 87 раз, потом ещё столько же, потом можете перечитать перевод, а затем подумать, имел ли смысл ваш комментарий.
 

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

Назад
Верх