Setting up
Lesson 3.1
In this lesson you install the tools, make a new C mod and look at what is inside it.
What you need
- Celestial itself. The download from the Celestial website is a folder with
Celestial.exein it. - The CLight SDK. It ships with Celestial, in the
clight-sdkfolder next toCelestial.exe. CLight is the name of the modding system, and the SDK is its toolbox: theclighttool, the C headers, templates and examples. - wasi-sdk, the C compiler for WebAssembly. The
clighttool downloads it for you. - A text editor. Visual Studio Code with Microsoft’s C/C++ extension works well, but any editor is fine.
You don’t need Visual Studio, MinGW or any other compiler. C mods are not Windows programs: they are compiled to WebAssembly (WASM), a portable format that the game runs in a sandbox. That is why one .clmod file works for every player.
Put the clight tool on your PATH
The SDK’s command-line tool is clight-sdk/bin/clight.exe. Add that bin folder to your PATH so you can type clight in any terminal:
- Press the Windows key and search for Edit environment variables for your account.
- Select Path, click Edit, then New, and paste the full path of the
binfolder, for exampleC:\Games\Celestial\clight-sdk\bin. - Click OK and open a new terminal window.
Install the compiler
Run clight setup once:
> clight setup
downloading https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-windows.tar.gz
verified sha256, extracting...
installed wasi-sdk-34 at C:\Games\Celestial\clight-sdk\wasi-sdk
It downloads the official wasi-sdk release from GitHub, checks it against a known checksum, and unpacks it into clight-sdk/wasi-sdk. It is a big download (a full clang compiler), so give it a minute. You only do this once; clight setup --force installs it again if something went wrong.
If you already have wasi-sdk somewhere else, set the WASI_SDK_PATH environment variable to its folder, and clight uses that one instead.
Now check the whole installation:
> clight doctor
CLight SDK 0.1.0 (API 1.24)
ok SDK folder C:\Games\Celestial\clight-sdk
ok clight.h C:\Games\Celestial\clight-sdk\include
ok wasi-sdk (C/C++ mods) C:\Games\Celestial\clight-sdk\wasi-sdk 34.0
ok Celestial C:\Games\Celestial\Celestial.exe
Lua mods need nothing else.
All four lines should say ok. A MISSING line tells you what to do next.
Make a new mod
Go to the folder where you keep your projects and run clight new c:
> clight new c my_mod
created C:\Projects\my_mod (c, 5 files)
next: cd my_mod && clight build && clight run
my_mod is the mod’s id. Every mod has one, and it has to be unique. The rules: lowercase letters, digits and _, starting with a letter, 2 to 64 characters. ruby_tools is fine, RubyTools and 2cool are not.
The display name is made from the id (my_mod becomes “My Mod”). Pick another with --name:
> clight new c ruby_tools --name "Ruby Tools"
What’s inside
my_mod/
clight.mod.json the manifest: id, version, name, licence, ...
src/
main.c your code starts here
assets/
my_mod/
lang/
en_us.json texts players see, by language
CMakeLists.txt only if you want to build with CMake (optional)
.gitignore
A bigger mod adds more folders next to these:
| Folder | What goes in it |
|---|---|
src/ |
Your .c files. clight build compiles every .c file in here, also in subfolders. Headers you write go here too. |
assets/<id>/ |
Resource-pack files: textures, models, sounds, language files, GUI files. |
datapack/<id>/ |
Data-pack files: recipes, loot tables, tags. |
icon.png |
The mod’s icon, square, 64 to 256 pixels. |
LICENSE |
The licence text. |
build/ |
Made by clight: object files, the compiled bin/my_mod.wasm and the packed mod. Don’t edit it. |
Your first source file
Open src/main.c. The template already does something useful:
// My Mod: a CLight mod in C, compiled to WebAssembly by `clight build`.
// clight_easy.h has short helpers for the common tasks; clight.h is the full API.
#include <clight_easy.h>
// When a player joins, say hello.
static void on_player_join(void* payload, void* user) {
(void)user;
cl_entity player = CL_EVENT(cl_ev_player, payload)->player;
char name[64];
cl_easy_player_name(player, name, sizeof name);
cl_easy_send_messagef(player, "Welcome, %s!", name);
}
// Runs once when the mod loads: subscribe to events here.
static cl_result mod_main(void) {
CL_LOG("My Mod loaded");
return CL_ON(CL_EV_PLAYER_JOIN, on_player_join);
}
CLIGHT_MOD_ENTRY(mod_main)
Read it from the bottom up:
CLIGHT_MOD_ENTRY(mod_main)tells the game which function to call when your mod loads. It takes the place ofmain. It must appear exactly once in your mod.mod_mainruns once. It tells the game what the mod wants to hear about, and returnsCL_OKif everything went well. Returning anything else stops the mod from loading.CL_ON(CL_EV_PLAYER_JOIN, on_player_join)means “when a player joins, callon_player_join”. It returnsCL_OKwhen the subscription worked, somod_maincan return its result directly.on_player_joinis a callback. The game calls it with the event’s details inpayload.CL_LOGwrites a line to the game’s log, likeprintf.
The (void)user; line only tells the compiler “I know I don’t use this parameter”, so it doesn’t warn. You will meet CL_EVENT, CL_ON and the cl_easy_ helpers properly in The easy header.
The sandbox
Your mod runs in a sandbox. It can call the game API and read its own folder, and nothing else: no other files, no programs, no network, no native code. A mod can’t read your saves or your account. That is why players can install mods without worrying.
Editor help
To get completion and error squiggles, tell your editor where the headers are. With VS Code and the C/C++ extension, create .vscode/c_cpp_properties.json in your mod folder (change the paths to yours):
{
"configurations": [
{
"name": "CLight",
"includePath": ["${workspaceFolder}/src", "C:/Games/Celestial/clight-sdk/include"],
"defines": ["__wasm__"],
"compilerPath": "C:/Games/Celestial/clight-sdk/wasi-sdk/bin/clang.exe",
"compilerArgs": ["--target=wasm32-wasip1"],
"cStandard": "c17"
}
]
}
The header has short comments above many functions. Hover over a function to read what it does, where it may run, and since which API version it exists.
Try it
Make a mod called hello_world with the display name “Hello World”. Change the welcome message so it says “Welcome, Alex! Hello World is installed.” (with the player’s real name).
Show a solution
> clight new c hello_world --name "Hello World"
In src/main.c, change only the message line:
cl_easy_send_messagef(player, "Welcome, %s! Hello World is installed.", name);
cl_easy_send_messagef works like printf: %s is replaced by name. The next lesson shows how to build the mod and see the message in the game.
Recap: put clight-sdk/bin on your PATH, run clight setup once for the compiler, make a mod with clight new c <id>, and write your code in src/main.c, starting at CLIGHT_MOD_ENTRY.