跳到正文
本頁目錄

📋 語言支持

🌏 開發語言支持情況

通過 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 不完全一致。

假設腳本插件的結構為:

Text Only
c:/bds
    bedrock_server_mod.exe
    plugins/
        your_plugin/
            manifest.json
            index.js
            command/
                command.js

index.js 入口文件:

JavaScript
import { initCommand } from "./command/command.js"

initCommand();

此時 QuickJS 會將入口模塊的 import.meta.url 解析為 file:///c:/bds 而不是 file:///c:/bds/plugins/your_plugin

因此 ./command/command.js 會解析失敗,導致插件加載失敗。

例如 QuickJS 可能會拋出類似如下的錯誤(原始日誌):

Text Only
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

解決方法是使用相對於工作目錄的路徑:

JavaScript
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 插件開發方法

  1. 首先,安裝Node.js
  2. 創建一個新的目錄進行插件開發。在此目錄啟動終端執行npm init命令。根據 npm 的提示創建新項目,填寫項目的相關信息。
  3. 在填寫的入口點文件中編寫插件代碼
  4. 如果有需要,可以創建多個源碼文件,並且通過 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)自動生成,以便於進行插件項目的創建和維護。
下面是具體的插件開發流程:
  1. 首先,安裝Python 3.12.10

  2. 在終端中執行pip install --user pdm命令安裝 pdm 包管理工具

  3. 創建一個新的目錄進行插件開發。在此目錄啟動終端執行pdm init命令。根據pdm工具的提示創建新項目,填寫項目的相關信息。

    • 如果需要安裝依賴包,在項目目錄執行pdm add <依赖包名>即可

    • 所有的項目元數據和依賴數據都會被自動儲存在pyproject.toml 中,無需手動編寫。你也可以打開此文件修改版本號、描述等元數據信息

    • 除了使用pdm add命令之外,你也可以直接把項目依賴手動寫在requirements.txt當中。在安裝插件時,pyproject.toml和 requirements.txt中描述的依賴都將被處理並自動安裝。

  4. 接下來創建__init__.py文件,並在其中編寫插件代碼。加載插件時,Python解釋器會首先讀取並執行這個文件。

  5. 如果有需要,可以創建多個源碼文件,並且通過 import 來引入他們。合理的對源碼進行分文件拆分編寫有助於提高項目結構的清晰度,方便後續對插件進行進一步的維護和擴展。

⭐ Python 多文件插件打包 & 部署方法

  • 在插件編寫完成之後,請將 pyproject.toml以及所有插件源碼打包為一個zip壓縮包,並將文件名後綴修改為 .llplugin
  • __pycache__ 和__pypackages__ 等目錄請勿打包在壓縮包之中
  • 將 .llplugin 文件作為插件分發,安裝插件時直接將此文件放置到 plugins 目錄即可
  • 在開服時,腳本引擎會自動識別 .llplugin 文件,將其解壓到plugins/python/插件名目錄,並在目錄中自動執行 pip install 安裝依賴包,整個過程無需人工干預

Python插件開發的已知問題

平心而論,CPython的代碼質量和維護狀況有些堪憂。下面給出了一些開發Python插件時需要注意的地方,其中有不少都是由CPython本身的Bug引起的:

  1. 暫時不要使用threading asyncio等特性
    • LSE使用CPython的子解釋器作為引擎調度的核心單位,然而CPython自身長期以來對子解釋器機制的支持並不完善,存在眾多Bug,令人一言難盡。目前上面這些機制所需要使用到的GIL api內部並沒有考慮到子解釋器的存在,因此一旦使用會發生死鎖、崩潰等問題。
    • 如果有並行計算需求的開發者可以暫時使用multiprocess進行多進程並行
  2. 所有Python引擎的sys.stdin被禁用
    • 這是另外一個CPython的bug,具體詳見:https://github.com/python/cpython/issues/83526
    • 另外,即使不是上述情況下加載的CPython引擎,也會出現搶奪stdin的問題,導致部分使用了輸入重定向機制的工具失效
    • 因此我們打patch禁用了所有Python引擎的sys.stdin,等待後續版本CPython將此係列bug徹底解決之後,再視情況恢復