diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java index af66ccedd63..a915c6cff67 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java @@ -1,5 +1,8 @@ package com.gregtechceu.gtceu.api.recipe.ingredient; +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.integration.kjs.recipe.KJSHelpers; + import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; @@ -327,6 +330,10 @@ public record TagValue(TagKey tag) implements Value { @Override public Collection getFluids() { + if (GTCEu.Mods.isKubeJSLoaded()) { + var resolved = KJSHelpers.getFluidsDuringLoad(this.tag); + if (resolved != null) return resolved; + } ArrayList list = Lists.newArrayList(); for (Holder holder : BuiltInRegistries.FLUID.getTagOrEmpty(this.tag)) { list.add(holder.value()); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java index 7704d092f7b..74758b76dfb 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java @@ -24,6 +24,8 @@ import com.gregtechceu.gtceu.common.item.behavior.IntCircuitBehaviour; import com.gregtechceu.gtceu.common.recipe.condition.*; import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.core.mixins.IngredientAccessor; +import com.gregtechceu.gtceu.core.mixins.TagValueAccessor; import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder; import com.gregtechceu.gtceu.integration.kjs.recipe.components.CapabilityMap; import com.gregtechceu.gtceu.integration.kjs.recipe.components.ExtendedOutputItem; @@ -792,6 +794,15 @@ private void validateItems(@NotNull String type, InputItem... items) { if (stack == null || stack.isEmpty()) { throw new RecipeExceptionJS(String.format("Invalid or empty %s item (recipe ID: %s)", type, id)); } + if (stack.ingredient.getItems().length == 0) { + String tagInfo = ""; + var values = ((IngredientAccessor) stack.ingredient).getValues(); + if (values.length == 1 && values[0] instanceof Ingredient.TagValue tagValue) { + tagInfo = " (empty or unknown tag: #" + ((TagValueAccessor) tagValue).getTag().location() + ")"; + } + throw new RecipeExceptionJS( + String.format("Invalid or empty %s item (recipe ID: %s)%s", type, id, tagInfo)); + } } } @@ -839,6 +850,15 @@ private void validateFluids(@NotNull String type, GTRecipeComponents.FluidIngred String.format("Invalid or empty %s fluid (recipe ID: %s)", type, id)); } } + if (fluid.ingredient().getStacks().length == 0) { + String tagInfo = ""; + var values = fluid.ingredient().values; + if (values.length == 1 && values[0] instanceof FluidIngredient.TagValue tagValue) { + tagInfo = " (empty or unknown tag: #" + tagValue.tag().location() + ")"; + } + throw new RecipeExceptionJS(String.format( + "Invalid or empty %s fluid (recipe ID: %s)%s", type, id, tagInfo)); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/KJSHelpers.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/KJSHelpers.java index 78cc410e131..b21b6d29c43 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/KJSHelpers.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/KJSHelpers.java @@ -3,12 +3,20 @@ import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.recipe.ingredient.EnergyStack; +import net.minecraft.core.Holder; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.material.Fluid; + +import com.google.common.collect.Lists; +import dev.latvian.mods.kubejs.item.ingredient.TagContext; +import dev.latvian.mods.kubejs.recipe.RecipesEventJS; import dev.latvian.mods.kubejs.util.MapJS; import dev.latvian.mods.kubejs.util.UtilsJS; import dev.latvian.mods.rhino.Wrapper; import it.unimi.dsi.fastutil.longs.LongLongPair; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; @@ -104,4 +112,21 @@ public static EnergyStack parseEnergyStack(Object o) { } return LongLongPair.of(voltage, amperage); } + + /** + * Resolves a fluid tag using KubeJS's TagContext during recipe (re)loading, since the server registry + * hasn't bound the tags yet. Returns null if a recipe event is not currently active. + * Analogous to KubeJS' TagContext::patchIngredientTags for items. + */ + @Nullable + public static ArrayList getFluidsDuringLoad(TagKey tag) { + if (RecipesEventJS.instance == null) return null; + + var holders = TagContext.INSTANCE.getValue().getTag(tag); + ArrayList list = Lists.newArrayList(); + for (Holder holder : holders) { + list.add(holder.value()); + } + return list; + } }