2014-12-14 3 views
1

Хорошо, я столкнулся с этой странной ошибкой, так как я изменил свой дизайн меню на Bukkit API.Java Bukkit События, зарегистрированные более одного раза

Прежде чем подчеркнуть проблему, вот что должна была делать программа.

  1. Когда игрок присоединяется, выполните следующее.
  2. Добавьте игрока в HashMap с помощью меню, которое он будет использовать.
  3. Прокрутите меню, связанные с этим проигрывателем, и вызовите необходимые функции.
  4. Когда игрок уходит, удалите его из HashMap и уничтожьте экземпляры меню.

Это нормально, до этапа 2, однако события на шаге 3, похоже, регистрируются равными количеству ключей внутри HashMap. Например, если 3 игрока находятся в режиме онлайн, события 4-го будут зарегистрированы x4 раз, что является серьезной утечкой памяти.

Теперь вот мой код, это целый класс.

package src.ares.core.menu; 

import java.util.ArrayList; 
import java.util.HashMap; 

import org.bukkit.entity.Player; 
import org.bukkit.event.EventHandler; 
import org.bukkit.event.player.PlayerJoinEvent; 
import org.bukkit.event.player.PlayerQuitEvent; 

import src.ares.core.Main; 
import src.ares.core.common.Module; 

public class MenuListener extends Module 
{ 
    private static MenuListener instance = new MenuListener(); 

    public static MenuListener getInstance() 
    { 
     return instance; 
    } 

    private HashMap<Player, ArrayList<Menu>> activeMenus; 

    public MenuListener() 
    { 
     super("Menu Listener"); 

     this.activeMenus = new HashMap<>(); 
    } 

    @EventHandler 
    public void onPlayerJoin(PlayerJoinEvent event) 
    { 
     Player player = event.getPlayer(); 
     ArrayList<Menu> defaultMenus = new ArrayList<>(); 

     defaultMenus.add(MenuFactory.getFactory().createMenu(MenuType.KIT_MENU)); 
     defaultMenus.add(MenuFactory.getFactory().createMenu(MenuType.WORLD_MENU)); 
     defaultMenus.add(MenuFactory.getFactory().createMenu(MenuType.STATS_MENU)); 

     if (!activeMenus.containsKey(player)) 
      activeMenus.put(player, defaultMenus); 
     else return; 

     Main.debug("Before For-Loop."); 

     for (Player registered : activeMenus.keySet()) 
     { 
      if (registered.equals(player)) 
      { 
       Main.debug("Player Validation Passed -> " + registered.getName()); 

       ArrayList<Menu> playerMenus = activeMenus.get(registered); 

       for (Menu specificMenu : playerMenus) 
       { 
        specificMenu.setSpecificTo(registered); 
        specificMenu.addItems(); 
        specificMenu.defineItems(); 
        specificMenu.registerEvents(); 
        Main.debug("Messing with -> " + specificMenu.getName()); 
       } 

       Main.debug("End of Menus."); 
      } 
     } 
    } 

    public HashMap<Player, ArrayList<Menu>> getMenus() 
    { 
     return activeMenus; 
    } 

    @EventHandler 
    public void onPlayerQuit(PlayerQuitEvent event) 
    { 
     for (Player registered : activeMenus.keySet()) 
     { 
      if (registered.equals(event.getPlayer())) 
      { 
       for (Menu playerMenu : activeMenus.get(registered)) 
       { 
        playerMenu.destroy(); 
       } 

       activeMenus.remove(registered); 
       Main.debug("Unregistering Menu Listeners."); 
      } 
     } 
    } 
} 

Так что мой вопрос здесь. Что может быть возможным решением этой проблемы с событиями? Кроме этого, все остальное работает отлично.

Heads up, я отлаживал его со вчерашнего дня и не добился прогресса.

ответ

1

Мне было интересно узнать о ваших циклах, поэтому я заменил большинство объектов на Строки и четыре раза вызывал onPlayerJoin(), чтобы проверить это.

Player Validation Passed -> aaaaa 
Messing with -> MenuType.KIT_MENU 
Messing with -> MenuType.WORLD_MENU 
Messing with -> MenuType.STATS_MENU 
End of Menus. 
Player Validation Passed -> bbbbb 
Messing with -> MenuType.KIT_MENU 
Messing with -> MenuType.WORLD_MENU 
Messing with -> MenuType.STATS_MENU 
End of Menus. 
Player Validation Passed -> ccccc 
Messing with -> MenuType.KIT_MENU 
Messing with -> MenuType.WORLD_MENU 
Messing with -> MenuType.STATS_MENU 
End of Menus. 
Player Validation Passed -> ddddd 
Messing with -> MenuType.KIT_MENU 
Messing with -> MenuType.WORLD_MENU 
Messing with -> MenuType.STATS_MENU 
End of Menus. 

Все было вызвано только один раз, и я не видел ни одного цикла, основанного на количестве игроков, как описано в OP. Мне кажется, что нет ничего плохого в том, как вы зацикливаетесь, а скорее в исполнении Bukkit.

Одна вещь, которая осталась для меня, была в onPlayerJoin(), как у вас был экземпляр игрока Player, а затем прокручивался через keySet, чтобы найти тот же Player и назвал его «зарегистрированным».

Main.debug("Before For-Loop."); 

    for (Player registered : activeMenus.keySet()) 
    { 
     if (registered.equals(player)) 
     { 
      Main.debug("Player Validation Passed -> " + registered.getName()); 

      ArrayList<Menu> playerMenus = activeMenus.get(registered); 

Я пробовал смотреть в Player.equals (Player) и казался некорректным для некоторых людей. Вместо того чтобы хранить и сравнивать экземпляры игроков, я бы:

  • заменить все виды использования проигрывателя в HashMaps/Массивы в UUID, (рекомендуется в любом случае, потому что хранение Игрок может вызвать утечку памяти). Можно получить UUID с Player.getUniqueId();
  • сравнить UUID двух объектов Игрока, которые могут выглядеть примерно как if (registered.getUniqueId() == player.getUniqueId()).

В вашем случае, однако, невозможно полностью избежать сравнения путем замены всех экземпляров «зарегистрированного» на «игрока»?

Main.debug("Before For-Loop."); 

// for (Player registered : activeMenus.keySet()) 
// { 
//  if (registered.equals(player)) 
//  { 
      Main.debug("Player Validation Passed -> " + player.getName()); 

      ArrayList<Menu> playerMenus = activeMenus.get(player); 

Источники:

Смежные вопросы