Minecraft 1.21.1遊戲伺服器運維筆記1:Ubuntu 18.04.6折騰Fabric配置及TinyRemapper、session.lock錯誤的解決方法

多玩我的世界盒子發表於2024-10-25

摘要

本文敘述瞭如何在 Linux 伺服器上透過完全命令列互動的方式配置基於 Minecraft 1.21.1 版本的 Fabric 伺服器,交代了環境配置流程,以及服務端檔案、模組檔案的下載方法,給出了命令列操作方式以及完整的遊戲啟動指令碼。

目錄
  • 摘要
  • 背景
  • 需求
    • 前瞻知識及材料準備
    • 準備工作
  • 環境配置
    • 作業系統
    • JDK 配置
    • 安裝 screen
    • 遊戲使用者與檔案目錄系統設計
  • 操作步驟
    • 備份舊的遊戲檔案
    • 下載安裝 Fabric 服務端
      • 下載 Server Jar
      • 下載 Fabric Installer
      • 指令碼啟動與引數配置
        • Aikar's flags
        • 記憶體分配
        • 垃圾回收器設定(GC)
        • G1GC 相關最佳化
        • 堆記憶體管理
        • 其他引數
        • 啟動服務引數
        • 啟動指令碼
  • 模組配置
    • 下載模組檔案資源
      • 平臺
      • Fabric API
      • Servux
      • MiniHUD
      • QuickBackupMulti
    • 伺服器模組的安裝
  • 遊戲配置
    • 編輯 Server Properties
    • 啟用 EULA 協議
    • 載入世界存檔
  • 啟動遊戲
  • 本地客戶端配置
  • 記錄報錯與解決方法
    • TinyRemapper 報錯
    • 程序佔用檔案的衝突
    • screen 許可權報錯
  • 附錄
    • 附錄 A:在獨立視窗中啟動 Minecraft 遊戲服務的指令碼

背景

上星期,我們的 Minecraft 伺服器裡大型的潛影貝農場剛剛完工,夜裡朋友上線跟我發訊息,問我是不是做了存檔回滾還回滾到了錯誤的版本,因為剛剛建造好的刷沙機不見了。

我當天下午清除了一次快取,備份目錄下面出現了一個沒有辦法開啟的檔案,叫做zit2d9Dt。我一開始以為是某個過程產生的奇怪文字檔案,所以直接用 cat 命令檢視了……在二進位制資料炸屏之後我的 ssh 當場被卡掉下來了……

我們伺服器的備份機制就是透過 crontab 定期執行一個指令碼,直接用 zip 命令把整個 world 資料夾都壓縮起來,然後放在一個 backups 目錄下面。因為世界出了問題,我跟同學就想到回滾到幾天前的版本,但是我們才發現前段時間所有的備份其實都有問題,只是我們沒有發現。這些備份出現了很奇怪的現象——像是箱子裡的物品是最新的狀態,但是世界的建造情況卻是半個月前的樣子。

所以現在我們伺服器末地的刷石機沒了、刷沙機、潛影貝農場、還有我們在末地的基地、前哨和社群都沒了。

在發生了這些事情之後,我對我原本搭建的伺服器和備份系統感到極度的不信任。在和一位多年運維 Minecraft 伺服器的朋友交流尋求幫助的時候,對方在聽聞我使用的是 Minecraft 原版的官方服務端的時候覺得這是一件很不可思議的事情。在他看來,這個服務端非常難以操作,體驗很糟糕。他表示他從來沒有使用過原版的服務端,因此無法提供幫助。

我說好吧,Mojang 造出來的東西這麼不堪嗎?既然這樣的話,我還是著手重新配置基於 Fabric 的遊戲伺服器服務端好了。

筆者作為 Minecraft 的萌新小白,完全沒有任何配置和運營 Minecraft 伺服器的經驗,只是會使用 Linux 而已,所以本文中所述的一切操作都是完完全全誤打誤撞摸索出來的野路子。 不過也正因如此,文中的敘述幾乎可以說是事無鉅細,將讀者可能會有困惑的方方面面都顧及到了,希望能給讀者提供一些幫助。

需求

前瞻知識及材料準備

閱讀本文你需要的前瞻知識包括:

  • 關於 Minecraft 遊戲版本、Fabric 等服務端、模組的基本常識;
  • 能夠正常使用 Linxu 作業系統,基本掌握命令列的操作方法。

同時,你需要的材料是一臺配置足以執行 Minecraft 1.21.1 遊戲服務的遠端伺服器(可以從任意的雲服務商那裡購買,或者自己做雲網穿),並且已經完成了 Minecraft 遊戲服務所需的 25565 埠的放行(也可以放行其他埠,遊戲使用的埠號可以在 server.properties 裡面修改,下文會講到)。

這部分內容我在這裡就不贅述了,一方面網上的資料比較多,另一方面我這邊已經配置好了,想要再演示這些基本內容會很不方便,文章就太長了,寫不完了。

準備工作

在開始配置 Minecraft 遊戲伺服器之前,最好先對伺服器大致的定位有一個認識,從而確定伺服器究竟需要安裝哪些模組。

對於我們的遊戲伺服器,主要經營的是生存模式遊戲,包含一些輕度的生電內容。一方面想要把原先自己寫的基於 Bash Shell 指令碼和 crontab 定時執行的備份系統替換為現有成熟的備份解決方案,另一方面也想為生電遊戲加上一些輔助外掛。總的來說,重新配置伺服器的需求可以分為三大類,分別是:

  1. Fabric 服務端遊戲本體;
  2. 各路生電輔助外掛;
  3. 正規的伺服器備份方案,如各類備份模組等。

這些內容需要服主與伺服器的玩家交流協商。最終決定要配置的遊戲和模組包括:

  • Fabric 服務端生存模式遊戲及其 API,遊戲版本為 1.21.1;
  • servux 用於支援 minihud 檢視結構邊界;
  • minihud 伺服器端(檢視世界生成的結構等);
  • QuickBackupMulti(用於備份世界)。

環境配置

作業系統

我們的伺服器所使用的作業系統是 Ubuntu 18.04.6,這是在買伺服器的時候就決定了的。

JDK 配置

目前伺服器上已經安裝了 JDK 21 環境,由於我們要執行比較新的 1.21.1 版本,JDK 17 已經不再可用。另,可以考慮根據 B站 UP 主的建議 更換到 Alibaba DragonWell JDK 以便取得更好的效能,但是我這裡為了方便沒有采用這個配置。

openjdk version "21.0.3.0.3" 2024-04-16
OpenJDK Runtime Environment (Alibaba Dragonwell Standard Edition)-21.0.3.0.3+9-GA (build 21.0.3.0.3)
OpenJDK 64-Bit Server VM (Alibaba Dragonwell Standard Edition)-21.0.3.0.3+9-GA (build 21.0.3.0.3, mixed mode, sharing)

因為我需要在本地 WSL 上配置一個模擬環境,測試一下配置伺服器的方法能否在本地的 WSL 環境裡面正常執行起來,正好可以講一下如何配置 Java 環境。關於換源之類的細節我就不再贅述了,首先在開始安裝 Java 之前最好先執行 sudo apt update更新軟體源。(不要小看這個細節,如果不執行這一步很可能會失敗)然後:

sudo apt install openjdk-21-jdk

等待安裝完成之後執行 java -version 檢視。

安裝 screen

screen 為多重視窗管理程式。此處所謂的視窗,是指一個全螢幕的文字模式畫面。通常只有在使用 telnet/ssh 登入遠端主機或是使用老式的終端機時,才有可能用到 screen 程式。

