Java 插件重新加载导致客户端与IndexOutOfBoundsException断开连接

Java 插件重新加载导致客户端与IndexOutOfBoundsException断开连接,java,minecraft,Java,Minecraft,一般信息 我正在为Spigot(Minecraft服务器)开发一个聊天插件。其想法是创建一个聊天系统,允许使用工作聊天选项卡: 为了实现这一点,我必须使用NMS(ProtocolLib),因为Minecraft在聊天中使用3种类型的消息: 聊天信息 系统消息 游戏信息信息 聊天信息很容易访问,但其他两条则不然。如果我看不到这些信息,他们会向上按tabs菜单,而不是进入自己的聊天频道 问题 我用来捕获这些消息的代码(如下)在连接的Minecraft客户端中导致以下异常,并在ingame插件通过/

一般信息
我正在为Spigot(Minecraft服务器)开发一个聊天插件。其想法是创建一个聊天系统,允许使用工作聊天选项卡:

为了实现这一点,我必须使用NMS(ProtocolLib),因为Minecraft在聊天中使用3种类型的消息:

  • 聊天信息
  • 系统消息
  • 游戏信息信息
  • 聊天信息很容易访问,但其他两条则不然。如果我看不到这些信息,他们会向上按tabs菜单,而不是进入自己的聊天频道

    问题
    我用来捕获这些消息的代码(如下)在连接的Minecraft客户端中导致以下异常,并在ingame插件通过
    /reload
    重新加载时断开它们的连接:

    DecodeException:java.lang.IndexOutOfBoundsException:readerIndex(0) +长度(1)超过writerIndex(0)unoledSlicedBytebuf(ridx:0,widx:0,cap:0/0,unwrapped:PooledUnsafeDirectByteBuf(ridx:2,widx: 6,cap:16384))@io.netty.handler.codec.MessageToMessageDecoder:98

    相关代码

    private void initPacketListener(){
        protocolManager.addPacketListener(new PacketAdapter(this, ListenerPriority.NORMAL, new PacketType[] { PacketType.Play.Server.CHAT })
        {
            @SuppressWarnings("unused")
            @Override
            public void onPacketSending(PacketEvent event) {
    
                if ((event.getPacketType() == PacketType.Play.Server.CHAT)){
                    PacketContainer packet = event.getPacket();
                    Player player = event.getPlayer();
                    String message = "";
    
                    try {
                        String jsonMessage = event.getPacket().getChatComponents().getValues().get(0).getJson();
    
                        if (jsonMessage!=null&&!jsonMessage.isEmpty()) {
                            message = jsonToString(jsonMessage);
    
                            if (message.isEmpty()) return;
    
                            Subscriber subscriber = UMM.plugin.getSubscribers().get(player.getUniqueId());
                            String uuid = player.getUniqueId().toString();
                            Channel messageChannel = UMM.serverChannels.get(uuid);
                            messageChannel.addMessage(message);
                            ChatListener cl = new ChatListener(UMM.plugin);
    
                            cl.notifyChanges(messageChannel);
                            event.setCancelled(true);
                        } else {
                            System.out.println("Not a system msg");
                        }
                    } catch (Throwable e){
                        System.out.println("UMM Packet Error:" + e.getMessage());
                    }
                }
            }
        });
    }
    
    我自己试图解决的问题
    我向其他开发人员询问了这个问题,他们告诉我:

    在进行#get调用之前,请确保event.getPacket().getChatComponents().getValues()的大小/长度大于0

    所以我试了一下:

    List<WrappedChatComponent> wrap = event.getPacket().getChatComponents().getValues();
    
    if(wrap.size() > 0) {
        if ((event.getPacketType() == PacketType.Play.Server.CHAT)){
            ...
        }
    }
    

    该问题的“临时”解决方案是在服务器完成重新加载后,使用
    BukkitRunnable
    调用方法1 tick。唯一不好的一面是,在第一次勾选之前出现的任何消息都会向上推tabs菜单。插件会在下一个消息事件时修复此问题。

    您不应该使用
    /reload
    命令,请参阅此处的更多信息,例如:


    你可以在你的插件中实现一个重载命令,如果你需要它,它可以做你想做的事情。也许您的问题可以通过内部重新加载命令解决,因为这可能是
    /reload
    命令的问题。

    这与我的工作无关。这是关于我正在开发的插件的用户所做的事情。我不需要用户重新加载这个插件。我只是想让它继续工作,以防他们这样做。因此,这不是问题的解决办法。这就像在说:我的程序有一个bug/问题,但我不是在修复它,而是告诉你不要使用内置服务器功能。
    private void initPacketListener(){
            protocolManager.addPacketListener(new PacketAdapter(this, ListenerPriority.NORMAL, new PacketType[] { PacketType.Play.Server.CHAT })
            {
                @SuppressWarnings("unused")
                @Override
                public void onPacketSending(PacketEvent event) {
                }
        });
    }