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

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

Способ с рефлексиями и расширением CraftPlayer (OBC), если интересно (рабочий вариант).
Написал без импортов т.к. они различаются в разных версиях.

Объект игрока
Java:
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;
   }
}

Использование, загрузка и сохранение
Java:
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()}
   }

Еще надо добавить загрузку и сохранение доп. данных при включении и выключении плагина, иначе данные не сохранятся при выключении сервера и "все сломается" при перезагрузке сервера.
 
Последнее редактирование:
Способ с рефлексиями и расширением CraftPlayer (OBC), если интересно.
Писал на коленке, поэтому код не проверял в работе и написал без импортов и т.д.
Java:
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);
   }

   // Для преобразования будем использовать этот метод и в нем нужно инициализировать все переменные
   public static CustomPlayer createFromPlayer(Player player) {
      CustomPlayer customPlayer = (CustomPlayer) player;
      // Тут надо разгружать кастомные данные из БД или файла, т.к. они не будут сохраняться в объект игрока
      // Я просто для примера устанавливаю ману в максимальное значение.
      customPlayer.setMana(customPlayer.getMaxMana());

      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;
   }
}
Так же можно изменять родные методы и значения.

Использование, загрузка и сохранение
Java:
public class PlayerListener implements Listener {
   @EventHandler(priority = EventPriority.MONITOR)
   public void onPlayerJoin(PlayerJoinEvent event) {
      CustomPlayer customPlayer = CustomPlayer.createFromPlayer(event.getPlayer());

      try {
         Field player = PlayerJoinEvent.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()}
   }
Ты можешь подробнее описать, что делают вот эти строки?
Код:
Field player = PlayerJoinEvent.class.getField("player");
player.setAccessible(true);
player.set(event, customPlayer);
Тоесть в любой момент я могу сделать "(CustomPlayer) player" и получу CustomPlayer этого игрока?
 
Способ с рефлексиями и расширением CraftPlayer (OBC), если интересно.
Писал на коленке, поэтому код не проверял в работе и написал без импортов и т.д.
Java:
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);
   }

   // Для преобразования будем использовать этот метод и в нем нужно инициализировать все переменные
   public static CustomPlayer createFromPlayer(Player player) {
      CustomPlayer customPlayer = (CustomPlayer) player;
      // Тут надо разгружать кастомные данные из БД или файла, т.к. они не будут сохраняться в объект игрока
      // Я просто для примера устанавливаю ману в максимальное значение.
      customPlayer.setMana(customPlayer.getMaxMana());

      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;
   }
}
Так же можно изменять родные методы и значения.

Использование, загрузка и сохранение
Java:
public class PlayerListener implements Listener {
   @EventHandler(priority = EventPriority.MONITOR)
   public void onPlayerJoin(PlayerJoinEvent event) {
      CustomPlayer customPlayer = CustomPlayer.createFromPlayer(event.getPlayer());
  
      try {
         Field player = PlayerJoinEvent.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()}
   }
Это не будет работать.
 
Ну серьёзно. Нельзя же вот так просто получить объект нового типа, взяв и скастовав его.
Омг, глупейшая ошибка. Исправил.
Ты можешь подробнее описать, что делают вот эти строки?
Java:
Field player = PlayerEvent.class.getField("player"); // Получаем поле player из класса PlayerEvent
player.setAccessible(true); // Оно имеет модификатор доступа protected, поэтому делаем его доступным
player.set(event, customPlayer); // Изменяем это поле на customPlayer в объекте event

UPD: Добрался до IDE'шки, все проверил, привел в работоспособное состояние
Тоесть в любой момент я могу сделать "(CustomPlayer) player" и получу CustomPlayer этого игрока?
Да
 

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

Назад
Верх