Java Bukkit Events不止一次注册

时间:2014-12-14 08:17:23

标签: java events for-loop bukkit

好的,自从我在Bukkit API上更改了我的菜单设计后,我就遇到了这个奇怪的错误。

在我强调问题之前,这是程序应该做的事情。

  1. 玩家加入时请执行以下操作。
  2. 使用他将使用的菜单将播放器添加到HashMap。
  3. 循环播放与该播放器相关的菜单,并调用必要的功能。
  4. 当玩家离开时,将他从HashMap中移除并销毁菜单实例。
  5. 直到第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.");
                }
            }
        }
    }
    

    所以我的问题是。 什么可能解决事件的问题? 除此之外,其他一切都很完美。

    抬头,我从昨天开始调试,没有进展。

1 个答案:

答案 0 :(得分:1)

我很好奇你的for循环,所以我用Strings替换了大部分对象,并调用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&#34; player&#34;然后循环访问keySet以找到同一个播放器并调用它#34;注册&#34;。

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(播放器)并且似乎对某些人来说是错误的。我会:

,而不是存储和比较玩家的实例
  • 将HashMaps / Arrays中Player的所有用途替换为UUID(无论如何推荐,因为存储Player会导致内存泄漏)。可以使用Player.getUniqueId();
  • 获取UUID
  • 比较两个Player对象的UUID,它们看起来像 if (registered.getUniqueId() == player.getUniqueId())

但是,在您的情况下,通过替换&#34;已注册的&#34;的所有实例,无法完全避免比较。到&#34;玩家&#34;?

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);

来源: