Concepts
A short orientation pass for modders who want the mental model before reaching for specific docs.
Modder tiers
Jiangyu is built around progressive layers. You only learn the next tier when you need it:
Asset replacement. Drop a file into
assets/replacements/and ship. No code, no Unity Editor, no template authoring. Covers the bulk of skin-style mods.Template patching and cloning. Tweak existing game data (stats, skills, weapons, perks) by writing KDL under
templates/. Patches edit a vanilla template in place. Clones deep-copy a vanilla template into a new ID and let further patches diverge from the source.Asset additions referenced from clones. When a cloned weapon needs its own icon (or audio, or texture), drop the file into
assets/additions/and reference it from the clone's KDL withset "Icon" asset="...". The compiler verifies the reference resolves to a real file, and the loader resolves the runtime asset by name at apply time.Unity content. New prefabs and custom UI markup (UXML), built through the mod's Unity project. Prefabs need the Unity Editor, but UXML is plain text.
Runtime SDK. Custom C# the game runs: your own template types (effects, conditions, values, the common case), hooks that react to game moments, game verbs that command the live game, and UI injection. For anything the data layers can't express.
The lower tiers stay simple. You don't pay the cost of the SDK to ship a re-skin.
Name-match contract
Both replacements and additions resolve by Unity Object name at runtime, not by path or GUID. A replacement file at assets/replacements/sprites/UICheckMark.png swaps every game Sprite named UICheckMark. An addition file at assets/additions/sprites/lrm5/icon.png becomes a Sprite named lrm5/icon, available to any clone that references asset="lrm5/icon".
This is why the asset index matters for replacements: it's the source of truth for what each game asset's name is. Build it with jiangyu assets index. Studio's Asset Browser and the jiangyu assets search CLI both read from it.
For additions, the modder picks the name. The folder layout under assets/additions/<category>/ is the source of truth: the path under the category folder, with the extension stripped, becomes the asset's runtime name.
Asset replacement vs addition
A replacement changes the game in place. Every site that used the vanilla asset now picks up your version instead. An addition does the reverse: it ships an asset the game never had, and nothing uses it until a clone references it by name.
| Replacement | Addition | |
|---|---|---|
| Source file | assets/replacements/<category>/<vanilla-name>.<ext> | assets/additions/<category>/<your-name>.<ext> |
| Name | Must match a vanilla asset's runtime name | Modder's choice |
| Effect | Global. Every game site using that asset name gets the new content. | Local. Only template clones that reference it use it. |
| Asset index needed | Yes. Targets are validated against the indexed game catalog. | No. The modder chooses the name. |
| Use when... | Re-skinning, voice swaps, music changes | A cloned weapon, item, or skill needs distinct visuals or audio |
Both can coexist in the same mod. Both compile into the same bundle.
Template operations
Templates take five operations on a field:
- Set writes a value into a scalar field, or into one element of a collection (
set "Field" index=N <value>). - Append adds a new element to the end of a collection.
- Insert adds a new element at a specific index (
insert "Field" index=N <value>). - Remove drops the element at a specific index (
remove "Field" index=N). - Clear empties a collection.
For the full syntax of each op, including descent and construction (type=), see Templates.
Patches and clones are both lists of operations. A patch targets an existing template by ID. A clone deep-copies a vanilla template into a new ID and then applies its inline operations to the copy.
Sequential within a template
Operations on the same template apply in source order. Each runs against the result of the previous one.
patch "WeaponTemplate" "weapon.foo" {
clear "SkillsGranted"
append "SkillsGranted" ref="SkillTemplate" "active.aimed_shot"
append "SkillsGranted" ref="SkillTemplate" "active.steady_aim"
}Reads as: empty the list, then append two skills. Move the clear below the appends and you wipe out everything you just added, so the order is load-bearing.
The same rule covers more involved compositions:
clearfollowed by appends is the idiomatic "replace the whole list" pattern.removefollowed byinsertat the same index swaps an element.- Two
setdirectives on the same field is last-write-wins.
Apply order across templates and mods
The loader sequences mods deterministically:
- Bundles load for every mod, in lexical mod-folder order.
- Clones register before patches run. A clone deep-copies a vanilla template into a new ID and adds it to the live template registry, so subsequent patches can target that new ID. Clones-before-patches is a hard rule.
- Patches apply to live templates once the game has materialised the relevant template type. Each patch's directives run in source order, as above.
- Per-type latching: once a template type has been patched in a session, it's marked applied and skipped on later scene loads.
This ordering means a patch on mod_weapon.light.rocket_launcher_lrm5 runs cleanly against the LRM5 clone every time, regardless of which mod registered the clone or in what order the templates appear in the source files.
Late-binding values
Some values resolve only at apply time, not at compile time:
- Template references look the target up in the live template registry. The target must already be registered. Clones-before-patches keeps cross-clone references working.
- Asset references look the target up in the loaded mod-bundle catalog first, then the live game-asset registry. Either source must have the asset by then.
The compiler validates everything it can verify offline (bundle assets, addition files, field types), but cross-mod references are resolved live. A typo in another mod's clone ID, or a stale reference to a removed game asset, surfaces as a runtime error logged through MelonLoader rather than a compile failure.
Conflicts and last-write-wins
When two patches target the same field of the same template, the later application wins. Within one mod, that's source order. Across mods, that's the lexical mod-folder order from step 1.
Conflict detection is intentional rather than blocked: shipping a patch that overrides another mod's value is a valid use case (compatibility patches, rebalance overlays). The loader logs every successful application so collisions are visible in MelonLoader/Logs/ and modders can confirm the final state matches their intent.
Value kinds
Operations carry a value. KDL templates support several kinds:
- Scalars (
set "Damage" 25.0) - Strings (
set "Name" "Long Range Missile Launcher") - Enums (
set "SlotType" enum="ItemSlot" "ModularVehicleLight") - Template references (
set "Skill" ref="SkillTemplate" "active.aimed_shot"): point at another liveDataTemplate-descended template by ID. - Asset references (
set "Icon" asset="lrm5/icon"): point at aSprite/Texture2D/AudioClip/Materialasset, either an addition shipped by the mod or a vanilla game asset of the same name. - Construction (
type="OperationResources" { set "m_Supplies" 75 }): name a type to build. The compiler picks the storage from the destination: an inline value for a struct field, a fresh polymorphic element for a list such asEventHandlers, or a tagged string for a tagged-string field.
The category for asset references is derived from the destination field's declared Unity type, so the modder writes only the name. See Templates for the full KDL grammar and Additions for the asset-reference contract.
Project layout
A typical Jiangyu mod project looks like this:
my-mod/
jiangyu.json # manifest
assets/
replacements/ # swap vanilla assets by name
textures/
sprites/
models/
audio/
additions/ # new data assets a clone references
sprites/
textures/
audio/
templates/ # KDL: patches and clones
weapon-foo.kdl
skill-bar.kdl
code/ # C# SDK mod, dormant until used
unity/ # Unity project for prefabs and UXML, dormant until used
compiled/ # build output (don't edit, don't commit)
jiangyu.json
bundles/ # compiled asset bundles
<mod-name>.bundle
code/ # compiled mod DLL, when code/ is usedjiangyu init scaffolds code/ (the SDK) and unity/ (the Unity project) too, both dormant until you add code or assets. Everything except compiled/ is author-owned. compiled/ is regenerated by jiangyu compile.