跳到正文
本頁目錄

Config(配置系統)

ll/api/Config.h · 通用

概述

Config 模塊提供了用於加載和保存模組配置文件(JSON 格式)的模板函數。它利用 Reflection(反射) 模塊進行自動序列化/反序列化,支持帶版本號的配置及自動遷移。

頭文件

頭文件說明
ll/api/Config.hsaveConfig、loadConfig 及相關工具

概念

IsConfig

配置類型必須滿足:

  • ll::reflection::Reflectable<T> — 類型必須是聚合體(用於反射)
  • 具有整數類型的 version 字段
C++
namespace ll::config {
template <class T>
concept IsConfig = ll::reflection::Reflectable<T>
    && std::integral<std::remove_cvref_t<decltype((std::declval<T>().version))>>;
}

核心函數

saveConfig

C++
template <IsConfig T, class J = nlohmann::ordered_json>
bool saveConfig(T const& config, std::filesystem::path const& path);

將 config 序列化為 JSON 並寫入 path。成功時返回 true。

loadConfig

C++
template <IsConfig T, class J = nlohmann::ordered_json, class F = bool(T&, J&)>
bool loadConfig(T& config, std::filesystem::path const& path, F&& updater = defaultConfigUpdater<T, J>);

從 path 加載配置到 config。如果文件不存在,則保存當前 config 作為默認值。返回 true 表示無需重寫(版本匹配)。

行為:

  1. 文件不存在 → 保存默認配置,返回 false
  2. 文件存在但版本不同 → 調用 updater,返回 false
  3. 文件存在且版本匹配 → 直接反序列化,返回 true

defaultConfigUpdater

C++
template <class T, class J>
bool defaultConfigUpdater(T& config, J& data);

默認更新策略:使用 merge_patch 將現有文件內容合併到默認配置上,在添加新字段的同時保留用戶的修改。

使用方法

定義配置結構體

C++
#include "ll/api/Config.h"

struct MyConfig {
    int         version = 1;
    std::string greeting = "Hello";
    int         maxPlayers = 20;
    bool        enableFeatureX = false;
};

Note

結構體必須是聚合類型(無用戶定義構造函數、無私有成員、無虛函數),反射才能正常工作。

加載和保存

C++
#include "ll/api/Config.h"
#include "ll/api/mod/Mod.h"

void loadMyConfig(ll::mod::Mod& mod) {
    MyConfig config;

    auto configPath = mod.getConfigDir() / "config.json";

    bool upToDate = ll::config::loadConfig(config, configPath);
    if (!upToDate) {
        // 配置已创建或已迁移,保存更新后的版本
        ll::config::saveConfig(config, configPath);
    }

    mod.getLogger().info("问候语: {}", config.greeting);
    mod.getLogger().info("最大玩家数: {}", config.maxPlayers);
}

自定義更新器

C++
#include "ll/api/Config.h"

struct MyConfigV2 {
    int         version = 2;
    std::string greeting = "Hello";
    int         maxPlayers = 20;
    bool        enableFeatureX = false;
    std::string newField = "default";  // v2 中新增
};

bool myUpdater(MyConfigV2& config, nlohmann::ordered_json& data) {
    int oldVersion = data.value("version", 1);
    if (oldVersion == 1) {
        // 从 v1 迁移:保留旧的 "greeting" 值
        if (data.contains("greeting")) {
            config.greeting = data["greeting"];
        }
    }
    data.erase("version");
    auto patch = ll::reflection::serialize<nlohmann::ordered_json>(config);
    patch.value().merge_patch(data);
    data = *std::move(patch);
    return true;
}

void loadConfigV2(ll::mod::Mod& mod) {
    MyConfigV2 config;
    ll::config::loadConfig(config, mod.getConfigDir() / "config.json", myUpdater);
}

生成的 JSON 示例

對於上述 MyConfig 結構體,生成的 JSON 如下:

JSON
{
    "version": 1,
    "greeting": "Hello",
    "maxPlayers": 20,
    "enableFeatureX": false
}

相關模塊