Config and a config screen
Status: Implemented. Options, comments, file reloads and the generated Config page in the Mods screen work. Custom config screens, enum and colour options and server-to-client config sync are Planned.
Goal: a join gift whose size and message players and server owners can change, with a Config page in the Mods screen, and code that reacts when the file changes.
Language: Lua, with C++ and C at the end. APIs: Configuration.
1. Define the options
Open the config and define options when the mod loads (top level of the script), so they exist before anything reads them:
local config = cl.config.open("common") -- config/my_mod.json
config:define_i32("gift.rubies", 1, 0, 64)
config:comment("gift.rubies", "Rubies every player gets on join")
config:define_bool("gift.message", true)
config:define_str("gift.text", "Welcome!")
A missing key is added to the file with its default; a value out of range falls back to the default.
2. Read values cheaply
Reading is cheap, but for code that runs often, keep the values in local variables and refresh them when the file changes:
local rubies, message, text
local function refresh()
rubies = config:get_i32("gift.rubies")
message = config:get_bool("gift.message")
text = config:get_str("gift.text")
end
refresh()
config:on_reload(refresh)
cl.on("player.join", function(event)
if rubies > 0 then event.player:give("my_mod:ruby", rubies) end
if message then event.player:send_message(text) end
end)
on_reload runs after the file was edited by hand (picked up within a second), saved from the Config page, re-read by /clight reload-config, or after a hot reload.
3. The generated screen
Mods → your mod → Config shows every option: a toggle for booleans, a slider for numbers with a range, a text box otherwise, with the comment as the tooltip.
Two string conventions get a better control in the Fancy config page:
- A value written as
#RRGGBB(for example"#FFAA00") is a colour: the page shows the colour picker (swatches plus hue, saturation and brightness sliders) and saves the result in the same#RRGGBBform. - A comment that ends in
One of: A, B, Cmakes the option a dropdown with those values, for exampleconfig:comment("bar.labels", "What the bar shows. One of: Letters, Degrees"). The part beforeOne of:stays the description. Labels come from lang entries:
{
"config.my_mod.gift.rubies": "Rubies on join",
"config.my_mod.gift.message": "Send a message",
"config.my_mod.gift.text": "Message"
}
4. Server values
Use the "server" scope (config/my_mod-server.json) for gameplay balance on a server. It is read on the server only; sending it to clients is planned.
5. C++
class GiftMod final : public clight::Mod {
clight::Config cfg_;
public:
void on_construct() override {
if (auto c = clight::config::open(CL_CONFIG_COMMON)) cfg_ = *c;
cfg_.define_i32("gift.rubies", 1, 0, 64);
cfg_.comment("gift.rubies", "Rubies every player gets on join");
clight::on<clight::ev::PlayerJoin>([this](cl_ev_player& e) {
clight::Entity(e.player).give("my_mod:ruby", cfg_.get_i32("gift.rubies"));
}).detach();
}
};
CLIGHT_MOD(GiftMod)
6. C
static cl_config g_cfg;
static void on_join(void* payload, void* user) {
(void)user;
cl_easy_give(CL_EVENT(cl_ev_player, payload)->player, "my_mod:ruby", cl_config_get_i32(g_cfg, CL_STR("gift.rubies")));
}
static cl_result mod_main(void) {
cl_result r = cl_config_open(CL_CONFIG_COMMON, &g_cfg);
if (r != CL_OK) return r;
cl_config_define_i32(g_cfg, CL_STR("gift.rubies"), 1, 0, 64);
return CL_ON(CL_EV_PLAYER_JOIN, on_join);
}
CLIGHT_MOD_ENTRY(mod_main)
Planned
A custom config screen (RML or widgets) opened from the Mods screen, enum, colour and list options, callbacks per option, and server config synced to clients.