Mod(模組系統)
ll/api/mod/ · 通用
概述
Mod 模塊管理模組生命週期、元數據(清單)、目錄結構,並提供對模組特定資源的訪問,如日誌器、配置目錄和數據目錄。
頭文件
| 頭文件 | 說明 |
|---|---|
ll/api/mod/Mod.h | 模組實例和生命週期 |
ll/api/mod/Manifest.h | 模組元數據結構 |
ll/api/mod/ModManager.h | 模組管理器基類 |
ll/api/mod/ModManagerRegistry.h | 所有模組管理器的註冊表 |
ll/api/mod/NativeMod.h | 原生(DLL)模組實現 |
核心類
Mod
表示已加載的模組,包含生命週期回調和資源訪問。
namespace ll::mod {
class Mod {
public:
enum class State { Enabled, Disabled };
State getState() const;
Manifest const& getManifest() const;
std::string const& getName() const;
std::string const& getType() const;
std::filesystem::path const& getModDir() const;
std::filesystem::path const& getDataDir() const;
std::filesystem::path const& getConfigDir() const;
std::optional<std::filesystem::path> getWorldDataDir() const;
std::optional<std::filesystem::path> getWorldConfigDir() const;
std::filesystem::path const& getLangDir() const;
std::filesystem::path const& getResourceDir() const;
std::filesystem::path const& getBehaviorDir() const;
io::Logger& getLogger() const;
bool isEnabled() const;
bool isDisabled() const;
void onLoad(CallbackFn func) noexcept;
void onUnload(CallbackFn func) noexcept;
void onEnable(CallbackFn func) noexcept;
void onDisable(CallbackFn func) noexcept;
};
std::filesystem::path const& getModsRoot();
}Manifest
從 manifest.json 加載的模組元數據。
namespace ll::mod {
struct Dependency {
std::string name;
std::optional<data::VersionRequirement> version;
};
struct Manifest {
std::string entry;
std::string name;
std::string type;
std::optional<std::string> platform;
std::optional<bool> passive;
std::optional<data::Version> version;
std::optional<std::string> author;
std::optional<std::string> description;
std::optional<SmallStringMap<std::string>> extraInfo;
std::optional<SmallDenseSet<Dependency>> dependencies;
std::optional<SmallDenseSet<Dependency>> optionalDependencies;
std::optional<SmallDenseSet<Dependency>> conflicts;
std::optional<SmallDenseSet<Dependency>> loadBefore;
};
}依賴項沿用現有的清單 JSON 結構:
{
"dependencies": [
{ "name": "RequiredMod", "version": "^1.2.3" }
],
"optionalDependencies": [
{ "name": "OptionalIntegration", "version": ">=2.0.0 <3.0.0" }
],
"loadBefore": [
{ "name": "LateInitializer" }
]
}依賴項省略 version 時可匹配任意版本,也可匹配未聲明版本的目標;一旦寫出範圍,目標必須聲明匹配的版本。
完整語法見 Data(數據結構)。裸完整版本 1.2.3 暫時保留舊語義
>=1.2.3 <2.0.0,並會輸出遷移警告;精確匹配請使用 =1.2.3。
模組類型
清單中的 type 字段決定由誰加載該模組:
type | 加載者 | 加載時機 |
|---|---|---|
native | LeviLamina 的原生模組管理器(NativeModManagerName) | LeviLamina 啟動後,與其他 LeviLamina 模組一起加載。普通的 C++ 模組使用此類型。 |
preload-native | PreLoader | 遊戲啟動前、LeviLamina 的模組之前加載。LeviLamina 本身就使用此類型。LeviLamina 的模組註冊表會跳過這類清單,因此它們不屬於 LeviLamina 模組。 |
其他 type 由通過 ModManagerRegistry 為該類型註冊的模組管理器加載(例如腳本引擎)。如果沒有為該類型註冊管理器,加載會失敗並提示 "Unrecognized mod type"。
無論哪種類型,將 passive 設為 true 後,只有當其他模組依賴它時才會加載該模組。
依賴語義
| 清單字段 | 加載順序 | 依賴加載失敗 | disable/unload 保護 |
|---|---|---|---|
dependencies | 依賴先加載 | 阻止依賴方加載 | 有 |
optionalDependencies | 可用且版本匹配的依賴先加載 | 不阻止使用方加載 | 加載時成功綁定後有 |
loadBefore | 聲明方先加載 | 不建立依賴關係 | 無 |
loadBefore 只約束啟動加載和批量操作順序,絕不會阻止任一方單獨 disable 或 unload。動態加載不會重排已經加載的
模組;若新模組要求在已加載目標之前加載,LeviLamina 會記錄警告並繼續。可選依賴只在使用方加載時綁定,因此之後
才動態加載的可選依賴提供方不會被追溯加入生命週期保護。
使用方法
訪問模組實例
#include "ll/api/mod/NativeMod.h"
ll::mod::NativeMod& getSelfMod() {
return ll::mod::NativeMod::current();
}使用模組資源
#include "ll/api/mod/Mod.h"
void setupMod(ll::mod::Mod& mod) {
auto& logger = mod.getLogger();
logger.info("模组名称: {}", mod.getName());
auto configPath = mod.getConfigDir() / "config.json";
auto dataPath = mod.getDataDir() / "database.db";
auto langPath = mod.getLangDir() / "zh_CN.json";
}生命週期回調
#include "ll/api/mod/Mod.h"
void registerCallbacks(ll::mod::Mod& mod) {
mod.onLoad([](ll::mod::Mod& self) -> bool {
self.getLogger().info("模组加载中");
return true; // 返回 false 中止加载
});
mod.onEnable([](ll::mod::Mod& self) -> bool {
self.getLogger().info("模组已启用");
return true;
});
mod.onDisable([](ll::mod::Mod& self) -> bool {
self.getLogger().info("模组已禁用");
return true;
});
mod.onUnload([](ll::mod::Mod& self) -> bool {
self.getLogger().info("模组卸载中");
return true;
});
}目錄結構
模組位於模組根目錄(getModsRoot())中:服務端為 plugins/,客戶端為 mods/。(plugins/ 目錄存在時 PreLoader
使用它,否則使用 mods/;PreLoaderConfig.json 中的 modsPath 可以覆蓋該設置。)每個模組具有以下目錄結構:
plugins/ # 客户端为 mods/
└── MyMod/
├── manifest.json # 模组元数据
├── MyMod.dll # 模组二进制文件
├── config/ # 配置文件 (getConfigDir())
├── data/ # 持久化数据 (getDataDir())
├── lang/ # 翻译文件 (getLangDir())
├── resource_packs/ # 资源包 (getResourceDir())
└── behavior_packs/ # 行为包 (getBehaviorDir())
worlds/
└── Bedrock level/ # 当前世界的文件夹
├── ll_config/
│ └── MyMod/ # 世界特定配置 (getWorldConfigDir())
└── ll_data/
└── MyMod/ # 世界特定数据 (getWorldDataDir())未加載世界時,getWorldConfigDir() 和 getWorldDataDir() 返回 std::nullopt。在客戶端連接遠程服務器時,它們分別是遊戲目錄下的
ll_config/<host>_<port>/MyMod/ 和 ll_data/<host>_<port>/MyMod/。
相關模塊
- Config(配置系統) — 使用
getConfigDir()獲取配置文件位置 - Data(數據結構) — 使用
getDataDir()存儲數據庫 - I18n(國際化) — 使用
getLangDir()存儲翻譯文件 - IO & Logger(輸入輸出與日誌) —
getLogger()返回模組的日誌器