当前位置:   article > 正文

【Minecraft】建立Bukkit/Spigot插件实时调试环境,并避免断点调试时客户端断开连接_spigot.yml

spigot.yml

        spigot以其轻量化著称,带来好处的同时,一个直接后果就是不提供像forge那样成熟的开发、调试、构建环境。笔者近日想学习一下MC spigot插件开发,遇到了不少坑,甚是令人烦躁。

        配置开发环境时,笔者本打算直接使用Minecraft Development插件,结果搞了几遍都是一个接近空白的文件夹。所幸找到了一篇高质量教程,顺利解决了问题:【Minecraft】Bukkit/Spigot插件开发教程---搭建一个开发环境_WYH2004的博客-CSDN博客_spigot插件开发

        (顺带一提,这篇教程的作者在B站发布了一些不错的spigot插件开发视频教程。衷心建议感兴趣的小伙伴去看看(我没收钱!))

        对于调试,笔者认识的几个开发者都是把插件构建出来,放到服务器上直接看运行效果,等于没有实时调试,对萌新小白极其不友好。在中文互联网检索如何配置断点调试,答案寥寥;spigot wiki上的方案也解决不了,最后结合stackoverflow上一个回答才搞定。此外,我没有找到解决断点时间过长导致客户端断开连接问题的方案。

        笔者总结自己的摸坑教训,感觉不如针对这些问题写一篇中文教程,供各位想要入坑spigot插件开发的MC爱好者参考。

        笔者教程使用的JAVA版本为jdk1.8.0_181(JAVA16及以下均可),API使用Spigot 1.16.5(bukkit也行,paper不提供API,不能用),IDEA版本为Community 2021.3,调试服务端使用paper 1.16.5(可以兼容bukkit/spigot,同时加载速度快几倍)。

        教程包含以下部分:

        1、如何建立spigot服务端实时调试环境 

        2、一个避免断点调试时间过长导致客户端断开连接的方案

1、建立spigot服务端实时调试环境  

