diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java index 1db210ce895..7754859593a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java @@ -179,9 +179,7 @@ public int getMaxParallelByInput(IRecipeCapabilityHolder holder, GTRecipe recipe for (Content content : inputs) { FluidIngredient ing = of(content.content()); - int amount; - if (ing instanceof IRangedIngredient provider) amount = provider.getMaxRoll(); - else amount = ing.getAmount(); + int amount = ing.getAmount(); if (content.chance() == 0) { nonConsumables.addTo(ing, amount); diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java index 41e6c0ca736..79c24814cf1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java @@ -88,9 +88,6 @@ public List compressIngredients(@Unmodifiable Collection ingredi } else if (ingredient instanceof SizedIngredient sized && sized.getInner() instanceof IntCircuitIngredient) { list.add(0, ingredient); - } else if (ingredient instanceof IntProviderIngredient intProvider && - intProvider.getInner() instanceof IntCircuitIngredient) { - list.add(0, ingredient); } else { list.add(ingredient); } @@ -152,7 +149,7 @@ public int limitMaxParallelByOutput(IRecipeCapabilityHolder holder, GTRecipe rec int count; if (ing instanceof SizedIngredient sized) count = sized.getAmount(); - else if (ing instanceof IntProviderIngredient provider) count = provider.getCountProvider().getMaxValue(); + else if (ing instanceof IntProviderIngredient provider) count = provider.getMaxRoll(); else count = 1; maxCount = Math.max(maxCount, count); @@ -204,7 +201,7 @@ public int getMaxParallelByInput(IRecipeCapabilityHolder holder, GTRecipe recipe int count; if (ing instanceof SizedIngredient sized) count = sized.getAmount(); - else if (ing instanceof IntProviderIngredient provider) count = provider.getCountProvider().getMaxValue(); + else if (ing instanceof IntProviderIngredient provider) count = provider.getMaxRoll(); else count = 1; if (content.chance() == 0) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableFluidTank.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableFluidTank.java index ea748777afe..d99dec635e0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableFluidTank.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableFluidTank.java @@ -118,15 +118,8 @@ public void onContentsChanged() { FluidStack[] fluids; - if (ingredient instanceof IntProviderFluidIngredient provider) { - provider.setFluidStacks(null); - provider.setSampledCount(-1); - - if (simulate) { - fluids = new FluidStack[] { provider.getMaxSizeStack() }; - } else { - fluids = provider.getStacks(); - } + if (ingredient instanceof IntProviderFluidIngredient provider && simulate) { + fluids = new FluidStack[] { provider.getMaxSizeStack() }; } else { fluids = ingredient.getStacks(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableItemStackHandler.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableItemStackHandler.java index 45dcd6279df..bfd16bb9676 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableItemStackHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableItemStackHandler.java @@ -120,9 +120,6 @@ public static List handleRecipe(IO io, GTRecipe recipe, List> validMachineClasses() { public long getInputAmperage() { var recipeLogic = getMachine().getTrait(RecipeLogic.TYPE); if (recipeLogic == null) return 0; - var lastRecipe = recipeLogic.getLastRecipe(); + var lastRecipe = recipeLogic.getLastDisplayedRecipe(); long amperage; if (lastRecipe != null) { amperage = lastRecipe.getInputEUt().amperage(); @@ -49,7 +49,7 @@ public long getInputAmperage() { public long getOutputAmperage() { var recipeLogic = getMachine().getTrait(RecipeLogic.TYPE); if (recipeLogic == null) return 0; - var lastRecipe = recipeLogic.getLastRecipe(); + var lastRecipe = recipeLogic.getLastDisplayedRecipe(); if (lastRecipe != null) { return lastRecipe.getOutputEUt().amperage(); } else { diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/RecipeLogic.java b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/RecipeLogic.java index 500fdc6f2af..ba498a83020 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/trait/RecipeLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/trait/RecipeLogic.java @@ -99,8 +99,12 @@ public enum Status implements StringRepresentable { @Nullable @Getter @SaveField - @SyncToClient protected GTRecipe lastRecipe; + @Nullable + @Getter + @SaveField + @SyncToClient + protected GTRecipe lastDisplayedRecipe; @Getter @SaveField @SyncToClient @@ -165,6 +169,7 @@ protected void onStatusSynced() { public void resetRecipeLogic() { recipeDirty = false; lastRecipe = null; + lastDisplayedRecipe = null; lastOriginRecipe = null; consecutiveRecipes = 0; progress = 0; @@ -354,16 +359,18 @@ public void findAndHandleRecipe() { if (!recipeDirty && lastRecipe != null && checkRecipe(lastRecipe).isSuccess()) { GTRecipe recipe = lastRecipe; lastRecipe = null; + lastDisplayedRecipe = null; lastOriginRecipe = null; setupRecipe(recipe); } else { // try to find and handle a new recipe failureReasonMap.clear(); lastRecipe = null; + lastDisplayedRecipe = null; lastOriginRecipe = null; handleSearchingRecipes(searchRecipe()); } - syncDataHolder.markClientSyncFieldDirty("lastRecipe"); + syncDataHolder.markClientSyncFieldDirty("lastDisplayedRecipe"); recipeDirty = false; } @@ -393,6 +400,8 @@ public ActionResult handleTickRecipe(GTRecipe recipe) { var result = RecipeHelper.matchTickRecipe(getRLMachine(), recipe); if (!result.isSuccess()) return result; + recipe.doTickPrerolls(this.chanceCaches); + result = handleTickRecipeIO(recipe, IO.IN); if (!result.isSuccess()) return result; @@ -410,6 +419,12 @@ public void setupRecipe(GTRecipe recipe) { syncDataHolder.resyncAllFields(); return; } + if (lastRecipe != null && !recipe.equals(lastRecipe)) { + chanceCaches.clear(); + } + lastDisplayedRecipe = recipe.copy(); + syncDataHolder.markClientSyncFieldDirty("lastDisplayedRecipe"); + recipe.doPrerolls(this.chanceCaches); var handledIO = handleRecipeIO(recipe, IO.IN); if (handledIO.isSuccess()) { if (lastRecipe != null && !recipe.equals(lastRecipe)) { @@ -423,6 +438,8 @@ public void setupRecipe(GTRecipe recipe) { duration = recipe.duration; isActive = true; syncDataHolder.resyncAllFields(); + } else { + lastDisplayedRecipe = null; } } @@ -541,6 +558,7 @@ public void onRecipeFinish() { isActive = false; // Force a recipe recheck. lastRecipe = null; + lastDisplayedRecipe = null; syncDataHolder.resyncAllFields(); return; } @@ -551,7 +569,6 @@ public void onRecipeFinish() { markLastRecipeDirty(); } else { lastRecipe = modified; - syncDataHolder.markClientSyncFieldDirty("lastRecipe"); } } else { markLastRecipeDirty(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipe.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipe.java index 762e6e5c463..b336fbe3199 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipe.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipe.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; import com.gregtechceu.gtceu.api.recipe.ingredient.EnergyStack; +import com.gregtechceu.gtceu.api.recipe.ingredient.IRangedIngredient; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.RegistryAccess; @@ -16,12 +17,14 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.level.Level; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter; import lombok.Setter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Stream; import javax.annotation.ParametersAreNonnullByDefault; @@ -231,6 +234,36 @@ public ChanceLogic getChanceLogicForCapability(RecipeCapability cap, IO io, b return new EnergyStack(v, a); } + public void doPrerolls(IdentityHashMap, Object2IntMap> chanceCaches) { + var rangedContents = getFullContents(); + for (Content item : rangedContents) { + if (item.content() instanceof IRangedIngredient ranged) + ranged.rollSampledCount(); + } + } + + public void doTickPrerolls(IdentityHashMap, Object2IntMap> chanceCaches) { + var rangedContents = getFullTickContents(); + for (Content item : rangedContents) { + if (item.content() instanceof IRangedIngredient ranged) + ranged.rollSampledCount(); + } + } + + public List getFullContents() { + return Stream + .concat(inputs.values().stream(), outputs.values().stream()) + .flatMap(List::stream) + .toList(); + } + + public List getFullTickContents() { + return Stream + .concat(tickInputs.values().stream(), tickOutputs.values().stream()) + .flatMap(List::stream) + .toList(); + } + public int getTotalRuns() { return parallels * subtickParallels * batchParallels; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/RecipeHelper.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/RecipeHelper.java index b8ebc067ba1..1648ecf4537 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/RecipeHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/RecipeHelper.java @@ -11,7 +11,6 @@ import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.api.recipe.ingredient.EnergyStack; import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; -import com.gregtechceu.gtceu.api.recipe.ingredient.IRangedIngredient; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder; import com.gregtechceu.gtceu.utils.GTUtil; @@ -401,7 +400,6 @@ public static int getRatioForDistillery(FluidIngredient fluidInput, FluidIngredi } public static boolean isFluidStackDivisibleForDistillery(FluidIngredient fluidStack, int divisor) { - int amount = (fluidStack instanceof IRangedIngredient ranged ? ranged.getMaxRoll() : fluidStack.getAmount()); - return amount % divisor == 0 && amount / divisor >= 25; + return fluidStack.getAmount() % divisor == 0 && fluidStack.getAmount() / divisor >= 25; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/content/ContentModifier.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/content/ContentModifier.java index 3ec1fb025fe..7623a4c21e0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/content/ContentModifier.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/content/ContentModifier.java @@ -42,7 +42,7 @@ public double apply(double number) { * @return A new Content map that is the modified version of the argument */ public Map, List> applyContents(Map, List> contents) { - if (this == IDENTITY) return new HashMap<>(contents); + // Prerolls require copying, even on IDENTITY Map, List> copyContents = new HashMap<>(); for (var entry : contents.entrySet()) { var contentList = entry.getValue(); 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 bda901a7aa2..450c1d74544 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 @@ -38,7 +38,7 @@ public class FluidIngredient implements Predicate { @Nullable public FluidStack[] stacks; @Getter - protected int amount; + private int amount; @Getter protected CompoundTag nbt; protected boolean changed = true; diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IRangedIngredient.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IRangedIngredient.java index 707f63186a3..5f3575731bb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IRangedIngredient.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IRangedIngredient.java @@ -28,6 +28,8 @@ default int rollSampledCount() { int rollSampledCount(@NotNull RandomSource random); + int getAmount(); + /** * @return the average roll of this ranged amount */ diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredient.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredient.java index 4620784369a..88b9e929175 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredient.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredient.java @@ -2,7 +2,6 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.GTValues; -import com.gregtechceu.gtceu.config.ConfigHolder; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; @@ -40,7 +39,6 @@ public class IntProviderFluidIngredient extends FluidIngredient implements IRang * The last result of {@link IntProviderFluidIngredient#getSampledCount()}. -1 if not rolled. */ @Getter - @Setter protected int sampledCount = -1; /** * The {@link FluidIngredient} to have a ranged amount. @@ -51,37 +49,31 @@ public class IntProviderFluidIngredient extends FluidIngredient implements IRang protected FluidStack[] fluidStacks = null; protected IntProviderFluidIngredient(FluidIngredient inner, IntProvider provider) { - super(inner.values, provider.getMaxValue(), null); + super(inner.values, provider.getMaxValue(), inner.nbt); this.inner = inner; this.countProvider = provider; + setAmount(provider.getMaxValue()); } protected IntProviderFluidIngredient(FluidIngredient inner, IntProvider provider, int sampledCount) { - super(inner.values, provider.getMaxValue(), null); + super(inner.values, provider.getMaxValue(), inner.nbt); this.inner = inner; this.countProvider = provider; this.sampledCount = sampledCount; + setAmount(isRolled() ? sampledCount : provider.getMaxValue()); } @Override public IntProviderFluidIngredient copy() { IntProviderFluidIngredient ipfi = new IntProviderFluidIngredient(this.inner, this.countProvider); ipfi.setSampledCount(this.sampledCount); + ipfi.setAmount(this.getAmount()); return ipfi; } - /** - * An {@link IntProviderFluidIngredient} does not have an amount. - * You probably want either {@link IntProviderFluidIngredient#getStacks()} or - * {@link IntProviderFluidIngredient#getMaxSizeStack()}. - */ - @Deprecated @Override - public int getAmount() { - if (ConfigHolder.INSTANCE.dev.debug) { - throw new IllegalCallerException("An IPFI should never have getAmount() called on it!"); - } - return -1; + public boolean isEmpty() { + return this.getAmount() == 0 || super.isEmpty(); } /** @@ -92,16 +84,20 @@ public int getAmount() { */ @Override public FluidStack[] getStacks() { - if (fluidStacks == null) { - int cachedAmount = rollSampledCount(GTValues.RNG); - if (cachedAmount == 0) { - return EMPTY_STACK_ARRAY; + if (changed || fluidStacks == null) { + changed = false; + if (!isRolled()) { + setAmount(rollSampledCount()); + if (getAmount() == 0) { + fluidStacks = EMPTY_STACK_ARRAY; + return EMPTY_STACK_ARRAY; + } } var innerStacks = inner.getStacks(); this.fluidStacks = new FluidStack[innerStacks.length]; for (int i = 0; i < fluidStacks.length; i++) { fluidStacks[i] = innerStacks[i].copy(); - fluidStacks[i].setAmount(cachedAmount); + fluidStacks[i].setAmount(getAmount()); } } return fluidStacks; @@ -129,10 +125,11 @@ public FluidStack[] getStacks() { * @return the amount rolled */ public int rollSampledCount(@NotNull RandomSource random) { - if (sampledCount == -1) { + if (!isRolled()) { sampledCount = countProvider.sample(random); + this.setAmount(sampledCount); } - return sampledCount; + return getAmount(); } /** @@ -142,19 +139,23 @@ public double getMidRoll() { return ((countProvider.getMaxValue() + countProvider.getMinValue()) / 2.0); } - @Override - public boolean isEmpty() { - return inner.isEmpty(); - } - /** * Resets the random roll on this ingredient */ public void reset() { sampledCount = -1; + super.setAmount(getMaxRoll()); fluidStacks = null; } + /** + * Also sets the Amount of this ingredient + */ + public void setSampledCount(int count) { + this.sampledCount = count; + super.setAmount(count); + } + /** * @param inner {@link FluidIngredient} * @param provider usually as {@link UniformInt#of(int, int)} @@ -201,11 +202,11 @@ public static IntProviderFluidIngredient fromJson(JsonElement json) { throw new JsonSyntaxException("Fluid ingredient cannot be null"); } JsonObject jsonObject = GsonHelper.convertToJsonObject(json, "ingredient"); - IntProvider amount = IntProvider.CODEC.parse(JsonOps.INSTANCE, jsonObject.get("count_provider")) + IntProvider provider = IntProvider.CODEC.parse(JsonOps.INSTANCE, jsonObject.get("count_provider")) .getOrThrow(false, GTCEu.LOGGER::error); int sampledCount = jsonObject.getAsJsonPrimitive("sampledCount").getAsInt(); FluidIngredient inner = FluidIngredient.fromJson(jsonObject.get("inner")); - return new IntProviderFluidIngredient(inner, amount, sampledCount); + return new IntProviderFluidIngredient(inner, provider, sampledCount); } public CompoundTag toNBT() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredient.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredient.java index f2731e6217e..af9bafd5e11 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredient.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredient.java @@ -44,7 +44,6 @@ public class IntProviderIngredient extends Ingredient implements IRangedIngredie * The last result of {@link IntProviderIngredient#rollSampledCount(RandomSource)}. -1 if not rolled. */ @Getter - @Setter protected int sampledCount = -1; /** * The {@link Ingredient} to have a ranged amount. @@ -53,18 +52,27 @@ public class IntProviderIngredient extends Ingredient implements IRangedIngredie protected final Ingredient inner; @Setter protected ItemStack[] itemStacks = null; + @Getter + private int amount; + private boolean changed = true; protected IntProviderIngredient(Ingredient inner, IntProvider countProvider) { super(Stream.empty()); this.inner = inner; this.countProvider = countProvider; + this.amount = getMaxRoll(); } - protected IntProviderIngredient(Ingredient inner, IntProvider countProvider, int sampledCount) { + protected IntProviderIngredient(Ingredient inner, IntProvider countProvider, int sampledCount, int amount) { super(Stream.empty()); this.inner = inner; this.countProvider = countProvider; this.sampledCount = sampledCount; + this.amount = amount; + } + + public IntProviderIngredient copy() { + return new IntProviderIngredient(this.inner, this.countProvider, this.sampledCount, this.amount); } /** @@ -99,20 +107,29 @@ public boolean test(@Nullable ItemStack stack) { */ @Override public ItemStack @NotNull [] getItems() { - if (itemStacks == null) { - int cachedCount = rollSampledCount(); - if (cachedCount == 0) { - return EMPTY_STACK_ARRAY; + if (changed || itemStacks == null) { + changed = false; + if (!isRolled()) { + setAmount(rollSampledCount()); + if (getAmount() == 0) { + itemStacks = EMPTY_STACK_ARRAY; + return EMPTY_STACK_ARRAY; + } } var innerStacks = inner.getItems(); this.itemStacks = new ItemStack[innerStacks.length]; for (int i = 0; i < itemStacks.length; i++) { - itemStacks[i] = innerStacks[i].copyWithCount(cachedCount); + itemStacks[i] = innerStacks[i].copyWithCount(getAmount()); } } return itemStacks; } + public void setAmount(int amount) { + this.amount = amount; + this.changed = true; + } + /** * Gets a {@link ItemStack} containing the maximum possible output from this {@link IntProviderIngredient}. * Mainly used for things like Recipe provider simulations to see if there is enough inventory space to handle @@ -134,17 +151,27 @@ public boolean test(@Nullable ItemStack stack) { * @return the count rolled */ public int rollSampledCount(@NotNull RandomSource random) { - if (sampledCount == -1) { + if (!isRolled()) { sampledCount = countProvider.sample(random); + this.setAmount(sampledCount); } return sampledCount; } + /** + * Also sets the Amount of this ingredient + */ + public void setSampledCount(int count) { + this.sampledCount = count; + this.setAmount(count); + } + /** * Resets the random roll on this ingredient */ public void reset() { sampledCount = -1; + setAmount(getMaxRoll()); itemStacks = null; } @@ -155,7 +182,7 @@ public void reset() { @Override public boolean isEmpty() { - return inner.isEmpty(); + return this.getAmount() == 0 || inner.isEmpty(); } @Override @@ -192,6 +219,7 @@ public static IntProviderIngredient fromJson(JsonObject json) { .getOrThrow(false, GTCEu.LOGGER::error)); json.add("ingredient", inner.toJson()); json.addProperty("sampledCount", sampledCount); + json.addProperty("amount", amount); return json; } @@ -203,7 +231,8 @@ public static IntProviderIngredient fromJson(JsonObject json) { IntProvider provider = IntProvider.CODEC.parse(NbtOps.INSTANCE, nbt.get("provider")) .getOrThrow(false, GTCEu.LOGGER::error); int sampledCount = nbt.getInt("sampledCount"); - return new IntProviderIngredient(Ingredient.fromNetwork(buffer), provider, sampledCount); + int amount = nbt.getInt("amount"); + return new IntProviderIngredient(Ingredient.fromNetwork(buffer), provider, sampledCount, amount); } @Override @@ -212,7 +241,8 @@ public static IntProviderIngredient fromJson(JsonObject json) { .getOrThrow(false, GTCEu.LOGGER::error); Ingredient inner = Ingredient.fromJson(json.get("ingredient")); int sampledCount = json.getAsJsonPrimitive("sampledCount").getAsInt(); - return new IntProviderIngredient(inner, provider, sampledCount); + int amount = json.getAsJsonPrimitive("amount").getAsInt(); + return new IntProviderIngredient(inner, provider, sampledCount, amount); } @Override @@ -221,6 +251,7 @@ public void write(FriendlyByteBuf buffer, IntProviderIngredient ingredient) { wrapper.put("provider", IntProvider.CODEC.encodeStart(NbtOps.INSTANCE, ingredient.countProvider) .getOrThrow(false, GTCEu.LOGGER::error)); wrapper.putInt("sampledCount", ingredient.sampledCount); + wrapper.putInt("amount", ingredient.amount); buffer.writeNbt(wrapper); ingredient.inner.toNetwork(buffer); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/SizedIngredient.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/SizedIngredient.java index 1f407d02ed0..75b8dd6c799 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/SizedIngredient.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/SizedIngredient.java @@ -83,20 +83,11 @@ public static Ingredient copy(Ingredient ingredient) { if (sizedIngredient.inner instanceof IntProviderIngredient intProviderIngredient) { return copy(intProviderIngredient); } - return SizedIngredient.create(sizedIngredient.inner, sizedIngredient.amount); } else if (ingredient instanceof IntCircuitIngredient circuit) { return circuit; - } else if (ingredient instanceof IntProviderIngredient intProviderIngredient) { - var copied = IntProviderIngredient.of(intProviderIngredient.inner, intProviderIngredient.countProvider); - if (intProviderIngredient.itemStacks != null) { - copied.itemStacks = Arrays.stream(intProviderIngredient.itemStacks).map(ItemStack::copy) - .toArray(ItemStack[]::new); - } - if (intProviderIngredient.sampledCount != -1) { - copied.sampledCount = intProviderIngredient.sampledCount; - } - return copied; + } else if (ingredient instanceof IntProviderIngredient provider) { + return provider.copy(); } return SizedIngredient.create(ingredient, ingredient.getItems()[0].getCount()); } @@ -135,9 +126,6 @@ public boolean test(@Nullable ItemStack stack) { @Override public ItemStack @NotNull [] getItems() { - if (getInner() instanceof IntProviderIngredient intProviderIngredient) { - return intProviderIngredient.getItems(); - } if (changed || itemStacks == null) { var innerStacks = inner.getItems(); this.itemStacks = new ItemStack[innerStacks.length]; diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/ingredient/fluid/FluidStackMapIngredient.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/ingredient/fluid/FluidStackMapIngredient.java index 5314097c110..49c18543a8c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/ingredient/fluid/FluidStackMapIngredient.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/ingredient/fluid/FluidStackMapIngredient.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.api.recipe.lookup.ingredient.fluid; import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; -import com.gregtechceu.gtceu.api.recipe.ingredient.IRangedIngredient; import com.gregtechceu.gtceu.api.recipe.lookup.ingredient.AbstractMapIngredient; import net.minecraftforge.fluids.FluidStack; @@ -31,11 +30,7 @@ public static List from(@NotNull FluidIngredient ingredie List ingredients = new ObjectArrayList<>(); for (FluidIngredient.Value value : ingredient.values) { if (value instanceof FluidIngredient.FluidValue fluidValue) { - FluidStack stack = new FluidStack(fluidValue.fluid(), - (ingredient instanceof IRangedIngredient provider ? - provider.getMaxRoll() : - ingredient.getAmount()), - ingredient.getNbt()); + FluidStack stack = new FluidStack(fluidValue.fluid(), ingredient.getAmount(), ingredient.getNbt()); ingredients.add(new FluidStackMapIngredient(stack, ingredient)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ModifierFunction.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ModifierFunction.java index 35067a36053..fca5c1f30b4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ModifierFunction.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ModifierFunction.java @@ -204,7 +204,7 @@ public ModifierFunction build() { private static Map, List> applyAllButEU(ContentModifier cm, Map, List> contents) { - if (cm == ContentModifier.IDENTITY) return new HashMap<>(contents); + // Prerolls require copying, even on IDENTITY Map, List> copyContents = new HashMap<>(); for (var entry : contents.entrySet()) { var cap = entry.getKey(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java index c1e5c2d5adf..db0883cc0aa 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java @@ -92,7 +92,7 @@ public void render(WorkableMultiblockMachine machine, float partialTick, if (trait == null || !machine.isFormed() || trait.getFluidOffsets().isEmpty()) return; if (!fixedFluid) { - var lastRecipe = machine.getRecipeLogic().getLastRecipe(); + var lastRecipe = machine.getRecipeLogic().getLastDisplayedRecipe(); if (lastRecipe == null) { cachedRecipe = null; cachedFluid = null; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/GrowingPlantRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/GrowingPlantRender.java index ef13449fab6..f1e554f4c66 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/GrowingPlantRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/GrowingPlantRender.java @@ -112,7 +112,7 @@ public void render(IRecipeLogicMachine rlm, float partialTick, PoseStack poseSta final RecipeLogic recipeLogic = rlm.getRecipeLogic(); Optional currentBlock = this.growingBlock - .or(() -> Optional.ofNullable(recipeLogic.getLastRecipe()).flatMap(this::findGrowing)); + .or(() -> Optional.ofNullable(recipeLogic.getLastDisplayedRecipe()).flatMap(this::findGrowing)); if (currentBlock.isEmpty()) return; Block growing = currentBlock.get(); BlockState state = growing.defaultBlockState(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/PortableScannerBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/PortableScannerBehavior.java index 4eb6b6066e7..eac730643c2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/PortableScannerBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/PortableScannerBehavior.java @@ -320,7 +320,7 @@ public int addScannerInfo(Player player, Level level, BlockPos pos, DisplayMode // Recipe logic for EU production/consumption RecipeLogic recipeLogic = machine.getTrait(RecipeLogic.TYPE); if (recipeLogic != null) { - GTRecipe recipe = recipeLogic.getLastRecipe(); + GTRecipe recipe = recipeLogic.getLastDisplayedRecipe(); if (recipeLogic.getStatus().equals(RecipeLogic.Status.WAITING)) { list.add(Component.translatable("behavior.portable_scanner.divider")); list.add(Component.translatable("gtceu.multiblock.waiting")); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/AssemblyLineMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/AssemblyLineMachine.java index 23748c9bec8..b652cf42cea 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/AssemblyLineMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/AssemblyLineMachine.java @@ -18,7 +18,6 @@ import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.RecipeHelper; import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; -import com.gregtechceu.gtceu.api.recipe.ingredient.IRangedIngredient; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; import com.gregtechceu.gtceu.config.ConfigHolder; @@ -153,9 +152,7 @@ private boolean checkFluidInputs(GTRecipe recipe, boolean isTick) { for (int i = 0; i < inputsSize; i++) { var fluidStack = fluidInventory.get(i); FluidIngredient recipeStack = FluidRecipeCapability.CAP.of(fluidInputs.get(i).content()); - if (!recipeStack.test(fluidStack) || - (recipeStack instanceof IRangedIngredient ? ((IRangedIngredient) recipeStack).getMaxRoll() : - recipeStack.getAmount()) > fluidStack.getAmount()) { + if (!recipeStack.test(fluidStack) || (recipeStack.getAmount()) > fluidStack.getAmount()) { return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java index 355f0084e1a..19e6c5ebeba 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java @@ -13,7 +13,7 @@ import com.gregtechceu.gtceu.api.recipe.RecipeHelper; import com.gregtechceu.gtceu.api.recipe.content.Content; import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; -import com.gregtechceu.gtceu.api.recipe.ingredient.IRangedIngredient; +import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; import com.gregtechceu.gtceu.api.recipe.modifier.ParallelLogic; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient; @@ -141,7 +141,7 @@ public int limitFluidParallel(GTRecipe recipe, int multiplier, boolean tick) { .map(Content::content) .map(FluidRecipeCapability.CAP::of) .filter(i -> !i.isEmpty()) - .mapToInt((i -> i instanceof IRangedIngredient ? ((IRangedIngredient) i).getMaxRoll() : i.getAmount())) + .mapToInt(FluidIngredient::getAmount) .max() .orElse(0); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java index 31517e494e4..fbde9285058 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java @@ -200,7 +200,7 @@ public static ModifierFunction recipeModifier(MetaMachine machine, GTRecipe reci @Override public boolean onWorking() { - GTRecipe recipe = recipeLogic.getLastRecipe(); + GTRecipe recipe = recipeLogic.getLastDisplayedRecipe(); assert recipe != null; if (recipe.data.contains("eu_to_start")) { long heatDiff = recipe.data.getLong("eu_to_start") - this.heat; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeCombustionEngineMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeCombustionEngineMachine.java index 8a66b859aaf..21c18988a3a 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeCombustionEngineMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeCombustionEngineMachine.java @@ -204,7 +204,7 @@ public boolean regressWhenWaiting() { @Nullable public String getRecipeFluidInputInfo() { // Previous Recipe is always null on first world load, so try to acquire a new recipe - GTRecipe recipe = recipeLogic.getLastRecipe(); + GTRecipe recipe = recipeLogic.getLastDisplayedRecipe(); if (recipe == null) { Iterator iterator = recipeLogic.searchRecipe(); recipe = iterator.hasNext() ? iterator.next() : null; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeTurbineMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeTurbineMachine.java index 8ebc5901ea6..28e855c767d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeTurbineMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/generator/LargeTurbineMachine.java @@ -101,8 +101,8 @@ public int getTotalEfficiency() { } public long getCurrentProduction() { - return isActive() && recipeLogic.getLastRecipe() != null ? - recipeLogic.getLastRecipe().getOutputEUt().voltage() : 0; + return isActive() && recipeLogic.getLastDisplayedRecipe() != null ? + recipeLogic.getLastDisplayedRecipe().getOutputEUt().voltage() : 0; } public int getRotorDurabilityPercent() { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java index b7ea4f2f473..d5b3b3031fc 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/steam/SteamSolidBoilerMachine.java @@ -81,8 +81,8 @@ protected long getBaseSteamOutput() { @Override public void afterWorking() { super.afterWorking(); - if (recipeLogic.getLastRecipe() != null) { - var inputs = recipeLogic.getLastRecipe().inputs.getOrDefault(ItemRecipeCapability.CAP, + if (recipeLogic.getLastDisplayedRecipe() != null) { + var inputs = recipeLogic.getLastDisplayedRecipe().inputs.getOrDefault(ItemRecipeCapability.CAP, Collections.emptyList()); if (!inputs.isEmpty()) { var input = ItemRecipeCapability.CAP.of(inputs.get(0).content()).getItems(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java b/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java index 6d61e33c5e8..7eaf7b86546 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java @@ -256,8 +256,8 @@ public static TextWidget addEnergyTierLine(WorkableElectricMultiblockMachine public static TextWidget addParallelLine(WorkableMultiblockMachine rlMachine, PanelSyncManager syncManager) { IntSyncValue parallelAmount = syncManager.getOrCreateSyncHandler("parallelAmount", IntSyncValue.class, () -> new IntSyncValue(() -> { - if (rlMachine.getRecipeLogic().getLastRecipe() == null) return 0; - return rlMachine.getRecipeLogic().getLastRecipe().parallels; + if (rlMachine.getRecipeLogic().getLastDisplayedRecipe() == null) return 0; + return rlMachine.getRecipeLogic().getLastDisplayedRecipe().parallels; })); return Text.dynamic(() -> { @@ -275,8 +275,8 @@ public static TextWidget addBatchModeLine(WorkableMultiblockMachine rlMachine () -> new BooleanSyncValue(rlMachine::isBatchEnabled)); IntSyncValue batchAmount = syncManager.getOrCreateSyncHandler("batchAmount", IntSyncValue.class, () -> new IntSyncValue(() -> { - if (rlMachine.getRecipeLogic().getLastRecipe() == null) return 0; - return rlMachine.getRecipeLogic().getLastRecipe().batchParallels; + if (rlMachine.getRecipeLogic().getLastDisplayedRecipe() == null) return 0; + return rlMachine.getRecipeLogic().getLastDisplayedRecipe().batchParallels; })); return Text.dynamic(() -> { @@ -293,8 +293,8 @@ public static TextWidget addSubtickParallelsLine(WorkableMultiblockMachine rl PanelSyncManager syncManager) { IntSyncValue subtickAmount = syncManager.getOrCreateSyncHandler("subtickAmount", IntSyncValue.class, () -> new IntSyncValue(() -> { - if (rlMachine.getRecipeLogic().getLastRecipe() == null) return 0; - return rlMachine.getRecipeLogic().getLastRecipe().subtickParallels; + if (rlMachine.getRecipeLogic().getLastDisplayedRecipe() == null) return 0; + return rlMachine.getRecipeLogic().getLastDisplayedRecipe().subtickParallels; })); return Text.dynamic(() -> { @@ -310,8 +310,8 @@ public static TextWidget addSubtickParallelsLine(WorkableMultiblockMachine rl public static TextWidget addTotalRunsLine(WorkableMultiblockMachine rlMachine, PanelSyncManager syncManager) { IntSyncValue totalRunAmount = syncManager.getOrCreateSyncHandler("totalRunAmount", IntSyncValue.class, () -> new IntSyncValue(() -> { - if (rlMachine.getRecipeLogic().getLastRecipe() == null) return 0; - return rlMachine.getRecipeLogic().getLastRecipe().getTotalRuns(); + if (rlMachine.getRecipeLogic().getLastDisplayedRecipe() == null) return 0; + return rlMachine.getRecipeLogic().getLastDisplayedRecipe().getTotalRuns(); })); return Text.dynamic(() -> { @@ -399,7 +399,7 @@ public static DynamicWidget addOutputLines(WorkableMultiblockMachine rlmachin "GTRecipe", GenericSyncValue.class, () -> GenericSyncValue.builder(GTRecipe.class) - .getter(() -> rlmachine.getRecipeLogic().getLastRecipe()) + .getter(() -> rlmachine.getRecipeLogic().getLastDisplayedRecipe()) .setter((newRecipe) -> {}) .adapter(GTByteBufAdapters.GTRECIPE) .copy(GTRecipe::copy) diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java index f23120d0b62..83bf7cc8c21 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java @@ -1704,7 +1704,7 @@ private void addOutputMaterialInfo() { if (items.length > 0) { out = items[0].getItem(); // use the max amount of items for decomp info so dupes can't happen - outputCount = intProvider.getCountProvider().getMaxValue(); + outputCount = intProvider.getMaxRoll(); } } else if (!currOutput.isEmpty()) { ItemStack[] items = currOutput.getItems(); @@ -1755,7 +1755,7 @@ private void removeExistingMaterialInfo() { if (items.length > 0) { out = items[0].getItem(); // use the max amount of items for decomp info so dupes can't happen - outputCount = intProvider.getCountProvider().getMaxValue(); + outputCount = intProvider.getMaxRoll(); } } else if (!currOutput.isEmpty()) { ItemStack[] items = currOutput.getItems(); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java index 5b6cd1339e4..27b5edbb546 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/ae2/machine/MEOutputHatchPartMachine.java @@ -196,15 +196,8 @@ public boolean isFluidValid(int tank, FluidStack stack) { } FluidStack[] fluids; - if (ingredient instanceof IntProviderFluidIngredient provider) { - provider.setFluidStacks(null); - provider.setSampledCount(-1); - - if (simulate) { - fluids = new FluidStack[] { provider.getMaxSizeStack() }; - } else { - fluids = provider.getStacks(); - } + if (ingredient instanceof IntProviderFluidIngredient provider && simulate) { + fluids = new FluidStack[] { provider.getMaxSizeStack() }; } else { fluids = ingredient.getStacks(); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ParallelProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ParallelProvider.java index 63ecc9a3358..2fac0cb9e37 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ParallelProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/ParallelProvider.java @@ -31,10 +31,10 @@ protected CompoundTag write(MetaMachine machine) { } else if (machine instanceof MultiblockControllerMachine controller) { if (controller instanceof IRecipeLogicMachine rlm && rlm.getRecipeLogic().isActive() && - rlm.getRecipeLogic().getLastRecipe() != null) { - compoundTag.putInt("parallel", rlm.getRecipeLogic().getLastRecipe().parallels); - compoundTag.putInt("batch", rlm.getRecipeLogic().getLastRecipe().batchParallels); - compoundTag.putInt("subtickParallel", rlm.getRecipeLogic().getLastRecipe().subtickParallels); + rlm.getRecipeLogic().getLastDisplayedRecipe() != null) { + compoundTag.putInt("parallel", rlm.getRecipeLogic().getLastDisplayedRecipe().parallels); + compoundTag.putInt("batch", rlm.getRecipeLogic().getLastDisplayedRecipe().batchParallels); + compoundTag.putInt("subtickParallel", rlm.getRecipeLogic().getLastDisplayedRecipe().subtickParallels); compoundTag.putBoolean("exact", true); } else { controller.getParallelHatch() diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeLogicProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeLogicProvider.java index 0868ace35ac..2ba708b77ba 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeLogicProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeLogicProvider.java @@ -37,7 +37,7 @@ protected CompoundTag write(RecipeLogic capability) { var data = new CompoundTag(); data.putBoolean("Working", capability.isWorking()); var recipeInfo = new CompoundTag(); - var recipe = capability.getLastRecipe(); + var recipe = capability.getLastDisplayedRecipe(); if (recipe != null) { var EUt = RecipeHelper.getRealEUtWithIO(recipe); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeOutputProvider.java b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeOutputProvider.java index 82be11a07ae..5717b1a2a10 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeOutputProvider.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/jade/provider/RecipeOutputProvider.java @@ -4,7 +4,6 @@ import com.gregtechceu.gtceu.api.capability.recipe.FluidRecipeCapability; import com.gregtechceu.gtceu.api.capability.recipe.ItemRecipeCapability; import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic; -import com.gregtechceu.gtceu.api.recipe.RecipeHelper; import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; import com.gregtechceu.gtceu.api.recipe.ingredient.IntProviderFluidIngredient; @@ -54,10 +53,8 @@ protected CompoundTag write(RecipeLogic recipeLogic) { CompoundTag data = new CompoundTag(); if (recipeLogic.isWorking()) { data.putBoolean("Working", recipeLogic.isWorking()); - var recipe = recipeLogic.getLastRecipe(); + var recipe = recipeLogic.getLastDisplayedRecipe(); if (recipe != null) { - int recipeTier = RecipeHelper.getPreOCRecipeEuTier(recipe); - int chanceTier = recipeTier + recipe.ocLevel; var itemContents = recipe.getOutputContents(ItemRecipeCapability.CAP); var fluidContents = recipe.getOutputContents(FluidRecipeCapability.CAP); int runs = recipe.getTotalRuns(); @@ -66,7 +63,6 @@ protected CompoundTag write(RecipeLogic recipeLogic) { for (var item : itemContents) { CompoundTag itemTag; if (item.content() instanceof IntProviderIngredient provider) { - // don't roll for output but do copy for chance and batch IntProviderIngredient chanced = provider; if (item.chance() < item.maxChance()) { double countD = ((double) runs * item.chance()) / item.maxChance(); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/components/GTRecipeComponents.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/components/GTRecipeComponents.java index 1f3aa7b27da..474708c1fc3 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/components/GTRecipeComponents.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/components/GTRecipeComponents.java @@ -8,7 +8,6 @@ import com.gregtechceu.gtceu.api.recipe.chance.logic.ChanceLogic; import com.gregtechceu.gtceu.api.recipe.ingredient.EnergyStack; import com.gregtechceu.gtceu.api.recipe.ingredient.FluidIngredient; -import com.gregtechceu.gtceu.api.recipe.ingredient.IRangedIngredient; import com.gregtechceu.gtceu.api.recipe.ingredient.IntProviderFluidIngredient; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.common.data.GTRecipeCapabilities; @@ -401,8 +400,7 @@ public FluidIngredientJS(Fluid fluid, int amount, @Nullable CompoundTag nbt) { @Override public long kjs$getAmount() { - return (ingredient instanceof IRangedIngredient ? ((IRangedIngredient) ingredient).getMaxRoll() : - ingredient.getAmount()); + return ingredient.getAmount(); } @Override diff --git a/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredientTest.java b/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredientTest.java index 3f28d1e1d55..1c500ea77c0 100644 --- a/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredientTest.java +++ b/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderFluidIngredientTest.java @@ -275,11 +275,10 @@ public static void singleblockRangedFluidOutputSabotaged(GameTestHelper helper) NotifiableFluidTank fluidOut = (NotifiableFluidTank) machine .getCapabilitiesFlat(IO.OUT, FluidRecipeCapability.CAP).get(0); - int runs = 7; - fluidIn.setFluidInTank(0, new FluidStack(CR_OUT, runs)); + fluidIn.setFluidInTank(0, new FluidStack(CR_OUT, REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; + int[] addedRolls = new int[REPLICAS]; helper.runAfterDelay(2, () -> { if (machine.getRecipeLogic().getLastRecipe().getOutputContents(FluidRecipeCapability.CAP).get(0) @@ -295,29 +294,29 @@ public static void singleblockRangedFluidOutputSabotaged(GameTestHelper helper) "Recipe logic did not contain a Ranged Output!"); } }); - for (int i = 0; i < runs; i++) { + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 3, () -> { addedRolls[finalI] = (int) fluidOut.getTotalContentAmount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { FluidStack results = fluidOut.getFluidInTank(0); - helper.assertFalse((results.getAmount() == runs * 0), + helper.assertFalse((results.getAmount() == REPLICAS * 0), "Sabotaged Singleblock CR rolled min value on every roll! " + "This is the failure this sabotage was intended to induce."); - helper.assertFalse((results.getAmount() == runs * 9), + helper.assertFalse((results.getAmount() == REPLICAS * 9), "Sabotaged Singleblock CR rolled max value on every roll (how??)"); - helper.assertTrue(TestUtils.isFluidWithinRange(results, runs, runs * 9), + helper.assertTrue(TestUtils.isFluidWithinRange(results, REPLICAS, REPLICAS * 9), "Sabotaged Singleblock CR didn't produce correct number of fluids, produced [" + - results.getAmount() + "] not [" + runs + "-" + (runs * 9) + "]"); + results.getAmount() + "] not [" + REPLICAS + "-" + (REPLICAS * 9) + "]"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -365,6 +364,57 @@ public static void singleblockRangedFluidInputFailure(GameTestHelper helper) { }); } + // Test for output preroll on singleblock machine with ranged fluid output + @GameTest(template = "singleblock_charged_cr", batch = "RangedFluidIngredients") + public static void singleblockRangedFluidOutputPreroll(GameTestHelper helper) { + SimpleTieredMachine machine = (SimpleTieredMachine) getMetaMachine( + helper.getBlockEntity(new BlockPos(0, 1, 0))); + + machine.setRecipeType(CR_RECIPE_TYPE); + NotifiableFluidTank fluidIn = (NotifiableFluidTank) machine + .getCapabilitiesFlat(IO.IN, FluidRecipeCapability.CAP).get(0); + NotifiableFluidTank fluidOut = (NotifiableFluidTank) machine + .getCapabilitiesFlat(IO.OUT, FluidRecipeCapability.CAP).get(0); + + fluidIn.setFluidInTank(0, new FluidStack(CR_OUT, REPLICAS)); + // 1t to turn on, 2t per recipe run + // get the result of each preroll independently + int[] prerolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(2 * i + 1, () -> { + helper.assertFalse(machine.recipeLogic.getLastRecipe() == null, + "Singleblock fluid CR Preroll was not running a recipe when preroll was checked!"); + var outputPrerolls = machine.recipeLogic.getLastRecipe().outputs.get(FluidRecipeCapability.CAP); + helper.assertFalse(outputPrerolls.size() == 0, + "Singleblock fluid CR Preroll's recipe output contained no fluids!"); + prerolls[finalI] = ((IRangedIngredient) (outputPrerolls.get(0).content())).getAmount();; + }); + } + // get the result of each roll independently + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(2 * i + 3, () -> { + addedRolls[finalI] = fluidOut.getFluidInTank(0).getAmount(); + }); + } + // check the results of all rolls together + helper.runAfterDelay(REPLICAS * 2 + 10, () -> { + // check if all the rolls were equal, but not min/max + int[] rolls = new int[REPLICAS]; + rolls[0] = addedRolls[0]; + helper.assertFalse(prerolls[0] != rolls[0], "Singleblock fluid CR Preroll failed on run 0"); + + for (int i = 1; i < REPLICAS; i++) { + rolls[i] = addedRolls[i] - addedRolls[i - 1]; + helper.assertFalse(prerolls[i] != rolls[i], + "Singleblock fluid CR Preroll failed on run [" + i + "]"); + } + helper.succeed(); + }); + } + // Test for singleblock machine with ranged fluid input @GameTest(template = "singleblock_charged_cr", batch = "RangedFluidIngredients") public static void singleblockRangedFluidInput(GameTestHelper helper) { @@ -379,26 +429,26 @@ public static void singleblockRangedFluidInput(GameTestHelper helper) { NotifiableFluidTank fluidOut = (NotifiableFluidTank) machine .getCapabilitiesFlat(IO.OUT, FluidRecipeCapability.CAP).get(0); - int runs = 7; fluidIn.setFluidInTank(0, new FluidStack(CR_IN, 64)); - itemIn.setStackInSlot(0, COBBLE.copyWithCount(runs)); + itemIn.setStackInSlot(0, COBBLE.copyWithCount(REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 1, () -> { addedRolls[finalI] = fluidIn.getFluidInTank(0).getAmount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 2, () -> { + helper.runAfterDelay(REPLICAS * 2 + 2, () -> { FluidStack results = fluidIn.getFluidInTank(0); - int upperLimit = 64 - (runs * 0); - int lowerLimit = 64 - (runs * 9); - helper.assertTrue(TestUtils.isFluidStackEqual(fluidOut.getFluidInTank(0), new FluidStack(REDSTONE, runs)), + int upperLimit = 64 - (REPLICAS * 0); + int lowerLimit = 64 - (REPLICAS * 9); + helper.assertTrue( + TestUtils.isFluidStackEqual(fluidOut.getFluidInTank(0), new FluidStack(REDSTONE, REPLICAS)), "Singleblock CR didn't complete correct number of recipes, completed [" + - fluidOut.getFluidInTank(0).getAmount() + "] not [" + runs + "]"); + fluidOut.getFluidInTank(0).getAmount() + "] not [" + REPLICAS + "]"); helper.assertTrue(TestUtils.isFluidWithinRange(results, lowerLimit, upperLimit), "Singleblock CR didn't consume correct number of fluids, consumed [" + (64 - results.getAmount()) + "] not [" + lowerLimit + "-" + upperLimit + "]"); @@ -408,10 +458,10 @@ public static void singleblockRangedFluidInput(GameTestHelper helper) { "Singleblock CR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = 64 - addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i - 1] - addedRolls[i]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -426,7 +476,7 @@ public static void singleblockRangedFluidInput(GameTestHelper helper) { }); } - // Test for singleblock machine with ranged fluid input + // Test for singleblock machine with ranged fluid output @GameTest(template = "singleblock_charged_cr", batch = "RangedFluidIngredients") public static void singleblockRangedFluidOutput(GameTestHelper helper) { SimpleTieredMachine machine = (SimpleTieredMachine) getMetaMachine( @@ -438,36 +488,35 @@ public static void singleblockRangedFluidOutput(GameTestHelper helper) { NotifiableFluidTank fluidOut = (NotifiableFluidTank) machine .getCapabilitiesFlat(IO.OUT, FluidRecipeCapability.CAP).get(0); - int runs = 7; - fluidIn.setFluidInTank(0, new FluidStack(CR_OUT, runs)); + fluidIn.setFluidInTank(0, new FluidStack(CR_OUT, REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 3, () -> { addedRolls[finalI] = fluidOut.getFluidInTank(0).getAmount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { helper.assertTrue(fluidIn.getFluidInTank(0).isEmpty(), "Singleblock CR didn't complete correct number of recipes, completed [" + - fluidIn.getFluidInTank(0).getAmount() + "] not [" + runs + "]"); + fluidIn.getFluidInTank(0).getAmount() + "] not [" + REPLICAS + "]"); FluidStack results = fluidOut.getFluidInTank(0); - helper.assertTrue(TestUtils.isFluidWithinRange(results, runs, runs * 9), + helper.assertTrue(TestUtils.isFluidWithinRange(results, REPLICAS, REPLICAS * 9), "Singleblock CR didn't produce correct number of fluids, produced [" + - results.getAmount() + "] not [" + runs + "-" + (runs * 9) + "]"); - helper.assertFalse((results.getAmount() == runs * 9), + results.getAmount() + "] not [" + REPLICAS + "-" + (REPLICAS * 9) + "]"); + helper.assertFalse((results.getAmount() == REPLICAS * 9), "Singleblock CR rolled max value on every roll"); - helper.assertFalse((results.getAmount() == runs * 0), + helper.assertFalse((results.getAmount() == REPLICAS * 0), "Singleblock CR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -491,26 +540,26 @@ public static void multiblockLCRRangedFluidInput(GameTestHelper helper) { NotifiableFluidTank fluidIn = busHolder.inputHatch1.tank; NotifiableFluidTank fluidOut = busHolder.outputHatch1.tank; - int runs = 7; fluidIn.setFluidInTank(0, new FluidStack(LCR_IN, 64)); - fluidIn.setFluidInTank(1, new FluidStack(RUBBER, runs)); + fluidIn.setFluidInTank(1, new FluidStack(RUBBER, REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 1, () -> { addedRolls[finalI] = fluidIn.getFluidInTank(0).getAmount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 2, () -> { + helper.runAfterDelay(REPLICAS * 2 + 2, () -> { FluidStack results = fluidIn.getFluidInTank(0); - int upperLimit = 64 - (runs * 0); - int lowerLimit = 64 - (runs * 9); - helper.assertTrue(TestUtils.isFluidStackEqual(fluidOut.getFluidInTank(0), new FluidStack(REDSTONE, runs)), + int upperLimit = 64 - (REPLICAS * 0); + int lowerLimit = 64 - (REPLICAS * 9); + helper.assertTrue( + TestUtils.isFluidStackEqual(fluidOut.getFluidInTank(0), new FluidStack(REDSTONE, REPLICAS)), "LCR didn't complete correct number of recipes, completed [" + - fluidOut.getFluidInTank(0).getAmount() + "] not [" + runs + "]"); + fluidOut.getFluidInTank(0).getAmount() + "] not [" + REPLICAS + "]"); helper.assertTrue(TestUtils.isFluidWithinRange(results, lowerLimit, upperLimit), "LCR didn't consume correct number of fluids, consumed [" + (64 - results.getAmount()) + "] not [" + lowerLimit + "-" + upperLimit + "]"); @@ -520,10 +569,10 @@ public static void multiblockLCRRangedFluidInput(GameTestHelper helper) { "LCR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = 64 - addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i - 1] - addedRolls[i]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -547,36 +596,35 @@ public static void multiblockLCRRangedFluidOutput(GameTestHelper helper) { final NotifiableFluidTank fluidIn = busHolder.inputHatch1.tank; final NotifiableFluidTank fluidOut = busHolder.outputHatch1.tank; - int runs = 7; - fluidIn.setFluidInTank(0, new FluidStack(LCR_OUT, runs)); + fluidIn.setFluidInTank(0, new FluidStack(LCR_OUT, REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 3, () -> { addedRolls[finalI] = fluidOut.getFluidInTank(0).getAmount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { helper.assertTrue(fluidIn.getFluidInTank(0).isEmpty(), "LCR didn't complete correct number of recipes, completed [" + - fluidIn.getFluidInTank(0).getAmount() + "] not [" + runs + "]"); + fluidIn.getFluidInTank(0).getAmount() + "] not [" + REPLICAS + "]"); FluidStack results = fluidOut.getFluidInTank(0); - helper.assertTrue(TestUtils.isFluidWithinRange(results, runs, runs * 9), + helper.assertTrue(TestUtils.isFluidWithinRange(results, REPLICAS, REPLICAS * 9), "LCR didn't produce correct number of fluids, produced [" + - results.getAmount() + "] not [" + runs + "-" + (runs * 9) + "]"); - helper.assertFalse((results.getAmount() == runs * 9), + results.getAmount() + "] not [" + REPLICAS + "-" + (REPLICAS * 9) + "]"); + helper.assertFalse((results.getAmount() == REPLICAS * 9), "LCR rolled max value on every roll"); - helper.assertFalse((results.getAmount() == runs * 0), + helper.assertFalse((results.getAmount() == REPLICAS * 0), "LCR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -1043,4 +1091,61 @@ public static void multiblockLCentRangedFluidOutput16ParallelBatched(GameTestHel helper.succeed(); }); } + + // test for multiblock machine with 16x Parallels with ranged fluid output preroll + @GameTest(template = "large_centrifuge_zpm_batch_parallel16", + batch = "RangedFluidIngredients", + timeoutTicks = 2000) + public static void multiblockLCentRangedFluidOutputPreroll16ParallelBatched(GameTestHelper helper) { + BusHolderBatchParallel busHolder = getBussesAndFormLCENT(helper); + + final NotifiableFluidTank fluidIn = busHolder.inputHatch1.tank; + final NotifiableFluidTank fluidOut = busHolder.outputHatch1.tank; + + int batches = 16; + int parallels = 16; + busHolder.controller.setBatchEnabled(true); + busHolder.parallelHatch.setCurrentParallel(parallels); + + fluidIn.setFluidInTank(0, new FluidStack(LCENT_OUT, batches * parallels)); + + // 1t to turn on, 64t per recipe run, 10t buffer for sanity + int[] prerolls = new int[MULTI_REPLICAS]; + for (int i = 0; i < MULTI_REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(75 * finalI + 20, () -> { + helper.assertFalse(busHolder.controller.recipeLogic.getLastRecipe() == null, + "Multiblock LCent fluid Preroll was not running a recipe when preroll was checked!"); + var outputPrerolls = busHolder.controller.recipeLogic.getLastRecipe().outputs + .get(FluidRecipeCapability.CAP); + helper.assertFalse(outputPrerolls.size() == 0, + "Multiblock LCent fluid Preroll's recipe output contained no fluids!"); + prerolls[finalI] = ((IRangedIngredient) (outputPrerolls.get(0).content())).getAmount();; + }); + } + // check the results of all rolls together + // repeat recipe MULTI_REPLICAS times + int[] addedRolls = new int[MULTI_REPLICAS]; + for (int i = 1; i <= MULTI_REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(75 * finalI, () -> { + addedRolls[finalI - 1] = fluidOut.getFluidInTank(0).getAmount(); + // reset for a rerun + fluidIn.setFluidInTank(0, new FluidStack(LCENT_OUT, batches * parallels)); + }); + } + + helper.runAfterDelay(1 + 75 * MULTI_REPLICAS, () -> { + int[] rolls = new int[MULTI_REPLICAS]; + rolls[0] = addedRolls[0]; + helper.assertFalse(prerolls[0] != rolls[0], "Multiblock LCent fluid Preroll failed on run 0"); + + for (int i = 1; i < MULTI_REPLICAS; i++) { + rolls[i] = addedRolls[i] - addedRolls[i - 1]; + helper.assertFalse(prerolls[i] != rolls[i], + "Multiblock LCent fluid Preroll failed on run [" + i + "]"); + } + helper.succeed(); + }); + } } diff --git a/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredientTest.java b/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredientTest.java index 964ca0a02a6..180207687bb 100644 --- a/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredientTest.java +++ b/src/test/java/com/gregtechceu/gtceu/api/recipe/ingredient/IntProviderIngredientTest.java @@ -269,11 +269,10 @@ public static void singleblockRangedItemOutputSabotaged(GameTestHelper helper) { NotifiableItemStackHandler itemOut = (NotifiableItemStackHandler) machine .getCapabilitiesFlat(IO.OUT, ItemRecipeCapability.CAP).get(0); - int runs = 7; - itemIn.setStackInSlot(0, CR_OUT.copyWithCount(runs)); + itemIn.setStackInSlot(0, CR_OUT.copyWithCount(REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; + int[] addedRolls = new int[REPLICAS]; helper.runAfterDelay(2, () -> { if (machine.getRecipeLogic().getLastRecipe().getOutputContents(ItemRecipeCapability.CAP).get(0) @@ -289,30 +288,30 @@ public static void singleblockRangedItemOutputSabotaged(GameTestHelper helper) { "Recipe logic did not contain a Ranged Output!"); } }); - for (int i = 0; i < runs; i++) { + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 3, () -> { addedRolls[finalI] = itemOut.getStackInSlot(0).getCount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { ItemStack results = itemOut.getStackInSlot(0); - helper.assertFalse((results.getCount() == runs * 0), + helper.assertFalse((results.getCount() == REPLICAS * 0), "Sabotaged Singleblock CR rolled min value on every roll! " + "This is the failure this sabotage was intended to induce."); - helper.assertFalse((results.getCount() == runs * 9), + helper.assertFalse((results.getCount() == REPLICAS * 9), "Sabotaged Singleblock CR rolled max value on every roll (how??)"); - helper.assertTrue(TestUtils.isItemWithinRange(results, runs, runs * 9), + helper.assertTrue(TestUtils.isItemWithinRange(results, REPLICAS, REPLICAS * 9), "Sabotaged Singleblock CR didn't produce correct number of items, produced [" + - results.getCount() + "] not [" + runs + "-" + (runs * 9) + "]"); + results.getCount() + "] not [" + REPLICAS + "-" + (REPLICAS * 9) + "]"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -358,6 +357,56 @@ public static void singleblockRangedItemInputFailure(GameTestHelper helper) { }); } + // Test for output preroll on singleblock machine with ranged item output + @GameTest(template = "singleblock_charged_cr", batch = "RangedIngredients") + public static void singleblockRangedItemOutputPreroll(GameTestHelper helper) { + SimpleTieredMachine machine = (SimpleTieredMachine) getMetaMachine( + helper.getBlockEntity(new BlockPos(0, 1, 0))); + + machine.setRecipeType(CR_RECIPE_TYPE); + NotifiableItemStackHandler itemIn = (NotifiableItemStackHandler) machine + .getCapabilitiesFlat(IO.IN, ItemRecipeCapability.CAP).get(0); + NotifiableItemStackHandler itemOut = (NotifiableItemStackHandler) machine + .getCapabilitiesFlat(IO.OUT, ItemRecipeCapability.CAP).get(0); + + itemIn.setStackInSlot(0, CR_OUT.copyWithCount(REPLICAS)); + // 1t to turn on, 2t per recipe run + // get the result of each preroll independently + int[] prerolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(2 * i + 1, () -> { + helper.assertFalse(machine.recipeLogic.getLastRecipe() == null, + "Singleblock item CR Preroll was not running a recipe when preroll was checked!"); + var outputPrerolls = machine.recipeLogic.getLastRecipe().outputs.get(ItemRecipeCapability.CAP); + helper.assertFalse(outputPrerolls.size() == 0, + "Singleblock item CR Preroll's recipe output contained no items!"); + prerolls[finalI] = ((IRangedIngredient) (outputPrerolls.get(0).content())).getAmount();; + }); + } + // get the result of each roll independently + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(2 * i + 3, () -> { + addedRolls[finalI] = itemOut.getStackInSlot(0).getCount(); + }); + } + // check the results of all rolls together + helper.runAfterDelay(REPLICAS * 2 + 10, () -> { + // check if all the rolls matched their preroll + int[] rolls = new int[REPLICAS]; + rolls[0] = addedRolls[0]; + helper.assertFalse(prerolls[0] != rolls[0], "Singleblock item CR Preroll failed on run 0"); + for (int i = 1; i < REPLICAS; i++) { + rolls[i] = addedRolls[i] - addedRolls[i - 1]; + helper.assertFalse(prerolls[i] != rolls[i], + "Singleblock CR Preroll failed on run [" + i + "]"); + } + helper.succeed(); + }); + } + // Test for singleblock machine with ranged item input @GameTest(template = "singleblock_charged_cr", batch = "RangedIngredients") public static void singleblockRangedItemInput(GameTestHelper helper) { @@ -370,26 +419,25 @@ public static void singleblockRangedItemInput(GameTestHelper helper) { NotifiableItemStackHandler itemOut = (NotifiableItemStackHandler) machine .getCapabilitiesFlat(IO.OUT, ItemRecipeCapability.CAP).get(0); - int runs = 7; itemIn.setStackInSlot(0, CR_IN.copyWithCount(64)); - itemIn.setStackInSlot(1, COBBLE.copyWithCount(runs)); + itemIn.setStackInSlot(1, COBBLE.copyWithCount(REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 1, () -> { addedRolls[finalI] = itemIn.getStackInSlot(0).getCount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { ItemStack results = itemIn.getStackInSlot(0); - int upperLimit = 64 - (runs * 0); - int lowerLimit = 64 - (runs * 9); - helper.assertTrue(TestUtils.isItemStackEqual(itemOut.getStackInSlot(0), STONE.copyWithCount(runs)), + int upperLimit = 64 - (REPLICAS * 0); + int lowerLimit = 64 - (REPLICAS * 9); + helper.assertTrue(TestUtils.isItemStackEqual(itemOut.getStackInSlot(0), STONE.copyWithCount(REPLICAS)), "Singleblock CR didn't complete correct number of recipes, completed [" + - itemOut.getStackInSlot(0).getCount() + "] not [" + runs + "]"); + itemOut.getStackInSlot(0).getCount() + "] not [" + REPLICAS + "]"); helper.assertTrue(TestUtils.isItemWithinRange(results, lowerLimit, upperLimit), "Singleblock CR didn't consume correct number of items, consumed [" + (64 - results.getCount()) + "] not [" + lowerLimit + "-" + upperLimit + "]"); @@ -399,10 +447,10 @@ public static void singleblockRangedItemInput(GameTestHelper helper) { "Singleblock CR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = 64 - addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i - 1] - addedRolls[i]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -429,36 +477,35 @@ public static void singleblockRangedItemOutput(GameTestHelper helper) { NotifiableItemStackHandler itemOut = (NotifiableItemStackHandler) machine .getCapabilitiesFlat(IO.OUT, ItemRecipeCapability.CAP).get(0); - int runs = 7; - itemIn.setStackInSlot(0, CR_OUT.copyWithCount(runs)); + itemIn.setStackInSlot(0, CR_OUT.copyWithCount(REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 3, () -> { addedRolls[finalI] = itemOut.getStackInSlot(0).getCount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { helper.assertTrue(itemIn.getStackInSlot(0).isEmpty(), "Singleblock CR didn't complete correct number of recipes, completed [" + - itemIn.getStackInSlot(0).getCount() + "] not [" + runs + "]"); + itemIn.getStackInSlot(0).getCount() + "] not [" + REPLICAS + "]"); ItemStack results = itemOut.getStackInSlot(0); - helper.assertTrue(TestUtils.isItemWithinRange(results, runs, runs * 9), + helper.assertTrue(TestUtils.isItemWithinRange(results, REPLICAS, REPLICAS * 9), "Singleblock CR didn't produce correct number of items, produced [" + - results.getCount() + "] not [" + runs + "-" + (runs * 9) + "]"); - helper.assertFalse((results.getCount() == runs * 9), + results.getCount() + "] not [" + REPLICAS + "-" + (REPLICAS * 9) + "]"); + helper.assertFalse((results.getCount() == REPLICAS * 9), "Singleblock CR rolled max value on every roll"); - helper.assertFalse((results.getCount() == runs * 0), + helper.assertFalse((results.getCount() == REPLICAS * 0), "Singleblock CR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -481,26 +528,25 @@ public static void multiblockLCRRangedItemInput(GameTestHelper helper) { NotifiableItemStackHandler itemIn = busHolder.inputBus1.getInventory(); NotifiableItemStackHandler itemOut = busHolder.outputBus1.getInventory(); - int runs = 7; itemIn.setStackInSlot(0, LCR_IN.copyWithCount(64)); - itemIn.setStackInSlot(1, COBBLE.copyWithCount(runs)); + itemIn.setStackInSlot(1, COBBLE.copyWithCount(REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 1, () -> { addedRolls[finalI] = itemIn.getStackInSlot(0).getCount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { ItemStack results = itemIn.getStackInSlot(0); - int upperLimit = 64 - (runs * 0); - int lowerLimit = 64 - (runs * 9); - helper.assertTrue(TestUtils.isItemStackEqual(itemOut.getStackInSlot(0), STONE.copyWithCount(runs)), + int upperLimit = 64 - (REPLICAS * 0); + int lowerLimit = 64 - (REPLICAS * 9); + helper.assertTrue(TestUtils.isItemStackEqual(itemOut.getStackInSlot(0), STONE.copyWithCount(REPLICAS)), "LCR didn't complete correct number of recipes, completed [" + - itemOut.getStackInSlot(0).getCount() + "] not [" + runs + "]"); + itemOut.getStackInSlot(0).getCount() + "] not [" + REPLICAS + "]"); helper.assertTrue(TestUtils.isItemWithinRange(results, lowerLimit, upperLimit), "LCR didn't consume correct number of items, consumed [" + (64 - results.getCount()) + "] not [" + lowerLimit + "-" + upperLimit + "]"); @@ -510,10 +556,10 @@ public static void multiblockLCRRangedItemInput(GameTestHelper helper) { "LCR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = 64 - addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i - 1] - addedRolls[i]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -536,36 +582,35 @@ public static void multiblockLCRRangedItemOutput(GameTestHelper helper) { NotifiableItemStackHandler itemIn = busHolder.inputBus1.getInventory(); NotifiableItemStackHandler itemOut = busHolder.outputBus1.getInventory(); - int runs = 7; - itemIn.setStackInSlot(0, LCR_OUT.copyWithCount(runs)); + itemIn.setStackInSlot(0, LCR_OUT.copyWithCount(REPLICAS)); // 1t to turn on, 2t per recipe run // get the result of each roll independently - int[] addedRolls = new int[runs]; - for (int i = 0; i < runs; i++) { + int[] addedRolls = new int[REPLICAS]; + for (int i = 0; i < REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(2 * i + 3, () -> { addedRolls[finalI] = itemOut.getStackInSlot(0).getCount(); }); } // check the results of all rolls together - helper.runAfterDelay(runs * 2 + 1, () -> { + helper.runAfterDelay(REPLICAS * 2 + 1, () -> { helper.assertTrue(itemIn.getStackInSlot(0).isEmpty(), "LCR didn't complete correct number of recipes, completed [" + - itemIn.getStackInSlot(0).getCount() + "] not [" + runs + "]"); + itemIn.getStackInSlot(0).getCount() + "] not [" + REPLICAS + "]"); ItemStack results = itemOut.getStackInSlot(0); - helper.assertTrue(TestUtils.isItemWithinRange(results, runs, runs * 9), + helper.assertTrue(TestUtils.isItemWithinRange(results, REPLICAS, REPLICAS * 9), "LCR didn't produce correct number of items, produced [" + - results.getCount() + "] not [" + runs + "-" + (runs * 9) + "]"); - helper.assertFalse((results.getCount() == runs * 9), + results.getCount() + "] not [" + REPLICAS + "-" + (REPLICAS * 9) + "]"); + helper.assertFalse((results.getCount() == REPLICAS * 9), "LCR rolled max value on every roll"); - helper.assertFalse((results.getCount() == runs * 0), + helper.assertFalse((results.getCount() == REPLICAS * 0), "LCR rolled min value on every roll"); // check if all the rolls were equal, but not min/max - int[] rolls = new int[runs]; + int[] rolls = new int[REPLICAS]; rolls[0] = addedRolls[0]; boolean allEqual = false; - for (int i = 1; i < runs; i++) { + for (int i = 1; i < REPLICAS; i++) { rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (rolls[i] == rolls[i - 1]) { allEqual = true; @@ -981,7 +1026,7 @@ public static void multiblockLCentRangedItemOutput16ParallelBatched(GameTestHelp // 16 parallels // check the results of all rolls together // repeat recipe MULTI_REPLICAS times - int[] addedRolls = new int[MULTI_REPLICAS]; + int[] rolls = new int[MULTI_REPLICAS]; for (int i = 1; i <= MULTI_REPLICAS; i++) { final int finalI = i; // lambda preserve you helper.runAfterDelay(75 * finalI, () -> { @@ -999,7 +1044,7 @@ public static void multiblockLCentRangedItemOutput16ParallelBatched(GameTestHelp "Batched Parallel LCent didn't produce correct number of items, produced [" + resultCount + "] not [" + lowerLimit + "-" + upperLimit + "]"); - addedRolls[finalI - 1] = resultCount; + rolls[finalI - 1] = resultCount; // reset for a rerun for (int j = 0; j < batches; j++) { @@ -1015,9 +1060,7 @@ public static void multiblockLCentRangedItemOutput16ParallelBatched(GameTestHelp helper.runAfterDelay(1 + 75 * MULTI_REPLICAS, () -> { // check if each roll was a multiple of run count boolean sus = false; - int[] rolls = new int[MULTI_REPLICAS]; - rolls[0] = addedRolls[0]; if (TestUtils.isStackSizeExactlyEvenMultiple(rolls[0], batches, parallels, 1)) { sus = true; GTCEu.LOGGER.warn("Batched Parallel LCent ranged item output test iteration " + 1 + " produced [" + @@ -1025,7 +1068,6 @@ public static void multiblockLCentRangedItemOutput16ParallelBatched(GameTestHelp "). If this message only appears once, this is likely a false positive."); } for (int i = 1; i < MULTI_REPLICAS; i++) { - rolls[i] = addedRolls[i] - addedRolls[i - 1]; if (TestUtils.isStackSizeExactlyEvenMultiple(rolls[i], batches, parallels, 1)) { sus = true; GTCEu.LOGGER.warn("Batched Parallel LCent ranged item output test iteration " + (i + 1) + @@ -1043,4 +1085,70 @@ public static void multiblockLCentRangedItemOutput16ParallelBatched(GameTestHelp helper.succeed(); }); } + + // test for multiblock machine with 16x Parallels with ranged item output + @GameTest(template = "large_centrifuge_zpm_batch_parallel16", + batch = "RangedIngredients", + timeoutTicks = 2000) + public static void multiblockLCentRangedItemOutputPreroll16ParallelBatched(GameTestHelper helper) { + BusHolderBatchParallel busHolder = getBussesAndFormLCENT(helper); + + NotifiableItemStackHandler itemIn = busHolder.inputBus1.getInventory(); + NotifiableItemStackHandler itemOut = busHolder.outputBus1.getInventory(); + + int batches = 16; + int parallels = 16; + busHolder.controller.setBatchEnabled(true); + busHolder.parallelHatch.setCurrentParallel(parallels); + + for (int j = 0; j < batches; j++) { + itemIn.setStackInSlot(j, LCENT_OUT.copyWithCount(16)); + } + + // 1t to turn on, 64t per recipe run, 10t buffer for sanity + // 16 parallels + int[] prerolls = new int[MULTI_REPLICAS]; + for (int i = 0; i < MULTI_REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(75 * finalI + 20, () -> { + helper.assertFalse(busHolder.controller.recipeLogic.getLastRecipe() == null, + "Multiblock LCent item Preroll was not running a recipe when preroll was checked!"); + var outputPrerolls = busHolder.controller.recipeLogic.getLastRecipe().outputs + .get(ItemRecipeCapability.CAP); + helper.assertFalse(outputPrerolls.size() == 0, + "Multiblock LCent item Preroll's recipe output contained no items!"); + prerolls[finalI] = ((IRangedIngredient) (outputPrerolls.get(0).content())).getAmount();; + }); + } + // check the results of all rolls together + // repeat recipe MULTI_REPLICAS times + int[] rolls = new int[MULTI_REPLICAS]; + for (int i = 1; i <= MULTI_REPLICAS; i++) { + final int finalI = i; // lambda preserve you + helper.runAfterDelay(75 * finalI, () -> { + int resultCount = (int) Math.round(itemOut.getTotalContentAmount()); + rolls[finalI - 1] = resultCount; + + // reset for a rerun + for (int j = 0; j < batches; j++) { + itemIn.setStackInSlot(j, LCENT_OUT.copyWithCount(16)); + } + // Don't overflow the output bus + for (int j = 0; j < itemOut.getSize(); j++) { + itemOut.setStackInSlot(j, ItemStack.EMPTY); + } + }); + } + + helper.runAfterDelay(1 + 75 * MULTI_REPLICAS, () -> { + + helper.assertFalse(prerolls[0] != rolls[0], "Multiblock LCent item Preroll failed on run 0"); + + for (int i = 1; i < REPLICAS; i++) { + helper.assertFalse(prerolls[i] != rolls[i], + "Multiblock LCent item Preroll failed on run [" + i + "]"); + } + helper.succeed(); + }); + } }