Minecraft 遊戲伺服器啟動之後會進入遊戲程序,這個程序就是遊戲的後臺。你可以在這個視窗裡面輸入 Minecraft 指令對世界生效,但是一旦你將這個視窗關閉,遊戲程序就會被殺死,遊戲就會停止。因此,我們需要將遊戲掛載在一個 screen 視窗下面執行,啟動遊戲之後可以用 Ctrl A + D 切換到原來的系統 shell,這樣即使你關閉、斷開了與 Linux 伺服器作業系統 shell 的 ssh 連結,遊戲也會繼續在獨立的 screen session 中執行,且再次登入伺服器也隨時可以透過 screen -r 命令返回檢視。

由於 Ubuntu 上的包管理器是 apt,因此使用 apt 命令安裝:

apt-get install screen

檢視是否已經正確安裝了 screen:

screen -version

如果出現類似如下的輸出就說明安裝基本正確:

Screen version 4.09.01 (GNU) 20-Aug-23

遊戲使用者與檔案目錄系統設計

好的檔案目錄設計是好的開始。為了執行 Minecraft 遊戲服務,我在伺服器上建立了一個專門的使用者 minecraft,在其主目錄 /home/minecraft 下建立了 mcserver 資料夾,後面將會被搭建稱為 Minecraft 伺服器的執行時目錄,這樣的設計可以確保伺服器的檔案不會和使用者主目錄下的各種配置檔案相沖突。

mcserver 下面會產生下面幾個比較重要的檔案和資料夾:

  • mods 資料夾——儲存所有伺服器端的 Mods 檔案的資料夾
  • world 資料夾——遊戲世界的存檔資料夾

這兩個資料夾不用急著建立,後面會講到的。

操作步驟

備份舊的遊戲檔案

由於我們的伺服器上面以前執行過 Minecraft 的遊戲,所以需要首先備份以前的遊戲記錄。首先備份原來的遊戲檔案目錄到 ./backups 目錄下,zip 命令操作參考zip 和 unzip 命令用法。

下載安裝 Fabric 服務端

下載 Server Jar

首先,Fabric 需要有 Minecraft 的服務端檔案 server.jar 才能執行,檔案需要自備而不會自動替你下載。因此,你需要在 Mojang 的官網的上下載正確版本的檔案,然後把 server.jar 和我們接下來下載的 fabric-installer.jar 放在同一級目錄下(放置的目錄就是遊戲的執行時目錄。我的方案是在伺服器的 minecraft 使用者的主目錄 ~ 下面建立了 ~/mcserver 資料夾)。

Note. 這一點非常重要,實踐發現如果你不這樣操作,Fabric Installer 就不能正確安裝 Fabric,那樣的話你就必須把產生的其餘檔案刪掉然後重新 Fabric Install 操作。

我這邊偷了個懶,找了個 收集不同版本的 Minecraft 的網站。要下載 1.21.1 你可以點選進入網站的下載頁面,也可以使用命令:

curl -OJ https://piston-data.mojang.com/v1/objects/59353fb40c36d304f2035d51e7d6e6baa98dc05c/server.jar

下載 Fabric Installer

官網文件 具體講解了如何透過 CLI 安裝 Fabric,以及詳細的操作。可以具體檢視。

首先需要從 Installer 下載頁面 下載檔案 fabric-installer.jar。檔案沒有按照版本區分,所以我猜測這東西應該就是針對所有版本的。

當然也可以在命令列下載:

curl -OJ https://maven.fabricmc.net/net/fabricmc/fabric-installer/1.0.1/fabric-installer-1.0.1.jar

這裡下載的 Fabric 版本目前為 0.16.7。

按照官網上的提示:

The Fabric Installer has full support from installing the client and the server from the command line. This could be used to automate the installation. The installer has a number of commands that can be used for a headless install.

可以直接在命令列操作選擇安裝伺服器的版本。

java -jar fabric-installer-1.0.1.jar server -mcversion "1.21.1"

Note. 執行時需要加上 -mcversion "1.21" 引數,否則的話就算已經給出了正確的 server.jar。報錯發生的時候還沒有安裝任何模組。

指令碼啟動與引數配置

Aikar's flags

瞭解一下什麼是 Aikar's flags:根據 PaperMC Docs 網站給出的資訊資料 顯示:

