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

Posted

技术标签:

【中文标题】插件重新加载导致客户端与 IndexOutOfBoundsException 断开连接【英文标题】:Plugin reload causes clients to disconnect with an IndexOutOfBoundsException 【发布时间】:2020-02-11 15:24:05 【问题描述】:

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

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

    聊天消息 系统消息 游戏信息消息

聊天消息很容易访问,但其他 2 个则不是。如果我没有收到这些消息,他们会将标签菜单向上推,而不是在他们自己的聊天频道中结束。

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

DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(0) + 长度 (1) 超过 writerIndex(0) UnpooledSlicedByteBuf(ridx: 0, widx: 0, cap: 0/0, unwrapped: PooledUnsafeDirectByteBuf(ridx: 2, widx: 6、上限: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))
        ...
    

但它根本没有效果。他们无法进一步帮助我,所以我希望其他人可以知道发生了什么以及我如何解决问题。

更新 即使将代码简化为这样,问题仍然存在:

private void initPacketListener()
        protocolManager.addPacketListener(new PacketAdapter(this, ListenerPriority.NORMAL, new PacketType[]  PacketType.Play.Server.CHAT )
        
            @SuppressWarnings("unused")
            @Override
            public void onPacketSending(PacketEvent event) 
            
    );

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

【问题讨论】:

【参考方案1】:

您永远不应该使用/reload 命令,请在此处查看更多信息,例如:https://madelinemiller.dev/blog/problem-with-reload/。

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

【讨论】:

这与我的工作无关。这是关于我正在开发的插件的用户所做的事情。我不需要用户重新加载这个插件。我只是想保持它的工作,以防他们这样做。因此,这不是问题的解决方案。这就像说:我的程序存在错误/问题,但我没有修复它,只是告诉您不要使用内置服务器功能。

以上是关于插件重新加载导致客户端与 IndexOutOfBoundsException 断开连接的主要内容,如果未能解决你的问题,请参考以下文章

出错后重新启用 Microsoft Word 加载项

jquery ajax 调用kkpager插件 异步加载重新生成分页后,点击页数还是跟首次加载一样

outlook2007,开发的vsto插件,安装到客户机提示:未加载。加载COM加载项时出现运行错误

将 CodeMirror 与 Vuejs/Nuxtjs 一起使用会导致服务器重新加载时未定义错误“CodeMirror”

重新加载具有相同内容的 div

ASP.NET AJAX