📋 語言支持
🌏 開發語言支持情況
通過 ScriptX 項目的支持,腳本引擎使用同一套源代碼,對多種開發語言進行了適配。
同時,由於API保持一致,使各種語言得以共享一份開發文檔,大大降低了維護難度。
目前,腳本引擎支持使用如下語言編寫插件:
| 語言後端 | 備註 |
|---|---|
JavaScript | 使用 QuickJS 引擎運行插件,支持 ES Module 機制 |
Lua | 使用 CLua 引擎運行插件 |
Node.js | 改造 Node.js 使其適合嵌入工作,支持 npm 包管理 |
Python | 使用 CPython 引擎運行插件,支持 pip 包管理 |
Tip
如果需要使用 C++、Go、Rust 等原生語言編寫插件,請移步 主頁 查看其他語言文檔
JavaScript 語言支持說明
- 使用 QuickJS 引擎對簡單的 JavaScript 插件提供支持,輕量級引擎資源佔用較少
- QuickJS 當前版本支持到 ES2020 語言特性,同時原生支持 ESModule 模塊機制,可以方便開發者進行項目管理
- 暫不支持包管理機制,如果需要請使用 Node.js 進行插件開發,使用 npm 包管理
- 在BDS控制台中使用
jsdebug命令進入和退出 QuickJS 交互式命令行環境。此功能便於編寫插件時進行一些簡單的測試
關於 QuickJS ESModule 的路徑解析行為
LegacyScriptEngine 使用的 ScriptX 來自上游 Tencent/ScriptX 項目的 fork, 並在其基礎上增加了一些功能(例如 Python 後端支持等)。
在 QuickJS 後端中,ScriptX 默認使用 quickjs-libc.h 中提供的 module loader。
該 loader 會導致 QuickJS ESModule 在解析入口模塊時的行為與標準 ESModule 不完全一致。
具體表現為:
該 loader 在加載 入口模塊 時,會將模塊的 base path 設為 當前工作目錄 (CWD),即服務器程序所在目錄,而不是腳本文件所在目錄。
因此入口文件中的相對 import 路徑解析行為與標準 ESModule 不完全一致。
假設腳本插件的結構為:
c:/bds
bedrock_server_mod.exe
plugins/
your_plugin/
manifest.json
index.js
command/
command.jsindex.js 入口文件:
import { initCommand } from "./command/command.js"
initCommand();此時 QuickJS 會將入口模塊的 import.meta.url 解析為 file:///c:/bds 而不是 file:///c:/bds/plugins/your_plugin
因此 ./command/command.js 會解析失敗,導致插件加載失敗。
例如 QuickJS 可能會拋出類似如下的錯誤(原始日誌):
19:26:12.343 ERROR [LeviLamina] Failed to load plugin your_plugin: Unexpected token '{'
19:26:12.343 ERROR [LeviLamina] at ./plugins/your_plugin\index.js:1:1解決方法是使用相對於工作目錄的路徑:
import { initCommand } from "./plugins/your_plugin/command/command.js"即可正常加載模塊。
Tip
該問題僅影響 manifest.json 指定的入口模塊。
入口模塊加載完成後,其它模塊之間的 import 行為均符合標準 ESModule 規則。
Lua 語言支持說明
- 使用 CLua 引擎,支持使用 require 進行簡單的項目管理
- 由於 Rocks 包管理機制需要引入編譯器,因此暫不提供相關實現。如果需要依賴擴展可以手動編譯後引入項目進行使用(如 SQLite 等常用庫)
- 在BDS控制台中使用
luadebug命令進入和退出 Lua 交互式命令行環境。此功能便於編寫插件時進行一些簡單的測試
Node.js 支持說明
- LSE 通過自行實現 Node.js 啟動代碼,使其可以在嵌入式模式下工作,並實現了不同插件的執行環境隔離
- 自行編寫接口實現了對 npm 的 programmic 支持。支持通過 package.json 安裝第三方擴展依賴包
⭐ Node.js 插件開發方法
- 首先,安裝Node.js
- 創建一個新的目錄進行插件開發。在此目錄啟動終端執行
npm init命令。根據 npm 的提示創建新項目,填寫項目的相關信息。 - 在填寫的入口點文件中編寫插件代碼
- 如果有需要,可以創建多個源碼文件,並且通過 require 來引入他們。合理的對源碼進行分文件拆分編寫有助於提高項目結構的清晰度,方便後續對插件進行進一步的維護和擴展。
⭐ Node.js 插件打包 & 部署方法
- 在插件編寫完成之後,請將
package.json以及所有插件源碼打包為一個zip壓縮包,並將文件名後綴修改為 .llplugin node_modules目錄請勿打包在壓縮包之中- 將 .llplugin 文件作為插件分發,安裝插件時直接將此文件放置到 plugins 目錄即可
- 在開服時,腳本引擎會自動識別 .llplugin 文件,將其解壓到
plugins/nodejs/插件名目錄,並在目錄中自動執行npm install --omit=dev安裝依賴包,整個過程無需人工干預
Python 語言支持說明
- 使用 CPython 引擎,Python版本為3.12.10。支持使用 pip 包管理機制為插件安裝第三方擴展依賴包,支持多文件插件開發和 import,支持現代項目管理機制
- 在BDS控制台中使用
pydebug命令進入和退出 Python 交互式命令行環境。此功能便於編寫插件時進行一些簡單的測試
Python 單文件插件開發方法
- 為了方便不熟悉Python的開發者快速上手,我們提供了一種簡單的 Python 插件支持:單文件插件。
- 單文件插件類似QuickJS和Lua插件。只要編寫單個.py文件作為插件,將插件直接放置到 plugins目錄中,在開服時就會被加載運行
- 單文件插件缺點:不支持插件元數據儲存、不支持源碼分文件、不支持pip第三方包。單文件插件僅用於開發者熟悉LSE的Python環境,或者開發非常簡易的插件而使用。
⭐ Python 多文件插件開發方法
- 對於大型、正式的Python插件,強烈建議使用此方法進行開發。多文件插件支持所有完整的Python特性。
- LSE 使用
pyproject.toml項目文件進行元數據儲存(類似 Node.js 的package.json)。此項目文件推薦使用支持現代項目特性的 PDM 包管理器(pdm-project/pdm)自動生成,以便於進行插件項目的創建和維護。
下面是具體的插件開發流程:
-
首先,安裝Python 3.12.10
-
在終端中執行
pip install --user pdm命令安裝 pdm 包管理工具 -
創建一個新的目錄進行插件開發。在此目錄啟動終端執行
pdm init命令。根據pdm工具的提示創建新項目,填寫項目的相關信息。-
如果需要安裝依賴包,在項目目錄執行
pdm add <依赖包名>即可 -
所有的項目元數據和依賴數據都會被自動儲存在
pyproject.toml中,無需手動編寫。你也可以打開此文件修改版本號、描述等元數據信息 -
除了使用
pdm add命令之外,你也可以直接把項目依賴手動寫在requirements.txt當中。在安裝插件時,pyproject.toml和requirements.txt中描述的依賴都將被處理並自動安裝。
-
-
接下來創建
__init__.py文件,並在其中編寫插件代碼。加載插件時,Python解釋器會首先讀取並執行這個文件。 -
如果有需要,可以創建多個源碼文件,並且通過 import 來引入他們。合理的對源碼進行分文件拆分編寫有助於提高項目結構的清晰度,方便後續對插件進行進一步的維護和擴展。
⭐ Python 多文件插件打包 & 部署方法
- 在插件編寫完成之後,請將
pyproject.toml以及所有插件源碼打包為一個zip壓縮包,並將文件名後綴修改為 .llplugin __pycache__和__pypackages__等目錄請勿打包在壓縮包之中- 將 .llplugin 文件作為插件分發,安裝插件時直接將此文件放置到 plugins 目錄即可
- 在開服時,腳本引擎會自動識別 .llplugin 文件,將其解壓到
plugins/python/插件名目錄,並在目錄中自動執行pip install安裝依賴包,整個過程無需人工干預
Python插件開發的已知問題
平心而論,CPython的代碼質量和維護狀況有些堪憂。下面給出了一些開發Python插件時需要注意的地方,其中有不少都是由CPython本身的Bug引起的:
- 暫時不要使用
threadingasyncio等特性- LSE使用CPython的子解釋器作為引擎調度的核心單位,然而CPython自身長期以來對子解釋器機制的支持並不完善,存在眾多Bug,令人一言難盡。目前上面這些機制所需要使用到的GIL api內部並沒有考慮到子解釋器的存在,因此一旦使用會發生死鎖、崩潰等問題。
- 如果有並行計算需求的開發者可以暫時使用
multiprocess進行多進程並行
- 所有Python引擎的
sys.stdin被禁用- 這是另外一個CPython的bug,具體詳見:https://github.com/python/cpython/issues/83526
- 另外,即使不是上述情況下加載的CPython引擎,也會出現搶奪stdin的問題,導致部分使用了輸入重定向機制的工具失效
- 因此我們打patch禁用了所有Python引擎的
sys.stdin,等待後續版本CPython將此係列bug徹底解決之後,再視情況恢復