Aikar's flags are a set of flags that can be used when running the game. These flags are designed to change certain settings on the JVM that can improve the performance of the game. Some of the flags include reducing the amount of RAM and processor usage, as well as optimizing the game for better performance.

這些是 Aikar 提供的 Java 啟動引數(Flags),專門為 Minecraft 伺服器的效能最佳化而設計,特別是在大型伺服器或長時間執行的伺服器上使用。它們主要是圍繞 Java 的垃圾回收器(Garbage Collector, GC)進行調整,以減少記憶體管理對伺服器效能的影響。

以下是網站給出的 Aikar's flags:

java -Xms10G -Xmx10G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -jar paper.jar --nogui

以下是由 ChatGPT 給出的對於這些引數的解釋:

記憶體分配

  • -Xms10G: 設定 Java 虛擬機器(JVM)的初始堆記憶體大小為 10 GB。這個值會在伺服器啟動時分配,不會動態變化。
  • -Xmx10G: 設定 JVM 的最大堆記憶體大小為 10 GB,伺服器執行時記憶體使用的上限。

當然在這裡我們羸弱的土豆伺服器不可能給 JVM 分配整整 10GB 的初始堆記憶體大小,所以這個數值需要根據實際情況進行修改。

垃圾回收器設定(GC)

  • -XX:+UseG1GC: 啟用 G1垃圾回收器,適用於大記憶體應用程式,特別是 Minecraft 伺服器。
  • -XX:+ParallelRefProcEnabled: 並行引用處理,加快垃圾回收中的引用處理速度。
  • -XX:MaxGCPauseMillis=200: 設定 最大GC暫停時間 為 200 毫秒,控制每次垃圾回收暫停的時長,減少對遊戲的卡頓。
  • -XX:+UnlockExperimentalVMOptions: 啟用一些 實驗性的 JVM 選項,為進一步最佳化開放可能的實驗功能。
  • -XX:+DisableExplicitGC: 禁用顯式GC,阻止程式呼叫 System.gc(),避免可能的效能損失。
  • -XX:+AlwaysPreTouch: 預熱記憶體,在啟動時預先分配堆記憶體,避免在伺服器執行過程中分配記憶體的效能開銷。

G1GC 相關最佳化

  • -XX:G1NewSizePercent=30: 設定 G1GC 的 新生代記憶體大小 佔堆記憶體的最小百分比為 30%。
  • -XX:G1MaxNewSizePercent=40: 設定 G1GC 的 新生代記憶體大小 佔堆記憶體的最大百分比為 40%。
  • -XX:G1HeapRegionSize=8M: 將 G1堆記憶體分割槽大小 設定為 8 MB,每個分割槽的大小影響記憶體分配和垃圾回收效率。
  • -XX:G1ReservePercent=20: 保留 20% 的堆記憶體不被使用,作為 記憶體回收的預留空間,以應對突發的記憶體需求。
  • -XX:G1HeapWastePercent=5: 允許 G1GC 垃圾回收過程中 最多浪費 5% 的堆記憶體,以提高回收效率。
  • -XX:G1MixedGCCountTarget=4: 混合垃圾回收目標次數 為 4,控制垃圾回收的頻率和時間。
  • -XX:InitiatingHeapOccupancyPercent=15: 當堆記憶體使用 超過 15% 時,觸發 G1GC 執行垃圾回收。
  • -XX:G1MixedGCLiveThresholdPercent=90: G1GC 只會在混合垃圾回收中處理存活物件 少於 90% 的分割槽。
  • -XX:G1RSetUpdatingPauseTimePercent=5: 更新 RSet 的暫停時間 不超過總暫停時間的 5%。

堆記憶體管理

  • -XX:SurvivorRatio=32: 新生代的存活區比例,設定為 32 意味著伊甸園區與倖存者區的比例是 32:1。
  • -XX:+PerfDisableSharedMem: 禁用 效能共享記憶體,減少對效能監控的開銷。
  • -XX:MaxTenuringThreshold=1: 最大晉升閾值 為 1,物件只在新生代停留一次後就被提升到老年代,減少新生代的垃圾回收次數。

