Porting existing mods to CLight: overview
Status: Implemented as a guide to the API that exists. The mapping tables in this folder mark every CLight feature that isn’t in the game yet as planned.
Celestial does not load, convert or translate Java mods or plugins. Fabric, Quilt, Forge and NeoForge mods, and Bukkit, Spigot, Paper and Folia plugins (
.jarfiles), do not run on Celestial. There is no conversion tool, no bytecode translator and no compatibility runtime, and none is planned. The guides in this folder are for authors who want to rewrite their own mod by hand against the CLight API.
Why there is no converter
Java mods are built on the original game’s Java classes: they call its methods, extend its classes and, with mixins or NMS code, change its bytecode. Celestial is a separate C++ engine. It reproduces the game’s behaviour, but it has no JVM and no Java classes for a mod to extend. A converter would have to emulate the whole original codebase.
What carries over without any work:
| Part of your mod | On Celestial |
|---|---|
| Data pack content: recipes, loot tables, tags, advancements, enchantments, damage types, functions | Works unchanged in the mod’s datapack/<ns>/ folder (note: no data/ level). Recipes, tags and loot tables can name your own items by id. |
| Resource pack content: textures, models, block states, item model definitions, sounds, lang files, fonts | Works unchanged in assets/<ns>/ |
| OptiFine-format CEM models, random and emissive textures, CIT, shader packs | Supported by Celestial’s renderer (Data packs, resource packs and OptiFine packs) |
| Java code | Rewrite it in Lua, C or C++ |
The porting workflow
- Inventory the mod. List what the code does, not how: “registers 12 blocks and 30 items”, “a shop GUI”, “changes fall damage”, “a sync packet”, “a HUD element”. Note which parts are data already.
- Check what exists. Compare the list with the tables in the platform guides and with API function index. Features marked planned decide whether a port is possible today.
- Pick the kind and the language.
sideandsync(Server-required vs client-only mods); Lua for plugins and small tweaks, C++ for heavy logic (Choosing a language and runtime). - Move data and assets into the new project. Keep your mod id, so identifiers stay the same.
- Replace patches with events, behaviours or CLight mixins (table below).
- Mind the model: handles go stale, content is vanilla-backed, a callback has a time limit, and nothing touches the world from a HUD or screen callback.
- Test in singleplayer and in multiplayer, with and without the mod on each side.
Replacing patches
| Your Java mod… | In CLight |
|---|---|
| Injects at the head of a method to cancel it | An event with cancel, or a CLight mixin at head with cancel() |
| Modifies a return value or an argument | A mutable event field (amount, xp, message), or a CLight mixin (return, value:<name>, wrap) on a game target |
| Overwrites a whole method | A CLight mixin overwrite on the target (only one mod can overwrite a target) |
| Changes the behaviour of your own block or item | Its behaviour table (use_without_item, attack, random_tick, use) |
| Changes one vanilla block’s or item’s behaviour | A mixin, where the game has a target; behaviour overrides on vanilla content are planned |
| Reads or writes a private field | A CLight accessor, where the game has one; otherwise request it |
| Changes networking internals | Not possible. Use payloads. |
| Changes worldgen RNG or protocol encoding | Not possible, by design (seed and wire parity) |
CLight mixins attach to named targets the engine compiles in (Mixins). The game’s targets arrive in batches; cl.has("mixin:<name>") tells you which exist, and Mixin targets lists them.
Things that work differently everywhere
| Assumption from Java modding | CLight reality |
|---|---|
| Objects are references you can keep | Handles that may go stale. Check is_valid, or keep UUIDs. |
| Numeric ids are stable | Raw ids are per session. Save identifiers as text. |
| Your blocks and items are new registry entries | They are vanilla-backed: a base block or item plus your id, model and properties |
| You can call anything | Only the published API, which keeps mods working across engine updates |
| A slow method only slows the game | A callback over its time limit is stopped, and repeated failures turn the mod off |
| Client and server share classes | Same mod, but check the side of each event and function |
| The garbage collector cleans up | True for Lua; in C, release owned values; in C++, RAII does it |
The guides
| From | Guide |
|---|---|
| Fabric (and Quilt) | Porting a Fabric mod by hand |
| Forge and NeoForge | Porting a Forge or NeoForge mod by hand |
| Bukkit, Spigot, Paper and Folia plugins | Porting a Bukkit, Spigot, Paper or Folia plugin by hand |
| Data packs, resource packs and OptiFine packs | Data packs, resource packs and OptiFine packs |
The tables name concepts from other platforms only to help you find the CLight equivalent; they are not documentation of those platforms.