# TC KubeJS Bridge (tckubejsbridge) > **English** | [中文](README.md) Bridges the **Thaumcraft 4 (port)** recipe system to **KubeJS**, allowing modpack authors and server admins to register TC infusion, crucible, arcane crafting recipes and item aspect tags directly from KubeJS scripts — including **replacing existing recipes**. Author: AlkSur | License: GPL-3.0 ## Requirements | Mod | Version | Relation | |---|---|---| | NeoForge | 21.1.234 | Required | | Minecraft | 1.21.1 | Required | | Thaumcraft (TC4 port) | 0.2.2.34-port.1 | Required | | KubeJS (NeoForge) | 2101.7.x | Required (plugin depends on its API) | > KubeJS is declared **optional** in `neoforge.mods.toml`: without KubeJS the plugin part > simply does not load, and the game still starts. ## Building The project lives at `modules/tc-kubejs-bridge` inside a multi-module Gradle build: ```bash # Run from the repository root gradle :tckubejsbridge:build ``` Artifact: `modules/tc-kubejs-bridge/build/libs/KubeJS Thaumcraft-+.jar` (e.g. `KubeJS Thaumcraft-1.0.0+21.1.234.jar`) Compile dependencies (local jars, paths editable in `build.gradle`): - KubeJS: `F:/downloads/kubejs-neoforge-2101.7.2-build.368.jar` - Rhino: `F:/downloads/rhino-2101.2.7-build.81.jar` (KubeJS script engine) - Thaumcraft: `modules/thaumicenergistics-neo/library/thaumcraft-0.2.2.34-port.1.jar` > Adjust the `files(...)` paths in the `dependencies` block if your local layout differs. ## Script Usage Put scripts into `kubejs/server_scripts/`, then **restart the game or run `/reload`** (see Note #1). ### 1. Infusion Recipe ```js ServerEvents.recipes(event => { event.recipes.thaumcraft.infusion( 'MY_INFUSION', // research key (globally unique; used by Thaumonomicon/dedup) 'minecraft:diamond', // result 3, // instability ['ignis 64', 'potentia 32'],// aspects: aspect tag + amount 'minecraft:golden_apple', // central item 'minecraft:blaze_rod', // components (one or more) 'minecraft:ender_pearl' ); }); ``` ### 2. Crucible Recipe ```js ServerEvents.recipes(event => { event.recipes.thaumcraft.crucible( 'MY_CRUCIBLE', 'minecraft:diamond', 'minecraft:coal', // catalyst { aer: 16, ignis: 8 } // object syntax also works ); }); ``` ### 3. Shaped Arcane Recipe ```js ServerEvents.recipes(event => { event.recipes.thaumcraft.arcane( 'MY_ARCANE', 'minecraft:diamond_sword', ['ignis 16', 'ordo 8'], [' I ', ' I ', ' S '], // pattern: up to 3 rows { I: 'minecraft:iron_ingot', S: 'minecraft:stick' } ); }); ``` ### 4. Shapeless Arcane Recipe ```js ServerEvents.recipes(event => { event.recipes.thaumcraft.arcane_shapeless( 'MY_SHAPELESS', 'minecraft:diamond_helmet', ['aer 8', 'aqua 8'], 'minecraft:leather_helmet', 'minecraft:diamond', 'minecraft:diamond', 'minecraft:diamond' ); }); ``` ### 5. Item Aspect Tags ```js ServerEvents.recipes(event => { event.thaumcraft.addObjectTag('minecraft:stick', { aer: 1, ignis: 2 }); }); ``` ### 6. Replacing an Existing Recipe (remove first, then register) ```js ServerEvents.recipes(event => { // NOTE: thaumcraft is a TOP-LEVEL binding, not event.thaumcraft thaumcraft.removeInfusion('INFUSIONPROVIDER'); // remove TC infusion recipes by research key // thaumcraft.removeArcane('RESEARCH_KEY'); // remove arcane recipes by research key // then register the new recipe for a true replacement event.recipes.thaumcraft.infusion( 'INFUSIONPROVIDER', 'thaumicenergistics:infusion_provider', 0, ['auram 10'], 'ae2:interface', 'minecraft:oak_planks' ); }); ``` ## Aspect Tag Reference (actual values in the TC4 port) **Important: the port uses the original Latin tags, not the TC4 English/localized names.** | Aspect | Tag | Aspect | Tag | |---|---|---|---| | Air | `aer` | Earth | `terra` | | Fire | `ignis` | Water | `aqua` | | Order | `ordo` | Entropy | `perditio` | | Void | `vacuos` | Light | `lux` | | Weather | `tempestas` | Motion | `motus` | | Crystal | `vitreus` | Life | `victus` | | Energy | `potentia` | Exchange | `permutatio` | | Death | `mortuus` | Darkness | `tenebrae` | | Soul | `spiritus` | Eldritch | `alienis` | | Magic | `praecantatio` | Aura | `auram` | | Slime | `limus` | Plant | `herba` | | Tree | `arbor` | Beast | `bestia` | | Flesh | `corpus` | Undead | `exanimis` | | Mind | `cognitio` | Senses | `sensus` | | Man | `humanus` | Tool | `instrumentum` | | Greed | `lucrum` | Craft | `fabrico` | | Cloth | `pannus` | Mechanism | `machina` | ## Notes 1. **Hot-reload supported**: after editing scripts, run `/reload` — no game restart needed. - KubeJS re-runs `ServerEvents.recipes` on every `/reload`, so scripts execute again. - With the "remove-then-register" pattern (`thaumcraft.removeInfusion(...)` followed by `infusion(...)`), the removal step clears this mod's dedup key and drops the old recipe from TC's in-memory list, so the new recipe registers correctly. - Scripts that only add recipes (without removing first) will be dedup-skipped on repeated `/reload`; call `thaumcraft.clearRegistered()` at the top of the script to reset the set. 2. **Research keys are globally unique**: duplicate keys are skipped (prevents double registration). Use a different key for same-name recipes. 3. **Recipes do NOT go into the vanilla RecipeManager**: TC infusion/crucible/arcane recipes live in TC's own in-memory list. The bridge calls the TC API directly during script execution and emits a harmless placeholder recipe to KubeJS, so it does not affect other mods' recipe operations. (The schema uses `typeOverride = minecraft:crafting_shapeless` so KubeJS can find a serializer.) 4. **Aspect lists accept two syntaxes**: array `['ignis 64']` or object `{ignis: 64}`. 5. **Item arguments** accept: item id strings (`minecraft:xxx` / `ae2:xxx`), `Item.of(...)`, and item tags (`#minecraft:planks`). 6. **AE2's namespace is `ae2`**: e.g. the AE2 interface is `ae2:interface`, NOT `appliedenergistics2:interface`. 7. **KubeJS version compatibility**: the bridge is built on KubeJS 2101.7.x RecipeSchema API (marked `@ApiStatus.Experimental`). Upgrading KubeJS to another patch version may require adjustments to the bridge layer. ## Troubleshooting | Symptom | Cause | |---|---| | Log shows `Serializer for type thaumcraft:infusion is not found` | Missing `typeOverride` (already fixed in code; rebuild) | | Log shows `Unknown aspect 'xxx'` | Wrong aspect tag — check the aspect table above | | Log shows `Item with ID xxx does not exist` | Wrong item id — remember the `ae2:` namespace | | No `TC-KubeJS-Bridge` lines in the log at all | Mod not installed, or script not in `server_scripts` | | Script reports `event.thaumcraft is undefined` | Use the top-level `thaumcraft.xxx`, not `event.thaumcraft.xxx` | ## Project Layout ``` src/main/java/tckubejsbridge/ ├── TCKubeJSBridge.java // @Mod main class └── kubejs/ ├── TCKubeJSPlugin.java // KubeJS plugin: schemas + bindings ├── TCRecipeKJS.java // Custom KubeRecipe base (bridge + placeholder serialization) ├── TCRecipeBridge.java // TC API calls + dedup + removal + placeholder JSON ├── AspectListComponent.java // Aspect list RecipeComponent ├── InfusionRecipeKJS.java // Infusion recipe ├── CrucibleRecipeKJS.java // Crucible recipe ├── ShapedArcaneRecipeKJS.java // Shaped arcane recipe └── ShapelessArcaneRecipeKJS.java // Shapeless arcane recipe src/main/resources/ ├── kubejs.plugins.txt // Plugin discovery file └── META-INF/neoforge.mods.toml example/infusion_example.js // Example script ```