Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Скрыть объявление

Помогите Как добавить в класс поле или метод не переписывая сам класс?

Тема в разделе "Разработка плагинов для новичков", создана пользователем JonBoss, 20 сен 2015.

  1. OsipXD

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

    Баллы:
    173
    Skype:
    osip.fatkullin
    Имя в Minecraft:
    OsipXD
    Способ с рефлексиями и расширением CraftPlayer (OBC), если интересно (рабочий вариант).
    Написал без импортов т.к. они различаются в разных версиях.

    Объект игрока
    Код:
    public class CustomPlayer extends CraftPlayer {
       // Добавим для примера ману
       private double maxMana = 20.0D;
       private double mana = 0.0D;
    
       // Конструктор никогда не будет вызываться извне, так что я сделал его приватным, чтобы не было соблазна :D
       private CustomPlayer(CraftServer server, EntityPlayer entity) {
          super(server, entity);
          // Тут надо загружать кастомные данные из БД или файла, т.к. они не будут сохраняться в объект игрока
          // Я просто для примера устанавливаю ману в максимальное значение.
          this.mana = this.maxMana;
       }
    
       // Для преобразования будем использовать этот метод
       public static CustomPlayer createFromPlayer(Player player) {
          CraftPlayer craftPlayer = (CraftPlayer) player;
          EntityPlayer entityPlayer = craftPlayer.getHandle();
          CustomPlayer customPlayer = new CustomPlayer((CraftServer) entityPlayer.getBukkitEntity().getServer(), entityPlayer);
    
          try {
             Field bukkitEntityField = Entity.class.getDeclaredField("bukkitEntity");
             bukkitEntityField.setAccessible(true);
             bukkitEntityField.set(entityPlayer, customPlayer);
          } catch (NoSuchFieldException | IllegalAccessException e) {
             e.printStackTrace();
             return null;
          }
    
          return customPlayer;
       }
    
       public void setMana(double mana) {
          this.mana = mana;
       }
    
       public void setMaxMana(double maxMana) {
          this.maxMana = maxMana;
       }
    
       public double getMana() {
          return this.mana;
       }
    
       public double getMaxMana() {
          return this.maxMana;
       }
    
       public boolean castSpell(double mana) {
          if (this.mana < mana) {
             return false;
          }
    
          this.mana -= mana;
          return true;
       }
    }
    
    Использование, загрузка и сохранение
    Код:
    public class PlayerListener implements Listener {
       @EventHandler(priority = EventPriority.MONITOR)
       public void onPlayerJoin(PlayerJoinEvent event) {
          CustomPlayer customPlayer = CustomPlayer.createFromPlayer(event.getPlayer());
    
          try {
             Field player = PlayerEvent.class.getField("player");
             player.setAccessible(true);
             player.set(event, customPlayer);
          } catch (NoSuchFieldException | IllegalAccessException e) {
             // Сюда можно пихнуть сообщение об ошибке.
             // Но если нужно отменить событие, надо использовать приоритет HIGHEST или ниже
             e.printStackTrace();
          }
       }
    
       @EventHandler(priority = EventPriority.MONITOR)
       public void onPlayerQuit(PlayerQuitEvent event) {
          // Мы не используем метод CustomPlayer.createFromPlayer() т.к. он работает для нас вместо конструктора
          CustomPlayer customPlayer = (CustomPlayer) event.getPlayer();
          // Тут надо сохранять кастомные значения в БД или файл
          // Значения получать просто: customPlayer.getMana(), customPlayer.getMaxMana()}
       }
    
    Еще надо добавить загрузку и сохранение доп. данных при включении и выключении плагина, иначе данные не сохранятся при выключении сервера и "все сломается" при перезагрузке сервера.
     
    Последнее редактирование: 21 сен 2015
  2. Хостинг MineCraft
    <
  3. Автор темы
    JonBoss

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

    Баллы:
    76
    Skype:
    ya_narik1
    Имя в Minecraft:
    Jon
    Ты можешь подробнее описать, что делают вот эти строки?
    Код:
    Field player = PlayerJoinEvent.class.getField("player");
    player.setAccessible(true);
    player.set(event, customPlayer);
    Тоесть в любой момент я могу сделать "(CustomPlayer) player" и получу CustomPlayer этого игрока?
     
  4. Den_Abr

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

    Баллы:
    173
    Skype:
    Den_Abr
    Имя в Minecraft:
    Den_Abr
    Это не будет работать.
     
  5. Dereku

    Dereku Старожил

    Баллы:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    glass_break.ogg
     
  6. Den_Abr

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

    Баллы:
    173
    Skype:
    Den_Abr
    Имя в Minecraft:
    Den_Abr
    Ну серьёзно. Нельзя же вот так просто получить объект нового типа, взяв и скастовав его.
     
  7. Автор темы
    JonBoss

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

    Баллы:
    76
    Skype:
    ya_narik1
    Имя в Minecraft:
    Jon
    Та, тут вы правы.
     
  8. OsipXD

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

    Баллы:
    173
    Skype:
    osip.fatkullin
    Имя в Minecraft:
    OsipXD
    Омг, глупейшая ошибка. Исправил.[DOUBLEPOST=1442777372,1442777053][/DOUBLEPOST]
    Код:
    Field player = PlayerEvent.class.getField("player"); // Получаем поле player из класса PlayerEvent
    player.setAccessible(true); // Оно имеет модификатор доступа protected, поэтому делаем его доступным
    player.set(event, customPlayer); // Изменяем это поле на customPlayer в объекте event
    
    [DOUBLEPOST=1442777461][/DOUBLEPOST]UPD: Добрался до IDE'шки, все проверил, привел в работоспособное состояние[DOUBLEPOST=1442845419][/DOUBLEPOST]
    Да
     

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