This commit is contained in:
1820982382
2026-08-18 22:23:25 +08:00
parent 2c1aabe78a
commit 429d21a72f
8 changed files with 798 additions and 163 deletions
+211 -66
View File
@@ -2,12 +2,21 @@
> **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**.
Bridges the **Thaumcraft 4 (port)** recipe and research systems to **KubeJS**.
Modpack authors can use scripts in `kubejs/server_scripts/` to register:
- Infusion recipes
- Crucible recipes
- Shaped / shapeless arcane recipes
- Item aspect tags
- Custom research categories / research nodes
- Replacing existing TC recipes
Author: AlkSur | License: GPL-3.0
---
## Requirements
| Mod | Version | Relation |
@@ -20,40 +29,56 @@ Author: AlkSur | License: GPL-3.0
> 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:
## Building & Installation
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-<mod_version>+<neoforge_version>.jar`
(e.g. `KubeJS Thaumcraft-1.0.0+21.1.234.jar`)
Artifact:
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`
```text
modules/tc-kubejs-bridge/build/libs/KubeJS Thaumcraft-<mod_version>+<neoforge_version>.jar
```
> Adjust the `files(...)` paths in the `dependencies` block if your local layout differs.
For example:
## Script Usage
```text
KubeJS Thaumcraft-1.0.0+21.1.234.jar
```
Put scripts into `kubejs/server_scripts/`, then **restart the game or run `/reload`** (see Note #1).
Put the jar into your `mods/` folder.
---
## Quick Start
1. Create a `.js` file under `kubejs/server_scripts/`.
2. Use `ServerEvents.recipes(event => { ... })`.
3. Run `/reload` or restart the game.
All `thaumcraft.xxx` calls are **top-level bindings**; do not use `event.thaumcraft.xxx`.
---
## Recipe Registration
### 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)
'MY_INFUSION', // research key (globally unique)
'minecraft:diamond', // result
3, // instability
['ignis 64', 'potentia 32'], // required aspects
'minecraft:golden_apple', // central item
'minecraft:blaze_rod', // component
'minecraft:ender_pearl'
);
});
@@ -66,8 +91,8 @@ ServerEvents.recipes(event => {
event.recipes.thaumcraft.crucible(
'MY_CRUCIBLE',
'minecraft:diamond',
'minecraft:coal', // catalyst
{ aer: 16, ignis: 8 } // object syntax also works
'minecraft:coal', // catalyst
{ aer: 16, ignis: 8 } // object syntax also works
);
});
```
@@ -80,7 +105,7 @@ ServerEvents.recipes(event => {
'MY_ARCANE',
'minecraft:diamond_sword',
['ignis 16', 'ordo 8'],
[' I ', ' I ', ' S '], // pattern: up to 3 rows
[' I ', ' I ', ' S '], // pattern: up to 3 rows
{ I: 'minecraft:iron_ingot', S: 'minecraft:stick' }
);
});
@@ -88,37 +113,50 @@ ServerEvents.recipes(event => {
### 4. Shapeless Arcane Recipe
> Note: `arcane_shapeless` ingredients must be provided as **one array**.
```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'
[
'minecraft:leather_helmet',
'minecraft:diamond',
'minecraft:diamond',
'minecraft:diamond'
]
);
});
```
### 5. Item Aspect Tags
---
## Item Aspect Tags
```js
ServerEvents.recipes(event => {
event.thaumcraft.addObjectTag('minecraft:stick', { aer: 1, ignis: 2 });
// add
thaumcraft.addObjectTag('minecraft:stick', { aer: 1, ignis: 2 });
// remove
thaumcraft.removeObjectTag('minecraft:stick');
});
```
### 6. Replacing an Existing Recipe (remove first, then register)
---
## Replacing Existing Recipes
```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
// remove first
thaumcraft.removeInfusion('INFUSIONPROVIDER'); // infusion
// thaumcraft.removeArcane('RESEARCH_KEY'); // arcane
// thaumcraft.removeCrucible('RESEARCH_KEY'); // crucible
// then register the new recipe for a true replacement
// then register a new recipe
event.recipes.thaumcraft.infusion(
'INFUSIONPROVIDER',
'thaumicenergistics:infusion_provider',
@@ -130,6 +168,96 @@ ServerEvents.recipes(event => {
});
```
---
## Custom Research Categories / Nodes
### Add a Research Category
```js
ServerEvents.recipes(event => {
thaumcraft.addResearchCategory(
'MY_CATEGORY',
'textures/research/cat_icon.png',
'textures/research/cat_bg.png'
);
});
```
- A two-argument form is also available: `addResearchCategory('MY_CATEGORY', 'textures/research/cat_icon.png')`
- Paths without a namespace default to the `kubejs:` namespace.
### Add a Research Node
```js
ServerEvents.recipes(event => {
thaumcraft.addResearchNode({
key: 'MY_RESEARCH',
category: 'MY_CATEGORY',
icon: 'textures/research/my_research.png',
parents: ['PARENT_KEY'],
autoUnlock: true, // unlocked by default
virtual: false, // visible in the Thaumonomicon; true hides it
hidden: false,
col: 0,
row: 0,
complexity: 1,
aspects: { aer: 1, ignis: 1 }
});
});
```
Supported fields:
| Field | Description |
|---|---|
| `key` | Unique research node ID |
| `category` | Existing research category |
| `icon` | Icon path |
| `parents` / `parentsHidden` / `siblings` | Research dependencies |
| `autoUnlock` | Unlocked by default |
| `virtual` | Hidden from the Thaumonomicon when `true` |
| `hidden` / `concealed` / `lost` | Visibility flags |
| `special` / `stub` / `secondary` / `round` | Research type flags |
| `col` / `row` / `complexity` | Position and complexity on the research map |
| `aspects` | Associated aspects |
### Icon File Location
If you write:
```js
icon: 'textures/research/my_research.png'
```
The file should be at:
```text
kubejs/assets/kubejs/textures/research/my_research.png
```
You can also use a full path:
```js
icon: 'kubejs:textures/research/my_research.png'
```
### Research Names / Descriptions
TC research names use language files.
Add this to `kubejs/assets/kubejs/lang/en_us.json`:
```json
{
"tc.research_category.MY_CATEGORY": "My Category",
"tc.research_name.MY_RESEARCH": "My Research",
"tc.research_text.MY_RESEARCH": "This is a research description."
}
```
For Chinese, add the same keys to `kubejs/assets/kubejs/lang/zh_cn.json`.
---
## Aspect Tag Reference (actual values in the TC4 port)
**Important: the port uses the original Latin tags, not the TC4 English/localized names.**
@@ -154,57 +282,74 @@ ServerEvents.recipes(event => {
| Greed | `lucrum` | Craft | `fabrico` |
| Cloth | `pannus` | Mechanism | `machina` |
## Notes
## Hot Reload
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.
| Content | `/reload` | Notes |
|---|---|---|
| Infusion / Crucible / Arcane recipes | ✅ | Can be hot-reloaded |
| Item aspect tags | ✅ | Can be hot-reloaded |
| Research categories / nodes | ❌ | Requires a game restart |
### Research key notes
- If `research` is **not** an existing TC research, the bridge registers a default-unlocked virtual research node and treats the recipe as having **no research requirement**.
- If `research` **is** an existing TC research, the recipe still requires that research to be completed.
- Research keys are globally unique; duplicate keys are skipped.
## 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` |
| `Constructor for thaumcraft:arcane_shapeless with N arguments not found` | Ingredients were not placed in an array |
| `Unknown aspect 'xxx'` | Wrong aspect tag |
| `Item with ID xxx does not exist` | Wrong item id |
| Research category name shows `tc.research_category.XXX` | Missing language file |
| Research icon / background is purple-black | Texture missing, wrong path, not a PNG, or KubeJS assets not loaded |
| `event.thaumcraft is undefined` | Use top-level `thaumcraft.xxx`, not `event.thaumcraft.xxx` |
## Project Layout
```
```text
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
├── TCRecipeKJS.java // Custom KubeRecipe base
├── TCRecipeBridge.java // TC API calls / dedup / removal / research registration
├── AspectListComponent.java // Aspect list component
├── 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
```