其他引數

  • -Dusing.aikars.flags=https://mcflags.emc.gs: 指定使用 Aikar 的最佳化標記,並引用它們的來源網站。
  • -Daikars.new.flags=true: 告訴伺服器啟用 Aikar 的新標記。

啟動服務引數

  • -jar paper.jar --nogui: 啟動 paper.jar,這是 Minecraft 伺服器的 jar 檔案,同時 --nogui 表示不使用圖形介面。

啟動指令碼

有一說一,上面這一大堆內容我也看不懂,我看著一愣一愣的。

不管了,反正照著來唄。將上文中出現的 Aikar's flags 整合起來,就可以編寫啟動指令碼了。指令碼可以取名 start_mc_server.sh,內容比較長,我放在了附錄 A 裡面。

模組配置

下載模組檔案資源

平臺

本文中所有的模組資源都可以在 CurseForge 平臺找到,但是經過實踐之後發現,CurseForge 這個平臺它就很離譜。它的搜尋框在搜尋模組的時候經常是輸錯一個字母(比如把 Servux 寫作 servux)就搜不到東西。所以我的建議是直接在 Google 裡面搜尋相關資源。

同時由於網站的限制,模組資原始檔不能透過 curl 命令從遠端伺服器下載,只能先一個一個下載,好然後使用 scp 命令一次性上傳到遠端伺服器。

Fabric API

Fabric API 是透過模組形式安裝的,網址在 https://www.curseforge.com/minecraft/mc-mods/fabric-api

Servux

用於支援 MiniHUD 顯示結構邊界的 Mod。網址在 https://www.curseforge.com/minecraft/mc-mods/servux

這個模組不需要在客戶端上安裝。官網上將這行文字標記為紅色,似乎很重要。

MiniHUD

網址在 https://www.curseforge.com/minecraft/mc-mods/minihud。按照原本的計劃是需要在伺服器安裝 minihud 模組的服務端。但在實際查詢 CurseForge 資料的時候發現了這樣一段資料文字:

minihud A client-side mod that allows displaying various "info lines" on the screen ("mini-F3"). The alignment (screen corner), background and text color and font size are configurable.

Note: This is a client-side-only mod! You can't put it on a server.

(翻譯:注意:這是一個僅限客戶端的模組!你不能把它放在伺服器上。)

Note: MiniHUD also requires the MaLiLib library mod.

Be sure to download the correct version of both mods from the Files page!

https://www.curseforge.com/minecraft/mc-mods/malilib

這裡提及的 MaLiLib 是一個為 Masa 的模組提供客戶端側支援的公共程式碼庫模組。 它基本上包含了所有可配置選項,按鍵繫結系統,做大多數 GUI 程式碼支援以及其他的實用元件供其他模組使用。也就是說所謂的 MiniHUD 服務端其實就是需要下載 MaLiLib。但其實 MaLiLib 需要同時在本地和伺服器上安裝,而 MiniHUD 只需要安裝在本地客戶端

QuickBackupMulti

網址在 https://www.curseforge.com/minecraft/mc-mods/quickbackupmulti

一個 Minecraft mod,用於在遊戲中建立、儲存備份和管理。它可以在單人遊戲和伺服器中使用。

您可以在遊戲中進行帶有描述的儲存備份,並且您可以隨時恢復它。 此外,您可以設定 make save-backup 的計劃。它將根據您設定的計劃建立儲存備份

2.x 版本的 Mod 現在支援建立備份! 它使用 NOSQL 資料庫來儲存備份資訊,

這個 Mod 不會對世界生成產生任何影響。

伺服器模組的安裝

理論上只需要將模組放置在執行時目錄下的 mods 資料夾下面就可以了。

  • 需要在伺服器端安裝的模組有:Servux、MaLiLib、QuickbackupMulti、Fabric API;
  • 需要在本地安裝的模組有:MaLiLib、MiniHUD、QuickbackupMulti,Fabric API 可以直接透過 PCL 或者 HMCL 之類的啟動器進行安裝。