(此处假设你已搭建好了开发环境:构建工件(artifact)可以将插件本体与plugins.yml编译为.jar。不知道怎么做的,可参考上文引用教程

        一共需要做三件事:(1)配置一个调试服务端(2)配置一个新工件(3)设置调试选项

(1)配置调试服务端

        这一步的服务端之后将用于调试插件,并不一定与开发的API依赖库相同,可以跑Bukkit/Spigot插件即可。笔者此处选择了加载速度较快的paper。

        我选择在本地部署调试服务端,这样操作完全与开服相同。知道如何开服的小伙伴可以直接跳下一节。想在远程部署调试服务端的,请参考spigot wiki 的相关教程

        首先,我们去paper官网整一个服务端下来。

        Legacy Downloads – PaperMC

        paper目前只支持1.17+,如果与笔者一样需要下载1.16.5及更早的版本,需要回答问题以表明自己理解paper将不会提供技术支持、论坛讨论;分别选择No 和 It will be closed即可。

        之后,把下载的.jar服务端(例如paper-1.16.5.jar)放在一个固定路径、纯英文路径的文件夹里,启动。笔者使用Win 10系统,就直接用批处理脚本启动了(新建文本文档-输入以下内容-另存为:保存类型:所有文件,文件名:随便写.bat)

  1. java -Xms1G -Xmx1G -jar paper-1.16.5.jar -nogui
  2. pause 

        双击运行一次,文件夹里会出现一个eula.txt。打开,将最后一行的false改成true,保存。

        再双击运行一次,服务端会自动下载运行环境,下载完成后自动运行。当显示开头为 > 的空行时,运行成功,如下图所示。

        运行成功后还需最后一步。关闭服务器,打开server.properties文件,将online-mode=true改为false;否则必须正版账号登陆的客户端才能进入调试服务器。

(2)配置一个新工件

        这一步的目的是,将插件构建到上一步配置好的调试服务器插件目录下。

        点击文件(Files)-项目结构(project structure)-工件(artifacts),点击对话框左上角的加号,新建一个JAR工件。

        工件名称任意(例如TestPluginDebug),输出布局与构建插件的要求一样:编译输出、plugin.yml(不知道是在说什么的,请继续参阅此篇教程)。

        唯一不同的是,输出目录为调试服务器的插件文件夹:例如,我将调试服务器放在Z:\SpigotPlugins\paper-1.16.5-runtime下;那这一步我的输出目录必须为Z:\SpigotPlugins\paper-1.16.5-runtime\plugins。

        点击确定,这一步就成功了;也可以构建此工件检查:构建(Build)-构建工件(Build Artifacts)-选择刚才的工件,如果在输出目录找到 TestPluginDebug.jar,则无误。

(3)配置调试环境

        这一步在IDEA中新建一个调试环境,用以在调试模式下运行(1)中的服务器与(2)中的插件。

        首先,点击右上角 添加配置(Add Configurations...),会跳出一个叫运行/调试配置的对话框。点击左上角+号,新建一个JAR应用程序配置。

之后,填入调试环境的属性:

        名称:自己取

        JAR路径:(1)中服务端路径

        虚拟机选项:服务端运行选项,只要两个参数即可:-Xmx2G -Xms2G。如果实际调试中内存不足导致服务端崩溃,可以适当增大这些数字。

        程序实参:一般只填一个 nogui

        工作目录:与第一行JAR路径相同,但只填到.jar文件父目录。没听懂的看图。

        最后,看到界面最下面,有一个“执行前”标签。点击+号-编译Artifacts,选择(2)中配置的工件,一路确定。这一步会自动在启动调试环境前,将插件更新同步到(1)的调试服务器中。

        现在万事俱备了!你可以在调试配置选项卡中看到刚设置好的调试环境。选择它,给自己的插件打一个断点,点击右边的小虫子,试一试程序是否如约暂停了。

        大功告成!

二、避免断点暂停时间过长导致掉线

        MC原版服务端、客户端代码中,都有这样的逻辑:如果连续x秒没有收到任何数据包,则认为连接已断开。这意味着我们断点调试超过x秒,客户端就会被强制踢出世界;对于不能接受这一点的小伙伴,此处笔者提供一种解决方法及其思路。

2.1 避免服务端掉线

        对spigot系列的服务端,默认x=60。spigot很文明地将这个参数暴露在服务端配置文件spigot.yml中:

timeout-time: 60

        将其改为6000即可。

        对paper服务端,操作一样;毕竟paper是spigot的儿子(狗头)。

2.2 避免客户端掉线

        客户端x=30。修改这个就比较麻烦,因为原版并没有提供相应接口。笔者转而使用Forge学习背后的机制(使用Forge MDK版本1.16.5-36.2.29):

        MC通信通过Netty进行。连接到服务器时,客户端建立一条ChannelPipeline负责处理数据包,其中第一个Pipeline名称为timeout、类型为ReadTimeOutHandler,正负责着30秒无流量时断开连接的工作。

        (关于netty.channel.ChannelPipeline的工作机制,请参阅此文。MC相关代码位于net.minecraft.network.NetworkManager.connectToserver方法中,如下:)

  1. @OnlyIn(Dist.CLIENT)
  2. public static NetworkManager connectToServer(InetAddress p_181124_0_, int p_181124_1_, boolean p_181124_2_) {
  3. ......
  4. (new Bootstrap()).group(lazyvalue.get()).handler(new ChannelInitializer<Channel>() {
  5. protected void initChannel(Channel p_initChannel_1_) throws Exception {
  6. try {
  7. p_initChannel_1_.config().setOption(ChannelOption.TCP_NODELAY, true);
  8. } catch (ChannelException channelexception) {
  9. }
  10. //以下是生成pipeline的关键代码,注意第一个addLast
  11. p_initChannel_1_.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("splitter", new NettyVarint21FrameDecoder()).addLast("decoder", new NettyPacketDecoder(PacketDirection.CLIENTBOUND)).addLast("prepender", new NettyVarint21FrameEncoder()).addLast("encoder", new NettyPacketEncoder(PacketDirection.SERVERBOUND)).addLast("packet_handler", networkmanager);
  12. }
  13. }).channel(oclass).connect(p_181124_0_, p_181124_1_).syncUninterruptibly();
  14. return networkmanager;
  15. }

        怎么办呢?我们只需要把30秒的ReadTimeOutHandler替换成超级延时版即可。

        笔者直接使用Forge,Forge Mod的开发环境配置教程网上有很多,大家可以百度学习一下。如果大家不能使用Forge客户端也没关系,最终替换掉旧的ReadTimeOutHandler即可,实现方式都无所谓啦~

        Forge很贴心的在客户端连接到服务端时,注入了一个事件:

ClientPlayerNetworkEvent.LoggedInEvent

        直接新建一个Forge Mod订阅这一事件,利用其返回的NetworkManager访问channel、替换pipeline。五行代码即可实现:

  1. @SubscribeEvent
  2. public void onConnectToServer(ClientPlayerNetworkEvent.LoggedInEvent event)
  3. {
  4. event.getNetworkManager().channel().pipeline().replace("timeout","timeout",new ReadTimeoutHandler(6000));
  5. }

        客户端、服务器联合调试时,用装有此mod的Forge客户端进服即可。

参考链接:

【Minecraft】Bukkit/Spigot插件开发教程---搭建一个开发环境_WYH2004的博客-CSDN博客_spigot插件开发

IntelliJ: Debug Your Plugin | SpigotMC - High Performance Minecraft

java - Run Configuration to Debug Bukkit/Minecraft Plugin in IntelliJ IDEA? - Stack Overflow

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号