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 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/fermenting_from_barrel.js b/server_scripts/biodiesel_fix/fermenting_from_barrel.js new file mode 100644 index 0000000..8be59ad --- /dev/null +++ b/server_scripts/biodiesel_fix/fermenting_from_barrel.js @@ -0,0 +1,513 @@ +// ============================================================================ +// 批量从TFC密封大桶配方创建Create发酵配方 +// 线性流水线:解析 → 过滤 → 计算倍率 → 生成Basin/Bulk配方 +// ============================================================================ + +var BULK_FLUID_LIMIT = 72000; + +/** + * 创建贯穿转换流程的上下文对象 + * @param {Internal.RecipeEventJS} event - 配方事件 + * @returns {Object} 包含事件引用、统计计数器和常量 + */ +function createConverterData(event) { + return { + event: event, + stats: { basin: 0, bulk: 0, skipped: 0 }, + FLUID_SLOT_LIMIT: 1000 + }; +} + +/** + * 从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, + inputFluid: null, + outputItem: null, + outputFluid: null, + sealTime: 0, + basinMaxMultiplier: Infinity, + basinMultiplier: 0, + recipeId: recipe ? recipe.getId() : null, + 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'); + if (json.has('seal_time')) { + result.sealTime = json.get('seal_time').getAsInt(); + } else if (json.has('duration')) { + result.sealTime = json.get('duration').getAsInt(); + } + + return result; +} + +/** + * 安全解析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) { + 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).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; +} + +/** + * 计算Basin配方的理论最大倍率 + * 受输入/输出物品堆叠上限和1000mB流体槽限制 + * @param {Object} recipeData - 配方数据 + * @param {Object} data - 转换上下文(提供FLUID_SLOT_LIMIT) + * @returns {number} 理论最大倍率 + */ +function calculateBasinMaxMultiplier(recipeData, data) { + var maxMultiplier = Infinity; + + if (recipeData.inputItem) { + var maxStack = getMaxStackSize(recipeData.inputItem); + if (maxStack) { + var count = recipeData.inputItem.count || 1; + 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; +} + +/** + * 计算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 }); + } + } 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; +} + +/** + * 构建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; + 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; +} + +/** + * 构建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) { + for (var i = 0; i < recipeData.itemMultiplier; 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 * recipeData.fluidMultiplier + recipeData.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配方的输出列表(物品/流体独立倍率,含满池返还的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) * 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 * recipeData.fluidMultiplier + recipeData.fluidAddition; + if (fluidAmount > 0) { + results.push({ id: fluidId, amount: fluidAmount }); + } + } + } + + return results; +} + +/** + * 尝试生成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; + + var ingredients = buildBasinIngredients(recipeData.inputItem, recipeData.inputFluid, recipeData.basinMultiplier); + var results = buildBasinResults(recipeData.outputItem, recipeData.outputFluid, recipeData.basinMultiplier); + + if (results.length === 0 || ingredients.length === 0) return; + + var processingTime = Math.max(100, Math.round(recipeData.sealTime / 5)); + + data.event.custom({ + type: 'createdieselgenerators:basin_fermenting', + ingredients: ingredients, + processing_time: processingTime, + results: results + }).id('kubejs:tfc_barrel_sealed/basin/' + recipeData.basinMultiplier + '_' + recipe.getId().replace(':', '_')); + + data.stats.basin++; +} + +/** + * 尝试生成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; + + var processingTime = Math.max(100, Math.round(recipeData.sealTime / 4)); + 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++; +} + +/** + * 转换单个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); + + if (recipeData.outputItem && recipeData.outputItem.modifiers) { + data.stats.skipped++; + return; + } + + if (!recipeData.outputItem && !recipeData.outputFluid) { + data.stats.skipped++; + return; + } + + 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) { + data.event.forEachRecipe({ type: 'tfc:barrel_sealed' }, function(recipe) { + convertSingleRecipe(data, recipe); + }); +} + +ServerEvents.recipes(function(event) { + var data = createConverterData(event); + verifyStackSizeLoaded(data); + convertAllRecipes(data); +}); 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..f9ac9ae --- /dev/null +++ b/server_scripts/biodiesel_fix/mixing_from_barrel_instant.js @@ -0,0 +1,351 @@ +// ============================================================================ +// 批量从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.children && recipeData.inputItem.children.length > 0) { + for (var i = 0; i < recipeData.inputItem.children.length; i++) { + var child = recipeData.inputItem.children[i]; + 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 { + 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/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/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' + ) +})