在安裝模組之前,你需要首先執行一次 java -jar ./fabric-server-launch.jar,這將會建立名為 mods 的模組資料夾。不必擔心遊戲會立即啟動或者建立不必要的世界存檔,由於沒有啟用 EULA 協議,遊戲會在啟動之後立即暴死。

Note. 不要一上來就執行指令碼 start_mc_server.sh,不知道為什麼這樣做會產生 Cannot create Java Virtual Machine 的錯誤。

遊戲配置

編輯 Server Properties

server.properties 檔案儲存了遊戲的世界配置,包括遊戲難度、遊戲模式(生存、創造、極限)、世界種子等等。裡面只有幾個地方需要修改:

  1. 遊戲難度 diffculity=hard
  2. levelseed=<世界種子>,需要和載入的遊戲存檔世界保持一致。我這裡就設定 levelseed=31011421 了,因為我們的遊戲存檔用的就是這個種子。

或者直接將以前編輯過的 server.properties 上傳到遠端伺服器。可以使用任何熟悉的文字編輯器,比如 nano,或者 vim 更方便。

vim ./server.properties

然後直接編輯裡面的內容就可以了。

啟用 EULA 協議

編輯 eula.txt,將 eula 選項改為 true,表示同意終端使用者協議。

載入世界存檔

需要載入的世界存檔必須是名為 world 的資料夾,資料夾內有包含 level.dat 在內的若干區塊資料 .dat 檔案及資料夾。將其安置在遊戲的執行時目錄下就可以了。

啟動遊戲

執行編寫好的指令碼 ./start_mc_server.sh 即可,使用 screen -r 切入遊戲後臺會話檢查遊戲是否正確啟動了。如果是就沒有問題了!

本地客戶端配置

如果你已經完成了上面的一系列操作,那麼你不大可能會在配置自己的本地客戶端的時候遇到困難。這個操作很簡單,首先就是在你的啟動器裡面勾選下載 Minecraft 1.21.1 Fabric + Fabric API,然後開啟本地配置中的 mods 資料夾將上文提及到的 MaLiLib、MiniHUD、QuickbackupMulti 模組一股腦塞進去。

關鍵問題在於服主需要向伺服器的玩家說明如何配置本地客戶端,這就要考驗服主的能力了。當然如果你的伺服器玩家學習能力比較強,就不需要在這方面費心,只需要向他們提供一份伺服器已安裝模組的清單檔案就好了。

記錄報錯與解決方法

TinyRemapper 報錯

第一次遇到這個報錯的時候我在 Reddit 論壇上面發了帖子求助:Error while setting up my first Minecraft 1.21 Fabric server.,最後的結果就是需要在執行 fabric-installer.jar 的時候指定 -mcversion "1.21.1" 引數,否則就算已經在遊戲的執行時目錄下安置了 1.21.1 版本的 server.jar,遊戲還是傾向於下載最新版本,也就是 1.21.3 的 Fabric 啟動程式。

報錯日誌:

Uncaught exception in thread "main"
java.lang.RuntimeException: An exception occurred when launching the server!
        at net.fabricmc.loader.impl.launch.server.FabricServerLauncher.main(FabricServerLauncher.java:71)
Caused by: java.lang.RuntimeException: Unfixable conflicts
        at net.fabricmc.loader.impl.lib.tinyremapper.TinyRemapper.handleConflicts(TinyRemapper.java:898)
        at net.fabricmc.loader.impl.lib.tinyremapper.TinyRemapper.propagate(TinyRemapper.java:798)
        at net.fabricmc.loader.impl.lib.tinyremapper.TinyRemapper.mrjRefresh(TinyRemapper.java:1077)
        at net.fabricmc.loader.impl.lib.tinyremapper.TinyRemapper.apply(TinyRemapper.java:929)
        at net.fabricmc.loader.impl.game.GameProviderHelper.deobfuscate0(GameProviderHelper.java:314)
        at net.fabricmc.loader.impl.game.GameProviderHelper.deobfuscate(GameProviderHelper.java:246)
        at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.initialize(MinecraftGameProvider.java:331)
        at net.fabricmc.loader.impl.launch.knot.Knot.init(Knot.java:140)
        at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:68)
        at net.fabricmc.loader.impl.launch.knot.KnotServer.main(KnotServer.java:23)
        at net.fabricmc.loader.impl.launch.server.FabricServerLauncher.main(FabricServerLauncher.java:69)

