【Minecraft】建立Bukkit/Spigot插件实时调试环境,并避免断点调试时客户端断开连接
????????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)
java -Xms1G -Xmx1G -jar paper-1.16.5.jar -nogui 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方法中,如下:)
@OnlyIn(Dist.CLIENT) public static NetworkManager connectToServer(InetAddress p_181124_0_, int p_181124_1_, boolean p_181124_2_) {......(new Bootstrap()).group(lazyvalue.get()).handler(new ChannelInitializer<Channel>() {protected void initChannel(Channel p_initChannel_1_) throws Exception {try {p_initChannel_1_.config().setOption(ChannelOption.TCP_NODELAY, true);} catch (ChannelException channelexception) {} //以下是生成pipeline的關鍵代碼,注意第一個addLastp_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);}}).channel(oclass).connect(p_181124_0_, p_181124_1_).syncUninterruptibly();return networkmanager; }? ? ? ? 怎么辦呢?我們只需要把30秒的ReadTimeOutHandler替換成超級延時版即可。
? ? ? ? 筆者直接使用Forge,Forge Mod的開發環境配置教程網上有很多,大家可以百度學習一下。如果大家不能使用Forge客戶端也沒關系,最終替換掉舊的ReadTimeOutHandler即可,實現方式都無所謂啦~
? ? ? ? Forge很貼心的在客戶端連接到服務端時,注入了一個事件:
ClientPlayerNetworkEvent.LoggedInEvent? ? ? ? 直接新建一個Forge Mod訂閱這一事件,利用其返回的NetworkManager訪問channel、替換pipeline。五行代碼即可實現:
@SubscribeEvent public void onConnectToServer(ClientPlayerNetworkEvent.LoggedInEvent event) {event.getNetworkManager().channel().pipeline().replace("timeout","timeout",new ReadTimeoutHandler(6000)); }? ? ? ? 客戶端、服務器聯合調試時,用裝有此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
總結
以上是生活随笔為你收集整理的【Minecraft】建立Bukkit/Spigot插件实时调试环境,并避免断点调试时客户端断开连接的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌搜索揭示人性最黑暗的秘密
- 下一篇: html提交成功跳转页面,提交表单后跳转