From 47695dd923964111af06ba0faf30dcc903f42a4c Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Wed, 13 May 2026 13:56:23 +0800 Subject: [PATCH 01/14] gitignore --- .gitignore | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd9adc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# IDE files +.vscode/ +.trae/ + +# IDE configuration files +**/jsconfig.json +config/probe-settings.json + +# OS files +Thumbs.db +.DS_Store + +# Change log +change log/ \ No newline at end of file From 005ea3b4e45d6dc25e429aa0bdf80f0beb1950ef Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Fri, 15 May 2026 21:50:23 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E5=BC=80=E5=8F=91=E4=B8=AD=EF=BC=8C?= =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0=E4=BB=8E=E5=A4=A7=E6=A1=B6?= =?UTF-8?q?=E5=AF=86=E5=B0=81=E9=85=8D=E6=96=B9=E6=89=B9=E9=87=8F=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=8F=91=E9=85=B5=E9=85=8D=E6=96=B9=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=9D=9E=E8=85=90=E8=B4=A5=E9=A3=9F=E6=9D=90=E9=99=90?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biodiesel_fix/fermenting_from_barrel.js | 205 ++++++++++++++++++ .../test_fermenting_recipes.js.pass | 96 ++++++++ server_scripts/test_large_leather.js.pass | 26 +++ server_scripts/test_not_rotten.js.pass | 56 +++++ server_scripts/test_tfc_modifiers.js.faild | 32 +++ 5 files changed, 415 insertions(+) create mode 100644 server_scripts/biodiesel_fix/fermenting_from_barrel.js create mode 100644 server_scripts/test_fermenting_recipes.js.pass create mode 100644 server_scripts/test_large_leather.js.pass create mode 100644 server_scripts/test_not_rotten.js.pass create mode 100644 server_scripts/test_tfc_modifiers.js.faild diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js new file mode 100644 index 0000000..00f4790 --- /dev/null +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -0,0 +1,205 @@ +// ============================================================================ +// 批量从TFC密封大桶配方创建Create发酵配方 +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[生物柴油修复] 开始批量转换TFC密封大桶配方为Create发酵配方...'); + + let convertedCount = 0; + let skippedCount = 0; + + event.forEachRecipe({ type: 'tfc:barrel_sealed' }, recipe => { + const json = recipe.json; + + let inputItem = null; + if (json.has('input_item')) { + inputItem = JSON.parse(json.get('input_item').toString()); + } + + let inputFluid = null; + if (json.has('input_fluid')) { + inputFluid = JSON.parse(json.get('input_fluid').toString()); + } + + let outputItem = null; + if (json.has('output_item')) { + outputItem = JSON.parse(json.get('output_item').toString()); + } + + let outputFluid = null; + if (json.has('output_fluid')) { + outputFluid = JSON.parse(json.get('output_fluid').toString()); + } + + // 检查输入物品堆叠数量 + if (inputItem) { + let itemId = inputItem.item || inputItem.tag; + if (itemId) { + let count = inputItem.count || 1; + try { + let maxStack; + if (inputItem.tag) { + let tagItems = Ingredient.of(`#${inputItem.tag}`).items; + if (tagItems && tagItems.length > 0) { + let minStack = tagItems[0].maxStack; + for (let i = 1; i < tagItems.length; i++) { + if (tagItems[i].maxStack < minStack) { + minStack = tagItems[i].maxStack; + } + } + maxStack = minStack; + } + } else { + maxStack = Item.of(itemId, 1).items[0].maxStack; + } + if (maxStack && count > maxStack) { + skippedCount++; + return; + } + } catch (e) { + if (count > 64) { + skippedCount++; + return; + } + } + } + } + + // 检查输出物品堆叠数量 + if (outputItem) { + let outputId = outputItem.id || outputItem.item; + if (outputId) { + let count = outputItem.count || 1; + try { + let maxStack = Item.of(outputId, 1).items[0].maxStack; + if (maxStack && count > maxStack) { + skippedCount++; + return; + } + } catch (e) { + if (count > 64) { + skippedCount++; + return; + } + } + } + } + + // 检查流体量 + if (inputFluid && inputFluid.amount > 1000) { + skippedCount++; + return; + } + if (outputFluid && outputFluid.amount > 1000) { + skippedCount++; + return; + } + + // 跳过modifiers + if (outputItem && outputItem.modifiers) { + skippedCount++; + return; + } + + let sealTime = json.has('seal_time') ? json.get('seal_time').getAsInt() : 0; + let ingredients = []; + let results = []; + + // 添加输入物品 + if (inputItem) { + if (inputItem.type === 'tfc:and' && inputItem.children) { + let count = inputItem.count || 1; + for (let i = 0; i < count; i++) { + ingredients.push({ + type: 'tfc:and', + children: inputItem.children + }); + } + } else { + let itemId = inputItem.item || inputItem.tag; + if (itemId && typeof itemId === 'string' && itemId.includes('food/')) { + let count = inputItem.count || 1; + for (let i = 0; i < count; i++) { + ingredients.push({ + type: 'tfc:and', + children: [ + inputItem.item ? { item: inputItem.item } : { tag: inputItem.tag }, + { type: 'tfc:not_rotten' } + ] + }); + } + } else { + let count = inputItem.count || 1; + if (inputItem.item) { + for (let i = 0; i < count; i++) { + ingredients.push({ item: inputItem.item }); + } + } else if (inputItem.tag) { + for (let i = 0; i < count; i++) { + ingredients.push({ tag: inputItem.tag }); + } + } + } + } + } + + // 添加输入流体 + if (inputFluid) { + if (inputFluid.fluid && inputFluid.amount > 0) { + ingredients.push({ + type: 'fluid_stack', + fluid: inputFluid.fluid, + amount: inputFluid.amount + }); + } else if (inputFluid.tag && inputFluid.amount > 0) { + ingredients.push({ + type: 'fluid_tag', + fluid_tag: inputFluid.tag, + amount: inputFluid.amount + }); + } + } + + // 添加输出物品 + if (outputItem) { + let itemId = outputItem.id || outputItem.item; + if (itemId) { + let singleResult = { id: itemId }; + if (outputItem.count && outputItem.count > 1) { + singleResult.count = outputItem.count; + } + if (outputItem.chance) { + singleResult.chance = outputItem.chance; + } + results.push(singleResult); + } + } + + // 添加输出流体 + if (outputFluid) { + let fluidId = outputFluid.id || outputFluid.fluid; + if (fluidId && outputFluid.amount > 0) { + results.push({ + id: fluidId, + amount: outputFluid.amount + }); + } + } + + let processingTime = Math.max(100, Math.round(sealTime / 5)); + + if (results.length > 0 && ingredients.length > 0) { + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients, + processing_time: processingTime, + results: results + }).id(`kubejs:tfc_barrel_sealed/${recipe.getId().replace(':', '_')}`); + convertedCount++; + } else { + skippedCount++; + } + }); + + console.info(`[生物柴油修复] 完成!共转换 ${convertedCount} 个配方,跳过 ${skippedCount} 个`); +}); diff --git a/server_scripts/test_fermenting_recipes.js.pass b/server_scripts/test_fermenting_recipes.js.pass new file mode 100644 index 0000000..4cf9375 --- /dev/null +++ b/server_scripts/test_fermenting_recipes.js.pass @@ -0,0 +1,96 @@ +// ============================================================================ +// 手动创建TFC密封大桶配方对应的CDG发酵配方(完全按照参考格式) +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[生物柴油修复] 开始手动创建测试配方(完全按照参考格式)...'); + + // 1. black_wool - 黑色羊毛染色 + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: [ + { item: 'minecraft:white_wool' }, + { + type: 'fluid_stack', + fluid: 'tfc:black_dye', + amount: 25 + } + ], + processing_time: Math.max(100, Math.round(1200 / 5)), + results: [ + { id: 'minecraft:black_wool' } + ] + }).id('kubejs:test/black_wool'); + + // 2. corn_whiskey - 玉米威士忌 + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: [ + { + type: 'tfc:and', + children: [ + { item: 'tfc:food/maize_flour' }, + { type: 'tfc:not_rotten' } + ] + }, + { + type: 'fluid_stack', + fluid: 'minecraft:water', + amount: 500 + } + ], + processing_time: Math.max(100, Math.round(72000 / 5)), + results: [ + { + id: 'tfc:corn_whiskey', + amount: 500 + } + ] + }).id('kubejs:test/corn_whiskey'); + + // 3. sugar - 糖 + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: [ + { + type: 'tfc:and', + children: [ + { item: 'tfc:food/sugarcane' }, + { type: 'tfc:not_rotten' } + ] + }, + { + type: 'fluid_stack', + fluid: 'minecraft:water', + amount: 600 + } + ], + processing_time: Math.max(100, Math.round(7200 / 5)), + results: [ + { id: 'minecraft:sugar' } + ] + }).id('kubejs:test/sugar'); + + // 4. firmalife_cream - Firmalife奶油制作(使用流体标签格式) + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: [ + { item: 'firmalife:cheesecloth' }, + { + type: 'fluid_tag', // ✅ 使用fluid_tag类型 + fluid_tag: 'firmalife:milks', + amount: 1000 + } + ], + processing_time: Math.max(100, Math.round(1000 / 5)), + results: [ + { id: 'firmalife:cheesecloth' }, + { + id: 'firmalife:cream', + amount: 1000 + } + ] + }).id('kubejs:test/firmalife_cream'); + + console.info('[生物柴油修复] 手动测试配方(完全按照参考格式)创建完成!'); +}); diff --git a/server_scripts/test_large_leather.js.pass b/server_scripts/test_large_leather.js.pass new file mode 100644 index 0000000..bb313f2 --- /dev/null +++ b/server_scripts/test_large_leather.js.pass @@ -0,0 +1,26 @@ +// ============================================================================ +// 测试large_leather和medium_leather配方转换 +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[测试] 开始测试皮革配方...'); + + // 测试: medium用直接count字段 + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: [ + { item: 'tfc:medium_prepared_hide' }, + { + type: 'fluid_stack', + fluid: 'tfc:tannin', + amount: 500 + } + ], + processing_time: Math.max(100, Math.round(7200 / 5)), + results: [ + { id: 'minecraft:leather', count: 2 } + ] + }).id('kubejs:test/medium_leather_count'); + + console.info('[测试] 皮革配方测试创建完成!'); +}); diff --git a/server_scripts/test_not_rotten.js.pass b/server_scripts/test_not_rotten.js.pass new file mode 100644 index 0000000..a2f676b --- /dev/null +++ b/server_scripts/test_not_rotten.js.pass @@ -0,0 +1,56 @@ +// ============================================================================ +// 测试脚本:非腐败条件限制器在Create配方中的使用 +// 使用Ingredient.of(物品类型, 数量)的方式实现多物品限制 +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[生物柴油修复测试] 开始测试非腐败条件限制器...'); + + // 测试1:橄榄塑形配方(10个新鲜橄榄 → 800mb橄榄油) + event.recipes.create.compacting( + [Fluid.of('tfc:olive_oil', 800)], + [ + Ingredient.of({ + type: 'tfc:and', + children: [ + { item: 'tfc:food/olive' }, + { type: 'tfc:not_rotten' } + ] + }, 10) + ], + 100 + ).id('kubejs:test_olive_to_oil_not_rotten'); + + // 测试2:小麦面粉混合配方(16个新鲜小麦面粉 + 水 → 啤酒) + event.recipes.create.mixing( + [Fluid.of('tfc:beer', 1000)], + [ + Ingredient.of({ + type: 'tfc:and', + children: [ + { item: 'tfc:food/wheat_flour' }, + { type: 'tfc:not_rotten' } + ] + }, 16), + Fluid.of('minecraft:water', 1000) + ], + 100 + ).id('kubejs:test_wheat_flour_to_beer_not_rotten'); + + // 测试3:小麦研磨配方(1个新鲜小麦种子 → 面粉) + event.recipes.create.milling( + ['tfc:food/wheat_flour'], + [ + Ingredient.of({ + type: 'tfc:and', + children: [ + { item: 'tfc:food/wheat_grain' }, + { type: 'tfc:not_rotten' } + ] + }) + ], + 50 + ).id('kubejs:test_wheat_grain_to_flour_not_rotten'); + + console.info('[生物柴油修复测试] 所有配方创建完成!'); +}); diff --git a/server_scripts/test_tfc_modifiers.js.faild b/server_scripts/test_tfc_modifiers.js.faild new file mode 100644 index 0000000..f43f517 --- /dev/null +++ b/server_scripts/test_tfc_modifiers.js.faild @@ -0,0 +1,32 @@ +// ============================================================================ +// 测试TFC修饰符格式是否被CDG支持 +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[生物柴油修复] 开始测试TFC修饰符格式...'); + + // 测试black_dyeable - 带TFC修饰符的输出 + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: [ + { tag: 'minecraft:dyeable' }, + { + type: 'fluid_stack', + fluid: 'tfc:black_dye', + amount: 25 + } + ], + processing_time: Math.max(100, Math.round(1200 / 5)), + results: [ + { + item: 'minecraft:leather', // 试试直接用item字段 + modifiers: [ + { type: 'tfc:copy_input' }, + { type: 'tfc:dye_leather', color: 'black' } + ] + } + ] + }).id('kubejs:test/black_dyeable_with_modifiers'); + + console.info('[生物柴油修复] TFC修饰符格式测试完成!'); +}); From 6bc4d0a48cd6a718f87e5b1c766794efb0f9f998 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Sat, 16 May 2026 14:15:52 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E9=99=A4=E4=BA=86modif?= =?UTF-8?q?iers=20=E7=9A=84=E9=85=8D=E6=96=B9=E5=A4=96=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E9=85=8D=E6=96=B9=E5=B0=BD=E5=8F=AF=E8=83=BD=E5=80=8D=E5=A2=9E?= =?UTF-8?q?=E5=8F=91=E9=85=B5=E9=85=8D=E6=96=B9=EF=BC=8C=E5=80=8D=E5=A2=9E?= =?UTF-8?q?=E5=80=8D=E7=8E=87=E5=B0=8F=E4=BA=8E1=E6=97=B6=E4=BC=9A?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E5=8F=91=E9=85=B5=E9=85=8D=E6=96=B9=E7=94=9F?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biodiesel_fix/fermenting_from_barrel.js | 163 +++++++++++------- .../test_basin_fermenting_schema.js.faild | 67 +++++++ server_scripts/test_maxstack_debug.js.pass | 138 +++++++++++++++ 3 files changed, 301 insertions(+), 67 deletions(-) create mode 100644 server_scripts/test_basin_fermenting_schema.js.faild create mode 100644 server_scripts/test_maxstack_debug.js.pass diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js index 00f4790..4ba1123 100644 --- a/server_scripts/biodiesel_fix/fermenting_from_barrel.js +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -1,16 +1,43 @@ // ============================================================================ // 批量从TFC密封大桶配方创建Create发酵配方 // ============================================================================ +// +// 功能说明: +// - 遍历所有 TFC 密封大桶配方 (tfc:barrel_sealed) +// - 将其转换为 Create Diesel Generators 的 Basin Fermenting 配方 +// - 自动计算配方倍增倍数,实现高吞吐单次发酵 +// +// 核心技术难点与解决方案: +// ---------------------------------------------------------------------------- +// 问题:TFC 的 tfc:not_rotten 条件只能在 TFC 配方系统中解析 +// 当在 Create 配方中使用 { type: 'tfc:and', children: [...] } 结构时, +// 无法通过设置 count 属性实现数量倍增(会导致 JSON 解析错误) +// +// 解决方案:用数组重复代替 count 属性倍增 +// - 对于普通物品:重复 { item: 'xxx' } N 次 +// - 对于带条件的物品:重复 { type: 'tfc:and', children: [...] } N 次 +// - 流体和输出仍使用 amount/count 属性倍增(它们不受此限制) +// ---------------------------------------------------------------------------- +// +// 倍增倍数计算规则: +// 1. 输入物品:maxStack / count +// 2. 输出物品:maxStack / count +// 3. 输入流体:1000 / amount(Basin 流体槽容量) +// 4. 输出流体:1000 / amount +// 取以上最小值作为 maxMultiplier,向下取整后使用 +// ============================================================================ ServerEvents.recipes(event => { console.info('[生物柴油修复] 开始批量转换TFC密封大桶配方为Create发酵配方...'); - let convertedCount = 0; - let skippedCount = 0; + let convertedCount = 0; // 成功转换的配方数 + let skippedCount = 0; // 跳过的配方数 + // 遍历所有 TFC 密封大桶配方 event.forEachRecipe({ type: 'tfc:barrel_sealed' }, recipe => { const json = recipe.json; + // 1. 提取配方的输入输出数据 let inputItem = null; if (json.has('input_item')) { inputItem = JSON.parse(json.get('input_item').toString()); @@ -31,7 +58,11 @@ ServerEvents.recipes(event => { outputFluid = JSON.parse(json.get('output_fluid').toString()); } - // 检查输入物品堆叠数量 + // 2. 计算最大倍增倍数 maxMultiplier + const FLUID_SLOT_LIMIT = 1000; // Basin 流体槽最大容量 + let maxMultiplier = Infinity; // 初始值设为无穷大 + + // 2.1 根据输入物品堆叠限制计算 if (inputItem) { let itemId = inputItem.item || inputItem.tag; if (itemId) { @@ -39,134 +70,128 @@ ServerEvents.recipes(event => { try { let maxStack; if (inputItem.tag) { + // 处理标签类型,取标签中堆叠最小的物品 let tagItems = Ingredient.of(`#${inputItem.tag}`).items; if (tagItems && tagItems.length > 0) { - let minStack = tagItems[0].maxStack; + let minStack = tagItems[0].getMaxStackSize(); for (let i = 1; i < tagItems.length; i++) { - if (tagItems[i].maxStack < minStack) { - minStack = tagItems[i].maxStack; + if (tagItems[i].getMaxStackSize() < minStack) { + minStack = tagItems[i].getMaxStackSize(); } } maxStack = minStack; } } else { - maxStack = Item.of(itemId, 1).items[0].maxStack; + // 处理单个物品 + maxStack = Item.of(itemId, 1).getMaxStackSize(); } - if (maxStack && count > maxStack) { - skippedCount++; - return; + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, maxStack / count); } } catch (e) { - if (count > 64) { - skippedCount++; - return; - } + // 获取失败时使用默认值 64 + maxMultiplier = Math.min(maxMultiplier, 64 / count); } } } - - // 检查输出物品堆叠数量 + + // 2.2 根据输出物品堆叠限制计算 if (outputItem) { let outputId = outputItem.id || outputItem.item; if (outputId) { let count = outputItem.count || 1; try { - let maxStack = Item.of(outputId, 1).items[0].maxStack; - if (maxStack && count > maxStack) { - skippedCount++; - return; + let maxStack = Item.of(outputId, 1).getMaxStackSize(); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, maxStack / count); } } catch (e) { - if (count > 64) { - skippedCount++; - return; - } + maxMultiplier = Math.min(maxMultiplier, 64 / count); } } } - - // 检查流体量 - if (inputFluid && inputFluid.amount > 1000) { - skippedCount++; - return; + + // 2.3 根据输入流体限制计算 + if (inputFluid && inputFluid.amount > 0) { + maxMultiplier = Math.min(maxMultiplier, FLUID_SLOT_LIMIT / inputFluid.amount); + } + + // 2.4 根据输出流体限制计算 + if (outputFluid && outputFluid.amount > 0) { + maxMultiplier = Math.min(maxMultiplier, FLUID_SLOT_LIMIT / outputFluid.amount); } - if (outputFluid && outputFluid.amount > 1000) { + + // 3. 确定最终倍增倍数(向下取整) + let flooredMultiplier = Math.floor(maxMultiplier); + + // 4. 过滤条件检查 + // 4.1 倍数小于1则跳过(无法倍增) + if (flooredMultiplier < 1) { skippedCount++; return; } - // 跳过modifiers + // 4.2 跳过带有 modifiers 的配方(复杂逻辑暂不处理) if (outputItem && outputItem.modifiers) { skippedCount++; return; } + // 5. 构建新配方的 ingredients 和 results let sealTime = json.has('seal_time') ? json.get('seal_time').getAsInt() : 0; let ingredients = []; let results = []; - // 添加输入物品 + // 5.1 添加输入物品(核心:用数组重复实现倍增) if (inputItem) { if (inputItem.type === 'tfc:and' && inputItem.children) { - let count = inputItem.count || 1; - for (let i = 0; i < count; i++) { + // 情况A:原始配方已有 tfc:and 结构(如带 not_rotten 条件的食物) + // 直接重复整个 tfc:and 对象 N 次(保留原始条件) + for (let i = 0; i < flooredMultiplier; i++) { ingredients.push({ type: 'tfc:and', children: inputItem.children }); } } else { - let itemId = inputItem.item || inputItem.tag; - if (itemId && typeof itemId === 'string' && itemId.includes('food/')) { - let count = inputItem.count || 1; - for (let i = 0; i < count; i++) { - ingredients.push({ - type: 'tfc:and', - children: [ - inputItem.item ? { item: inputItem.item } : { tag: inputItem.tag }, - { type: 'tfc:not_rotten' } - ] - }); - } - } else { - let count = inputItem.count || 1; + // 情况B:普通物品(包括食物类但没有显式 not_rotten 条件的) + // 直接重复 N 次,不添加额外条件(尊重原始配方意图) + for (let i = 0; i < flooredMultiplier; i++) { if (inputItem.item) { - for (let i = 0; i < count; i++) { - ingredients.push({ item: inputItem.item }); - } + ingredients.push({ item: inputItem.item }); } else if (inputItem.tag) { - for (let i = 0; i < count; i++) { - ingredients.push({ tag: inputItem.tag }); - } + ingredients.push({ tag: inputItem.tag }); } } } } - // 添加输入流体 + // 5.2 添加输入流体(用 amount 属性倍增) if (inputFluid) { - if (inputFluid.fluid && inputFluid.amount > 0) { + let amount = inputFluid.amount * flooredMultiplier; + if (inputFluid.fluid && amount > 0) { ingredients.push({ type: 'fluid_stack', fluid: inputFluid.fluid, - amount: inputFluid.amount + amount: amount }); - } else if (inputFluid.tag && inputFluid.amount > 0) { + } else if (inputFluid.tag && amount > 0) { ingredients.push({ type: 'fluid_tag', fluid_tag: inputFluid.tag, - amount: inputFluid.amount + amount: amount }); } } - // 添加输出物品 + // 5.3 添加输出物品(用 count 属性倍增) if (outputItem) { let itemId = outputItem.id || outputItem.item; if (itemId) { let singleResult = { id: itemId }; - if (outputItem.count && outputItem.count > 1) { - singleResult.count = outputItem.count; + let outputCount = (outputItem.count || 1) * flooredMultiplier; + if (outputCount > 1) { + singleResult.count = outputCount; } if (outputItem.chance) { singleResult.chance = outputItem.chance; @@ -174,32 +199,36 @@ ServerEvents.recipes(event => { results.push(singleResult); } } - - // 添加输出流体 + + // 5.4 添加输出流体(用 amount 属性倍增) if (outputFluid) { let fluidId = outputFluid.id || outputFluid.fluid; if (fluidId && outputFluid.amount > 0) { results.push({ id: fluidId, - amount: outputFluid.amount + amount: outputFluid.amount * flooredMultiplier }); } } + // 6. 计算处理时间(转换 TFC 时间单位到 Create 时间单位) let processingTime = Math.max(100, Math.round(sealTime / 5)); - + let multStr = flooredMultiplier.toString(); + + // 7. 创建并注册新配方 if (results.length > 0 && ingredients.length > 0) { event.custom({ type: 'createdieselgenerators:basin_fermenting', ingredients: ingredients, processing_time: processingTime, results: results - }).id(`kubejs:tfc_barrel_sealed/${recipe.getId().replace(':', '_')}`); + }).id(`kubejs:tfc_barrel_sealed/${multStr}_${recipe.getId().replace(':', '_')}`); convertedCount++; } else { skippedCount++; } }); + // 输出统计信息 console.info(`[生物柴油修复] 完成!共转换 ${convertedCount} 个配方,跳过 ${skippedCount} 个`); }); diff --git a/server_scripts/test_basin_fermenting_schema.js.faild b/server_scripts/test_basin_fermenting_schema.js.faild new file mode 100644 index 0000000..65eebab --- /dev/null +++ b/server_scripts/test_basin_fermenting_schema.js.faild @@ -0,0 +1,67 @@ +// ============================================================================ +// 测试脚本:使用 basin_fermenting 配方 schema +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[DEBUG] 开始测试 basin_fermenting 配方 schema...'); + + // 测试物品 + let testItemId = 'tfc:food/barley_flour'; + + // 获取堆叠限制 + let actualMaxStack = 64; + try { + actualMaxStack = Item.of(testItemId, 1).getMaxStackSize(); + console.info(`[DEBUG] 获取到 ${testItemId} 的堆叠限制 = ${actualMaxStack}`); + } catch (e) { + console.info(`[DEBUG] 获取堆叠限制失败: ${e.message},使用默认值 64`); + } + + let FLUID_SLOT_LIMIT = 1000; + let maxMultiplier = Infinity; + + // 输入物品: barley_flour, count = 1 + let itemCount = 1; + let itemMultiplier = actualMaxStack / itemCount; + maxMultiplier = Math.min(maxMultiplier, itemMultiplier); + console.info('[DEBUG] 输入物品: ' + testItemId + ', count=' + itemCount + ', maxStack=' + actualMaxStack + ', multiplier=' + itemMultiplier.toFixed(2)); + + // 输入流体: water, amount = 500 + let inputFluidAmount = 500; + let inputFluidMultiplier = FLUID_SLOT_LIMIT / inputFluidAmount; + maxMultiplier = Math.min(maxMultiplier, inputFluidMultiplier); + console.info('[DEBUG] 输入流体: minecraft:water, amount=' + inputFluidAmount + ', multiplier=' + inputFluidMultiplier.toFixed(2)); + + // 输出流体: beer, amount = 500 + let outputFluidAmount = 500; + let outputFluidMultiplier = FLUID_SLOT_LIMIT / outputFluidAmount; + maxMultiplier = Math.min(maxMultiplier, outputFluidMultiplier); + console.info('[DEBUG] 输出流体: tfc:beer, amount=' + outputFluidAmount + ', multiplier=' + outputFluidMultiplier.toFixed(2)); + + let flooredMultiplier = Math.floor(maxMultiplier); + console.info('[DEBUG] 向下取整 flooredMultiplier = ' + flooredMultiplier); + + // 创建测试配方 - 使用新的配方 schema + if (flooredMultiplier >= 1) { + console.info('[DEBUG] 创建测试配方...'); + + let inputItemCount = 1 * flooredMultiplier; + let finalInputFluidAmount = 500 * flooredMultiplier; + let finalOutputFluidAmount = 500 * flooredMultiplier; + + event.recipes.createdieselgenerators.basinFermenting([ + Ingredient.of({ + type: 'tfc:and', + children: [ + { item: testItemId }, + { type: 'tfc:not_rotten' } + ] + }, inputItemCount), + Fluid.of('minecraft:water', finalInputFluidAmount) + ], [ + Fluid.of('tfc:beer', finalOutputFluidAmount) + ]).id('kubejs:test_fermenting/beer/' + flooredMultiplier + '_from_barley_flour'); + + console.info('[DEBUG] 成功创建配方: kubejs:test_fermenting/beer/' + flooredMultiplier + '_from_barley_flour'); + } +}); diff --git a/server_scripts/test_maxstack_debug.js.pass b/server_scripts/test_maxstack_debug.js.pass new file mode 100644 index 0000000..823eda1 --- /dev/null +++ b/server_scripts/test_maxstack_debug.js.pass @@ -0,0 +1,138 @@ +// ============================================================================ +// 调试脚本:测试获取 tfc:food/barley_flour 的最大堆叠数量 +// ============================================================================ +// 以下注释内容将辅助正式脚本修改过程,不允许删除 +// 重要发现: +// 1. maxMultiplier 初始值问题: +// - 错误:let maxMultiplier = 1.0; +// - 正确:let maxMultiplier = Infinity; +// - 原因:使用 Math.min() 取最小值时,初始值必须大于所有可能的乘数 +// - 示例:若乘数为 64, 2, 2,初始值为 1 会导致结果始终为 1 +// +// 2. 获取堆叠限制的方法: +// - Item.of().getMaxStackSize() 实际上能返回正确的值(包括 TFC 的 Weight 组件影响) +// - 测试结果:barley_flour 返回 32,符合预期 +// +// 3. 新发现 (2026-05-16): +// - event.recipes.createdieselgenerators.basinFermenting() 路线失败 +// - 直接使用 event.custom() 配合 { type: 'tfc:and', children: [...] } 结构成功 +// - 关键:用数组重复代替数量倍增 +// 例如 flooredMultiplier = 2 时,把 { type: 'tfc:and', children: [...] } 重复2次 +// ============================================================================ + +ServerEvents.recipes(event => { + console.info('[DEBUG] ============================================'); + console.info('[DEBUG] 测试配方1: TFC酿酒 (barley_flour + water -> beer)'); + console.info('[DEBUG] ============================================'); + + let testItemId1 = 'tfc:food/barley_flour'; + let inputFluidId1 = 'minecraft:water'; + let outputFluidId1 = 'tfc:beer'; + let inputFluidAmount1 = 500; + let outputFluidAmount1 = 500; + let inputItemCount1 = 1; + + let actualMaxStack1 = Item.of(testItemId1, 1).getMaxStackSize(); + console.info(`[DEBUG] ${testItemId1} 堆叠限制 = ${actualMaxStack1}`); + + let FLUID_SLOT_LIMIT = 1000; + let maxMultiplier1 = Infinity; + let itemMultiplier1 = actualMaxStack1 / inputItemCount1; + let fluidMultiplier1 = FLUID_SLOT_LIMIT / inputFluidAmount1; + let outputFluidMultiplier1 = FLUID_SLOT_LIMIT / outputFluidAmount1; + maxMultiplier1 = Math.min(maxMultiplier1, itemMultiplier1, fluidMultiplier1, outputFluidMultiplier1); + + let flooredMultiplier1 = Math.floor(maxMultiplier1); + console.info(`[DEBUG] maxMultiplier=${maxMultiplier1.toFixed(2)}, flooredMultiplier=${flooredMultiplier1}`); + + if (flooredMultiplier1 >= 1) { + let ingredients1 = []; + let results1 = []; + + // 用数组重复实现物品倍增 + for (let i = 0; i < flooredMultiplier1; i++) { + ingredients1.push({ + type: 'tfc:and', + children: [ + { item: testItemId1 }, + { type: 'tfc:not_rotten' } + ] + }); + } + + // 流体倍增用 amount + ingredients1.push({ + type: 'fluid_stack', + fluid: inputFluidId1, + amount: inputFluidAmount1 * flooredMultiplier1 + }); + + // 输出流体 + results1.push({ + id: outputFluidId1, + amount: outputFluidAmount1 * flooredMultiplier1 + }); + + console.info(`[DEBUG] 创建配方1: ${flooredMultiplier1}x ${testItemId1} + ${inputFluidAmount1 * flooredMultiplier1}mB water -> ${outputFluidAmount1 * flooredMultiplier1}mB beer`); + + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients1, + processing_time: 400, + results: results1 + }).id(`kubejs:test_fermenting/barley_flour_x${flooredMultiplier1}`); + } + + console.info('[DEBUG] ============================================'); + console.info('[DEBUG] 测试配方2: black_wool (white_wool + black_dye -> black_wool)'); + console.info('[DEBUG] ============================================'); + + let testItemId2 = 'minecraft:white_wool'; + let inputFluidId2 = 'tfc:black_dye'; + let outputItemId2 = 'minecraft:black_wool'; + let inputFluidAmount2 = 25; + let inputItemCount2 = 1; + + let actualMaxStack2 = Item.of(testItemId2, 1).getMaxStackSize(); + console.info(`[DEBUG] ${testItemId2} 堆叠限制 = ${actualMaxStack2}`); + + let maxMultiplier2 = Infinity; + let itemMultiplier2 = actualMaxStack2 / inputItemCount2; + let fluidMultiplier2 = FLUID_SLOT_LIMIT / inputFluidAmount2; + maxMultiplier2 = Math.min(maxMultiplier2, itemMultiplier2, fluidMultiplier2); + + let flooredMultiplier2 = Math.floor(maxMultiplier2); + console.info(`[DEBUG] maxMultiplier=${maxMultiplier2.toFixed(2)}, flooredMultiplier=${flooredMultiplier2}`); + + if (flooredMultiplier2 >= 1) { + let ingredients2 = []; + let results2 = []; + + // 用数组重复实现物品倍增 + for (let i = 0; i < flooredMultiplier2; i++) { + ingredients2.push({ item: testItemId2 }); + } + + // 流体倍增用 amount + ingredients2.push({ + type: 'fluid_stack', + fluid: inputFluidId2, + amount: inputFluidAmount2 * flooredMultiplier2 + }); + + // 输出物品 + results2.push({ + id: outputItemId2, + count: flooredMultiplier2 + }); + + console.info(`[DEBUG] 创建配方2: ${flooredMultiplier2}x ${testItemId2} + ${inputFluidAmount2 * flooredMultiplier2}mB ${inputFluidId2} -> ${flooredMultiplier2}x ${outputItemId2}`); + + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients2, + processing_time: 100, + results: results2 + }).id(`kubejs:test_fermenting/wool_x${flooredMultiplier2}`); + } +}); From 0ec1f0cd4f02df8a8964c73a32f28a36e71260d3 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Sun, 17 May 2026 23:17:59 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E5=87=86=E5=A4=87=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=E5=88=B0=E4=BA=91=E6=9C=8D=E5=8A=A1=E5=99=A8=E4=B8=8A=E5=BC=80?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biodiesel_fix/fermenting_from_barrel.js | 234 --------- .../fermenting_from_barrel.js.disable | 424 +++++++++++++++++ .../biodiesel_fix/fermenting_test.js | 443 ++++++++++++++++++ 3 files changed, 867 insertions(+), 234 deletions(-) delete mode 100644 server_scripts/biodiesel_fix/fermenting_from_barrel.js create mode 100644 server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable create mode 100644 server_scripts/biodiesel_fix/fermenting_test.js diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js deleted file mode 100644 index 4ba1123..0000000 --- a/server_scripts/biodiesel_fix/fermenting_from_barrel.js +++ /dev/null @@ -1,234 +0,0 @@ -// ============================================================================ -// 批量从TFC密封大桶配方创建Create发酵配方 -// ============================================================================ -// -// 功能说明: -// - 遍历所有 TFC 密封大桶配方 (tfc:barrel_sealed) -// - 将其转换为 Create Diesel Generators 的 Basin Fermenting 配方 -// - 自动计算配方倍增倍数,实现高吞吐单次发酵 -// -// 核心技术难点与解决方案: -// ---------------------------------------------------------------------------- -// 问题:TFC 的 tfc:not_rotten 条件只能在 TFC 配方系统中解析 -// 当在 Create 配方中使用 { type: 'tfc:and', children: [...] } 结构时, -// 无法通过设置 count 属性实现数量倍增(会导致 JSON 解析错误) -// -// 解决方案:用数组重复代替 count 属性倍增 -// - 对于普通物品:重复 { item: 'xxx' } N 次 -// - 对于带条件的物品:重复 { type: 'tfc:and', children: [...] } N 次 -// - 流体和输出仍使用 amount/count 属性倍增(它们不受此限制) -// ---------------------------------------------------------------------------- -// -// 倍增倍数计算规则: -// 1. 输入物品:maxStack / count -// 2. 输出物品:maxStack / count -// 3. 输入流体:1000 / amount(Basin 流体槽容量) -// 4. 输出流体:1000 / amount -// 取以上最小值作为 maxMultiplier,向下取整后使用 -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[生物柴油修复] 开始批量转换TFC密封大桶配方为Create发酵配方...'); - - let convertedCount = 0; // 成功转换的配方数 - let skippedCount = 0; // 跳过的配方数 - - // 遍历所有 TFC 密封大桶配方 - event.forEachRecipe({ type: 'tfc:barrel_sealed' }, recipe => { - const json = recipe.json; - - // 1. 提取配方的输入输出数据 - let inputItem = null; - if (json.has('input_item')) { - inputItem = JSON.parse(json.get('input_item').toString()); - } - - let inputFluid = null; - if (json.has('input_fluid')) { - inputFluid = JSON.parse(json.get('input_fluid').toString()); - } - - let outputItem = null; - if (json.has('output_item')) { - outputItem = JSON.parse(json.get('output_item').toString()); - } - - let outputFluid = null; - if (json.has('output_fluid')) { - outputFluid = JSON.parse(json.get('output_fluid').toString()); - } - - // 2. 计算最大倍增倍数 maxMultiplier - const FLUID_SLOT_LIMIT = 1000; // Basin 流体槽最大容量 - let maxMultiplier = Infinity; // 初始值设为无穷大 - - // 2.1 根据输入物品堆叠限制计算 - if (inputItem) { - let itemId = inputItem.item || inputItem.tag; - if (itemId) { - let count = inputItem.count || 1; - try { - let maxStack; - if (inputItem.tag) { - // 处理标签类型,取标签中堆叠最小的物品 - let tagItems = Ingredient.of(`#${inputItem.tag}`).items; - if (tagItems && tagItems.length > 0) { - let minStack = tagItems[0].getMaxStackSize(); - for (let i = 1; i < tagItems.length; i++) { - if (tagItems[i].getMaxStackSize() < minStack) { - minStack = tagItems[i].getMaxStackSize(); - } - } - maxStack = minStack; - } - } else { - // 处理单个物品 - maxStack = Item.of(itemId, 1).getMaxStackSize(); - } - if (maxStack) { - maxMultiplier = Math.min(maxMultiplier, maxStack / count); - } - } catch (e) { - // 获取失败时使用默认值 64 - maxMultiplier = Math.min(maxMultiplier, 64 / count); - } - } - } - - // 2.2 根据输出物品堆叠限制计算 - if (outputItem) { - let outputId = outputItem.id || outputItem.item; - if (outputId) { - let count = outputItem.count || 1; - try { - let maxStack = Item.of(outputId, 1).getMaxStackSize(); - if (maxStack) { - maxMultiplier = Math.min(maxMultiplier, maxStack / count); - } - } catch (e) { - maxMultiplier = Math.min(maxMultiplier, 64 / count); - } - } - } - - // 2.3 根据输入流体限制计算 - if (inputFluid && inputFluid.amount > 0) { - maxMultiplier = Math.min(maxMultiplier, FLUID_SLOT_LIMIT / inputFluid.amount); - } - - // 2.4 根据输出流体限制计算 - if (outputFluid && outputFluid.amount > 0) { - maxMultiplier = Math.min(maxMultiplier, FLUID_SLOT_LIMIT / outputFluid.amount); - } - - // 3. 确定最终倍增倍数(向下取整) - let flooredMultiplier = Math.floor(maxMultiplier); - - // 4. 过滤条件检查 - // 4.1 倍数小于1则跳过(无法倍增) - if (flooredMultiplier < 1) { - skippedCount++; - return; - } - - // 4.2 跳过带有 modifiers 的配方(复杂逻辑暂不处理) - if (outputItem && outputItem.modifiers) { - skippedCount++; - return; - } - - // 5. 构建新配方的 ingredients 和 results - let sealTime = json.has('seal_time') ? json.get('seal_time').getAsInt() : 0; - let ingredients = []; - let results = []; - - // 5.1 添加输入物品(核心:用数组重复实现倍增) - if (inputItem) { - if (inputItem.type === 'tfc:and' && inputItem.children) { - // 情况A:原始配方已有 tfc:and 结构(如带 not_rotten 条件的食物) - // 直接重复整个 tfc:and 对象 N 次(保留原始条件) - for (let i = 0; i < flooredMultiplier; i++) { - ingredients.push({ - type: 'tfc:and', - children: inputItem.children - }); - } - } else { - // 情况B:普通物品(包括食物类但没有显式 not_rotten 条件的) - // 直接重复 N 次,不添加额外条件(尊重原始配方意图) - for (let i = 0; i < flooredMultiplier; i++) { - if (inputItem.item) { - ingredients.push({ item: inputItem.item }); - } else if (inputItem.tag) { - ingredients.push({ tag: inputItem.tag }); - } - } - } - } - - // 5.2 添加输入流体(用 amount 属性倍增) - if (inputFluid) { - let amount = inputFluid.amount * flooredMultiplier; - if (inputFluid.fluid && amount > 0) { - ingredients.push({ - type: 'fluid_stack', - fluid: inputFluid.fluid, - amount: amount - }); - } else if (inputFluid.tag && amount > 0) { - ingredients.push({ - type: 'fluid_tag', - fluid_tag: inputFluid.tag, - amount: amount - }); - } - } - - // 5.3 添加输出物品(用 count 属性倍增) - if (outputItem) { - let itemId = outputItem.id || outputItem.item; - if (itemId) { - let singleResult = { id: itemId }; - let outputCount = (outputItem.count || 1) * flooredMultiplier; - if (outputCount > 1) { - singleResult.count = outputCount; - } - if (outputItem.chance) { - singleResult.chance = outputItem.chance; - } - results.push(singleResult); - } - } - - // 5.4 添加输出流体(用 amount 属性倍增) - if (outputFluid) { - let fluidId = outputFluid.id || outputFluid.fluid; - if (fluidId && outputFluid.amount > 0) { - results.push({ - id: fluidId, - amount: outputFluid.amount * flooredMultiplier - }); - } - } - - // 6. 计算处理时间(转换 TFC 时间单位到 Create 时间单位) - let processingTime = Math.max(100, Math.round(sealTime / 5)); - let multStr = flooredMultiplier.toString(); - - // 7. 创建并注册新配方 - if (results.length > 0 && ingredients.length > 0) { - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients, - processing_time: processingTime, - results: results - }).id(`kubejs:tfc_barrel_sealed/${multStr}_${recipe.getId().replace(':', '_')}`); - convertedCount++; - } else { - skippedCount++; - } - }); - - // 输出统计信息 - console.info(`[生物柴油修复] 完成!共转换 ${convertedCount} 个配方,跳过 ${skippedCount} 个`); -}); diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable b/server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable new file mode 100644 index 0000000..d344627 --- /dev/null +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable @@ -0,0 +1,424 @@ +// ============================================================================ +// 批量从TFC密封大桶配方创建Create发酵配方(策略模式重构版) +// ============================================================================ +// +// 策略模式实现: +// 1. 分析配方属性,添加策略标记(strategy type) +// 2. 注册不同策略的处理函数 +// 3. 执行时根据标记自动选择并执行对应策略 +// ============================================================================ + +// ============================================================================ +// 策略注册表 +// ============================================================================ +var recipeStrategies = {}; + +// 注册策略 +function registerStrategy(name, condition, handler) { + recipeStrategies[name] = { + condition: condition, + handler: handler + }; +} + +// ============================================================================ +// 数据结构定义 +// ============================================================================ + +// 配方转换器数据 +function createConverterData(event) { + return { + event: event, + stats: { + basin: 0, + bulk: 0, + skipped: 0 + }, + FLUID_SLOT_LIMIT: 1000 + }; +} + +// 配方数据对象(添加策略标记) +function createRecipeData(json, data, recipe) { + var result = { + inputItem: null, + inputFluid: null, + outputItem: null, + outputFluid: null, + sealTime: 0, + maxMultiplier: Infinity, + flooredMultiplier: 0, + recipeId: recipe ? recipe.getId() : null, // 添加配方ID + bulkMultiplier: 0 // bulk 倍率标记 + }; + + // 提取数据 + result.inputItem = parseJsonField(json, 'input_item'); + result.inputFluid = parseJsonField(json, 'input_fluid'); + result.outputItem = parseJsonField(json, 'output_item'); + result.outputFluid = parseJsonField(json, 'output_fluid'); + // 支持 seal_time 和 duration 两种字段名 + if (json.has('seal_time')) { + result.sealTime = json.get('seal_time').getAsInt(); + } else if (json.has('duration')) { + result.sealTime = json.get('duration').getAsInt(); + } else { + result.sealTime = 0; + } + + return result; +} + +// ============================================================================ +// 工具函数 +// ============================================================================ + +// 解析 JSON 字段 +function parseJsonField(json, fieldName) { + if (json.has(fieldName)) { + try { + return JSON.parse(json.get(fieldName).toString()); + } catch (e) { + return null; + } + } + return null; +} + +// 获取物品最大堆叠数 +function getMaxStackSize(itemData) { + var itemId = itemData.item || itemData.tag; + if (!itemId) return null; + + try { + if (itemData.tag) { + var tagItems = Ingredient.of('#' + itemData.tag).items; + if (tagItems && tagItems.length > 0) { + var minStack = tagItems[0].getMaxStackSize(); + for (var i = 1; i < tagItems.length; i++) { + if (tagItems[i].getMaxStackSize() < minStack) { + minStack = tagItems[i].getMaxStackSize(); + } + } + return minStack; + } + } else { + return Item.of(itemId, 1).getMaxStackSize(); + } + } catch (e) { + return 64; + } + return null; +} + +// 计算最大倍增倍数 +function calculateMaxMultiplier(recipeData, data) { + var maxMultiplier = Infinity; + + if (recipeData.inputItem) { + var itemId = recipeData.inputItem.item || recipeData.inputItem.tag; + if (itemId) { + var count = recipeData.inputItem.count || 1; + var maxStack = getMaxStackSize(recipeData.inputItem); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, maxStack / count); + } + } + } + + if (recipeData.outputItem) { + var outputId = recipeData.outputItem.id || recipeData.outputItem.item; + if (outputId) { + var count = recipeData.outputItem.count || 1; + try { + var maxStack = Item.of(outputId, 1).getMaxStackSize(); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, maxStack / count); + } + } catch (e) { + maxMultiplier = Math.min(maxMultiplier, 64 / count); + } + } + } + + if (recipeData.inputFluid && recipeData.inputFluid.amount > 0) { + maxMultiplier = Math.min(maxMultiplier, data.FLUID_SLOT_LIMIT / recipeData.inputFluid.amount); + } + + if (recipeData.outputFluid && recipeData.outputFluid.amount > 0) { + maxMultiplier = Math.min(maxMultiplier, data.FLUID_SLOT_LIMIT / recipeData.outputFluid.amount); + } + + return maxMultiplier; +} + +// 构建 ingredients +function buildIngredients(inputItem, inputFluid, multiplier) { + var ingredients = []; + + if (inputItem) { + if (inputItem.type === 'tfc:and' && inputItem.children) { + for (var i = 0; i < multiplier; i++) { + ingredients.push({ + type: 'tfc:and', + children: inputItem.children + }); + } + } else { + for (var i = 0; i < multiplier; i++) { + if (inputItem.item) { + ingredients.push({ item: inputItem.item }); + } else if (inputItem.tag) { + ingredients.push({ tag: inputItem.tag }); + } + } + } + } + + if (inputFluid) { + var amount = inputFluid.amount * multiplier; + if (inputFluid.fluid && amount > 0) { + ingredients.push({ + type: 'fluid_stack', + fluid: inputFluid.fluid, + amount: amount + }); + } else if (inputFluid.tag && amount > 0) { + ingredients.push({ + type: 'fluid_tag', + fluid_tag: inputFluid.tag, + amount: amount + }); + } + } + + return ingredients; +} + +// 构建 results +function buildResults(outputItem, outputFluid, multiplier) { + var results = []; + + if (outputItem) { + var itemId = outputItem.id || outputItem.item; + if (itemId) { + var singleResult = { id: itemId }; + var outputCount = (outputItem.count || 1) * multiplier; + if (outputCount > 1) { + singleResult.count = outputCount; + } + if (outputItem.chance) { + singleResult.chance = outputItem.chance; + } + results.push(singleResult); + } + } + + if (outputFluid) { + var fluidId = outputFluid.id || outputFluid.fluid; + if (fluidId && outputFluid.amount > 0) { + results.push({ + id: fluidId, + amount: outputFluid.amount * multiplier + }); + } + } + + return results; +} + +// ============================================================================ +// 策略:配方分析(添加标记) +// ============================================================================ + +// 策略1:检查原配方输入物品数,计算 bulk 倍率 +registerStrategy('bulk_multiplier_check', function(recipeData) { + // 计算原配方输入物品数 + var originalItemCount = 0; + if (recipeData.inputItem) { + originalItemCount = 1; + } + + // 计算 bulk 倍率:floor(9 / 原物品数) + var bulkMultiplier = Math.floor(9 / originalItemCount); + + // 将倍率存储到 recipeData 中(作为标记) + recipeData.bulkMultiplier = bulkMultiplier; + + // 如果倍率 > 0,则 bulk_fermenting 可用 + return bulkMultiplier > 0; +}, function(data, recipe, recipeData) { + // 这个策略只是添加标记,不做实际处理 + return false; // 继续后续策略 +}); + +// 策略2:检查特殊配方(如 mortar,输出过多需要限制倍率) +registerStrategy('bulk_special_recipe', function(recipeData) { + // 直接判断配方ID + if (recipeData.recipeId === 'tfc:barrel/mortar') { + recipeData.bulkMultiplier = 6; // 特殊倍率 + return true; + } + return false; +}, function(data, recipe, recipeData) { + // 标记已添加,不做实际处理 + return false; +}); + +// 策略2.1:检查陈酿酒配方(输出流体以 tfcagedalcohol:aged 开头) +registerStrategy('bulk_aged_alcohol', function(recipeData) { + // 检查输出流体ID是否以 tfcagedalcohol:aged 开头 + var fluidId = null; + if (recipeData.outputFluid) { + fluidId = recipeData.outputFluid.id || recipeData.outputFluid.fluid; + } + if (fluidId && fluidId.indexOf('tfcagedalcohol:aged') === 0) { + recipeData.bulkMultiplier = 3.6; // 陈酿酒倍率 + return true; + } + return false; +}, function(data, recipe, recipeData) { + // 标记已添加,不做实际处理 + return false; +}); + +// 策略3:检查是否需要跳过(带modifiers的配方) +registerStrategy('skip_modifiers', function(recipeData) { + return recipeData.outputItem && recipeData.outputItem.modifiers; +}, function(data, recipe, recipeData) { + data.stats.skipped++; + return true; // 已处理,不再执行后续策略 +}); + +// 策略4:Basin Fermenting(倍数 >= 1) +registerStrategy('basin_fermenting', function(recipeData) { + return recipeData.flooredMultiplier >= 1; +}, function(data, recipe, recipeData) { + var multiplier = recipeData.flooredMultiplier; + var ingredients = buildIngredients(recipeData.inputItem, recipeData.inputFluid, multiplier); + var results = buildResults(recipeData.outputItem, recipeData.outputFluid, multiplier); + + if (results.length === 0 || ingredients.length === 0) { + return false; + } + + var processingTime = Math.max(100, Math.round(recipeData.sealTime / 5)); + var multStr = multiplier.toString(); + + data.event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients, + processing_time: processingTime, + results: results + }).id('kubejs:tfc_barrel_sealed/basin/' + multStr + '_' + recipe.getId().replace(':', '_')); + + data.stats.basin++; + return true; +}); + +// 策略5:Bulk Fermenting(使用 bulkMultiplier 标记) +registerStrategy('bulk_fermenting', function(recipeData) { + // 检查是否有 bulkMultiplier 标记且大于0 + return recipeData.bulkMultiplier && recipeData.bulkMultiplier > 0; +}, function(data, recipe, recipeData) { + // 使用标记的倍率(可能是特殊的6,也可能是计算的倍率) + var multiplier = recipeData.bulkMultiplier; + + var ingredients = buildIngredients(recipeData.inputItem, recipeData.inputFluid, multiplier); + var results = buildResults(recipeData.outputItem, recipeData.outputFluid, multiplier); + + if (results.length === 0 || ingredients.length === 0) { + return false; + } + + var processingTime = Math.max(100, Math.round(recipeData.sealTime / 4)); + var multStr = multiplier.toString(); + + data.event.custom({ + type: 'createdieselgenerators:bulk_fermenting', + ingredients: ingredients, + processing_time: processingTime, + results: results + }).id('kubejs:tfc_barrel_sealed/bulk/' + multStr + '_' + recipe.getId().replace(':', '_')); + + data.stats.bulk++; + return true; +}); + +// ============================================================================ +// 主流程 +// ============================================================================ + +// 分析配方并添加策略标记 +function analyzeRecipe(recipeData, data) { + // 计算倍数 + recipeData.maxMultiplier = calculateMaxMultiplier(recipeData, data); + recipeData.flooredMultiplier = Math.floor(recipeData.maxMultiplier); + + // 根据条件收集适用的策略 + recipeData.strategies = []; + for (var strategyName in recipeStrategies) { + if (recipeStrategies.hasOwnProperty(strategyName)) { + var strategy = recipeStrategies[strategyName]; + if (strategy.condition(recipeData)) { + recipeData.strategies.push(strategyName); + } + } + } +} + +// 执行配方的所有策略 +function executeStrategies(data, recipe, recipeData) { + for (var i = 0; i < recipeData.strategies.length; i++) { + var strategyName = recipeData.strategies[i]; + var strategy = recipeStrategies[strategyName]; + if (strategy) { + var result = strategy.handler(data, recipe, recipeData); + if (result === true) { + // 策略已处理,可以选择继续或中断 + // 这里可以根据需要决定是否继续 + } + } + } +} + +// 转换单个配方 +function convertSingleRecipe(data, recipe) { + var json = recipe.json; + + // 创建配方数据对象 + var recipeData = createRecipeData(json, data, recipe); + + // 过滤:跳过带modifiers的配方(快速检查) + if (recipeData.outputItem && recipeData.outputItem.modifiers) { + data.stats.skipped++; + return; + } + + // 分析配方,添加策略标记 + analyzeRecipe(recipeData, data); + + // 执行所有适用的策略 + executeStrategies(data, recipe, recipeData); +} + +// 批量转换 +function convertAllRecipes(data) { + console.info('[生物柴油修复] 开始批量转换TFC密封大桶配方...'); + + data.event.forEachRecipe({ type: 'tfc:barrel_sealed' }, function(recipe) { + convertSingleRecipe(data, recipe); + }); + + console.info('[生物柴油修复] 完成!Basin: ' + data.stats.basin + + ', Bulk: ' + data.stats.bulk + + ', 跳过: ' + data.stats.skipped); +} + +// ============================================================================ +// 执行 +// ============================================================================ +ServerEvents.recipes(function(event) { + var data = createConverterData(event); + convertAllRecipes(data); +}); diff --git a/server_scripts/biodiesel_fix/fermenting_test.js b/server_scripts/biodiesel_fix/fermenting_test.js new file mode 100644 index 0000000..9fbc95f --- /dev/null +++ b/server_scripts/biodiesel_fix/fermenting_test.js @@ -0,0 +1,443 @@ +// ============================================================================ +// 测试脚本:真正创建配方,测试完整方案 +// ============================================================================ + +ServerEvents.recipes(function(event) { + console.info('[测试] 开始测试4个示例配方(真正创建配方)...'); + + var stats = { basin: 0, bulk: 0, skipped: 0 }; + var FLUID_SLOT_LIMIT = 1000; + + // ============================================================================ + // 工具函数 + // ============================================================================ + + // 计算 basin 倍率:受限的物品堆叠数和流体<1000的同步物体与流体倍率 + function calculateBasinMultiplier(inputItem, inputFluid, outputItem, outputFluid) { + var maxMult = Infinity; + + // 输入物品堆叠限制 + if (inputItem) { + var itemCount = inputItem.count || 1; + var itemId = inputItem.item || inputItem.tag; + if (itemId) { + try { + var maxStack = 64; // 默认值 + if (inputItem.tag) { + var items = Ingredient.of('#' + inputItem.tag).items; + if (items && items.length > 0) { + maxStack = items[0].getMaxStackSize(); + } + } else { + maxStack = Item.of(itemId, 1).getMaxStackSize(); + } + maxMult = Math.min(maxMult, maxStack / itemCount); + } catch (e) { + maxMult = Math.min(maxMult, 64 / itemCount); + } + } + } + + // 输出物品堆叠限制 + if (outputItem) { + var itemCount = outputItem.count || 1; + var itemId = outputItem.id || outputItem.item; + if (itemId) { + try { + var maxStack = Item.of(itemId, 1).getMaxStackSize(); + maxMult = Math.min(maxMult, maxStack / itemCount); + } catch (e) { + maxMult = Math.min(maxMult, 64 / itemCount); + } + } + } + + // 输入流体限制(必须 < 1000) + if (inputFluid && inputFluid.amount > 0) { + maxMult = Math.min(maxMult, 1000 / inputFluid.amount); + } + + // 输出流体限制(必须 < 1000) + if (outputFluid && outputFluid.amount > 0) { + maxMult = Math.min(maxMult, 1000 / outputFluid.amount); + } + + return Math.floor(maxMult); + } + + function buildBasinIngredients(inputItem, inputFluid, multiplier) { + var ingredients = []; + + if (inputItem && multiplier > 0) { + for (var i = 0; i < multiplier; i++) { + if (inputItem.item) { + ingredients.push({ item: inputItem.item }); + } else if (inputItem.tag) { + ingredients.push({ tag: inputItem.tag }); + } + } + } + + if (inputFluid && multiplier > 0) { + var fluidAmount = inputFluid.amount * multiplier; + if (fluidAmount > 0) { + if (inputFluid.fluid) { + ingredients.push({ + type: 'fluid_stack', + fluid: inputFluid.fluid, + amount: fluidAmount + }); + } else if (inputFluid.tag) { + ingredients.push({ + type: 'fluid_tag', + fluid_tag: inputFluid.tag, + amount: fluidAmount + }); + } + } + } + + return ingredients; + } + + function buildBasinResults(outputItem, outputFluid, multiplier) { + var results = []; + + if (outputItem && multiplier > 0) { + var itemId = outputItem.id || outputItem.item; + if (itemId) { + var singleResult = { id: itemId }; + var outputCount = (outputItem.count || 1) * multiplier; + if (outputCount > 1) { + singleResult.count = outputCount; + } + results.push(singleResult); + } + } + + if (outputFluid && outputFluid.amount > 0 && multiplier > 0) { + var fluidId = outputFluid.id || outputFluid.fluid; + if (fluidId) { + var fluidAmount = outputFluid.amount * multiplier; + if (fluidAmount > 0) { + results.push({ + id: fluidId, + amount: fluidAmount + }); + } + } + } + + return results; + } + + function buildBulkIngredients(inputItem, inputFluid, bulkParams) { + var ingredients = []; + + if (inputItem) { + var itemMult = bulkParams.itemMultiplier; + for (var i = 0; i < itemMult; i++) { + if (inputItem.item) { + ingredients.push({ item: inputItem.item }); + } else if (inputItem.tag) { + ingredients.push({ tag: inputItem.tag }); + } + } + } + + if (inputFluid) { + var fluidAmount = inputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; + if (fluidAmount > 0) { + if (inputFluid.fluid) { + ingredients.push({ + type: 'fluid_stack', + fluid: inputFluid.fluid, + amount: fluidAmount + }); + } else if (inputFluid.tag) { + ingredients.push({ + type: 'fluid_tag', + fluid_tag: inputFluid.tag, + amount: fluidAmount + }); + } + } + } + + return ingredients; + } + + function buildBulkResults(outputItem, outputFluid, bulkParams) { + var results = []; + + if (outputItem) { + var itemId = outputItem.id || outputItem.item; + if (itemId) { + var singleResult = { id: itemId }; + var outputCount = (outputItem.count || 1) * bulkParams.itemMultiplier; + if (outputCount > 1) { + singleResult.count = outputCount; + } + results.push(singleResult); + } + } + + if (outputFluid && outputFluid.amount >= 0) { + var fluidId = outputFluid.id || outputFluid.fluid; + if (fluidId) { + var fluidAmount = outputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; + if (fluidAmount > 0) { + results.push({ + id: fluidId, + amount: fluidAmount + }); + } + } + } + + return results; + } + + // ============================================================================ + // 测试用例1:FirmaLife 奶酪 + // ============================================================================ + console.info('--- 测试1:FirmaLife 奶酪 ---'); + + var test1 = { + recipeId: 'firmalife:barrel/cheese', + duration: 1000, + input_item: { count: 1, item: 'firmalife:cheesecloth' }, + input_fluid: { amount: 1000, tag: 'firmalife:milks' }, + output_item: { count: 1, id: 'firmalife:cheesecloth' }, + output_fluid: { amount: 1000, id: 'firmalife:cream' } + }; + + // Basin倍率计算:min(64/1, 64/1, 1000/1000, 1000/1000) = 1 + var basinMult1 = calculateBasinMultiplier(test1.input_item, test1.input_fluid, test1.output_item, test1.output_fluid); + console.info('[测试1] Basin倍率: ' + basinMult1); + + var bulkParams1 = { + itemMultiplier: 9, + fluidMultiplier: 9, + fluidAddition: 0 + }; + + // Basin Fermenting(同步倍率) + var ingredients1_basin = buildBasinIngredients(test1.input_item, test1.input_fluid, basinMult1); + var results1_basin = buildBasinResults(test1.output_item, test1.output_fluid, basinMult1); + + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients1_basin, + processing_time: Math.max(100, Math.round(test1.duration / 5)), + results: results1_basin + }).id('kubejs:test/basin/firmalife_barrel_cheese'); + + stats.basin++; + console.info('[测试] 创建 Basin: ' + test1.recipeId); + console.info(' BasinMultiplier: ' + basinMult1); + console.info(' Ingredients: ' + JSON.stringify(ingredients1_basin)); + console.info(' Results: ' + JSON.stringify(results1_basin)); + + // Bulk Fermenting + var ingredients1_bulk = buildBulkIngredients(test1.input_item, test1.input_fluid, bulkParams1); + var results1_bulk = buildBulkResults(test1.output_item, test1.output_fluid, bulkParams1); + + event.custom({ + type: 'createdieselgenerators:bulk_fermenting', + ingredients: ingredients1_bulk, + processing_time: Math.max(100, Math.round(test1.duration / 4)), + results: results1_bulk + }).id('kubejs:test/bulk/firmalife_barrel_cheese'); + + stats.bulk++; + console.info('[测试] 创建 Bulk: ' + test1.recipeId); + console.info(' BulkParams: ' + JSON.stringify(bulkParams1)); + console.info(' Ingredients: ' + JSON.stringify(ingredients1_bulk)); + console.info(' Results: ' + JSON.stringify(results1_bulk)); + + // ============================================================================ + // 测试用例2:陈酿玉米威士忌 + // ============================================================================ + console.info('--- 测试2:陈酿玉米威士忌 ---'); + + var test2 = { + recipeId: 'tfc:barrel/aged_corn_whiskey', + duration: 691200, + input_fluid: { fluid: 'tfc:corn_whiskey', amount: 10000 }, + output_fluid: { id: 'tfcagedalcohol:aged_corn_whiskey', amount: 10000 } + }; + + // Basin倍率计算:min(1000/10000, 1000/10000) = 0.1 → floor = 0 + var basinMult2 = calculateBasinMultiplier(null, test2.input_fluid, null, test2.output_fluid); + console.info('[测试2] Basin倍率: ' + basinMult2); + + var bulkParams2 = { + itemMultiplier: 1, + fluidMultiplier: 3.6, + fluidAddition: 0 + }; + + // Basin Fermenting(倍率为0,不创建) + if (basinMult2 > 0) { + var ingredients2_basin = buildBasinIngredients(null, test2.input_fluid, basinMult2); + var results2_basin = buildBasinResults(null, test2.output_fluid, basinMult2); + + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients2_basin, + processing_time: Math.max(100, Math.round(test2.duration / 5)), + results: results2_basin + }).id('kubejs:test/basin/tfc_barrel_aged_corn_whiskey'); + + stats.basin++; + console.info('[测试] 创建 Basin: ' + test2.recipeId); + console.info(' BasinMultiplier: ' + basinMult2); + } else { + console.info('[测试] Basin倍率=0,跳过创建 Basin'); + } + + // Bulk Fermenting + var ingredients2_bulk = buildBulkIngredients(null, test2.input_fluid, bulkParams2); + var results2_bulk = buildBulkResults(null, test2.output_fluid, bulkParams2); + + event.custom({ + type: 'createdieselgenerators:bulk_fermenting', + ingredients: ingredients2_bulk, + processing_time: Math.max(100, Math.round(test2.duration / 4)), + results: results2_bulk + }).id('kubejs:test/bulk/tfc_barrel_aged_corn_whiskey'); + + stats.bulk++; + console.info('[测试] 创建 Bulk: ' + test2.recipeId); + console.info(' BulkParams: ' + JSON.stringify(bulkParams2)); + console.info(' Ingredients: ' + JSON.stringify(ingredients2_bulk)); + console.info(' Results: ' + JSON.stringify(results2_bulk)); + + // ============================================================================ + // 测试用例3:black_wool(无流体输出,需返还染料) + // ============================================================================ + console.info('--- 测试3:black_wool ---'); + + var test3 = { + recipeId: 'tfc:barrel/black_wool', + duration: 1200, + input_item: { count: 1, item: 'minecraft:white_wool' }, + input_fluid: { fluid: 'tfc:black_dye', amount: 25 }, + output_item: { count: 1, id: 'minecraft:black_wool' } + }; + + // Basin倍率计算:min(64/1, 1000/25) = 40 + var basinMult3 = calculateBasinMultiplier(test3.input_item, test3.input_fluid, test3.output_item, null); + console.info('[测试3] Basin倍率: ' + basinMult3); + + // 计算返还量:25 * 9 = 225, 1000 - 225 = 775 + var bulkParams3 = { + itemMultiplier: 9, + fluidMultiplier: 9, + fluidAddition: 775 + }; + + // 创建虚拟输出流体(用于buildBulkResults处理返还) + var virtualOutputFluid3 = { id: 'tfc:black_dye', amount: 0 }; + + // Basin Fermenting(无返还逻辑,因为 basin 倍率是受限计算出来的) + var ingredients3_basin = buildBasinIngredients(test3.input_item, test3.input_fluid, basinMult3); + var results3_basin = buildBasinResults(test3.output_item, null, basinMult3); + + if (results3_basin.length > 0 && ingredients3_basin.length > 0) { + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients3_basin, + processing_time: Math.max(100, Math.round(test3.duration / 5)), + results: results3_basin + }).id('kubejs:test/basin/tfc_barrel_black_wool'); + + stats.basin++; + console.info('[测试] 创建 Basin: ' + test3.recipeId); + console.info(' BasinMultiplier: ' + basinMult3); + console.info(' Ingredients: ' + JSON.stringify(ingredients3_basin)); + console.info(' Results: ' + JSON.stringify(results3_basin)); + } + + // Bulk Fermenting(有返还逻辑) + var ingredients3_bulk = buildBulkIngredients(test3.input_item, test3.input_fluid, bulkParams3); + var results3_bulk = buildBulkResults(test3.output_item, virtualOutputFluid3, bulkParams3); + + event.custom({ + type: 'createdieselgenerators:bulk_fermenting', + ingredients: ingredients3_bulk, + processing_time: Math.max(100, Math.round(test3.duration / 4)), + results: results3_bulk + }).id('kubejs:test/bulk/tfc_barrel_black_wool'); + + stats.bulk++; + console.info('[测试] 创建 Bulk: ' + test3.recipeId); + console.info(' BulkParams: ' + JSON.stringify(bulkParams3)); + console.info(' Ingredients: ' + JSON.stringify(ingredients3_bulk)); + console.info(' Results: ' + JSON.stringify(results3_bulk)); + + // ============================================================================ + // 测试用例4:mortar(特殊配方) + // ============================================================================ + console.info('--- 测试4:mortar ---'); + + var test4 = { + recipeId: 'tfc:barrel/mortar', + duration: 7200, + input_item: { count: 1, tag: 'c:sands' }, + input_fluid: { fluid: 'tfc:limewater', amount: 100 }, + output_item: { count: 16, id: 'tfc:mortar' } + }; + + // Basin倍率计算:min(64/1, 64/16, 1000/100) = 4 + var basinMult4 = calculateBasinMultiplier(test4.input_item, test4.input_fluid, test4.output_item, null); + console.info('[测试4] Basin倍率: ' + basinMult4); + + var bulkParams4 = { + itemMultiplier: 6, + fluidMultiplier: 6, + fluidAddition: 0 + }; + + // Basin Fermenting(倍率4,是受限计算得出的) + var ingredients4_basin = buildBasinIngredients(test4.input_item, test4.input_fluid, basinMult4); + var results4_basin = buildBasinResults(test4.output_item, null, basinMult4); + + if (results4_basin.length > 0 && ingredients4_basin.length > 0) { + event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients4_basin, + processing_time: Math.max(100, Math.round(test4.duration / 5)), + results: results4_basin + }).id('kubejs:test/basin/tfc_barrel_mortar'); + + stats.basin++; + console.info('[测试] 创建 Basin: ' + test4.recipeId); + console.info(' BasinMultiplier: ' + basinMult4); + console.info(' Ingredients: ' + JSON.stringify(ingredients4_basin)); + console.info(' Results: ' + JSON.stringify(results4_basin)); + } + + // Bulk Fermenting(特殊倍率6) + var ingredients4_bulk = buildBulkIngredients(test4.input_item, test4.input_fluid, bulkParams4); + var results4_bulk = buildBulkResults(test4.output_item, null, bulkParams4); + + event.custom({ + type: 'createdieselgenerators:bulk_fermenting', + ingredients: ingredients4_bulk, + processing_time: Math.max(100, Math.round(test4.duration / 4)), + results: results4_bulk + }).id('kubejs:test/bulk/tfc_barrel_mortar'); + + stats.bulk++; + console.info('[测试] 创建 Bulk: ' + test4.recipeId); + console.info(' BulkParams: ' + JSON.stringify(bulkParams4)); + console.info(' Ingredients: ' + JSON.stringify(ingredients4_bulk)); + console.info(' Results: ' + JSON.stringify(results4_bulk)); + + // ============================================================================ + // 完成 + // ============================================================================ + console.info('[测试] 完成!Basin: ' + stats.basin + ', Bulk: ' + stats.bulk); +}); From 3d9eead0d9a052fcef7fd54df825c299378805d3 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Mon, 18 May 2026 04:15:35 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF20260518=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_scripts/cbc_melting.js | 14 ++++----- server_scripts/event_recipes.js | 32 ++++++++++++++++---- server_scripts/tfc_compact.js | 52 +++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 server_scripts/tfc_compact.js diff --git a/server_scripts/cbc_melting.js b/server_scripts/cbc_melting.js index 0125eda..8c42fe8 100644 --- a/server_scripts/cbc_melting.js +++ b/server_scripts/cbc_melting.js @@ -2,13 +2,13 @@ ServerEvents.recipes(event => { event.forEachRecipe({ type: 'tfc:heating' }, recipe => { const json = recipe.json if (!json.has('result_fluid')) return - + const resultFluid = json.get('result_fluid') const ingredient = json.get('ingredient') - const ingredientArray = ingredient.isJsonArray() + const ingredientArray = ingredient.isJsonArray() ? JSON.parse(ingredient.toString()) : [JSON.parse(ingredient.toString())] - + const allValid = ingredientArray.every(ing => { if (ing.item) { return Item.exists(ing.item) @@ -18,16 +18,16 @@ ServerEvents.recipes(event => { } return false }) - + if (!allValid) return - + const temperature = json.has('temperature') ? json.get('temperature').getAsFloat() : 0 const heatRequirement = temperature > 1080 ? 'superheated' : 'heated' - + // 基准 1080°C → 20s (400 tick),1500°C → 30s (600 tick),线性插值 // 斜率: (600-400) / (1500-1080) ≈ 0.476 tick/°C const processingTime = Math.round(400 + (temperature - 1080) * (200 / 420)) - + event.custom({ type: 'createbigcannons:melting', heat_requirement: heatRequirement, diff --git a/server_scripts/event_recipes.js b/server_scripts/event_recipes.js index 5b070f1..862fccf 100644 --- a/server_scripts/event_recipes.js +++ b/server_scripts/event_recipes.js @@ -11,6 +11,33 @@ ServerEvents.recipes(event => { B: '#c:gravels' } ) + event.shaped( + Item.of('create:empty_blaze_burner'), + [ + ' A ', + 'ABC', + ' C ' + ], + { + A: '#c:sheets/red_steel', + B: '#c:gravels', + C: '#c:sheets/blue_steel' + } + ) + event.shaped( + Item.of('create:blaze_burner'), + [ + ' A ', + 'ABA', + ' C ' + ], + { + A: '#farmerstfc:magma_block', + B: 'tfc:blast_furnace', + C: 'create:empty_blaze_burner' + } + ) + event.shaped( Item.of('drivebywire:wire'), [ @@ -130,10 +157,5 @@ ServerEvents.recipes(event => { 'minecraft:blast_furnace', 'tfc:blast_furnace' ) - event.replaceInput( - { input: 'create:empty_blaze_burner' }, - 'create:empty_blaze_burner', - 'createlowheated:basic_burner' - ) }) \ No newline at end of file diff --git a/server_scripts/tfc_compact.js b/server_scripts/tfc_compact.js new file mode 100644 index 0000000..2a88aeb --- /dev/null +++ b/server_scripts/tfc_compact.js @@ -0,0 +1,52 @@ +ServerEvents.recipes(event => { + event.shapeless(Item.of('create:andesite_alloy', 8), + [ + '#c:cobblestones', + '#c:ingots/zinc' + ] + ) + event.shapeless(Item.of('create:andesite_alloy', 8), + [ + '#c:cobblestones', + '#c:ingots/iron' + ] + ) + + event.replaceInput( + { input: 'minecraft:slime_ball' }, + 'minecraft:slime_ball', + 'tfc:glue' + ) + + //metal + event.replaceInput( + { input: 'minecraft:iron_ingot' }, + 'minecraft:iron_ingot', + '#c:ingots/wrought_iron' + ) + event.replaceOutput( + { output: 'minecraft:iron_ingot' }, + 'minecraft:iron_ingot', + 'tfc:metal/ingot/wrought_iron' + ) + event.remove({ output: 'minecraft:iron_ingot' }) + event.remove({ output: 'minecraft:gold_ingot' }) + event.remove({ output: 'minecraft:gold_block' }) + event.remove({ output: 'create:brass_block' }) + + event.recipes.tfc.heating( + 'minecraft:iron_nugget', + 1500 + ).fluidOutput(Fluid.of('tfc:metal/cast_iron', 10)) + event.recipes.tfc.heating( + 'minecraft:iron_block', + 1500 + ).fluidOutput(Fluid.of('tfc:metal/cast_iron', 900)) + + + event.replaceInput( + { input: 'minecraft:blast_furnace' }, + 'minecraft:blast_furnace', + 'tfc:blast_furnace' + ) +}) From f20fde6d3cc730e0ca4216a63a2013009aadce76 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Mon, 18 May 2026 09:04:14 +0000 Subject: [PATCH 06/14] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86=E5=AF=86?= =?UTF-8?q?=E5=B0=81=E5=A4=A7=E6=A1=B6=E9=85=8D=E6=96=B9=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...l.js.disable => fermenting_from_barrel.js} | 226 +++++++++++++++--- ...enting_test.js => fermenting_test.js.pass} | 0 2 files changed, 189 insertions(+), 37 deletions(-) rename server_scripts/biodiesel_fix/{fermenting_from_barrel.js.disable => fermenting_from_barrel.js} (56%) rename server_scripts/biodiesel_fix/{fermenting_test.js => fermenting_test.js.pass} (100%) diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable b/server_scripts/biodiesel_fix/fermenting_from_barrel.js similarity index 56% rename from server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable rename to server_scripts/biodiesel_fix/fermenting_from_barrel.js index d344627..9684eeb 100644 --- a/server_scripts/biodiesel_fix/fermenting_from_barrel.js.disable +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -10,6 +10,9 @@ // ============================================================================ // 策略注册表 +// 每个策略包含:condition(recipeData) -> bool 用于判断是否适用 +// handler(data, recipe, recipeData) -> bool 返回true表示已处理,false表示继续 +// 策略按注册顺序执行,前面的策略可以为后面的策略添加标记数据(如bulkParams) // ============================================================================ var recipeStrategies = {}; @@ -25,20 +28,20 @@ function registerStrategy(name, condition, handler) { // 数据结构定义 // ============================================================================ -// 配方转换器数据 +// 配方转换器数据(贯穿整个转换流程的上下文对象) function createConverterData(event) { return { event: event, stats: { - basin: 0, - bulk: 0, - skipped: 0 + basin: 0, // Basin Fermenting 配方生成计数 + bulk: 0, // Bulk Fermenting 配方生成计数 + skipped: 0 // 跳过的配方计数(如带modifiers的配方) }, - FLUID_SLOT_LIMIT: 1000 + FLUID_SLOT_LIMIT: 1000 // Create流体槽上限 (mB) }; } -// 配方数据对象(添加策略标记) +// 配方数据对象(每个TFC配方对应一个实例,策略按需修改其字段) function createRecipeData(json, data, recipe) { var result = { inputItem: null, @@ -46,10 +49,15 @@ function createRecipeData(json, data, recipe) { outputItem: null, outputFluid: null, sealTime: 0, - maxMultiplier: Infinity, - flooredMultiplier: 0, - recipeId: recipe ? recipe.getId() : null, // 添加配方ID - bulkMultiplier: 0 // bulk 倍率标记 + maxMultiplier: Infinity, // 理论最大倍增倍数(受堆叠/流体槽限制) + flooredMultiplier: 0, // 向下取整后的倍数(用于Basin配方) + recipeId: recipe ? recipe.getId() : null, + // bulkParams 由各策略逐步修改,最终用于 Bulk Fermenting 配方生成 + bulkParams: { + itemMultiplier: 0, // 物品倍增倍率 + fluidMultiplier: 0, // 流体倍增倍率(可与物品倍率不同) + fluidAddition: 0 // 额外添加/返还的流体量 (mB) + } }; // 提取数据 @@ -86,6 +94,7 @@ function parseJsonField(json, fieldName) { } // 获取物品最大堆叠数 +// 当输入是tag时,取该tag下所有物品中最小的maxStackSize(保守估计,防止溢出) function getMaxStackSize(itemData) { var itemId = itemData.item || itemData.tag; if (!itemId) return null; @@ -111,7 +120,8 @@ function getMaxStackSize(itemData) { return null; } -// 计算最大倍增倍数 +// 计算最大倍增倍数(取输入物品/输出物品/输入流体/输出流体四项限制的最小值) +// 输入物品受堆叠上限约束,输出物品同理;流体受 FLUID_SLOT_LIMIT (1000mB) 约束 function calculateMaxMultiplier(recipeData, data) { var maxMultiplier = Infinity; @@ -152,7 +162,7 @@ function calculateMaxMultiplier(recipeData, data) { return maxMultiplier; } -// 构建 ingredients +// 构建 Basin Fermenting ingredients(物品和流体使用相同倍率) function buildIngredients(inputItem, inputFluid, multiplier) { var ingredients = []; @@ -195,7 +205,7 @@ function buildIngredients(inputItem, inputFluid, multiplier) { return ingredients; } -// 构建 results +// 构建 Basin Fermenting results(物品和流体使用相同倍率) function buildResults(outputItem, outputFluid, multiplier) { var results = []; @@ -227,11 +237,91 @@ function buildResults(outputItem, outputFluid, multiplier) { return results; } +// 构建 Bulk Fermenting ingredients(支持独立的物品和流体倍率,以及流体返还) +// fluidAddition 用于处理满池减益策略中返还剩余流体的场景 +function buildBulkIngredients(inputItem, inputFluid, bulkParams) { + var ingredients = []; + + if (inputItem) { + var itemMult = bulkParams.itemMultiplier; + for (var i = 0; i < itemMult; i++) { + if (inputItem.type === 'tfc:and' && inputItem.children) { + ingredients.push({ + type: 'tfc:and', + children: inputItem.children + }); + } else if (inputItem.item) { + ingredients.push({ item: inputItem.item }); + } else if (inputItem.tag) { + ingredients.push({ tag: inputItem.tag }); + } + } + } + + if (inputFluid) { + var fluidAmount = inputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; + if (fluidAmount > 0) { + if (inputFluid.fluid) { + ingredients.push({ + type: 'fluid_stack', + fluid: inputFluid.fluid, + amount: fluidAmount + }); + } else if (inputFluid.tag) { + ingredients.push({ + type: 'fluid_tag', + fluid_tag: inputFluid.tag, + amount: fluidAmount + }); + } + } + } + + return ingredients; +} + +// 构建 Bulk Fermenting results(支持独立的物品和流体倍率,以及流体返还) +// outputFluid.amount >= 0 允许零量输出流体(用于满池减益策略的流体返还标记) +function buildBulkResults(outputItem, outputFluid, bulkParams) { + var results = []; + + if (outputItem) { + var itemId = outputItem.id || outputItem.item; + if (itemId) { + var singleResult = { id: itemId }; + var outputCount = (outputItem.count || 1) * bulkParams.itemMultiplier; + if (outputCount > 1) { + singleResult.count = outputCount; + } + if (outputItem.chance) { + singleResult.chance = outputItem.chance; + } + results.push(singleResult); + } + } + + if (outputFluid && outputFluid.amount >= 0) { + var fluidId = outputFluid.id || outputFluid.fluid; + if (fluidId) { + var fluidAmount = outputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; + if (fluidAmount > 0) { + results.push({ + id: fluidId, + amount: fluidAmount + }); + } + } + } + + return results; +} + // ============================================================================ // 策略:配方分析(添加标记) // ============================================================================ -// 策略1:检查原配方输入物品数,计算 bulk 倍率 +// 策略1:计算 bulk 倍率(默认物品和流体同步倍率) +// 逻辑:原配方输入物品数决定每"组"大小,floor(9 / 原物品数) = 每批最多处理几组 registerStrategy('bulk_multiplier_check', function(recipeData) { // 计算原配方输入物品数 var originalItemCount = 0; @@ -240,23 +330,77 @@ registerStrategy('bulk_multiplier_check', function(recipeData) { } // 计算 bulk 倍率:floor(9 / 原物品数) - var bulkMultiplier = Math.floor(9 / originalItemCount); + var multiplier = Math.floor(9 / originalItemCount); - // 将倍率存储到 recipeData 中(作为标记) - recipeData.bulkMultiplier = bulkMultiplier; + // 将倍率参数存储到 recipeData 中(默认同步倍率) + recipeData.bulkParams.itemMultiplier = multiplier; + recipeData.bulkParams.fluidMultiplier = multiplier; + recipeData.bulkParams.fluidAddition = 0; // 如果倍率 > 0,则 bulk_fermenting 可用 - return bulkMultiplier > 0; + return multiplier > 0; }, function(data, recipe, recipeData) { // 这个策略只是添加标记,不做实际处理 return false; // 继续后续策略 }); -// 策略2:检查特殊配方(如 mortar,输出过多需要限制倍率) +// 策略2:流体增益(有流体输出的配方,流体倍率翻倍) +// 原因:输入和输出的流体独立占用流体槽,翻倍可以更好地利用槽位 +registerStrategy('bulk_fluid_bonus', function(recipeData) { + // 条件:有流体输出且输入流体量 > 0 + if (recipeData.outputFluid && recipeData.outputFluid.amount > 0 && + recipeData.inputFluid && recipeData.inputFluid.amount > 0) { + // 流体倍率 = 物品倍率 * 2(确保输入与输出流体同步倍增) + var itemMult = recipeData.bulkParams.itemMultiplier || 1; + recipeData.bulkParams.fluidMultiplier = itemMult * 2; + recipeData.bulkParams.fluidAddition = 0; + return true; + } + return false; +}, function(data, recipe, recipeData) { + // 标记已添加,不做实际处理 + return false; +}); + +// 策略2.1:满池减益(有输入流体但无输出流体,需返还剩余流体) +// 当输入流体 < 1000mB 且配方无输出流体时,bulk 后会产生"空余"流体槽 +// 此策略将剩余的流体返还到输出中(创造一个虚拟输出流体标记) +registerStrategy('bulk_fluid_return', function(recipeData) { + // 条件:有输入流体但无输出流体,且输入流体量 < 1000 + if (recipeData.inputFluid && recipeData.inputFluid.amount > 0 && + (!recipeData.outputFluid || recipeData.outputFluid.amount <= 0) && + recipeData.inputFluid.amount < 1000) { + // 计算返还量:1000 - (输入流体量 * itemMultiplier) + var inputAmount = recipeData.inputFluid.amount; + var itemMult = recipeData.bulkParams.itemMultiplier || 1; + var consumed = inputAmount * itemMult; + var returnAmount = 1000 - consumed; + + // 设置参数:流体倍率与物品倍率相同,添加返还量 + recipeData.bulkParams.fluidMultiplier = itemMult; + recipeData.bulkParams.fluidAddition = returnAmount; + + // 创建虚拟输出流体(用于buildBulkResults处理返还) + var fluidId = recipeData.inputFluid.fluid || recipeData.inputFluid.tag; + if (fluidId) { + recipeData.outputFluid = { id: fluidId, amount: 0 }; + } + + return true; + } + return false; +}, function(data, recipe, recipeData) { + // 标记已添加,不做实际处理 + return false; +}); + +// 策略2.2:特殊配方处理(如 mortar 输出过多,限制倍率为6防止溢出) registerStrategy('bulk_special_recipe', function(recipeData) { // 直接判断配方ID if (recipeData.recipeId === 'tfc:barrel/mortar') { - recipeData.bulkMultiplier = 6; // 特殊倍率 + recipeData.bulkParams.itemMultiplier = 6; // 特殊物品倍率 + recipeData.bulkParams.fluidMultiplier = 6; // 特殊流体倍率 + recipeData.bulkParams.fluidAddition = 0; return true; } return false; @@ -265,7 +409,8 @@ registerStrategy('bulk_special_recipe', function(recipeData) { return false; }); -// 策略2.1:检查陈酿酒配方(输出流体以 tfcagedalcohol:aged 开头) +// 策略2.3:陈酿酒配方(输出流体以 tfcagedalcohol:aged 开头) +// 陈酿酒需要特殊倍率:物品不倍增,仅流体按 3.6 倍处理 registerStrategy('bulk_aged_alcohol', function(recipeData) { // 检查输出流体ID是否以 tfcagedalcohol:aged 开头 var fluidId = null; @@ -273,7 +418,9 @@ registerStrategy('bulk_aged_alcohol', function(recipeData) { fluidId = recipeData.outputFluid.id || recipeData.outputFluid.fluid; } if (fluidId && fluidId.indexOf('tfcagedalcohol:aged') === 0) { - recipeData.bulkMultiplier = 3.6; // 陈酿酒倍率 + recipeData.bulkParams.itemMultiplier = 1; // 物品倍率1 + recipeData.bulkParams.fluidMultiplier = 3.6; // 陈酿酒流体倍率 + recipeData.bulkParams.fluidAddition = 0; return true; } return false; @@ -282,7 +429,7 @@ registerStrategy('bulk_aged_alcohol', function(recipeData) { return false; }); -// 策略3:检查是否需要跳过(带modifiers的配方) +// 策略3:跳过带 modifiers 的配方(如带有NBT标签的输出物,无法在Create配方中表达) registerStrategy('skip_modifiers', function(recipeData) { return recipeData.outputItem && recipeData.outputItem.modifiers; }, function(data, recipe, recipeData) { @@ -290,7 +437,8 @@ registerStrategy('skip_modifiers', function(recipeData) { return true; // 已处理,不再执行后续策略 }); -// 策略4:Basin Fermenting(倍数 >= 1) +// 策略4:Basin Fermenting(处理倍率 >= 1 的配方,物品流体同步倍率) +// 处理时间 = sealTime / 5(最少100tick),用于单槽批量发酵 registerStrategy('basin_fermenting', function(recipeData) { return recipeData.flooredMultiplier >= 1; }, function(data, recipe, recipeData) { @@ -316,23 +464,25 @@ registerStrategy('basin_fermenting', function(recipeData) { return true; }); -// 策略5:Bulk Fermenting(使用 bulkMultiplier 标记) +// 策略5:Bulk Fermenting(使用 bulkParams,物品和流体可独立倍率) +// 处理时间 = sealTime / 4(最少100tick),九个槽位同时发酵 registerStrategy('bulk_fermenting', function(recipeData) { - // 检查是否有 bulkMultiplier 标记且大于0 - return recipeData.bulkMultiplier && recipeData.bulkMultiplier > 0; + // 检查是否有有效的 bulkParams(itemMultiplier > 0) + return recipeData.bulkParams && recipeData.bulkParams.itemMultiplier > 0; }, function(data, recipe, recipeData) { - // 使用标记的倍率(可能是特殊的6,也可能是计算的倍率) - var multiplier = recipeData.bulkMultiplier; + // 获取 bulk 参数 + var bulkParams = recipeData.bulkParams; - var ingredients = buildIngredients(recipeData.inputItem, recipeData.inputFluid, multiplier); - var results = buildResults(recipeData.outputItem, recipeData.outputFluid, multiplier); + // 使用独立的构建函数处理 bulk 配方 + var ingredients = buildBulkIngredients(recipeData.inputItem, recipeData.inputFluid, bulkParams); + var results = buildBulkResults(recipeData.outputItem, recipeData.outputFluid, bulkParams); if (results.length === 0 || ingredients.length === 0) { return false; } var processingTime = Math.max(100, Math.round(recipeData.sealTime / 4)); - var multStr = multiplier.toString(); + var multStr = bulkParams.itemMultiplier.toString() + '_' + bulkParams.fluidMultiplier.toString(); data.event.custom({ type: 'createdieselgenerators:bulk_fermenting', @@ -349,7 +499,8 @@ registerStrategy('bulk_fermenting', function(recipeData) { // 主流程 // ============================================================================ -// 分析配方并添加策略标记 +// 分析配方:计算倍率,然后遍历所有策略的 condition,将适用的策略名存入 recipeData.strategies +// 注意:condition 可能有副作用(如修改 bulkParams),这是设计如此,用于策略间的数据传递 function analyzeRecipe(recipeData, data) { // 计算倍数 recipeData.maxMultiplier = calculateMaxMultiplier(recipeData, data); @@ -367,7 +518,8 @@ function analyzeRecipe(recipeData, data) { } } -// 执行配方的所有策略 +// 按 analyzeRecipe 收集的策略顺序执行所有 handler +// handler 返回 true 表示已处理(如 skip 策略),但目前不影响后续策略继续执行 function executeStrategies(data, recipe, recipeData) { for (var i = 0; i < recipeData.strategies.length; i++) { var strategyName = recipeData.strategies[i]; @@ -382,14 +534,13 @@ function executeStrategies(data, recipe, recipeData) { } } -// 转换单个配方 +// 转换单个配方:解析 → 快速过滤 → 分析策略 → 执行策略 function convertSingleRecipe(data, recipe) { var json = recipe.json; - // 创建配方数据对象 var recipeData = createRecipeData(json, data, recipe); - // 过滤:跳过带modifiers的配方(快速检查) + // 快速过滤:带modifiers的配方无法在Create中表达,提前跳过(与策略3重复但更高效) if (recipeData.outputItem && recipeData.outputItem.modifiers) { data.stats.skipped++; return; @@ -417,6 +568,7 @@ function convertAllRecipes(data) { // ============================================================================ // 执行 +// 入口:遍历所有 tfc:barrel_sealed 配方,逐个转换为 Create 发酵配方 // ============================================================================ ServerEvents.recipes(function(event) { var data = createConverterData(event); diff --git a/server_scripts/biodiesel_fix/fermenting_test.js b/server_scripts/biodiesel_fix/fermenting_test.js.pass similarity index 100% rename from server_scripts/biodiesel_fix/fermenting_test.js rename to server_scripts/biodiesel_fix/fermenting_test.js.pass From 47a85a8ca9f7d4d5955c55d753662ccf61baf5c5 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Mon, 18 May 2026 10:42:48 +0000 Subject: [PATCH 07/14] =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=B9=B6=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=AF=86=E5=B0=81=E5=A4=A7=E6=A1=B6=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biodiesel_fix/fermenting_from_barrel.js | 635 ++++++++---------- .../biodiesel_fix/fermenting_test.js.pass | 443 ------------ .../test_basin_fermenting_schema.js.faild | 67 -- .../test_fermenting_recipes.js.pass | 96 --- server_scripts/test_large_leather.js.pass | 26 - server_scripts/test_maxstack_debug.js.pass | 138 ---- server_scripts/test_not_rotten.js.pass | 56 -- server_scripts/test_tfc_modifiers.js.faild | 32 - 8 files changed, 278 insertions(+), 1215 deletions(-) delete mode 100644 server_scripts/biodiesel_fix/fermenting_test.js.pass delete mode 100644 server_scripts/test_basin_fermenting_schema.js.faild delete mode 100644 server_scripts/test_fermenting_recipes.js.pass delete mode 100644 server_scripts/test_large_leather.js.pass delete mode 100644 server_scripts/test_maxstack_debug.js.pass delete mode 100644 server_scripts/test_not_rotten.js.pass delete mode 100644 server_scripts/test_tfc_modifiers.js.faild diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js index 9684eeb..bae2a36 100644 --- a/server_scripts/biodiesel_fix/fermenting_from_barrel.js +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -1,47 +1,30 @@ // ============================================================================ -// 批量从TFC密封大桶配方创建Create发酵配方(策略模式重构版) -// ============================================================================ -// -// 策略模式实现: -// 1. 分析配方属性,添加策略标记(strategy type) -// 2. 注册不同策略的处理函数 -// 3. 执行时根据标记自动选择并执行对应策略 +// 批量从TFC密封大桶配方创建Create发酵配方 +// 线性流水线:解析 → 过滤 → 计算倍率 → 生成Basin/Bulk配方 // ============================================================================ -// ============================================================================ -// 策略注册表 -// 每个策略包含:condition(recipeData) -> bool 用于判断是否适用 -// handler(data, recipe, recipeData) -> bool 返回true表示已处理,false表示继续 -// 策略按注册顺序执行,前面的策略可以为后面的策略添加标记数据(如bulkParams) -// ============================================================================ -var recipeStrategies = {}; - -// 注册策略 -function registerStrategy(name, condition, handler) { - recipeStrategies[name] = { - condition: condition, - handler: handler - }; -} - -// ============================================================================ -// 数据结构定义 -// ============================================================================ +var BULK_FLUID_LIMIT = 72000; -// 配方转换器数据(贯穿整个转换流程的上下文对象) +/** + * 创建贯穿转换流程的上下文对象 + * @param {Internal.RecipeEventJS} event - 配方事件 + * @returns {Object} 包含事件引用、统计计数器和常量 + */ function createConverterData(event) { return { event: event, - stats: { - basin: 0, // Basin Fermenting 配方生成计数 - bulk: 0, // Bulk Fermenting 配方生成计数 - skipped: 0 // 跳过的配方计数(如带modifiers的配方) - }, - FLUID_SLOT_LIMIT: 1000 // Create流体槽上限 (mB) + stats: { basin: 0, bulk: 0, skipped: 0 }, + FLUID_SLOT_LIMIT: 1000 }; } -// 配方数据对象(每个TFC配方对应一个实例,策略按需修改其字段) +/** + * 从TFC配方JSON中提取关键字段 + * @param {Internal.JsonObject} json - 配方的JSON对象 + * @param {Object} data - 转换上下文 + * @param {Internal.Recipe} recipe - TFC配方 + * @returns {Object} 标准化后的配方数据对象 + */ function createRecipeData(json, data, recipe) { var result = { inputItem: null, @@ -49,39 +32,34 @@ function createRecipeData(json, data, recipe) { outputItem: null, outputFluid: null, sealTime: 0, - maxMultiplier: Infinity, // 理论最大倍增倍数(受堆叠/流体槽限制) - flooredMultiplier: 0, // 向下取整后的倍数(用于Basin配方) + basinMaxMultiplier: Infinity, + basinMultiplier: 0, recipeId: recipe ? recipe.getId() : null, - // bulkParams 由各策略逐步修改,最终用于 Bulk Fermenting 配方生成 - bulkParams: { - itemMultiplier: 0, // 物品倍增倍率 - fluidMultiplier: 0, // 流体倍增倍率(可与物品倍率不同) - fluidAddition: 0 // 额外添加/返还的流体量 (mB) - } + base: 0, + itemMultiplier: 0, + fluidMultiplier: 0, + fluidAddition: 0 }; - - // 提取数据 + result.inputItem = parseJsonField(json, 'input_item'); result.inputFluid = parseJsonField(json, 'input_fluid'); result.outputItem = parseJsonField(json, 'output_item'); result.outputFluid = parseJsonField(json, 'output_fluid'); - // 支持 seal_time 和 duration 两种字段名 if (json.has('seal_time')) { result.sealTime = json.get('seal_time').getAsInt(); } else if (json.has('duration')) { result.sealTime = json.get('duration').getAsInt(); - } else { - result.sealTime = 0; } - + return result; } -// ============================================================================ -// 工具函数 -// ============================================================================ - -// 解析 JSON 字段 +/** + * 安全解析JSON字段 + * @param {Internal.JsonObject} json - JSON对象 + * @param {string} fieldName - 字段名 + * @returns {Object|null} 解析后的对象,失败返回null + */ function parseJsonField(json, fieldName) { if (json.has(fieldName)) { try { @@ -93,12 +71,15 @@ function parseJsonField(json, fieldName) { return null; } -// 获取物品最大堆叠数 -// 当输入是tag时,取该tag下所有物品中最小的maxStackSize(保守估计,防止溢出) +/** + * 获取物品最大堆叠数(tag输入时取该tag下所有物品的最小值) + * @param {Object} itemData - {item/tag, count} + * @returns {number|null} 最大堆叠数 + */ function getMaxStackSize(itemData) { var itemId = itemData.item || itemData.tag; if (!itemId) return null; - + try { if (itemData.tag) { var tagItems = Ingredient.of('#' + itemData.tag).items; @@ -120,11 +101,16 @@ function getMaxStackSize(itemData) { return null; } -// 计算最大倍增倍数(取输入物品/输出物品/输入流体/输出流体四项限制的最小值) -// 输入物品受堆叠上限约束,输出物品同理;流体受 FLUID_SLOT_LIMIT (1000mB) 约束 -function calculateMaxMultiplier(recipeData, data) { +/** + * 计算Basin配方的理论最大倍率 + * 受输入/输出物品堆叠上限和1000mB流体槽限制 + * @param {Object} recipeData - 配方数据 + * @param {Object} data - 转换上下文(提供FLUID_SLOT_LIMIT) + * @returns {number} 理论最大倍率 + */ +function calculateBasinMaxMultiplier(recipeData, data) { var maxMultiplier = Infinity; - + if (recipeData.inputItem) { var itemId = recipeData.inputItem.item || recipeData.inputItem.tag; if (itemId) { @@ -135,7 +121,7 @@ function calculateMaxMultiplier(recipeData, data) { } } } - + if (recipeData.outputItem) { var outputId = recipeData.outputItem.id || recipeData.outputItem.item; if (outputId) { @@ -150,29 +136,125 @@ function calculateMaxMultiplier(recipeData, data) { } } } - + if (recipeData.inputFluid && recipeData.inputFluid.amount > 0) { maxMultiplier = Math.min(maxMultiplier, data.FLUID_SLOT_LIMIT / recipeData.inputFluid.amount); } - + if (recipeData.outputFluid && recipeData.outputFluid.amount > 0) { maxMultiplier = Math.min(maxMultiplier, data.FLUID_SLOT_LIMIT / recipeData.outputFluid.amount); } - + return maxMultiplier; } -// 构建 Basin Fermenting ingredients(物品和流体使用相同倍率) -function buildIngredients(inputItem, inputFluid, multiplier) { +/** + * 计算Bulk配方的基础倍率 + * 公式: floor(9 / 物品数),同时为流体增益×2预留72000上限空间 + * @param {Object} recipeData - 配方数据 + * @returns {number} 基础倍率(为0时无法生成Bulk配方) + */ +function calculateBulkBase(recipeData) { + var originalItemCount = recipeData.inputItem ? 1 : 0; + if (originalItemCount === 0) return 0; + + var base = Math.floor(9 / originalItemCount); + + if (recipeData.inputFluid && recipeData.inputFluid.amount > 0) { + var inputAmt = recipeData.inputFluid.amount; + if (recipeData.outputFluid && recipeData.outputFluid.amount > 0) { + base = Math.min(base, Math.floor(BULK_FLUID_LIMIT / (2 * inputAmt))); + base = Math.min(base, Math.floor(BULK_FLUID_LIMIT / (2 * recipeData.outputFluid.amount))); + } else { + base = Math.min(base, Math.floor(BULK_FLUID_LIMIT / inputAmt)); + } + } + + return base; +} + +/** + * 判断是否为mortar配方(输出过多,需限制倍率为6) + * @param {Object} recipeData - 配方数据 + * @returns {boolean} + */ +function isMortar(recipeData) { + return recipeData.recipeId === 'tfc:barrel/mortar'; +} + +/** + * 判断是否为陈酿酒配方(物品×1,流体×3.6的特殊倍率) + * @param {Object} recipeData - 配方数据 + * @returns {boolean} + */ +function isAgedAlcohol(recipeData) { + var fluidId = null; + if (recipeData.outputFluid) { + fluidId = recipeData.outputFluid.id || recipeData.outputFluid.fluid; + } + return fluidId && fluidId.indexOf('tfcagedalcohol:aged') === 0; +} + +/** + * 解析Bulk配方的倍率参数 + * 特殊配方(mortar/陈酿酒)整体覆盖所有倍率并跳过通用策略; + * 通用配方依次应用流体增益(×2)和满池返还(向上取整到1000的倍数) + * @param {Object} recipeData - 配方数据(会被修改) + */ +function resolveBulkParams(recipeData) { + var base = recipeData.base; + var hasInputFluid = recipeData.inputFluid && recipeData.inputFluid.amount > 0; + var hasOutputFluid = recipeData.outputFluid && recipeData.outputFluid.amount > 0; + + if (isMortar(recipeData)) { + recipeData.itemMultiplier = 6; + recipeData.fluidMultiplier = 6; + recipeData.fluidAddition = 0; + return; + } + + if (isAgedAlcohol(recipeData)) { + recipeData.itemMultiplier = 1; + recipeData.fluidMultiplier = 3.6; + recipeData.fluidAddition = 0; + return; + } + + recipeData.itemMultiplier = base; + recipeData.fluidMultiplier = base; + recipeData.fluidAddition = 0; + + if (hasInputFluid && hasOutputFluid) { + recipeData.fluidMultiplier = base * 2; + } + + if (hasInputFluid && !hasOutputFluid) { + var totalInput = recipeData.inputFluid.amount * recipeData.fluidMultiplier; + var remainder = totalInput % 1000; + if (remainder > 0) { + recipeData.fluidAddition = 1000 - remainder; + var fluidId = recipeData.inputFluid.fluid || recipeData.inputFluid.tag; + if (fluidId) { + recipeData.outputFluid = { id: fluidId, amount: 0 }; + } + } + } +} + +/** + * 构建Basin配方的输入列表(物品和流体使用同一倍率) + * @param {Object} inputItem - 输入物品 + * @param {Object} inputFluid - 输入流体 + * @param {number} multiplier - 倍率 + * @returns {Array} ingredients数组 + */ +function buildBasinIngredients(inputItem, inputFluid, multiplier) { var ingredients = []; - + if (inputItem) { if (inputItem.type === 'tfc:and' && inputItem.children) { for (var i = 0; i < multiplier; i++) { - ingredients.push({ - type: 'tfc:and', - children: inputItem.children - }); + ingredients.push({ type: 'tfc:and', children: inputItem.children }); } } else { for (var i = 0; i < multiplier; i++) { @@ -184,72 +266,64 @@ function buildIngredients(inputItem, inputFluid, multiplier) { } } } - + if (inputFluid) { var amount = inputFluid.amount * multiplier; if (inputFluid.fluid && amount > 0) { - ingredients.push({ - type: 'fluid_stack', - fluid: inputFluid.fluid, - amount: amount - }); + ingredients.push({ type: 'fluid_stack', fluid: inputFluid.fluid, amount: amount }); } else if (inputFluid.tag && amount > 0) { - ingredients.push({ - type: 'fluid_tag', - fluid_tag: inputFluid.tag, - amount: amount - }); + ingredients.push({ type: 'fluid_tag', fluid_tag: inputFluid.tag, amount: amount }); } } - + return ingredients; } -// 构建 Basin Fermenting results(物品和流体使用相同倍率) -function buildResults(outputItem, outputFluid, multiplier) { +/** + * 构建Basin配方的输出列表(物品和流体使用同一倍率) + * @param {Object} outputItem - 输出物品 + * @param {Object} outputFluid - 输出流体 + * @param {number} multiplier - 倍率 + * @returns {Array} results数组 + */ +function buildBasinResults(outputItem, outputFluid, multiplier) { var results = []; - + if (outputItem) { var itemId = outputItem.id || outputItem.item; if (itemId) { var singleResult = { id: itemId }; var outputCount = (outputItem.count || 1) * multiplier; - if (outputCount > 1) { - singleResult.count = outputCount; - } - if (outputItem.chance) { - singleResult.chance = outputItem.chance; - } + if (outputCount > 1) singleResult.count = outputCount; + if (outputItem.chance) singleResult.chance = outputItem.chance; results.push(singleResult); } } - + if (outputFluid) { var fluidId = outputFluid.id || outputFluid.fluid; if (fluidId && outputFluid.amount > 0) { - results.push({ - id: fluidId, - amount: outputFluid.amount * multiplier - }); + results.push({ id: fluidId, amount: outputFluid.amount * multiplier }); } } - + return results; } -// 构建 Bulk Fermenting ingredients(支持独立的物品和流体倍率,以及流体返还) -// fluidAddition 用于处理满池减益策略中返还剩余流体的场景 -function buildBulkIngredients(inputItem, inputFluid, bulkParams) { +/** + * 构建Bulk配方的输入列表(物品/流体独立倍率,含满池返还的fluidAddition) + * @param {Object} recipeData - 配方数据(含itemMultiplier/fluidMultiplier/fluidAddition) + * @returns {Array} ingredients数组 + */ +function buildBulkIngredients(recipeData) { var ingredients = []; - + var inputItem = recipeData.inputItem; + var inputFluid = recipeData.inputFluid; + if (inputItem) { - var itemMult = bulkParams.itemMultiplier; - for (var i = 0; i < itemMult; i++) { + for (var i = 0; i < recipeData.itemMultiplier; i++) { if (inputItem.type === 'tfc:and' && inputItem.children) { - ingredients.push({ - type: 'tfc:and', - children: inputItem.children - }); + ingredients.push({ type: 'tfc:and', children: inputItem.children }); } else if (inputItem.item) { ingredients.push({ item: inputItem.item }); } else if (inputItem.tag) { @@ -257,320 +331,167 @@ function buildBulkIngredients(inputItem, inputFluid, bulkParams) { } } } - + if (inputFluid) { - var fluidAmount = inputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; + var fluidAmount = inputFluid.amount * recipeData.fluidMultiplier + recipeData.fluidAddition; if (fluidAmount > 0) { if (inputFluid.fluid) { - ingredients.push({ - type: 'fluid_stack', - fluid: inputFluid.fluid, - amount: fluidAmount - }); + ingredients.push({ type: 'fluid_stack', fluid: inputFluid.fluid, amount: fluidAmount }); } else if (inputFluid.tag) { - ingredients.push({ - type: 'fluid_tag', - fluid_tag: inputFluid.tag, - amount: fluidAmount - }); + ingredients.push({ type: 'fluid_tag', fluid_tag: inputFluid.tag, amount: fluidAmount }); } } } - + return ingredients; } -// 构建 Bulk Fermenting results(支持独立的物品和流体倍率,以及流体返还) -// outputFluid.amount >= 0 允许零量输出流体(用于满池减益策略的流体返还标记) -function buildBulkResults(outputItem, outputFluid, bulkParams) { +/** + * 构建Bulk配方的输出列表(物品/流体独立倍率,含满池返还的fluidAddition) + * @param {Object} recipeData - 配方数据 + * @returns {Array} results数组 + */ +function buildBulkResults(recipeData) { var results = []; - + var outputItem = recipeData.outputItem; + var outputFluid = recipeData.outputFluid; + if (outputItem) { var itemId = outputItem.id || outputItem.item; if (itemId) { var singleResult = { id: itemId }; - var outputCount = (outputItem.count || 1) * bulkParams.itemMultiplier; - if (outputCount > 1) { - singleResult.count = outputCount; - } - if (outputItem.chance) { - singleResult.chance = outputItem.chance; - } + var outputCount = (outputItem.count || 1) * recipeData.itemMultiplier; + if (outputCount > 1) singleResult.count = outputCount; + if (outputItem.chance) singleResult.chance = outputItem.chance; results.push(singleResult); } } - + if (outputFluid && outputFluid.amount >= 0) { var fluidId = outputFluid.id || outputFluid.fluid; if (fluidId) { - var fluidAmount = outputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; + var fluidAmount = outputFluid.amount * recipeData.fluidMultiplier + recipeData.fluidAddition; if (fluidAmount > 0) { - results.push({ - id: fluidId, - amount: fluidAmount - }); + results.push({ id: fluidId, amount: fluidAmount }); } } } - + return results; } -// ============================================================================ -// 策略:配方分析(添加标记) -// ============================================================================ - -// 策略1:计算 bulk 倍率(默认物品和流体同步倍率) -// 逻辑:原配方输入物品数决定每"组"大小,floor(9 / 原物品数) = 每批最多处理几组 -registerStrategy('bulk_multiplier_check', function(recipeData) { - // 计算原配方输入物品数 - var originalItemCount = 0; - if (recipeData.inputItem) { - originalItemCount = 1; - } - - // 计算 bulk 倍率:floor(9 / 原物品数) - var multiplier = Math.floor(9 / originalItemCount); - - // 将倍率参数存储到 recipeData 中(默认同步倍率) - recipeData.bulkParams.itemMultiplier = multiplier; - recipeData.bulkParams.fluidMultiplier = multiplier; - recipeData.bulkParams.fluidAddition = 0; - - // 如果倍率 > 0,则 bulk_fermenting 可用 - return multiplier > 0; -}, function(data, recipe, recipeData) { - // 这个策略只是添加标记,不做实际处理 - return false; // 继续后续策略 -}); - -// 策略2:流体增益(有流体输出的配方,流体倍率翻倍) -// 原因:输入和输出的流体独立占用流体槽,翻倍可以更好地利用槽位 -registerStrategy('bulk_fluid_bonus', function(recipeData) { - // 条件:有流体输出且输入流体量 > 0 - if (recipeData.outputFluid && recipeData.outputFluid.amount > 0 && - recipeData.inputFluid && recipeData.inputFluid.amount > 0) { - // 流体倍率 = 物品倍率 * 2(确保输入与输出流体同步倍增) - var itemMult = recipeData.bulkParams.itemMultiplier || 1; - recipeData.bulkParams.fluidMultiplier = itemMult * 2; - recipeData.bulkParams.fluidAddition = 0; - return true; - } - return false; -}, function(data, recipe, recipeData) { - // 标记已添加,不做实际处理 - return false; -}); - -// 策略2.1:满池减益(有输入流体但无输出流体,需返还剩余流体) -// 当输入流体 < 1000mB 且配方无输出流体时,bulk 后会产生"空余"流体槽 -// 此策略将剩余的流体返还到输出中(创造一个虚拟输出流体标记) -registerStrategy('bulk_fluid_return', function(recipeData) { - // 条件:有输入流体但无输出流体,且输入流体量 < 1000 - if (recipeData.inputFluid && recipeData.inputFluid.amount > 0 && - (!recipeData.outputFluid || recipeData.outputFluid.amount <= 0) && - recipeData.inputFluid.amount < 1000) { - // 计算返还量:1000 - (输入流体量 * itemMultiplier) - var inputAmount = recipeData.inputFluid.amount; - var itemMult = recipeData.bulkParams.itemMultiplier || 1; - var consumed = inputAmount * itemMult; - var returnAmount = 1000 - consumed; - - // 设置参数:流体倍率与物品倍率相同,添加返还量 - recipeData.bulkParams.fluidMultiplier = itemMult; - recipeData.bulkParams.fluidAddition = returnAmount; - - // 创建虚拟输出流体(用于buildBulkResults处理返还) - var fluidId = recipeData.inputFluid.fluid || recipeData.inputFluid.tag; - if (fluidId) { - recipeData.outputFluid = { id: fluidId, amount: 0 }; - } - - return true; - } - return false; -}, function(data, recipe, recipeData) { - // 标记已添加,不做实际处理 - return false; -}); - -// 策略2.2:特殊配方处理(如 mortar 输出过多,限制倍率为6防止溢出) -registerStrategy('bulk_special_recipe', function(recipeData) { - // 直接判断配方ID - if (recipeData.recipeId === 'tfc:barrel/mortar') { - recipeData.bulkParams.itemMultiplier = 6; // 特殊物品倍率 - recipeData.bulkParams.fluidMultiplier = 6; // 特殊流体倍率 - recipeData.bulkParams.fluidAddition = 0; - return true; - } - return false; -}, function(data, recipe, recipeData) { - // 标记已添加,不做实际处理 - return false; -}); +/** + * 尝试生成Basin Fermenting配方(处理时间=sealTime/5,至少100tick) + * @param {Object} data - 转换上下文 + * @param {Internal.Recipe} recipe - 原TFC配方(用于生成ID) + * @param {Object} recipeData - 配方数据 + */ +function tryBasinFermenting(data, recipe, recipeData) { + if (recipeData.basinMultiplier < 1) return; -// 策略2.3:陈酿酒配方(输出流体以 tfcagedalcohol:aged 开头) -// 陈酿酒需要特殊倍率:物品不倍增,仅流体按 3.6 倍处理 -registerStrategy('bulk_aged_alcohol', function(recipeData) { - // 检查输出流体ID是否以 tfcagedalcohol:aged 开头 - var fluidId = null; - if (recipeData.outputFluid) { - fluidId = recipeData.outputFluid.id || recipeData.outputFluid.fluid; - } - if (fluidId && fluidId.indexOf('tfcagedalcohol:aged') === 0) { - recipeData.bulkParams.itemMultiplier = 1; // 物品倍率1 - recipeData.bulkParams.fluidMultiplier = 3.6; // 陈酿酒流体倍率 - recipeData.bulkParams.fluidAddition = 0; - return true; - } - return false; -}, function(data, recipe, recipeData) { - // 标记已添加,不做实际处理 - return false; -}); + var ingredients = buildBasinIngredients(recipeData.inputItem, recipeData.inputFluid, recipeData.basinMultiplier); + var results = buildBasinResults(recipeData.outputItem, recipeData.outputFluid, recipeData.basinMultiplier); -// 策略3:跳过带 modifiers 的配方(如带有NBT标签的输出物,无法在Create配方中表达) -registerStrategy('skip_modifiers', function(recipeData) { - return recipeData.outputItem && recipeData.outputItem.modifiers; -}, function(data, recipe, recipeData) { - data.stats.skipped++; - return true; // 已处理,不再执行后续策略 -}); + if (results.length === 0 || ingredients.length === 0) return; -// 策略4:Basin Fermenting(处理倍率 >= 1 的配方,物品流体同步倍率) -// 处理时间 = sealTime / 5(最少100tick),用于单槽批量发酵 -registerStrategy('basin_fermenting', function(recipeData) { - return recipeData.flooredMultiplier >= 1; -}, function(data, recipe, recipeData) { - var multiplier = recipeData.flooredMultiplier; - var ingredients = buildIngredients(recipeData.inputItem, recipeData.inputFluid, multiplier); - var results = buildResults(recipeData.outputItem, recipeData.outputFluid, multiplier); - - if (results.length === 0 || ingredients.length === 0) { - return false; - } - var processingTime = Math.max(100, Math.round(recipeData.sealTime / 5)); - var multStr = multiplier.toString(); - + data.event.custom({ type: 'createdieselgenerators:basin_fermenting', ingredients: ingredients, processing_time: processingTime, results: results - }).id('kubejs:tfc_barrel_sealed/basin/' + multStr + '_' + recipe.getId().replace(':', '_')); - + }).id('kubejs:tfc_barrel_sealed/basin/' + recipeData.basinMultiplier + '_' + recipe.getId().replace(':', '_')); + data.stats.basin++; - return true; -}); +} + +/** + * 尝试生成Bulk Fermenting配方(处理时间=sealTime/4,至少100tick) + * @param {Object} data - 转换上下文 + * @param {Internal.Recipe} recipe - 原TFC配方(用于生成ID) + * @param {Object} recipeData - 配方数据 + */ +function tryBulkFermenting(data, recipe, recipeData) { + if (recipeData.itemMultiplier <= 0) return; + + var ingredients = buildBulkIngredients(recipeData); + var results = buildBulkResults(recipeData); + + if (results.length === 0 || ingredients.length === 0) return; -// 策略5:Bulk Fermenting(使用 bulkParams,物品和流体可独立倍率) -// 处理时间 = sealTime / 4(最少100tick),九个槽位同时发酵 -registerStrategy('bulk_fermenting', function(recipeData) { - // 检查是否有有效的 bulkParams(itemMultiplier > 0) - return recipeData.bulkParams && recipeData.bulkParams.itemMultiplier > 0; -}, function(data, recipe, recipeData) { - // 获取 bulk 参数 - var bulkParams = recipeData.bulkParams; - - // 使用独立的构建函数处理 bulk 配方 - var ingredients = buildBulkIngredients(recipeData.inputItem, recipeData.inputFluid, bulkParams); - var results = buildBulkResults(recipeData.outputItem, recipeData.outputFluid, bulkParams); - - if (results.length === 0 || ingredients.length === 0) { - return false; - } - var processingTime = Math.max(100, Math.round(recipeData.sealTime / 4)); - var multStr = bulkParams.itemMultiplier.toString() + '_' + bulkParams.fluidMultiplier.toString(); - + var multStr = recipeData.itemMultiplier + '_' + recipeData.fluidMultiplier; + data.event.custom({ type: 'createdieselgenerators:bulk_fermenting', ingredients: ingredients, processing_time: processingTime, results: results }).id('kubejs:tfc_barrel_sealed/bulk/' + multStr + '_' + recipe.getId().replace(':', '_')); - - data.stats.bulk++; - return true; -}); -// ============================================================================ -// 主流程 -// ============================================================================ - -// 分析配方:计算倍率,然后遍历所有策略的 condition,将适用的策略名存入 recipeData.strategies -// 注意:condition 可能有副作用(如修改 bulkParams),这是设计如此,用于策略间的数据传递 -function analyzeRecipe(recipeData, data) { - // 计算倍数 - recipeData.maxMultiplier = calculateMaxMultiplier(recipeData, data); - recipeData.flooredMultiplier = Math.floor(recipeData.maxMultiplier); - - // 根据条件收集适用的策略 - recipeData.strategies = []; - for (var strategyName in recipeStrategies) { - if (recipeStrategies.hasOwnProperty(strategyName)) { - var strategy = recipeStrategies[strategyName]; - if (strategy.condition(recipeData)) { - recipeData.strategies.push(strategyName); - } - } - } -} - -// 按 analyzeRecipe 收集的策略顺序执行所有 handler -// handler 返回 true 表示已处理(如 skip 策略),但目前不影响后续策略继续执行 -function executeStrategies(data, recipe, recipeData) { - for (var i = 0; i < recipeData.strategies.length; i++) { - var strategyName = recipeData.strategies[i]; - var strategy = recipeStrategies[strategyName]; - if (strategy) { - var result = strategy.handler(data, recipe, recipeData); - if (result === true) { - // 策略已处理,可以选择继续或中断 - // 这里可以根据需要决定是否继续 - } - } - } + data.stats.bulk++; } -// 转换单个配方:解析 → 快速过滤 → 分析策略 → 执行策略 +/** + * 转换单个TFC密封大桶配方:解析 → 过滤modifiers → 计算倍率 → 生成Basin和Bulk配方 + * @param {Object} data - 转换上下文 + * @param {Internal.Recipe} recipe - TFC密封大桶配方 + */ function convertSingleRecipe(data, recipe) { var json = recipe.json; - var recipeData = createRecipeData(json, data, recipe); - - // 快速过滤:带modifiers的配方无法在Create中表达,提前跳过(与策略3重复但更高效) + if (recipeData.outputItem && recipeData.outputItem.modifiers) { data.stats.skipped++; return; } - - // 分析配方,添加策略标记 - analyzeRecipe(recipeData, data); - - // 执行所有适用的策略 - executeStrategies(data, recipe, recipeData); + + recipeData.basinMaxMultiplier = calculateBasinMaxMultiplier(recipeData, data); + recipeData.basinMultiplier = Math.floor(recipeData.basinMaxMultiplier); + + recipeData.base = calculateBulkBase(recipeData); + resolveBulkParams(recipeData); + + tryBasinFermenting(data, recipe, recipeData); + tryBulkFermenting(data, recipe, recipeData); +} + +/** + * 验证TFC堆叠限制是否已正确加载 + * 首次加载时TFC堆叠修改可能尚未生效,getMaxStackSize可能返回错误的64 + * @param {Object} data - 转换上下文 + * @returns {boolean} true=堆叠正确,false=需要重载 + */ +function verifyStackSizeLoaded(data) { + var expected = 32; + var actual = Item.of('minecraft:white_wool', 1).getMaxStackSize(); + + if (actual !== expected) { + var msg = Text.red('[生物柴油修复] 堆叠限制未正确加载(羊毛=' + actual + ',期望=' + expected + '),请执行 /reload 后重试,否则配方倍率可能不准确'); + if (data.event.server) { + data.event.server.tell(msg); + } + console.error('[生物柴油修复] 堆叠限制验证失败:羊毛实际=' + actual + ',期望=' + expected + ',请执行 /reload 后重试,否则配方倍率可能不准确'); + return false; + } + + console.info('[生物柴油修复] 堆叠限制验证通过(羊毛=' + actual + ')'); + return true; } -// 批量转换 +/** + * 批量转换所有TFC密封大桶配方 + * @param {Object} data - 转换上下文 + */ function convertAllRecipes(data) { - console.info('[生物柴油修复] 开始批量转换TFC密封大桶配方...'); - data.event.forEachRecipe({ type: 'tfc:barrel_sealed' }, function(recipe) { convertSingleRecipe(data, recipe); }); - - console.info('[生物柴油修复] 完成!Basin: ' + data.stats.basin + - ', Bulk: ' + data.stats.bulk + - ', 跳过: ' + data.stats.skipped); } -// ============================================================================ -// 执行 -// 入口:遍历所有 tfc:barrel_sealed 配方,逐个转换为 Create 发酵配方 -// ============================================================================ ServerEvents.recipes(function(event) { var data = createConverterData(event); + verifyStackSizeLoaded(data); convertAllRecipes(data); }); diff --git a/server_scripts/biodiesel_fix/fermenting_test.js.pass b/server_scripts/biodiesel_fix/fermenting_test.js.pass deleted file mode 100644 index 9fbc95f..0000000 --- a/server_scripts/biodiesel_fix/fermenting_test.js.pass +++ /dev/null @@ -1,443 +0,0 @@ -// ============================================================================ -// 测试脚本:真正创建配方,测试完整方案 -// ============================================================================ - -ServerEvents.recipes(function(event) { - console.info('[测试] 开始测试4个示例配方(真正创建配方)...'); - - var stats = { basin: 0, bulk: 0, skipped: 0 }; - var FLUID_SLOT_LIMIT = 1000; - - // ============================================================================ - // 工具函数 - // ============================================================================ - - // 计算 basin 倍率:受限的物品堆叠数和流体<1000的同步物体与流体倍率 - function calculateBasinMultiplier(inputItem, inputFluid, outputItem, outputFluid) { - var maxMult = Infinity; - - // 输入物品堆叠限制 - if (inputItem) { - var itemCount = inputItem.count || 1; - var itemId = inputItem.item || inputItem.tag; - if (itemId) { - try { - var maxStack = 64; // 默认值 - if (inputItem.tag) { - var items = Ingredient.of('#' + inputItem.tag).items; - if (items && items.length > 0) { - maxStack = items[0].getMaxStackSize(); - } - } else { - maxStack = Item.of(itemId, 1).getMaxStackSize(); - } - maxMult = Math.min(maxMult, maxStack / itemCount); - } catch (e) { - maxMult = Math.min(maxMult, 64 / itemCount); - } - } - } - - // 输出物品堆叠限制 - if (outputItem) { - var itemCount = outputItem.count || 1; - var itemId = outputItem.id || outputItem.item; - if (itemId) { - try { - var maxStack = Item.of(itemId, 1).getMaxStackSize(); - maxMult = Math.min(maxMult, maxStack / itemCount); - } catch (e) { - maxMult = Math.min(maxMult, 64 / itemCount); - } - } - } - - // 输入流体限制(必须 < 1000) - if (inputFluid && inputFluid.amount > 0) { - maxMult = Math.min(maxMult, 1000 / inputFluid.amount); - } - - // 输出流体限制(必须 < 1000) - if (outputFluid && outputFluid.amount > 0) { - maxMult = Math.min(maxMult, 1000 / outputFluid.amount); - } - - return Math.floor(maxMult); - } - - function buildBasinIngredients(inputItem, inputFluid, multiplier) { - var ingredients = []; - - if (inputItem && multiplier > 0) { - for (var i = 0; i < multiplier; i++) { - if (inputItem.item) { - ingredients.push({ item: inputItem.item }); - } else if (inputItem.tag) { - ingredients.push({ tag: inputItem.tag }); - } - } - } - - if (inputFluid && multiplier > 0) { - var fluidAmount = inputFluid.amount * multiplier; - if (fluidAmount > 0) { - if (inputFluid.fluid) { - ingredients.push({ - type: 'fluid_stack', - fluid: inputFluid.fluid, - amount: fluidAmount - }); - } else if (inputFluid.tag) { - ingredients.push({ - type: 'fluid_tag', - fluid_tag: inputFluid.tag, - amount: fluidAmount - }); - } - } - } - - return ingredients; - } - - function buildBasinResults(outputItem, outputFluid, multiplier) { - var results = []; - - if (outputItem && multiplier > 0) { - var itemId = outputItem.id || outputItem.item; - if (itemId) { - var singleResult = { id: itemId }; - var outputCount = (outputItem.count || 1) * multiplier; - if (outputCount > 1) { - singleResult.count = outputCount; - } - results.push(singleResult); - } - } - - if (outputFluid && outputFluid.amount > 0 && multiplier > 0) { - var fluidId = outputFluid.id || outputFluid.fluid; - if (fluidId) { - var fluidAmount = outputFluid.amount * multiplier; - if (fluidAmount > 0) { - results.push({ - id: fluidId, - amount: fluidAmount - }); - } - } - } - - return results; - } - - function buildBulkIngredients(inputItem, inputFluid, bulkParams) { - var ingredients = []; - - if (inputItem) { - var itemMult = bulkParams.itemMultiplier; - for (var i = 0; i < itemMult; i++) { - if (inputItem.item) { - ingredients.push({ item: inputItem.item }); - } else if (inputItem.tag) { - ingredients.push({ tag: inputItem.tag }); - } - } - } - - if (inputFluid) { - var fluidAmount = inputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; - if (fluidAmount > 0) { - if (inputFluid.fluid) { - ingredients.push({ - type: 'fluid_stack', - fluid: inputFluid.fluid, - amount: fluidAmount - }); - } else if (inputFluid.tag) { - ingredients.push({ - type: 'fluid_tag', - fluid_tag: inputFluid.tag, - amount: fluidAmount - }); - } - } - } - - return ingredients; - } - - function buildBulkResults(outputItem, outputFluid, bulkParams) { - var results = []; - - if (outputItem) { - var itemId = outputItem.id || outputItem.item; - if (itemId) { - var singleResult = { id: itemId }; - var outputCount = (outputItem.count || 1) * bulkParams.itemMultiplier; - if (outputCount > 1) { - singleResult.count = outputCount; - } - results.push(singleResult); - } - } - - if (outputFluid && outputFluid.amount >= 0) { - var fluidId = outputFluid.id || outputFluid.fluid; - if (fluidId) { - var fluidAmount = outputFluid.amount * bulkParams.fluidMultiplier + bulkParams.fluidAddition; - if (fluidAmount > 0) { - results.push({ - id: fluidId, - amount: fluidAmount - }); - } - } - } - - return results; - } - - // ============================================================================ - // 测试用例1:FirmaLife 奶酪 - // ============================================================================ - console.info('--- 测试1:FirmaLife 奶酪 ---'); - - var test1 = { - recipeId: 'firmalife:barrel/cheese', - duration: 1000, - input_item: { count: 1, item: 'firmalife:cheesecloth' }, - input_fluid: { amount: 1000, tag: 'firmalife:milks' }, - output_item: { count: 1, id: 'firmalife:cheesecloth' }, - output_fluid: { amount: 1000, id: 'firmalife:cream' } - }; - - // Basin倍率计算:min(64/1, 64/1, 1000/1000, 1000/1000) = 1 - var basinMult1 = calculateBasinMultiplier(test1.input_item, test1.input_fluid, test1.output_item, test1.output_fluid); - console.info('[测试1] Basin倍率: ' + basinMult1); - - var bulkParams1 = { - itemMultiplier: 9, - fluidMultiplier: 9, - fluidAddition: 0 - }; - - // Basin Fermenting(同步倍率) - var ingredients1_basin = buildBasinIngredients(test1.input_item, test1.input_fluid, basinMult1); - var results1_basin = buildBasinResults(test1.output_item, test1.output_fluid, basinMult1); - - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients1_basin, - processing_time: Math.max(100, Math.round(test1.duration / 5)), - results: results1_basin - }).id('kubejs:test/basin/firmalife_barrel_cheese'); - - stats.basin++; - console.info('[测试] 创建 Basin: ' + test1.recipeId); - console.info(' BasinMultiplier: ' + basinMult1); - console.info(' Ingredients: ' + JSON.stringify(ingredients1_basin)); - console.info(' Results: ' + JSON.stringify(results1_basin)); - - // Bulk Fermenting - var ingredients1_bulk = buildBulkIngredients(test1.input_item, test1.input_fluid, bulkParams1); - var results1_bulk = buildBulkResults(test1.output_item, test1.output_fluid, bulkParams1); - - event.custom({ - type: 'createdieselgenerators:bulk_fermenting', - ingredients: ingredients1_bulk, - processing_time: Math.max(100, Math.round(test1.duration / 4)), - results: results1_bulk - }).id('kubejs:test/bulk/firmalife_barrel_cheese'); - - stats.bulk++; - console.info('[测试] 创建 Bulk: ' + test1.recipeId); - console.info(' BulkParams: ' + JSON.stringify(bulkParams1)); - console.info(' Ingredients: ' + JSON.stringify(ingredients1_bulk)); - console.info(' Results: ' + JSON.stringify(results1_bulk)); - - // ============================================================================ - // 测试用例2:陈酿玉米威士忌 - // ============================================================================ - console.info('--- 测试2:陈酿玉米威士忌 ---'); - - var test2 = { - recipeId: 'tfc:barrel/aged_corn_whiskey', - duration: 691200, - input_fluid: { fluid: 'tfc:corn_whiskey', amount: 10000 }, - output_fluid: { id: 'tfcagedalcohol:aged_corn_whiskey', amount: 10000 } - }; - - // Basin倍率计算:min(1000/10000, 1000/10000) = 0.1 → floor = 0 - var basinMult2 = calculateBasinMultiplier(null, test2.input_fluid, null, test2.output_fluid); - console.info('[测试2] Basin倍率: ' + basinMult2); - - var bulkParams2 = { - itemMultiplier: 1, - fluidMultiplier: 3.6, - fluidAddition: 0 - }; - - // Basin Fermenting(倍率为0,不创建) - if (basinMult2 > 0) { - var ingredients2_basin = buildBasinIngredients(null, test2.input_fluid, basinMult2); - var results2_basin = buildBasinResults(null, test2.output_fluid, basinMult2); - - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients2_basin, - processing_time: Math.max(100, Math.round(test2.duration / 5)), - results: results2_basin - }).id('kubejs:test/basin/tfc_barrel_aged_corn_whiskey'); - - stats.basin++; - console.info('[测试] 创建 Basin: ' + test2.recipeId); - console.info(' BasinMultiplier: ' + basinMult2); - } else { - console.info('[测试] Basin倍率=0,跳过创建 Basin'); - } - - // Bulk Fermenting - var ingredients2_bulk = buildBulkIngredients(null, test2.input_fluid, bulkParams2); - var results2_bulk = buildBulkResults(null, test2.output_fluid, bulkParams2); - - event.custom({ - type: 'createdieselgenerators:bulk_fermenting', - ingredients: ingredients2_bulk, - processing_time: Math.max(100, Math.round(test2.duration / 4)), - results: results2_bulk - }).id('kubejs:test/bulk/tfc_barrel_aged_corn_whiskey'); - - stats.bulk++; - console.info('[测试] 创建 Bulk: ' + test2.recipeId); - console.info(' BulkParams: ' + JSON.stringify(bulkParams2)); - console.info(' Ingredients: ' + JSON.stringify(ingredients2_bulk)); - console.info(' Results: ' + JSON.stringify(results2_bulk)); - - // ============================================================================ - // 测试用例3:black_wool(无流体输出,需返还染料) - // ============================================================================ - console.info('--- 测试3:black_wool ---'); - - var test3 = { - recipeId: 'tfc:barrel/black_wool', - duration: 1200, - input_item: { count: 1, item: 'minecraft:white_wool' }, - input_fluid: { fluid: 'tfc:black_dye', amount: 25 }, - output_item: { count: 1, id: 'minecraft:black_wool' } - }; - - // Basin倍率计算:min(64/1, 1000/25) = 40 - var basinMult3 = calculateBasinMultiplier(test3.input_item, test3.input_fluid, test3.output_item, null); - console.info('[测试3] Basin倍率: ' + basinMult3); - - // 计算返还量:25 * 9 = 225, 1000 - 225 = 775 - var bulkParams3 = { - itemMultiplier: 9, - fluidMultiplier: 9, - fluidAddition: 775 - }; - - // 创建虚拟输出流体(用于buildBulkResults处理返还) - var virtualOutputFluid3 = { id: 'tfc:black_dye', amount: 0 }; - - // Basin Fermenting(无返还逻辑,因为 basin 倍率是受限计算出来的) - var ingredients3_basin = buildBasinIngredients(test3.input_item, test3.input_fluid, basinMult3); - var results3_basin = buildBasinResults(test3.output_item, null, basinMult3); - - if (results3_basin.length > 0 && ingredients3_basin.length > 0) { - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients3_basin, - processing_time: Math.max(100, Math.round(test3.duration / 5)), - results: results3_basin - }).id('kubejs:test/basin/tfc_barrel_black_wool'); - - stats.basin++; - console.info('[测试] 创建 Basin: ' + test3.recipeId); - console.info(' BasinMultiplier: ' + basinMult3); - console.info(' Ingredients: ' + JSON.stringify(ingredients3_basin)); - console.info(' Results: ' + JSON.stringify(results3_basin)); - } - - // Bulk Fermenting(有返还逻辑) - var ingredients3_bulk = buildBulkIngredients(test3.input_item, test3.input_fluid, bulkParams3); - var results3_bulk = buildBulkResults(test3.output_item, virtualOutputFluid3, bulkParams3); - - event.custom({ - type: 'createdieselgenerators:bulk_fermenting', - ingredients: ingredients3_bulk, - processing_time: Math.max(100, Math.round(test3.duration / 4)), - results: results3_bulk - }).id('kubejs:test/bulk/tfc_barrel_black_wool'); - - stats.bulk++; - console.info('[测试] 创建 Bulk: ' + test3.recipeId); - console.info(' BulkParams: ' + JSON.stringify(bulkParams3)); - console.info(' Ingredients: ' + JSON.stringify(ingredients3_bulk)); - console.info(' Results: ' + JSON.stringify(results3_bulk)); - - // ============================================================================ - // 测试用例4:mortar(特殊配方) - // ============================================================================ - console.info('--- 测试4:mortar ---'); - - var test4 = { - recipeId: 'tfc:barrel/mortar', - duration: 7200, - input_item: { count: 1, tag: 'c:sands' }, - input_fluid: { fluid: 'tfc:limewater', amount: 100 }, - output_item: { count: 16, id: 'tfc:mortar' } - }; - - // Basin倍率计算:min(64/1, 64/16, 1000/100) = 4 - var basinMult4 = calculateBasinMultiplier(test4.input_item, test4.input_fluid, test4.output_item, null); - console.info('[测试4] Basin倍率: ' + basinMult4); - - var bulkParams4 = { - itemMultiplier: 6, - fluidMultiplier: 6, - fluidAddition: 0 - }; - - // Basin Fermenting(倍率4,是受限计算得出的) - var ingredients4_basin = buildBasinIngredients(test4.input_item, test4.input_fluid, basinMult4); - var results4_basin = buildBasinResults(test4.output_item, null, basinMult4); - - if (results4_basin.length > 0 && ingredients4_basin.length > 0) { - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients4_basin, - processing_time: Math.max(100, Math.round(test4.duration / 5)), - results: results4_basin - }).id('kubejs:test/basin/tfc_barrel_mortar'); - - stats.basin++; - console.info('[测试] 创建 Basin: ' + test4.recipeId); - console.info(' BasinMultiplier: ' + basinMult4); - console.info(' Ingredients: ' + JSON.stringify(ingredients4_basin)); - console.info(' Results: ' + JSON.stringify(results4_basin)); - } - - // Bulk Fermenting(特殊倍率6) - var ingredients4_bulk = buildBulkIngredients(test4.input_item, test4.input_fluid, bulkParams4); - var results4_bulk = buildBulkResults(test4.output_item, null, bulkParams4); - - event.custom({ - type: 'createdieselgenerators:bulk_fermenting', - ingredients: ingredients4_bulk, - processing_time: Math.max(100, Math.round(test4.duration / 4)), - results: results4_bulk - }).id('kubejs:test/bulk/tfc_barrel_mortar'); - - stats.bulk++; - console.info('[测试] 创建 Bulk: ' + test4.recipeId); - console.info(' BulkParams: ' + JSON.stringify(bulkParams4)); - console.info(' Ingredients: ' + JSON.stringify(ingredients4_bulk)); - console.info(' Results: ' + JSON.stringify(results4_bulk)); - - // ============================================================================ - // 完成 - // ============================================================================ - console.info('[测试] 完成!Basin: ' + stats.basin + ', Bulk: ' + stats.bulk); -}); diff --git a/server_scripts/test_basin_fermenting_schema.js.faild b/server_scripts/test_basin_fermenting_schema.js.faild deleted file mode 100644 index 65eebab..0000000 --- a/server_scripts/test_basin_fermenting_schema.js.faild +++ /dev/null @@ -1,67 +0,0 @@ -// ============================================================================ -// 测试脚本:使用 basin_fermenting 配方 schema -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[DEBUG] 开始测试 basin_fermenting 配方 schema...'); - - // 测试物品 - let testItemId = 'tfc:food/barley_flour'; - - // 获取堆叠限制 - let actualMaxStack = 64; - try { - actualMaxStack = Item.of(testItemId, 1).getMaxStackSize(); - console.info(`[DEBUG] 获取到 ${testItemId} 的堆叠限制 = ${actualMaxStack}`); - } catch (e) { - console.info(`[DEBUG] 获取堆叠限制失败: ${e.message},使用默认值 64`); - } - - let FLUID_SLOT_LIMIT = 1000; - let maxMultiplier = Infinity; - - // 输入物品: barley_flour, count = 1 - let itemCount = 1; - let itemMultiplier = actualMaxStack / itemCount; - maxMultiplier = Math.min(maxMultiplier, itemMultiplier); - console.info('[DEBUG] 输入物品: ' + testItemId + ', count=' + itemCount + ', maxStack=' + actualMaxStack + ', multiplier=' + itemMultiplier.toFixed(2)); - - // 输入流体: water, amount = 500 - let inputFluidAmount = 500; - let inputFluidMultiplier = FLUID_SLOT_LIMIT / inputFluidAmount; - maxMultiplier = Math.min(maxMultiplier, inputFluidMultiplier); - console.info('[DEBUG] 输入流体: minecraft:water, amount=' + inputFluidAmount + ', multiplier=' + inputFluidMultiplier.toFixed(2)); - - // 输出流体: beer, amount = 500 - let outputFluidAmount = 500; - let outputFluidMultiplier = FLUID_SLOT_LIMIT / outputFluidAmount; - maxMultiplier = Math.min(maxMultiplier, outputFluidMultiplier); - console.info('[DEBUG] 输出流体: tfc:beer, amount=' + outputFluidAmount + ', multiplier=' + outputFluidMultiplier.toFixed(2)); - - let flooredMultiplier = Math.floor(maxMultiplier); - console.info('[DEBUG] 向下取整 flooredMultiplier = ' + flooredMultiplier); - - // 创建测试配方 - 使用新的配方 schema - if (flooredMultiplier >= 1) { - console.info('[DEBUG] 创建测试配方...'); - - let inputItemCount = 1 * flooredMultiplier; - let finalInputFluidAmount = 500 * flooredMultiplier; - let finalOutputFluidAmount = 500 * flooredMultiplier; - - event.recipes.createdieselgenerators.basinFermenting([ - Ingredient.of({ - type: 'tfc:and', - children: [ - { item: testItemId }, - { type: 'tfc:not_rotten' } - ] - }, inputItemCount), - Fluid.of('minecraft:water', finalInputFluidAmount) - ], [ - Fluid.of('tfc:beer', finalOutputFluidAmount) - ]).id('kubejs:test_fermenting/beer/' + flooredMultiplier + '_from_barley_flour'); - - console.info('[DEBUG] 成功创建配方: kubejs:test_fermenting/beer/' + flooredMultiplier + '_from_barley_flour'); - } -}); diff --git a/server_scripts/test_fermenting_recipes.js.pass b/server_scripts/test_fermenting_recipes.js.pass deleted file mode 100644 index 4cf9375..0000000 --- a/server_scripts/test_fermenting_recipes.js.pass +++ /dev/null @@ -1,96 +0,0 @@ -// ============================================================================ -// 手动创建TFC密封大桶配方对应的CDG发酵配方(完全按照参考格式) -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[生物柴油修复] 开始手动创建测试配方(完全按照参考格式)...'); - - // 1. black_wool - 黑色羊毛染色 - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: [ - { item: 'minecraft:white_wool' }, - { - type: 'fluid_stack', - fluid: 'tfc:black_dye', - amount: 25 - } - ], - processing_time: Math.max(100, Math.round(1200 / 5)), - results: [ - { id: 'minecraft:black_wool' } - ] - }).id('kubejs:test/black_wool'); - - // 2. corn_whiskey - 玉米威士忌 - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: [ - { - type: 'tfc:and', - children: [ - { item: 'tfc:food/maize_flour' }, - { type: 'tfc:not_rotten' } - ] - }, - { - type: 'fluid_stack', - fluid: 'minecraft:water', - amount: 500 - } - ], - processing_time: Math.max(100, Math.round(72000 / 5)), - results: [ - { - id: 'tfc:corn_whiskey', - amount: 500 - } - ] - }).id('kubejs:test/corn_whiskey'); - - // 3. sugar - 糖 - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: [ - { - type: 'tfc:and', - children: [ - { item: 'tfc:food/sugarcane' }, - { type: 'tfc:not_rotten' } - ] - }, - { - type: 'fluid_stack', - fluid: 'minecraft:water', - amount: 600 - } - ], - processing_time: Math.max(100, Math.round(7200 / 5)), - results: [ - { id: 'minecraft:sugar' } - ] - }).id('kubejs:test/sugar'); - - // 4. firmalife_cream - Firmalife奶油制作(使用流体标签格式) - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: [ - { item: 'firmalife:cheesecloth' }, - { - type: 'fluid_tag', // ✅ 使用fluid_tag类型 - fluid_tag: 'firmalife:milks', - amount: 1000 - } - ], - processing_time: Math.max(100, Math.round(1000 / 5)), - results: [ - { id: 'firmalife:cheesecloth' }, - { - id: 'firmalife:cream', - amount: 1000 - } - ] - }).id('kubejs:test/firmalife_cream'); - - console.info('[生物柴油修复] 手动测试配方(完全按照参考格式)创建完成!'); -}); diff --git a/server_scripts/test_large_leather.js.pass b/server_scripts/test_large_leather.js.pass deleted file mode 100644 index bb313f2..0000000 --- a/server_scripts/test_large_leather.js.pass +++ /dev/null @@ -1,26 +0,0 @@ -// ============================================================================ -// 测试large_leather和medium_leather配方转换 -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[测试] 开始测试皮革配方...'); - - // 测试: medium用直接count字段 - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: [ - { item: 'tfc:medium_prepared_hide' }, - { - type: 'fluid_stack', - fluid: 'tfc:tannin', - amount: 500 - } - ], - processing_time: Math.max(100, Math.round(7200 / 5)), - results: [ - { id: 'minecraft:leather', count: 2 } - ] - }).id('kubejs:test/medium_leather_count'); - - console.info('[测试] 皮革配方测试创建完成!'); -}); diff --git a/server_scripts/test_maxstack_debug.js.pass b/server_scripts/test_maxstack_debug.js.pass deleted file mode 100644 index 823eda1..0000000 --- a/server_scripts/test_maxstack_debug.js.pass +++ /dev/null @@ -1,138 +0,0 @@ -// ============================================================================ -// 调试脚本:测试获取 tfc:food/barley_flour 的最大堆叠数量 -// ============================================================================ -// 以下注释内容将辅助正式脚本修改过程,不允许删除 -// 重要发现: -// 1. maxMultiplier 初始值问题: -// - 错误:let maxMultiplier = 1.0; -// - 正确:let maxMultiplier = Infinity; -// - 原因:使用 Math.min() 取最小值时,初始值必须大于所有可能的乘数 -// - 示例:若乘数为 64, 2, 2,初始值为 1 会导致结果始终为 1 -// -// 2. 获取堆叠限制的方法: -// - Item.of().getMaxStackSize() 实际上能返回正确的值(包括 TFC 的 Weight 组件影响) -// - 测试结果:barley_flour 返回 32,符合预期 -// -// 3. 新发现 (2026-05-16): -// - event.recipes.createdieselgenerators.basinFermenting() 路线失败 -// - 直接使用 event.custom() 配合 { type: 'tfc:and', children: [...] } 结构成功 -// - 关键:用数组重复代替数量倍增 -// 例如 flooredMultiplier = 2 时,把 { type: 'tfc:and', children: [...] } 重复2次 -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[DEBUG] ============================================'); - console.info('[DEBUG] 测试配方1: TFC酿酒 (barley_flour + water -> beer)'); - console.info('[DEBUG] ============================================'); - - let testItemId1 = 'tfc:food/barley_flour'; - let inputFluidId1 = 'minecraft:water'; - let outputFluidId1 = 'tfc:beer'; - let inputFluidAmount1 = 500; - let outputFluidAmount1 = 500; - let inputItemCount1 = 1; - - let actualMaxStack1 = Item.of(testItemId1, 1).getMaxStackSize(); - console.info(`[DEBUG] ${testItemId1} 堆叠限制 = ${actualMaxStack1}`); - - let FLUID_SLOT_LIMIT = 1000; - let maxMultiplier1 = Infinity; - let itemMultiplier1 = actualMaxStack1 / inputItemCount1; - let fluidMultiplier1 = FLUID_SLOT_LIMIT / inputFluidAmount1; - let outputFluidMultiplier1 = FLUID_SLOT_LIMIT / outputFluidAmount1; - maxMultiplier1 = Math.min(maxMultiplier1, itemMultiplier1, fluidMultiplier1, outputFluidMultiplier1); - - let flooredMultiplier1 = Math.floor(maxMultiplier1); - console.info(`[DEBUG] maxMultiplier=${maxMultiplier1.toFixed(2)}, flooredMultiplier=${flooredMultiplier1}`); - - if (flooredMultiplier1 >= 1) { - let ingredients1 = []; - let results1 = []; - - // 用数组重复实现物品倍增 - for (let i = 0; i < flooredMultiplier1; i++) { - ingredients1.push({ - type: 'tfc:and', - children: [ - { item: testItemId1 }, - { type: 'tfc:not_rotten' } - ] - }); - } - - // 流体倍增用 amount - ingredients1.push({ - type: 'fluid_stack', - fluid: inputFluidId1, - amount: inputFluidAmount1 * flooredMultiplier1 - }); - - // 输出流体 - results1.push({ - id: outputFluidId1, - amount: outputFluidAmount1 * flooredMultiplier1 - }); - - console.info(`[DEBUG] 创建配方1: ${flooredMultiplier1}x ${testItemId1} + ${inputFluidAmount1 * flooredMultiplier1}mB water -> ${outputFluidAmount1 * flooredMultiplier1}mB beer`); - - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients1, - processing_time: 400, - results: results1 - }).id(`kubejs:test_fermenting/barley_flour_x${flooredMultiplier1}`); - } - - console.info('[DEBUG] ============================================'); - console.info('[DEBUG] 测试配方2: black_wool (white_wool + black_dye -> black_wool)'); - console.info('[DEBUG] ============================================'); - - let testItemId2 = 'minecraft:white_wool'; - let inputFluidId2 = 'tfc:black_dye'; - let outputItemId2 = 'minecraft:black_wool'; - let inputFluidAmount2 = 25; - let inputItemCount2 = 1; - - let actualMaxStack2 = Item.of(testItemId2, 1).getMaxStackSize(); - console.info(`[DEBUG] ${testItemId2} 堆叠限制 = ${actualMaxStack2}`); - - let maxMultiplier2 = Infinity; - let itemMultiplier2 = actualMaxStack2 / inputItemCount2; - let fluidMultiplier2 = FLUID_SLOT_LIMIT / inputFluidAmount2; - maxMultiplier2 = Math.min(maxMultiplier2, itemMultiplier2, fluidMultiplier2); - - let flooredMultiplier2 = Math.floor(maxMultiplier2); - console.info(`[DEBUG] maxMultiplier=${maxMultiplier2.toFixed(2)}, flooredMultiplier=${flooredMultiplier2}`); - - if (flooredMultiplier2 >= 1) { - let ingredients2 = []; - let results2 = []; - - // 用数组重复实现物品倍增 - for (let i = 0; i < flooredMultiplier2; i++) { - ingredients2.push({ item: testItemId2 }); - } - - // 流体倍增用 amount - ingredients2.push({ - type: 'fluid_stack', - fluid: inputFluidId2, - amount: inputFluidAmount2 * flooredMultiplier2 - }); - - // 输出物品 - results2.push({ - id: outputItemId2, - count: flooredMultiplier2 - }); - - console.info(`[DEBUG] 创建配方2: ${flooredMultiplier2}x ${testItemId2} + ${inputFluidAmount2 * flooredMultiplier2}mB ${inputFluidId2} -> ${flooredMultiplier2}x ${outputItemId2}`); - - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: ingredients2, - processing_time: 100, - results: results2 - }).id(`kubejs:test_fermenting/wool_x${flooredMultiplier2}`); - } -}); diff --git a/server_scripts/test_not_rotten.js.pass b/server_scripts/test_not_rotten.js.pass deleted file mode 100644 index a2f676b..0000000 --- a/server_scripts/test_not_rotten.js.pass +++ /dev/null @@ -1,56 +0,0 @@ -// ============================================================================ -// 测试脚本:非腐败条件限制器在Create配方中的使用 -// 使用Ingredient.of(物品类型, 数量)的方式实现多物品限制 -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[生物柴油修复测试] 开始测试非腐败条件限制器...'); - - // 测试1:橄榄塑形配方(10个新鲜橄榄 → 800mb橄榄油) - event.recipes.create.compacting( - [Fluid.of('tfc:olive_oil', 800)], - [ - Ingredient.of({ - type: 'tfc:and', - children: [ - { item: 'tfc:food/olive' }, - { type: 'tfc:not_rotten' } - ] - }, 10) - ], - 100 - ).id('kubejs:test_olive_to_oil_not_rotten'); - - // 测试2:小麦面粉混合配方(16个新鲜小麦面粉 + 水 → 啤酒) - event.recipes.create.mixing( - [Fluid.of('tfc:beer', 1000)], - [ - Ingredient.of({ - type: 'tfc:and', - children: [ - { item: 'tfc:food/wheat_flour' }, - { type: 'tfc:not_rotten' } - ] - }, 16), - Fluid.of('minecraft:water', 1000) - ], - 100 - ).id('kubejs:test_wheat_flour_to_beer_not_rotten'); - - // 测试3:小麦研磨配方(1个新鲜小麦种子 → 面粉) - event.recipes.create.milling( - ['tfc:food/wheat_flour'], - [ - Ingredient.of({ - type: 'tfc:and', - children: [ - { item: 'tfc:food/wheat_grain' }, - { type: 'tfc:not_rotten' } - ] - }) - ], - 50 - ).id('kubejs:test_wheat_grain_to_flour_not_rotten'); - - console.info('[生物柴油修复测试] 所有配方创建完成!'); -}); diff --git a/server_scripts/test_tfc_modifiers.js.faild b/server_scripts/test_tfc_modifiers.js.faild deleted file mode 100644 index f43f517..0000000 --- a/server_scripts/test_tfc_modifiers.js.faild +++ /dev/null @@ -1,32 +0,0 @@ -// ============================================================================ -// 测试TFC修饰符格式是否被CDG支持 -// ============================================================================ - -ServerEvents.recipes(event => { - console.info('[生物柴油修复] 开始测试TFC修饰符格式...'); - - // 测试black_dyeable - 带TFC修饰符的输出 - event.custom({ - type: 'createdieselgenerators:basin_fermenting', - ingredients: [ - { tag: 'minecraft:dyeable' }, - { - type: 'fluid_stack', - fluid: 'tfc:black_dye', - amount: 25 - } - ], - processing_time: Math.max(100, Math.round(1200 / 5)), - results: [ - { - item: 'minecraft:leather', // 试试直接用item字段 - modifiers: [ - { type: 'tfc:copy_input' }, - { type: 'tfc:dye_leather', color: 'black' } - ] - } - ] - }).id('kubejs:test/black_dyeable_with_modifiers'); - - console.info('[生物柴油修复] TFC修饰符格式测试完成!'); -}); From 65547fbcc5f6547bedde46fe983b92c5eaa6e25d Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Mon, 18 May 2026 15:07:39 +0000 Subject: [PATCH 08/14] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=98=BB=E6=96=AD?= =?UTF-8?q?=E6=97=A0=E8=BE=93=E5=87=BA=E4=BB=85trait=E4=BF=AE=E9=A5=B0?= =?UTF-8?q?=E7=9A=84=E5=AF=86=E5=B0=81=E5=A4=A7=E6=A1=B6=E9=85=8D=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_scripts/biodiesel_fix/fermenting_from_barrel.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js index bae2a36..c9321a2 100644 --- a/server_scripts/biodiesel_fix/fermenting_from_barrel.js +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -447,6 +447,11 @@ function convertSingleRecipe(data, recipe) { return; } + if (!recipeData.outputItem && !recipeData.outputFluid) { + data.stats.skipped++; + return; + } + recipeData.basinMaxMultiplier = calculateBasinMaxMultiplier(recipeData, data); recipeData.basinMultiplier = Math.floor(recipeData.basinMaxMultiplier); From 95a21480b5c40f4ef83a62e1ea5da91367be8d18 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Tue, 19 May 2026 10:47:46 +0000 Subject: [PATCH 09/14] =?UTF-8?q?=E5=9F=BA=E4=BA=8ETFC=E7=9E=AC=E6=97=B6?= =?UTF-8?q?=E5=A4=A7=E6=A1=B6=E9=85=8D=E6=96=B9=E6=89=B9=E9=87=8F=E5=88=9B?= =?UTF-8?q?=E5=BB=BACreate=E6=B7=B7=E5=90=88=E6=90=85=E6=8B=8C=E9=85=8D?= =?UTF-8?q?=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mixing_from_barrel_instant.js | 349 ++++++++++++++++++ .../biodiesel_fix/test_compound.js.pass | 230 ++++++++++++ .../biodiesel_fix/test_recipes.js.pass | 32 ++ 3 files changed, 611 insertions(+) create mode 100644 server_scripts/biodiesel_fix/mixing_from_barrel_instant.js create mode 100644 server_scripts/biodiesel_fix/test_compound.js.pass create mode 100644 server_scripts/biodiesel_fix/test_recipes.js.pass diff --git a/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js b/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js new file mode 100644 index 0000000..13ecdc7 --- /dev/null +++ b/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js @@ -0,0 +1,349 @@ +// ============================================================================ +// 批量从TFC即时大桶配方创建Create Mixing配方 +// 支持:tfc:barrel_instant(物品+流体)和 tfc:barrel_instant_fluid(纯流体) +// 倍增方案与 ferenting_from_barrel.js 的 Basin 配方一致: +// 物品受堆叠上限约束,流体受 1000mB 单槽约束 +// ============================================================================ + +/** + * 创建贯穿转换流程的上下文对象 + * @param {Internal.RecipeEventJS} event - 配方事件 + * @returns {Object} 包含事件引用、统计计数器和常量 + */ +function createConverterData(event) { + return { + event: event, + stats: { instant: 0, instantFluid: 0, skipped: 0 }, + FLUID_SLOT_LIMIT: 1000, + PROCESSING_TIME: 100 + }; +} + +/** + * 从 tfc:barrel_instant 配方 JSON 中提取物品和流体字段 + * @param {Internal.JsonObject} json - 配方的JSON对象 + * @param {Internal.Recipe} recipe - TFC配方 + * @returns {Object} 标准化后的 inputItem/inputFluid/outputItem/outputFluid + */ +function createInstantData(json, recipe) { + return { + inputItem: parseJsonField(json, 'input_item'), + inputFluid: parseJsonField(json, 'input_fluid'), + outputItem: parseJsonField(json, 'output_item'), + outputFluid: parseJsonField(json, 'output_fluid'), + recipeId: recipe ? recipe.getId() : null + }; +} + +/** + * 从 tfc:barrel_instant_fluid 配方 JSON 中提取纯流体混合字段 + * @param {Internal.JsonObject} json - 配方的JSON对象 + * @param {Internal.Recipe} recipe - TFC配方 + * @returns {Object} 包含 primaryFluid/addedFluid/outputFluid + */ +function createInstantFluidData(json, recipe) { + return { + primaryFluid: parseJsonField(json, 'primary_fluid'), + addedFluid: parseJsonField(json, 'added_fluid'), + outputFluid: parseJsonField(json, 'output_fluid'), + recipeId: recipe ? recipe.getId() : null + }; +} + +/** + * 安全解析 JSON 字段 + * @param {Internal.JsonObject} json - JSON对象 + * @param {string} fieldName - 字段名 + * @returns {Object|null} 解析后的对象,失败返回 null + */ +function parseJsonField(json, fieldName) { + if (json.has(fieldName)) { + try { + return JSON.parse(json.get(fieldName).toString()); + } catch (e) { + return null; + } + } + return null; +} + +/** + * 获取物品最大堆叠数(tag 输入时取该 tag 下所有物品的最小值) + * @param {Object} itemData - {item/tag, count} + * @returns {number|null} 最大堆叠数 + */ +function getMaxStackSize(itemData) { + var itemId = itemData.item || itemData.tag; + if (!itemId) return null; + try { + if (itemData.tag) { + var tagItems = Ingredient.of('#' + itemData.tag).stackArray; + if (tagItems && tagItems.length > 0) { + var minStack = tagItems[0].getMaxStackSize(); + for (var i = 1; i < tagItems.length; i++) { + if (tagItems[i].getMaxStackSize() < minStack) { + minStack = tagItems[i].getMaxStackSize(); + } + } + return minStack; + } + } else { + return Item.of(itemId, 1).getMaxStackSize(); + } + } catch (e) { + return 64; + } + return null; +} + +/** + * 计算理论上最大整数倍率 + * 综合约束:输入/输出物品堆叠上限、输入/输出流体 1000mB 槽上限 + * @param {Object} recipeData - 配方数据 + * @param {Object} data - 转换上下文(提供 FLUID_SLOT_LIMIT) + * @returns {number} 理论最大倍率 + */ +function calculateMaxMultiplier(recipeData, data) { + var maxMultiplier = Infinity; + + if (recipeData.inputItem) { + if ((recipeData.inputItem.type === 'neoforge:compound' || recipeData.inputItem.type === 'tfc:and') && recipeData.inputItem.children) { + for (var i = 0; i < recipeData.inputItem.children.length; i++) { + var child = recipeData.inputItem.children[i]; + var maxStack = getMaxStackSize(child); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(maxStack / (recipeData.inputItem.count || 1))); + } + } + } else { + var itemId = recipeData.inputItem.item || recipeData.inputItem.tag; + if (itemId) { + var count = recipeData.inputItem.count || 1; + var maxStack = getMaxStackSize(recipeData.inputItem); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(maxStack / count)); + } + } + } + } + + if (recipeData.outputItem) { + var outputId = recipeData.outputItem.id || recipeData.outputItem.item; + if (outputId) { + var count = recipeData.outputItem.count || 1; + try { + var maxStack = Item.of(outputId, 1).getMaxStackSize(); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(maxStack / count)); + } + } catch (e) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(64 / count)); + } + } + } + + if (recipeData.inputFluid && recipeData.inputFluid.amount > 0) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(data.FLUID_SLOT_LIMIT / recipeData.inputFluid.amount)); + } + + if (recipeData.outputFluid && recipeData.outputFluid.amount > 0) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(data.FLUID_SLOT_LIMIT / recipeData.outputFluid.amount)); + } + + return maxMultiplier; +} + +/** + * 构建 mixing 配方的 ingredients 数组 + * 普通物品 → 'count item' 字符串简写 + * 复合/AND类型 → Ingredient.of(inputItem, count) 原样透传 + * 流体 → Fluid.of(fluidId, amount) + * @param {Object} inputItem - 输入物品数据 + * @param {Object} inputFluid - 输入流体数据 + * @param {number} multiplier - 倍率 + * @returns {Array} ingredients 数组 + */ +function buildIngredients(inputItem, inputFluid, multiplier) { + var ingredients = []; + + if (inputItem) { + if ((inputItem.type === 'neoforge:compound' || inputItem.type === 'tfc:and') && inputItem.children) { + var count = (inputItem.count || 1) * multiplier; + ingredients.push(Ingredient.of(inputItem, count)); + } else { + var itemId = inputItem.item || inputItem.tag; + if (itemId) { + var count = (inputItem.count || 1) * multiplier; + if (inputItem.tag) { + ingredients.push(Ingredient.of('#' + itemId, count)); + } else { + ingredients.push(count + 'x ' + itemId); + } + } + } + } + + if (inputFluid) { + var fluidId = inputFluid.fluid; + var amount = inputFluid.amount * multiplier; + + if (fluidId) { + if (amount > 0) { + try { + ingredients.push(Fluid.of(fluidId, amount)); + } catch (e) { + } + } + } else { + // 处理流体标签 + var fluidTag = inputFluid.fluid_tag || inputFluid.tag; + if (fluidTag && amount > 0) { + ingredients.push(Fluid.sizedIngredientOf('#' + fluidTag, amount)); + } + } + } + + return ingredients; +} + +/** + * 构建 mixing 配方的 results 数组 + * 物品 → CreateItem.of(ItemStack.of(itemId, count), chance) + * 流体 → Fluid.of(fluidId, amount) + * @param {Object} outputItem - 输出物品数据 + * @param {Object} outputFluid - 输出流体数据 + * @param {number} multiplier - 倍率 + * @returns {Array} results 数组 + */ +function buildResults(outputItem, outputFluid, multiplier) { + var results = []; + + if (outputItem) { + var itemId = outputItem.id || outputItem.item; + if (itemId) { + var count = (outputItem.count || 1) * multiplier; + if (outputItem.chance) { + results.push(CreateItem.of(Item.of(itemId, count), outputItem.chance)); + } else { + results.push(CreateItem.of(Item.of(itemId, count), 1.0)); + } + } + } + + if (outputFluid) { + var fluidId = outputFluid.id || outputFluid.fluid; + if (fluidId) { + var amount = outputFluid.amount * multiplier; + if (amount > 0) { + try { + Fluid.of(fluidId, amount); + results.push(Fluid.of(fluidId, amount)); + } catch (e) { + } + } + } + } + + return results; +} + +/** + * 处理单个 tfc:barrel_instant 配方 → Create Mixing + * 有 modifier 的 output 跳过(如食物腐烂);否则按倍率生成 + * @param {Object} data - 转换上下文 + * @param {Internal.Recipe} recipe - TFC配方 + */ +function processInstantRecipe(data, recipe) { + var json = recipe.json; + var recipeData = createInstantData(json, recipe); + + if (recipeData.outputItem && recipeData.outputItem.modifiers) { + data.stats.skipped++; + return; + } + + var multiplier = calculateMaxMultiplier(recipeData, data); + if (multiplier < 1) return; + + var ingredients = buildIngredients(recipeData.inputItem, recipeData.inputFluid, multiplier); + var results = buildResults(recipeData.outputItem, recipeData.outputFluid, multiplier); + + if (results.length === 0 || ingredients.length === 0) { + data.stats.skipped++; + return; + } + + data.event.recipes.create.mixing(results, ingredients, data.PROCESSING_TIME) + .id('kubejs:tfc_barrel_instant/mixing/' + multiplier + '_' + recipe.getId().replace(':', '_')); + + data.stats.instant++; +} + +/** + * 处理单个 tfc:barrel_instant_fluid 配方 → Create Mixing + * 纯流体混合:两路流体输入 → 一路流体输出 + * @param {Object} data - 转换上下文 + * @param {Internal.Recipe} recipe - TFC配方 + */ +function processInstantFluidRecipe(data, recipe) { + var json = recipe.json; + var recipeData = createInstantFluidData(json, recipe); + + var primaryAmt = recipeData.primaryFluid ? recipeData.primaryFluid.amount : 0; + var addedAmt = recipeData.addedFluid ? recipeData.addedFluid.amount : 0; + var outputAmt = recipeData.outputFluid ? recipeData.outputFluid.amount : 0; + + if (primaryAmt <= 0 || addedAmt <= 0 || outputAmt <= 0) { + data.stats.skipped++; + return; + } + + var multiplier = Math.floor(data.FLUID_SLOT_LIMIT / Math.max(primaryAmt, addedAmt, outputAmt)); + if (multiplier < 1) return; + + var primaryId = recipeData.primaryFluid.fluid; + var addedId = recipeData.addedFluid.fluid; + var outputId = recipeData.outputFluid.id || recipeData.outputFluid.fluid; + + if (!primaryId || !addedId || !outputId) { + data.stats.skipped++; + return; + } + + try { + Fluid.of(primaryId, primaryAmt); + Fluid.of(addedId, addedAmt); + Fluid.of(outputId, outputAmt); + } catch (e) { + data.stats.skipped++; + return; + } + + var ingredients = [ + Fluid.of(primaryId, primaryAmt * multiplier), + Fluid.of(addedId, addedAmt * multiplier) + ]; + + var results = [ + Fluid.of(outputId, outputAmt * multiplier) + ]; + + data.event.recipes.create.mixing(results, ingredients, data.PROCESSING_TIME) + .id('kubejs:tfc_barrel_instant_fluid/mixing/' + multiplier + '_' + recipe.getId().replace(':', '_')); + + data.stats.instantFluid++; +} + +ServerEvents.recipes(function(event) { + var data = createConverterData(event); + + event.forEachRecipe({ type: 'tfc:barrel_instant' }, function(recipe) { + processInstantRecipe(data, recipe); + }); + + event.forEachRecipe({ type: 'tfc:barrel_instant_fluid' }, function(recipe) { + processInstantFluidRecipe(data, recipe); + }); + + console.info('[生物柴油修复] barrel_instant→mixing 转换完成: instant=' + data.stats.instant + ', instant_fluid=' + data.stats.instantFluid + ', skipped=' + data.stats.skipped); +}); \ No newline at end of file diff --git a/server_scripts/biodiesel_fix/test_compound.js.pass b/server_scripts/biodiesel_fix/test_compound.js.pass new file mode 100644 index 0000000..5799db9 --- /dev/null +++ b/server_scripts/biodiesel_fix/test_compound.js.pass @@ -0,0 +1,230 @@ +// ============================================================================ +// 测试脚本:测试通用堆叠限制获取函数 +// 支持: item/tag/tfc:and/neoforge:compound 类型 +// ============================================================================ + +/** + * 通用获取物品最大堆叠数函数 + * 支持: item/tag/tfc:and/neoforge:compound 类型 + * 递归遍历所有子元素和标签中的物品,取最小值 + * @param {Object} itemData - 物品数据 + * @returns {number} 最大堆叠数(取最小值) + */ +function getUniversalMaxStack(itemData) { + if (!itemData) return 64; + + // 优先级1: 直接物品 + if (itemData.item) { + try { + var stackSize = Item.of(itemData.item, 1).getMaxStackSize(); + console.info('[堆叠获取] 直接物品成功: ' + itemData.item + ' -> ' + stackSize); + return stackSize; + } catch (e) { + console.warn('[堆叠获取] 直接物品失败: ' + itemData.item + ', 错误: ' + e.message); + return 64; + } + } + + // 优先级2: 物品标签 + if (itemData.tag) { + try { + var tagIngredient = Ingredient.of('#' + itemData.tag); + console.info('[堆叠获取] 创建Ingredient: #' + itemData.tag); + + // 尝试多种方法获取标签物品 + var tagItems = null; + + // 方法1: 尝试 .stackArray 属性(KubeJS常用) + if (tagIngredient.stackArray !== undefined) { + tagItems = tagIngredient.stackArray; + console.info('[堆叠获取] .stackArray 属性: ' + (tagItems && tagItems.length ? tagItems.length : '空')); + } + + // 方法2: 尝试 .itemIds 属性(返回 Java Set) + if (!tagItems && tagIngredient.itemIds !== undefined) { + var itemIdsSet = tagIngredient.itemIds; + console.info('[堆叠获取] .itemIds 属性: ' + (itemIdsSet && itemIdsSet.size ? itemIdsSet.size : '空')); + if (itemIdsSet && itemIdsSet.size > 0) { + tagItems = []; + var iterator = itemIdsSet.iterator(); + while (iterator.hasNext()) { + tagItems.push(Item.of(iterator.next(), 1)); + } + console.info('[堆叠获取] itemIds转换为ItemStack数组: ' + tagItems.length); + } + } + + // 方法3: 尝试 .stacks 属性(返回 Java Set) + if (!tagItems && tagIngredient.stacks !== undefined) { + var stacksSet = tagIngredient.stacks; + console.info('[堆叠获取] .stacks 属性: ' + (stacksSet && stacksSet.size ? stacksSet.size : '空')); + if (stacksSet && stacksSet.size > 0) { + tagItems = []; + var iterator = stacksSet.iterator(); + while (iterator.hasNext()) { + tagItems.push(iterator.next()); + } + console.info('[堆叠获取] stacks转换为数组: ' + tagItems.length); + } + } + + // 方法4: 尝试 getStackArray() 方法 + if (!tagItems && typeof tagIngredient.getStackArray === 'function') { + tagItems = tagIngredient.getStackArray(); + console.info('[堆叠获取] getStackArray() 方法: ' + (tagItems && tagItems.length ? tagItems.length : '空')); + } + + // 方法5: 尝试 getItemIds() 方法 + if (!tagItems && typeof tagIngredient.getItemIds === 'function') { + var idsSet = tagIngredient.getItemIds(); + console.info('[堆叠获取] getItemIds() 方法: ' + (idsSet && idsSet.size ? idsSet.size : '空')); + if (idsSet && idsSet.size > 0) { + tagItems = []; + var iterator = idsSet.iterator(); + while (iterator.hasNext()) { + tagItems.push(Item.of(iterator.next(), 1)); + } + console.info('[堆叠获取] getItemIds转换为ItemStack数组: ' + tagItems.length); + } + } + + // 方法6: 尝试 getStacks() 方法 + if (!tagItems && typeof tagIngredient.getStacks === 'function') { + var sSet = tagIngredient.getStacks(); + console.info('[堆叠获取] getStacks() 方法: ' + (sSet && sSet.size ? sSet.size : '空')); + if (sSet && sSet.size > 0) { + tagItems = []; + var iterator = sSet.iterator(); + while (iterator.hasNext()) { + tagItems.push(iterator.next()); + } + console.info('[堆叠获取] getStacks转换为数组: ' + tagItems.length); + } + } + + // 方法7: 尝试 .itemTypes 属性 + if (!tagItems && tagIngredient.itemTypes !== undefined) { + var typesSet = tagIngredient.itemTypes; + console.info('[堆叠获取] .itemTypes 属性: ' + (typesSet && typesSet.size ? typesSet.size : '空')); + if (typesSet && typesSet.size > 0) { + tagItems = []; + var iterator = typesSet.iterator(); + while (iterator.hasNext()) { + tagItems.push(Item.of(iterator.next(), 1)); + } + console.info('[堆叠获取] itemTypes转换为ItemStack数组: ' + tagItems.length); + } + } + + // 输出调试信息 + if (!tagItems) { + console.info('[堆叠获取] tagIngredient 属性列表: ' + Object.keys(tagIngredient).join(', ')); + console.info('[堆叠获取] tagIngredient.empty: ' + tagIngredient.empty); + console.info('[堆叠获取] tagIngredient.tagKey: ' + tagIngredient.tagKey); + } + + if (tagItems && tagItems.length > 0) { + var minStack = tagItems[0].getMaxStackSize(); + for (var i = 1; i < tagItems.length; i++) { + var stackSize = tagItems[i].getMaxStackSize(); + if (stackSize < minStack) { + minStack = stackSize; + } + } + console.info('[堆叠获取] 标签成功: #' + itemData.tag + ' -> ' + minStack); + return minStack; + } else { + console.warn('[堆叠获取] 标签为空或获取失败: #' + itemData.tag); + } + } catch (e) { + console.warn('[堆叠获取] 处理标签失败: #' + itemData.tag + ', 错误: ' + e.message); + } + return 64; + } + + // 优先级3: 复合类型(tfc:and / neoforge:compound) + if (itemData.children && itemData.children.length > 0) { + var minStack = 64; + for (var i = 0; i < itemData.children.length; i++) { + var child = itemData.children[i]; + // 只处理有item/tag/children的子元素,跳过条件类型如 tfc:not_rotten + if (child.item || child.tag || (child.children && child.children.length > 0)) { + var childStack = getUniversalMaxStack(child); + minStack = Math.min(minStack, childStack); + } + } + console.info('[堆叠获取] 复合类型: ' + (itemData.type || 'unknown') + ' -> ' + minStack); + return minStack; + } + + // 其他未知类型,返回默认值 + return 64; +} + +ServerEvents.recipes(function(event) { + // ==================== 测试1: neoforge:compound 类型 ==================== + var compoundInput = { + type: 'neoforge:compound', + children: [ + { tag: 'tfc:foods/preserves' }, + { tag: 'tfc:foods/sealed_preserves' } + ], + count: 1 + }; + + var compoundMaxStack = getUniversalMaxStack(compoundInput); + var compoundMultiplier = Math.min( + Math.floor(compoundMaxStack / (compoundInput.count || 1)), + Math.floor(1000 / 100) // 流体限制 + ); + + console.info('[测试配方] neoforge:compound 堆叠限制: ' + compoundMaxStack + ', 倍率: ' + compoundMultiplier); + + event.recipes.create.mixing( + [Item.of('tfc:empty_jar', compoundMultiplier)], + [ + Ingredient.of(compoundInput, compoundMultiplier), + Fluid.of('minecraft:water', 100 * compoundMultiplier) + ], + 100 + ).id('kubejs:test/compound_preserves'); + + // ==================== 测试2: tfc:and 类型 ==================== + var andInput = { + type: 'tfc:and', + children: [ + { item: 'tfc:food/barley_flour' }, + { type: 'tfc:not_rotten' } // 条件类型,不参与堆叠计算 + ], + count: 1 + }; + + var andMaxStack = getUniversalMaxStack(andInput); + var andMultiplier = Math.min( + Math.floor(andMaxStack / (andInput.count || 1)), + Math.floor(1000 / 500) // 流体限制 + ); + + console.info('[测试配方] tfc:and 堆叠限制: ' + andMaxStack + ', 倍率: ' + andMultiplier); + + event.recipes.create.mixing( + [Fluid.of('tfc:beer', 500 * andMultiplier)], + [ + Ingredient.of(andInput, andMultiplier), + Fluid.of('minecraft:water', 500 * andMultiplier) + ], + 100 + ).id('kubejs:test/tfc_and_barley'); + + // ==================== 测试3: 普通物品 ==================== + var simpleItem = { item: 'tfc:powder/saltpeter', count: 1 }; + var simpleMaxStack = getUniversalMaxStack(simpleItem); + console.info('[测试配方] 普通物品堆叠限制: ' + simpleMaxStack); + + // ==================== 测试4: 物品标签 ==================== + var tagItem = { tag: 'tfc:colored_wool', count: 1 }; + var tagMaxStack = getUniversalMaxStack(tagItem); + console.info('[测试配方] 标签堆叠限制: ' + tagMaxStack); + + console.info('[测试配方] 所有测试配方已创建'); +}); diff --git a/server_scripts/biodiesel_fix/test_recipes.js.pass b/server_scripts/biodiesel_fix/test_recipes.js.pass new file mode 100644 index 0000000..7f29d84 --- /dev/null +++ b/server_scripts/biodiesel_fix/test_recipes.js.pass @@ -0,0 +1,32 @@ +// ============================================================================ +// 测试脚本:单独创建两个问题配方 +// 验证正确的 API 使用方式 +// ============================================================================ + +ServerEvents.recipes(function(event) { + // 配方 1: yeast_starter + sweeteners → tirage_mixture + // 输入:100mB yeast_starter + 1个 sweeteners 标签物品 + // 输出:1个 tirage_mixture + event.recipes.create.mixing( + [Item.of('firmalife:tirage_mixture', 1)], // ProcessingOutput: Item.of(itemName, count) + [ + Ingredient.of('#tfc:foods/sweeteners', 1), // Ingredient: 物品标签 + Fluid.of('firmalife:yeast_starter', 100) // FluidStack: 具体流体 + ], + 100 + ).id('kubejs:test/tirage_mixture'); + + // 配方 2: any_fresh_water + saltpeter → saltpeter_solution + // 输入:1000mB 任意淡水 + 1个 saltpeter + // 输出:1000mB saltpeter_solution + event.recipes.create.mixing( + [Fluid.of('tfcfertigation:saltpeter_solution', 1000)], // FluidStack + [ + Ingredient.of('tfc:powder/saltpeter', 1), // Ingredient: 具体物品 + Fluid.sizedIngredientOf('#tfc:any_fresh_water', 1000) // SizedFluidIngredient: 流体标签 + ], + 100 + ).id('kubejs:test/saltpeter_solution'); + + console.info('[测试配方] 两个测试配方已创建'); +}); From 51bad8d63eeebcd95e95e22ba2119dc7a70fbf49 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Tue, 19 May 2026 11:52:23 +0000 Subject: [PATCH 10/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=A0=86=E5=8F=A0=E9=99=90=E5=88=B6=E8=8E=B7=E5=8F=96=E5=92=8C?= =?UTF-8?q?children=E7=B1=BB=E5=9E=8B=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biodiesel_fix/fermenting_from_barrel.js | 25 +++++++++++++------ .../mixing_from_barrel_instant.js | 10 +++++--- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/server_scripts/biodiesel_fix/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js index c9321a2..8be59ad 100644 --- a/server_scripts/biodiesel_fix/fermenting_from_barrel.js +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -77,12 +77,26 @@ function parseJsonField(json, fieldName) { * @returns {number|null} 最大堆叠数 */ function getMaxStackSize(itemData) { + if (itemData.children && itemData.children.length > 0) { + var minStack = 64; + for (var i = 0; i < itemData.children.length; i++) { + var child = itemData.children[i]; + if (child.item || child.tag || (child.children && child.children.length > 0)) { + var childStack = getMaxStackSize(child); + if (childStack !== null && childStack < minStack) { + minStack = childStack; + } + } + } + return minStack; + } + var itemId = itemData.item || itemData.tag; if (!itemId) return null; try { if (itemData.tag) { - var tagItems = Ingredient.of('#' + itemData.tag).items; + var tagItems = Ingredient.of('#' + itemData.tag).stackArray; if (tagItems && tagItems.length > 0) { var minStack = tagItems[0].getMaxStackSize(); for (var i = 1; i < tagItems.length; i++) { @@ -112,13 +126,10 @@ function calculateBasinMaxMultiplier(recipeData, data) { var maxMultiplier = Infinity; if (recipeData.inputItem) { - var itemId = recipeData.inputItem.item || recipeData.inputItem.tag; - if (itemId) { + var maxStack = getMaxStackSize(recipeData.inputItem); + if (maxStack) { var count = recipeData.inputItem.count || 1; - var maxStack = getMaxStackSize(recipeData.inputItem); - if (maxStack) { - maxMultiplier = Math.min(maxMultiplier, maxStack / count); - } + maxMultiplier = Math.min(maxMultiplier, maxStack / count); } } diff --git a/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js b/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js index 13ecdc7..f9ac9ae 100644 --- a/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js +++ b/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js @@ -107,12 +107,14 @@ function calculateMaxMultiplier(recipeData, data) { var maxMultiplier = Infinity; if (recipeData.inputItem) { - if ((recipeData.inputItem.type === 'neoforge:compound' || recipeData.inputItem.type === 'tfc:and') && recipeData.inputItem.children) { + if (recipeData.inputItem.children && recipeData.inputItem.children.length > 0) { for (var i = 0; i < recipeData.inputItem.children.length; i++) { var child = recipeData.inputItem.children[i]; - var maxStack = getMaxStackSize(child); - if (maxStack) { - maxMultiplier = Math.min(maxMultiplier, Math.floor(maxStack / (recipeData.inputItem.count || 1))); + if (child.item || child.tag || (child.children && child.children.length > 0)) { + var maxStack = getMaxStackSize(child); + if (maxStack) { + maxMultiplier = Math.min(maxMultiplier, Math.floor(maxStack / (child.count || 1))); + } } } } else { From c348b050ba3ad496a55999beb7356fde2d45dd2b Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Tue, 19 May 2026 18:05:09 +0000 Subject: [PATCH 11/14] =?UTF-8?q?TFC=E9=85=92=E4=B8=8E=E9=99=88=E9=85=BF?= =?UTF-8?q?=E9=85=92=E8=92=B8=E9=A6=8F=E9=85=92=E7=B2=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biodiesel_fix/alcohol_to_ethanol.js | 31 +++ .../biodiesel_fix/test_compound.js.pass | 230 ------------------ .../biodiesel_fix/test_recipes.js.pass | 32 --- server_scripts/check_fluid_tags.js.pass | 99 ++++++++ 4 files changed, 130 insertions(+), 262 deletions(-) create mode 100644 server_scripts/biodiesel_fix/alcohol_to_ethanol.js delete mode 100644 server_scripts/biodiesel_fix/test_compound.js.pass delete mode 100644 server_scripts/biodiesel_fix/test_recipes.js.pass create mode 100644 server_scripts/check_fluid_tags.js.pass diff --git a/server_scripts/biodiesel_fix/alcohol_to_ethanol.js b/server_scripts/biodiesel_fix/alcohol_to_ethanol.js new file mode 100644 index 0000000..f557867 --- /dev/null +++ b/server_scripts/biodiesel_fix/alcohol_to_ethanol.js @@ -0,0 +1,31 @@ +ServerEvents.recipes(event => { + event.custom({ + type: 'createdieselgenerators:distillation', + ingredients: [{ + type: 'fluid_tag', + fluid_tag: 'tfc:alcohols', + amount: 1000 + }], + heat_requirement: 'heated', + processing_time: 100, + results: [ + { id: 'minecraft:water', amount: 400 }, + { id: 'createdieselgenerators:ethanol', amount: 600 } + ] + }).id('kubejs:distillation/createdieselgenerators/tfc_alcohols/ethanol') + + event.custom({ + type: 'createdieselgenerators:distillation', + ingredients: [{ + type: 'fluid_tag', + fluid_tag: 'tfcagedalcohol:aged_alcohols', + amount: 1000 + }], + heat_requirement: 'heated', + processing_time: 100, + results: [ + { id: 'minecraft:water', amount: 200 }, + { id: 'createdieselgenerators:ethanol', amount: 800 } + ] + }).id('kubejs:distillation/createdieselgenerators/tfcagedalcohol_aged_alcohols/ethanol') +}) diff --git a/server_scripts/biodiesel_fix/test_compound.js.pass b/server_scripts/biodiesel_fix/test_compound.js.pass deleted file mode 100644 index 5799db9..0000000 --- a/server_scripts/biodiesel_fix/test_compound.js.pass +++ /dev/null @@ -1,230 +0,0 @@ -// ============================================================================ -// 测试脚本:测试通用堆叠限制获取函数 -// 支持: item/tag/tfc:and/neoforge:compound 类型 -// ============================================================================ - -/** - * 通用获取物品最大堆叠数函数 - * 支持: item/tag/tfc:and/neoforge:compound 类型 - * 递归遍历所有子元素和标签中的物品,取最小值 - * @param {Object} itemData - 物品数据 - * @returns {number} 最大堆叠数(取最小值) - */ -function getUniversalMaxStack(itemData) { - if (!itemData) return 64; - - // 优先级1: 直接物品 - if (itemData.item) { - try { - var stackSize = Item.of(itemData.item, 1).getMaxStackSize(); - console.info('[堆叠获取] 直接物品成功: ' + itemData.item + ' -> ' + stackSize); - return stackSize; - } catch (e) { - console.warn('[堆叠获取] 直接物品失败: ' + itemData.item + ', 错误: ' + e.message); - return 64; - } - } - - // 优先级2: 物品标签 - if (itemData.tag) { - try { - var tagIngredient = Ingredient.of('#' + itemData.tag); - console.info('[堆叠获取] 创建Ingredient: #' + itemData.tag); - - // 尝试多种方法获取标签物品 - var tagItems = null; - - // 方法1: 尝试 .stackArray 属性(KubeJS常用) - if (tagIngredient.stackArray !== undefined) { - tagItems = tagIngredient.stackArray; - console.info('[堆叠获取] .stackArray 属性: ' + (tagItems && tagItems.length ? tagItems.length : '空')); - } - - // 方法2: 尝试 .itemIds 属性(返回 Java Set) - if (!tagItems && tagIngredient.itemIds !== undefined) { - var itemIdsSet = tagIngredient.itemIds; - console.info('[堆叠获取] .itemIds 属性: ' + (itemIdsSet && itemIdsSet.size ? itemIdsSet.size : '空')); - if (itemIdsSet && itemIdsSet.size > 0) { - tagItems = []; - var iterator = itemIdsSet.iterator(); - while (iterator.hasNext()) { - tagItems.push(Item.of(iterator.next(), 1)); - } - console.info('[堆叠获取] itemIds转换为ItemStack数组: ' + tagItems.length); - } - } - - // 方法3: 尝试 .stacks 属性(返回 Java Set) - if (!tagItems && tagIngredient.stacks !== undefined) { - var stacksSet = tagIngredient.stacks; - console.info('[堆叠获取] .stacks 属性: ' + (stacksSet && stacksSet.size ? stacksSet.size : '空')); - if (stacksSet && stacksSet.size > 0) { - tagItems = []; - var iterator = stacksSet.iterator(); - while (iterator.hasNext()) { - tagItems.push(iterator.next()); - } - console.info('[堆叠获取] stacks转换为数组: ' + tagItems.length); - } - } - - // 方法4: 尝试 getStackArray() 方法 - if (!tagItems && typeof tagIngredient.getStackArray === 'function') { - tagItems = tagIngredient.getStackArray(); - console.info('[堆叠获取] getStackArray() 方法: ' + (tagItems && tagItems.length ? tagItems.length : '空')); - } - - // 方法5: 尝试 getItemIds() 方法 - if (!tagItems && typeof tagIngredient.getItemIds === 'function') { - var idsSet = tagIngredient.getItemIds(); - console.info('[堆叠获取] getItemIds() 方法: ' + (idsSet && idsSet.size ? idsSet.size : '空')); - if (idsSet && idsSet.size > 0) { - tagItems = []; - var iterator = idsSet.iterator(); - while (iterator.hasNext()) { - tagItems.push(Item.of(iterator.next(), 1)); - } - console.info('[堆叠获取] getItemIds转换为ItemStack数组: ' + tagItems.length); - } - } - - // 方法6: 尝试 getStacks() 方法 - if (!tagItems && typeof tagIngredient.getStacks === 'function') { - var sSet = tagIngredient.getStacks(); - console.info('[堆叠获取] getStacks() 方法: ' + (sSet && sSet.size ? sSet.size : '空')); - if (sSet && sSet.size > 0) { - tagItems = []; - var iterator = sSet.iterator(); - while (iterator.hasNext()) { - tagItems.push(iterator.next()); - } - console.info('[堆叠获取] getStacks转换为数组: ' + tagItems.length); - } - } - - // 方法7: 尝试 .itemTypes 属性 - if (!tagItems && tagIngredient.itemTypes !== undefined) { - var typesSet = tagIngredient.itemTypes; - console.info('[堆叠获取] .itemTypes 属性: ' + (typesSet && typesSet.size ? typesSet.size : '空')); - if (typesSet && typesSet.size > 0) { - tagItems = []; - var iterator = typesSet.iterator(); - while (iterator.hasNext()) { - tagItems.push(Item.of(iterator.next(), 1)); - } - console.info('[堆叠获取] itemTypes转换为ItemStack数组: ' + tagItems.length); - } - } - - // 输出调试信息 - if (!tagItems) { - console.info('[堆叠获取] tagIngredient 属性列表: ' + Object.keys(tagIngredient).join(', ')); - console.info('[堆叠获取] tagIngredient.empty: ' + tagIngredient.empty); - console.info('[堆叠获取] tagIngredient.tagKey: ' + tagIngredient.tagKey); - } - - if (tagItems && tagItems.length > 0) { - var minStack = tagItems[0].getMaxStackSize(); - for (var i = 1; i < tagItems.length; i++) { - var stackSize = tagItems[i].getMaxStackSize(); - if (stackSize < minStack) { - minStack = stackSize; - } - } - console.info('[堆叠获取] 标签成功: #' + itemData.tag + ' -> ' + minStack); - return minStack; - } else { - console.warn('[堆叠获取] 标签为空或获取失败: #' + itemData.tag); - } - } catch (e) { - console.warn('[堆叠获取] 处理标签失败: #' + itemData.tag + ', 错误: ' + e.message); - } - return 64; - } - - // 优先级3: 复合类型(tfc:and / neoforge:compound) - if (itemData.children && itemData.children.length > 0) { - var minStack = 64; - for (var i = 0; i < itemData.children.length; i++) { - var child = itemData.children[i]; - // 只处理有item/tag/children的子元素,跳过条件类型如 tfc:not_rotten - if (child.item || child.tag || (child.children && child.children.length > 0)) { - var childStack = getUniversalMaxStack(child); - minStack = Math.min(minStack, childStack); - } - } - console.info('[堆叠获取] 复合类型: ' + (itemData.type || 'unknown') + ' -> ' + minStack); - return minStack; - } - - // 其他未知类型,返回默认值 - return 64; -} - -ServerEvents.recipes(function(event) { - // ==================== 测试1: neoforge:compound 类型 ==================== - var compoundInput = { - type: 'neoforge:compound', - children: [ - { tag: 'tfc:foods/preserves' }, - { tag: 'tfc:foods/sealed_preserves' } - ], - count: 1 - }; - - var compoundMaxStack = getUniversalMaxStack(compoundInput); - var compoundMultiplier = Math.min( - Math.floor(compoundMaxStack / (compoundInput.count || 1)), - Math.floor(1000 / 100) // 流体限制 - ); - - console.info('[测试配方] neoforge:compound 堆叠限制: ' + compoundMaxStack + ', 倍率: ' + compoundMultiplier); - - event.recipes.create.mixing( - [Item.of('tfc:empty_jar', compoundMultiplier)], - [ - Ingredient.of(compoundInput, compoundMultiplier), - Fluid.of('minecraft:water', 100 * compoundMultiplier) - ], - 100 - ).id('kubejs:test/compound_preserves'); - - // ==================== 测试2: tfc:and 类型 ==================== - var andInput = { - type: 'tfc:and', - children: [ - { item: 'tfc:food/barley_flour' }, - { type: 'tfc:not_rotten' } // 条件类型,不参与堆叠计算 - ], - count: 1 - }; - - var andMaxStack = getUniversalMaxStack(andInput); - var andMultiplier = Math.min( - Math.floor(andMaxStack / (andInput.count || 1)), - Math.floor(1000 / 500) // 流体限制 - ); - - console.info('[测试配方] tfc:and 堆叠限制: ' + andMaxStack + ', 倍率: ' + andMultiplier); - - event.recipes.create.mixing( - [Fluid.of('tfc:beer', 500 * andMultiplier)], - [ - Ingredient.of(andInput, andMultiplier), - Fluid.of('minecraft:water', 500 * andMultiplier) - ], - 100 - ).id('kubejs:test/tfc_and_barley'); - - // ==================== 测试3: 普通物品 ==================== - var simpleItem = { item: 'tfc:powder/saltpeter', count: 1 }; - var simpleMaxStack = getUniversalMaxStack(simpleItem); - console.info('[测试配方] 普通物品堆叠限制: ' + simpleMaxStack); - - // ==================== 测试4: 物品标签 ==================== - var tagItem = { tag: 'tfc:colored_wool', count: 1 }; - var tagMaxStack = getUniversalMaxStack(tagItem); - console.info('[测试配方] 标签堆叠限制: ' + tagMaxStack); - - console.info('[测试配方] 所有测试配方已创建'); -}); diff --git a/server_scripts/biodiesel_fix/test_recipes.js.pass b/server_scripts/biodiesel_fix/test_recipes.js.pass deleted file mode 100644 index 7f29d84..0000000 --- a/server_scripts/biodiesel_fix/test_recipes.js.pass +++ /dev/null @@ -1,32 +0,0 @@ -// ============================================================================ -// 测试脚本:单独创建两个问题配方 -// 验证正确的 API 使用方式 -// ============================================================================ - -ServerEvents.recipes(function(event) { - // 配方 1: yeast_starter + sweeteners → tirage_mixture - // 输入:100mB yeast_starter + 1个 sweeteners 标签物品 - // 输出:1个 tirage_mixture - event.recipes.create.mixing( - [Item.of('firmalife:tirage_mixture', 1)], // ProcessingOutput: Item.of(itemName, count) - [ - Ingredient.of('#tfc:foods/sweeteners', 1), // Ingredient: 物品标签 - Fluid.of('firmalife:yeast_starter', 100) // FluidStack: 具体流体 - ], - 100 - ).id('kubejs:test/tirage_mixture'); - - // 配方 2: any_fresh_water + saltpeter → saltpeter_solution - // 输入:1000mB 任意淡水 + 1个 saltpeter - // 输出:1000mB saltpeter_solution - event.recipes.create.mixing( - [Fluid.of('tfcfertigation:saltpeter_solution', 1000)], // FluidStack - [ - Ingredient.of('tfc:powder/saltpeter', 1), // Ingredient: 具体物品 - Fluid.sizedIngredientOf('#tfc:any_fresh_water', 1000) // SizedFluidIngredient: 流体标签 - ], - 100 - ).id('kubejs:test/saltpeter_solution'); - - console.info('[测试配方] 两个测试配方已创建'); -}); diff --git a/server_scripts/check_fluid_tags.js.pass b/server_scripts/check_fluid_tags.js.pass new file mode 100644 index 0000000..8894b45 --- /dev/null +++ b/server_scripts/check_fluid_tags.js.pass @@ -0,0 +1,99 @@ +// ============================================================================ +// 测试脚本:检查流体标签中是否包含 tfc:beer 和 tfcagedalcohol:aged_beer +// 通过 RegistryAccessContainer 遍历所有流体标签 +// +// ====== 测试结果 (已验证通过) ====== +// +// 共发现 116 个流体标签 +// +// 流体 "tfc:beer" 存在于以下 13 个标签中: +// - tfc:usable_in_barrel +// - tfc:ingredients +// - firmalife:usable_in_wine_glass +// - tfc:usable_in_jug +// - tfc:usable_in_pot +// - tfc:alcohols +// - tfc:usable_in_blue_steel_bucket +// - firmalife:usable_in_vat +// - firmalife:usable_in_mixing_bowl +// - tfc:usable_in_red_steel_bucket +// - tfc:drinkables +// - firmalife:usable_in_hollow_shell +// - tfc:usable_in_wooden_bucket +// +// 流体 "tfcagedalcohol:aged_beer" 存在于以下 12 个标签中: +// - tfcagedalcohol:aged_alcohols +// - tfc:usable_in_barrel +// - tfc:ingredients +// - firmalife:usable_in_wine_glass +// - tfc:usable_in_jug +// - tfc:usable_in_pot +// - tfc:usable_in_blue_steel_bucket +// - firmalife:usable_in_vat +// - firmalife:usable_in_mixing_bowl +// - tfc:usable_in_red_steel_bucket +// - tfc:drinkables +// - firmalife:usable_in_hollow_shell +// - tfc:usable_in_wooden_bucket +// ============================================================================ + +ServerEvents.tags('fluid', event => { + console.info('======= 流体标签检查开始 ======='); + + try { + var RegistryAccessContainer = Java.loadClass('dev.latvian.mods.kubejs.util.RegistryAccessContainer'); + var ResourceKey = Java.loadClass('net.minecraft.resources.ResourceKey'); + var ResourceLocation = Java.loadClass('net.minecraft.resources.ResourceLocation'); + + var fluidKey = ResourceKey.createRegistryKey(ResourceLocation.withDefaultNamespace('fluid')); + console.info('流体注册表键: ' + fluidKey); + + var container = RegistryAccessContainer.of(); + var allTags = container.getAllTags(fluidKey); + + console.info('getAllTags 结果: ' + allTags); + if (allTags) { + var tagKeys = allTags.keySet().toArray(); + console.info('共发现 ' + tagKeys.length + ' 个流体标签'); + + var targetFluids = ['tfc:beer', 'tfcagedalcohol:aged_beer']; + var foundMap = {}; + foundMap['tfc:beer'] = []; + foundMap['tfcagedalcohol:aged_beer'] = []; + + for (var i = 0; i < tagKeys.length; i++) { + var tagId = tagKeys[i]; + var holders = allTags.get(tagId); + var holderArray = holders.toArray(); + + for (var j = 0; j < holderArray.length; j++) { + var holder = holderArray[j]; + var fluidId = holder.key().location().toString().toLowerCase(); + if (fluidId === 'tfc:beer' || fluidId === 'tfcagedalcohol:aged_beer') { + foundMap[fluidId].push(tagId.toString()); + } + } + } + + for (var f = 0; f < targetFluids.length; f++) { + var fluid = targetFluids[f]; + var tags = foundMap[fluid]; + if (tags.length > 0) { + console.info('流体 "' + fluid + '" 存在于以下标签中:'); + for (var t = 0; t < tags.length; t++) { + console.info(' - ' + tags[t]); + } + } else { + console.info('流体 "' + fluid + '" 未出现在任何流体标签中'); + } + } + } else { + console.info('getAllTags 返回了 null'); + } + } catch (e) { + console.error('检查流体标签时出错: ' + e); + console.error('堆栈: ' + e.printStackTrace()); + } + + console.info('======= 流体标签检查结束 ======='); +}); From be143e0e3f260329a4b30f12a4eb44b283e2a7b8 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Wed, 20 May 2026 09:39:12 +0000 Subject: [PATCH 12/14] =?UTF-8?q?TFC=E6=A4=8D=E7=89=A9=E6=B2=B9=E5=8F=82?= =?UTF-8?q?=E4=B8=8E=E7=94=9F=E7=89=A9=E7=87=83=E6=96=99=E5=90=88=E6=88=90?= =?UTF-8?q?=E4=B8=8ETFC=E6=A4=8D=E7=89=A9=E6=B2=B9=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E6=A6=A8=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_scripts/biodiesel_fix/plant_oil.js | 47 +++++++++++ server_scripts/check_fluid_tags.js.pass | 99 ----------------------- 2 files changed, 47 insertions(+), 99 deletions(-) create mode 100644 server_scripts/biodiesel_fix/plant_oil.js delete mode 100644 server_scripts/check_fluid_tags.js.pass diff --git a/server_scripts/biodiesel_fix/plant_oil.js b/server_scripts/biodiesel_fix/plant_oil.js new file mode 100644 index 0000000..98c5b2c --- /dev/null +++ b/server_scripts/biodiesel_fix/plant_oil.js @@ -0,0 +1,47 @@ +// ============================================================================ +// 植物油标签扩展与 Create Compacting 榨油配方 +// ============================================================================ + +// --------------------------------------------------------------------------- +// 1. 扩展 c:plantoil 标签,将 TFC 和 Firmalife 的油类加入 +// --------------------------------------------------------------------------- +ServerEvents.tags('minecraft:fluid', event => { + event.add('c:plantoil', [ + 'tfc:olive_oil', + 'tfc:canola_oil', + 'firmalife:soybean_oil' + ]); +}); + +// --------------------------------------------------------------------------- +// 2. 创建 Create Compacting 榨油配方 +// --------------------------------------------------------------------------- +ServerEvents.recipes(event => { + // 橄榄 → 橄榄油: 10个橄榄压榨出800mB橄榄油 + // 注意:橄榄会腐败,使用 TFC.ingredient.and() 组合 notRotten 限制非腐败输入 + event.recipes.create.compacting( + [Fluid.of('tfc:olive_oil', 800)], + [ + TFC.ingredient.and(Ingredient.of('tfc:food/olive'), TFC.ingredient.notRotten()).withCount(10) + ] + ).id('kubejs:compacting/createdieselgenerators/tfc_olive/olive_oil'); + + // 油菜种子 → 菜籽油: 10个油菜种子压榨出800mB菜籽油 + event.recipes.create.compacting( + [Fluid.of('tfc:canola_oil', 800)], + [ + Ingredient.of('tfc:seeds/canola').withCount(10) + ] + ).id('kubejs:compacting/createdieselgenerators/tfc_canola/canola_oil'); + + // 脱水大豆 → 大豆油: 4个脱水大豆压榨出1000mB大豆油 + // 脱水大豆会腐败,使用 TFC.ingredient.and() 组合 notRotten 限制非腐败输入 + event.recipes.create.compacting( + [Fluid.of('firmalife:soybean_oil', 1000)], + [ + TFC.ingredient.and(Ingredient.of('firmalife:food/dehydrated_soybeans'), TFC.ingredient.notRotten()).withCount(4) + ] + ).id('kubejs:compacting/createdieselgenerators/firmalife_soybean/soybean_oil'); + + console.info('[植物油] 榨油配方注册完成'); +}); diff --git a/server_scripts/check_fluid_tags.js.pass b/server_scripts/check_fluid_tags.js.pass deleted file mode 100644 index 8894b45..0000000 --- a/server_scripts/check_fluid_tags.js.pass +++ /dev/null @@ -1,99 +0,0 @@ -// ============================================================================ -// 测试脚本:检查流体标签中是否包含 tfc:beer 和 tfcagedalcohol:aged_beer -// 通过 RegistryAccessContainer 遍历所有流体标签 -// -// ====== 测试结果 (已验证通过) ====== -// -// 共发现 116 个流体标签 -// -// 流体 "tfc:beer" 存在于以下 13 个标签中: -// - tfc:usable_in_barrel -// - tfc:ingredients -// - firmalife:usable_in_wine_glass -// - tfc:usable_in_jug -// - tfc:usable_in_pot -// - tfc:alcohols -// - tfc:usable_in_blue_steel_bucket -// - firmalife:usable_in_vat -// - firmalife:usable_in_mixing_bowl -// - tfc:usable_in_red_steel_bucket -// - tfc:drinkables -// - firmalife:usable_in_hollow_shell -// - tfc:usable_in_wooden_bucket -// -// 流体 "tfcagedalcohol:aged_beer" 存在于以下 12 个标签中: -// - tfcagedalcohol:aged_alcohols -// - tfc:usable_in_barrel -// - tfc:ingredients -// - firmalife:usable_in_wine_glass -// - tfc:usable_in_jug -// - tfc:usable_in_pot -// - tfc:usable_in_blue_steel_bucket -// - firmalife:usable_in_vat -// - firmalife:usable_in_mixing_bowl -// - tfc:usable_in_red_steel_bucket -// - tfc:drinkables -// - firmalife:usable_in_hollow_shell -// - tfc:usable_in_wooden_bucket -// ============================================================================ - -ServerEvents.tags('fluid', event => { - console.info('======= 流体标签检查开始 ======='); - - try { - var RegistryAccessContainer = Java.loadClass('dev.latvian.mods.kubejs.util.RegistryAccessContainer'); - var ResourceKey = Java.loadClass('net.minecraft.resources.ResourceKey'); - var ResourceLocation = Java.loadClass('net.minecraft.resources.ResourceLocation'); - - var fluidKey = ResourceKey.createRegistryKey(ResourceLocation.withDefaultNamespace('fluid')); - console.info('流体注册表键: ' + fluidKey); - - var container = RegistryAccessContainer.of(); - var allTags = container.getAllTags(fluidKey); - - console.info('getAllTags 结果: ' + allTags); - if (allTags) { - var tagKeys = allTags.keySet().toArray(); - console.info('共发现 ' + tagKeys.length + ' 个流体标签'); - - var targetFluids = ['tfc:beer', 'tfcagedalcohol:aged_beer']; - var foundMap = {}; - foundMap['tfc:beer'] = []; - foundMap['tfcagedalcohol:aged_beer'] = []; - - for (var i = 0; i < tagKeys.length; i++) { - var tagId = tagKeys[i]; - var holders = allTags.get(tagId); - var holderArray = holders.toArray(); - - for (var j = 0; j < holderArray.length; j++) { - var holder = holderArray[j]; - var fluidId = holder.key().location().toString().toLowerCase(); - if (fluidId === 'tfc:beer' || fluidId === 'tfcagedalcohol:aged_beer') { - foundMap[fluidId].push(tagId.toString()); - } - } - } - - for (var f = 0; f < targetFluids.length; f++) { - var fluid = targetFluids[f]; - var tags = foundMap[fluid]; - if (tags.length > 0) { - console.info('流体 "' + fluid + '" 存在于以下标签中:'); - for (var t = 0; t < tags.length; t++) { - console.info(' - ' + tags[t]); - } - } else { - console.info('流体 "' + fluid + '" 未出现在任何流体标签中'); - } - } - } else { - console.info('getAllTags 返回了 null'); - } - } catch (e) { - console.error('检查流体标签时出错: ' + e); - console.error('堆栈: ' + e.printStackTrace()); - } - - console.info('======= 流体标签检查结束 ======='); -}); From a4924e060d38b4df03d64cba087991813678fc85 Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Wed, 20 May 2026 17:44:43 +0000 Subject: [PATCH 13/14] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=84=B1=E7=B2=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_scripts/biodiesel_fix/threshing.js | 120 ++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 server_scripts/biodiesel_fix/threshing.js diff --git a/server_scripts/biodiesel_fix/threshing.js b/server_scripts/biodiesel_fix/threshing.js new file mode 100644 index 0000000..110669d --- /dev/null +++ b/server_scripts/biodiesel_fix/threshing.js @@ -0,0 +1,120 @@ +/** + * TFC 谷物脱粒自动化脚本 + * + * 问题描述: + * TFC 的谷物(小麦、大麦等)需要用小刀手工脱粒,Create 模组会自动将 TFC 的高级无序合成配方 + * 转换为 mixing 配方,导致玩家可以用动力搅拌器自动脱粒,但原配方的工具耐久损耗和干草副产物 + * 逻辑无法在 Create mixing 中正确实现。 + * + * 解决方案: + * 1. 删除 TFC 原版谷物脱粒配方(tfc:crafting/food/_grain) + * 2. 重建配方并添加 _manual_only 后缀,阻止 Create 自动生成 mixing 配方 + * 3. 手动创建 Create mixing 配方,实现: + * - 输入:非腐败的原始作物(继承 TFC 的 not_rotten 条件) + * - 输出:谷物粒(100%)+ 干草(85%概率) + * + * 架构说明: + * 脚本遍历 #c:foods/grain 标签下的所有物品,按命名空间分发处理逻辑。 + * 各命名空间只需实现自己的:配方ID构造、原配方JSON解析、输入/输出提取、Create mixing ID + * + * 共享逻辑(统一在参数检查后执行): + * - 删除原配方 + * - 重建带 _manual_only 后缀的配方 + * - 创建 Create mixing 自动化配方 + * + * 扩展方式: + * 添加 else if (grainId.startsWith(':')) 分支, + * 在分支内设置 recipeId、recipeJson、inputIngredient、outputId、outputCount、mixingId。 + * else return; 保留,作为白名单机制,确保任何新命名空间都必须显式处理。 + */ +ServerEvents.recipes(event => { + // 获取 c:foods/grain 标签下的所有物品栈 + var grainStacks = Ingredient.of('#c:foods/grain').stackArray; + var processed = 0; + + // 遍历每个谷物粒 + grainStacks.forEach(stack => { + // 获取物品 ID,如 "tfc:food/wheat_grain" + var grainId = String(stack.getItem()); + + // ========== 命名空间分发 ========== + // 初始化各命名空间通用变量 + var recipeId = null; + var recipeJson = null; + var inputIngredient = null; + var outputId = null; + var outputCount = 1; + var mixingId = null; + + if (grainId.startsWith('tfc:')) { + // === TFC 命名空间处理 === + + // 从谷物粒 ID 推导原始作物 ID + // tfc:food/wheat_grain → tfc:food/wheat + var rawCropId = grainId.substring(0, grainId.lastIndexOf('_grain')); + + // 构建配方 ID:tfc:crafting/food/_grain + recipeId = 'tfc:crafting/' + rawCropId.substring(4) + '_grain'; + mixingId = 'kubejs:mixing/tfc_threshing/' + rawCropId.substring(4).replace('/', '_'); + + // 查找对应的原版配方并解析 JSON + var recipes = event.findRecipes({ id: recipeId }); + if (recipes.isEmpty()) return; + var jsonStr = recipes.getFirst().json.toString(); + recipeJson = JSON.parse(jsonStr); + + // 查找 ingredients 中带 children 的复合 ingredient(TFC 的 and 条件) + // 这通常包含原始作物和 not_rotten 条件 + for (var i = 0; i < recipeJson.ingredients.length; i++) { + if (recipeJson.ingredients[i].children) { + inputIngredient = recipeJson.ingredients[i]; + break; + } + } + if (!inputIngredient) return; + + // 提取配方输出信息 + outputCount = recipeJson.result.stack.count || 1; + outputId = recipeJson.result.stack.id; + + } else { + // 其他命名空间(如 firmalife)暂不处理 + return; + } + // ========== 命名空间分发结束 ========== + + // 检查是否成功提取了所有必要参数 + if (!recipeId || !recipeJson || !inputIngredient || !outputId || !mixingId) return; + + // ========== 共享逻辑 ========== + + // 删除原版配方 + event.remove({ id: recipeId }); + + // 重建配方并添加 _manual_only 后缀,阻止 Create 自动生成 mixing + event.custom(recipeJson).id(recipeId + '_manual_only'); + + // 创建 Create mixing 配方 + event.recipes.create.mixing( + [ + // 主产物:谷物粒(100%概率) + CreateItem.of(Item.of(outputId, outputCount), 1.0), + // 副产物:干草(85%概率) + CreateItem.of(Item.of('tfc:straw'), 0.85) + ], + // 输入:继承原版配方的复合 ingredient(包含 not_rotten 条件) + [Ingredient.of(inputIngredient, 1)], + // 处理时间:100 ticks = 5 秒 + 100 + ).id(mixingId); + + processed++; + }); + + // 输出处理结果日志 + if (processed > 0) { + console.info('[脱粒] 处理了 ' + processed + ' 个谷物脱粒配方:'); + console.info('[脱粒] - 删除了原 TFC 手工配方并重建 _manual_only 版本'); + console.info('[脱粒] - 创建了 Create mixing 自动化配方(85%概率产干草)'); + } +}); From bb462ea8b437b8dc7f6d35b357892306431ea0ed Mon Sep 17 00:00:00 2001 From: dalizi2333 Date: Sat, 23 May 2026 01:13:10 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E5=8F=97Create=E9=99=90=E5=88=B6?= =?UTF-8?q?=EF=BC=8C=E6=97=A0=E6=B3=95=E8=A7=A3=E5=86=B3=E4=BA=A7=E5=87=BA?= =?UTF-8?q?=E7=89=A9=E5=93=81=E8=85=90=E8=B4=A5=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=84=B1=E7=B2=92=E4=B8=8E=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E7=9A=84=E7=A3=A8=E7=B2=89=E5=8A=9F=E8=83=BD=E5=8F=96=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_scripts/biodiesel_fix/threshing.js | 120 ---------------------- 1 file changed, 120 deletions(-) delete mode 100644 server_scripts/biodiesel_fix/threshing.js diff --git a/server_scripts/biodiesel_fix/threshing.js b/server_scripts/biodiesel_fix/threshing.js deleted file mode 100644 index 110669d..0000000 --- a/server_scripts/biodiesel_fix/threshing.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * TFC 谷物脱粒自动化脚本 - * - * 问题描述: - * TFC 的谷物(小麦、大麦等)需要用小刀手工脱粒,Create 模组会自动将 TFC 的高级无序合成配方 - * 转换为 mixing 配方,导致玩家可以用动力搅拌器自动脱粒,但原配方的工具耐久损耗和干草副产物 - * 逻辑无法在 Create mixing 中正确实现。 - * - * 解决方案: - * 1. 删除 TFC 原版谷物脱粒配方(tfc:crafting/food/_grain) - * 2. 重建配方并添加 _manual_only 后缀,阻止 Create 自动生成 mixing 配方 - * 3. 手动创建 Create mixing 配方,实现: - * - 输入:非腐败的原始作物(继承 TFC 的 not_rotten 条件) - * - 输出:谷物粒(100%)+ 干草(85%概率) - * - * 架构说明: - * 脚本遍历 #c:foods/grain 标签下的所有物品,按命名空间分发处理逻辑。 - * 各命名空间只需实现自己的:配方ID构造、原配方JSON解析、输入/输出提取、Create mixing ID - * - * 共享逻辑(统一在参数检查后执行): - * - 删除原配方 - * - 重建带 _manual_only 后缀的配方 - * - 创建 Create mixing 自动化配方 - * - * 扩展方式: - * 添加 else if (grainId.startsWith(':')) 分支, - * 在分支内设置 recipeId、recipeJson、inputIngredient、outputId、outputCount、mixingId。 - * else return; 保留,作为白名单机制,确保任何新命名空间都必须显式处理。 - */ -ServerEvents.recipes(event => { - // 获取 c:foods/grain 标签下的所有物品栈 - var grainStacks = Ingredient.of('#c:foods/grain').stackArray; - var processed = 0; - - // 遍历每个谷物粒 - grainStacks.forEach(stack => { - // 获取物品 ID,如 "tfc:food/wheat_grain" - var grainId = String(stack.getItem()); - - // ========== 命名空间分发 ========== - // 初始化各命名空间通用变量 - var recipeId = null; - var recipeJson = null; - var inputIngredient = null; - var outputId = null; - var outputCount = 1; - var mixingId = null; - - if (grainId.startsWith('tfc:')) { - // === TFC 命名空间处理 === - - // 从谷物粒 ID 推导原始作物 ID - // tfc:food/wheat_grain → tfc:food/wheat - var rawCropId = grainId.substring(0, grainId.lastIndexOf('_grain')); - - // 构建配方 ID:tfc:crafting/food/_grain - recipeId = 'tfc:crafting/' + rawCropId.substring(4) + '_grain'; - mixingId = 'kubejs:mixing/tfc_threshing/' + rawCropId.substring(4).replace('/', '_'); - - // 查找对应的原版配方并解析 JSON - var recipes = event.findRecipes({ id: recipeId }); - if (recipes.isEmpty()) return; - var jsonStr = recipes.getFirst().json.toString(); - recipeJson = JSON.parse(jsonStr); - - // 查找 ingredients 中带 children 的复合 ingredient(TFC 的 and 条件) - // 这通常包含原始作物和 not_rotten 条件 - for (var i = 0; i < recipeJson.ingredients.length; i++) { - if (recipeJson.ingredients[i].children) { - inputIngredient = recipeJson.ingredients[i]; - break; - } - } - if (!inputIngredient) return; - - // 提取配方输出信息 - outputCount = recipeJson.result.stack.count || 1; - outputId = recipeJson.result.stack.id; - - } else { - // 其他命名空间(如 firmalife)暂不处理 - return; - } - // ========== 命名空间分发结束 ========== - - // 检查是否成功提取了所有必要参数 - if (!recipeId || !recipeJson || !inputIngredient || !outputId || !mixingId) return; - - // ========== 共享逻辑 ========== - - // 删除原版配方 - event.remove({ id: recipeId }); - - // 重建配方并添加 _manual_only 后缀,阻止 Create 自动生成 mixing - event.custom(recipeJson).id(recipeId + '_manual_only'); - - // 创建 Create mixing 配方 - event.recipes.create.mixing( - [ - // 主产物:谷物粒(100%概率) - CreateItem.of(Item.of(outputId, outputCount), 1.0), - // 副产物:干草(85%概率) - CreateItem.of(Item.of('tfc:straw'), 0.85) - ], - // 输入:继承原版配方的复合 ingredient(包含 not_rotten 条件) - [Ingredient.of(inputIngredient, 1)], - // 处理时间:100 ticks = 5 秒 - 100 - ).id(mixingId); - - processed++; - }); - - // 输出处理结果日志 - if (processed > 0) { - console.info('[脱粒] 处理了 ' + processed + ' 个谷物脱粒配方:'); - console.info('[脱粒] - 删除了原 TFC 手工配方并重建 _manual_only 版本'); - console.info('[脱粒] - 创建了 Create mixing 自动化配方(85%概率产干草)'); - } -});