程序佔用檔案的衝突

Minecraft 伺服器無法啟動,因為 session.lock 檔案已經被鎖定。這個通常是由於以下原因之一:

  1. 伺服器已經在執行:可能有另一個 Minecraft 伺服器例項已經啟動,並正在使用這個 world 資料夾。如果你嘗試在同一個資料夾中啟動多個伺服器例項,會導致該檔案被鎖定。

  2. 伺服器崩潰後未正確關閉:如果伺服器在崩潰或非正常關閉時沒有釋放 session.lock 檔案,它會保持鎖定狀態,阻止其他例項啟動。

檢查後發現,這個問題產生的原因是因為我在執行 start_mc_server.sh 指令碼的時候不小心使用了 sudo

sudo ./start_mc_server

這就導致了啟動的遊戲服務的 screen session 實際上是在 root 使用者下,但是我卻沒有意識到。直接執行了 screen -r 之後發現找不到遊戲後臺的 session,於是我就再次執行了 start_mc_server.sh,就遭遇了報錯。

可以嘗試以下方法來解決這個問題:

  1. 檢查是否有其他例項在執行:透過以下命令檢視當前是否有 Minecraft 伺服器正在執行:

    ps aux | grep java
    

    如果有正在執行的 Minecraft 程序,你可以終止它們:

    kill <PID>
    

    替換 <PID> 為程序 ID。

  2. 刪除 session.lock 檔案:如果沒有其他伺服器例項在執行,可以手動刪除 session.lock 檔案。進入你的 world 目錄,找到並刪除 session.lock 檔案:

    rm ./world/session.lock
    

    然後嘗試重新啟動伺服器。當然如果程序已經被正確殺死,應該就不需要手動刪除 session.lock 了。這是最好的。

報錯日誌:

$ java -jar ./fabric-server-launch.jar --nogui
Starting net.fabricmc.loader.impl.game.minecraft.BundlerClassPathCapture
[00:01:19] [main/INFO]: Loading Minecraft 1.21 with Fabric Loader 0.16.7
[00:01:20] [main/INFO]: Loading 4 mods:
        - fabricloader 0.16.7
           \-- mixinextras 0.4.1
        - java 22
        - minecraft 1.21
[00:01:20] [main/INFO]: SpongePowered MIXIN Subsystem Version=0.8.7 Source=file:/mnt/e/dev/mcserver-localtest/mcserver/libraries/net/fabricmc/sponge-mixin/0.15.3+mixin.0.8.7/sponge-mixin-0.15.3+mixin.0.8.7.jar Service=Knot/Fabric Env=SERVER
[00:01:27] [main/INFO]: Environment: Environment[sessionHost=https://sessionserver.mojang.com, servicesHost=https://api.minecraftservices.com, name=PROD]
[00:01:28] [main/ERROR]: Failed to start the minecraft server
net.minecraft.class_5125$class_5126: /mnt/e/dev/mcserver-localtest/mcserver/./world/session.lock: already locked (possibly by other Minecraft instance?)
        at knot/net.minecraft.class_5125$class_5126.method_26805(class_5125.java:95) ~[server-intermediary.jar:?]
        at knot/net.minecraft.class_5125.method_26803(class_5125.java:41) ~[server-intermediary.jar:?]
        at knot/net.minecraft.class_32$class_5143.<init>(class_32.java:374) ~[server-intermediary.jar:?]
        at knot/net.minecraft.class_32.method_52236(class_32.java:353) ~[server-intermediary.jar:?]
        at knot/net.minecraft.server.Main.main(Main.java:137) [server-intermediary.jar:?]
        at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:480) [fabric-loader-0.16.7.jar:?]
        at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:74) [fabric-loader-0.16.7.jar:?]
        at net.fabricmc.loader.impl.launch.knot.KnotServer.main(KnotServer.java:23) [fabric-loader-0.16.7.jar:?]
        at net.fabricmc.loader.impl.launch.server.FabricServerLauncher.main(FabricServerLauncher.java:69) [fabric-loader-0.16.7.jar:?]

screen 許可權報錯

這個錯誤很奇怪,我想不通是怎麼產生的。在本地 WSL 上測試的時候報錯說無法訪問 /run/screen 因為沒有許可權。既然如此那麼直接加權吧:

chmod +777 -R /run/screen

附錄

附錄 A:在獨立視窗中啟動 Minecraft 遊戲服務的指令碼

#!/bin/bash
# 
# name    : start_mc_server.sh
# author  : BOXonline_1396529
# usage   : start_mc_server.sh [OPTIONS]
# date    : 2024-10-25
# version : 1.0.0.1
#
# start_mc_server.sh - Script to start Minecraft server

# Function to display help message
function show_help {
    echo "Usage: start_mc_server [OPTIONS]"
    echo
    echo "To launch Minecraft service in an independent screen session. Notice"
    echo "that the screen should be installed to the server first.            "
    echo
    echo "Options:"
    echo "  -h, --help   Show this help message and exit"
}

# Parse the first argument
case "$1" in
    -h|--help)
        show_help
        exit 0
        ;;
    *)
        FILE="$1"
        ;;
esac

echo "Starting server..."

name="Minecraft"

# Memory Settings
mem_args="-Xmx2048M -Xms1024M"

# GC Settings
gc_args=\
" -XX:+UseG1GC"\
" -XX:+ParallelRefProcEnabled"\
" -XX:MaxGCPauseMillis=200"\
" -XX:G1NewSizePercent=30"\
" -XX:G1MaxNewSizePercent=40"\
" -XX:G1HeapRegionSize=8M"\
" -XX:G1ReservePercent=20"\
" -XX:G1HeapWastePercent=5"\
" -XX:G1MixedGCCountTarget=4"\
" -XX:InitiatingHeapOccupancyPercent=15"\
" -XX:G1MixedGCLiveThresholdPercent=90"\
" -XX:G1RSetUpdatingPauseTimePercent=5"\
" -XX:SurvivorRatio=32"

# JVM Optimizations
jvm_optim_args=\
" -XX:+UnlockExperimentalVMOptions"\
" -XX:+DisableExplicitGC"\
" -XX:+AlwaysPreTouch"\
" -XX:+PerfDisableSharedMem"\
" -XX:MaxTenuringThreshold=1"

# Aikar's flags
aikar_args=\
" -Dusing.aikars.flags=https://mcflags.emc.gs"\
" -Daikars.new.flags=true"

# To start the server
server_jar="./fabric-server-launch.jar"
server_args="--nogui"

# Combine all the flags together
cmd=\
"java ${mem_args} ${jvm_optim_args} ${gc_args} ${aikar_args} "\
"-jar ${server_jar} ${server_args}"

# Start the screen session and run the server
screen -dmS ${name}
screen -x -S ${name} -p 0 -X stuff "${cmd}\n"

echo "
___  ___                             __ _   
|  \\/  (                            / _| |  
| .  . |_ _ __   ___  ___ _ __ __ _| |_| |_ 
| |\\/| | | '_ \\ / _ \\/ __| '__/ _\` |  _| __|
| |  | | | | | |  __/ (__| | | (_| | | | |_ 
\\_|  |_/_|_| |_|\\___|\\___|_|  \\__,_|_|  \\__|"

echo "
The server should be running under the screen session named \`Minecraft\` now
if there's no error. You can use \`screen -r\` switching to the backstage of 
the game.
"

相關文章