Skip to content

Commit

Permalink
Cache the capturing lambdas used by the cached recipe system when cal…
Browse files Browse the repository at this point in the history
…culating the operations that can be performed each tick
  • Loading branch information
pupnewfster committed Apr 4, 2024
1 parent a7ea195 commit 2dac808
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 40 deletions.
27 changes: 27 additions & 0 deletions src/api/java/mekanism/api/functions/ConstantPredicates.java
Expand Up @@ -4,7 +4,11 @@
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
import mekanism.api.AutomationType;
import mekanism.api.chemical.Chemical;
import mekanism.api.chemical.ChemicalStack;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.common.util.TriPredicate;
import net.neoforged.neoforge.fluids.FluidStack;
import org.jetbrains.annotations.NotNull;

/**
Expand All @@ -27,6 +31,20 @@ private ConstantPredicates() {
private static final BiPredicate<Object, Object> alwaysTrueBi = (t, u) -> true;
private static final TriPredicate<Object, Object, Object> alwaysTrueTri = (t, u, v) -> true;

/**
* Represents a predicate that checks if an item stack is empty.
*
* @since 10.5.15
*/
public static final Predicate<ItemStack> ITEM_EMPTY = ItemStack::isEmpty;
/**
* Represents a predicate that checks if a fluid stack is empty.
*
* @since 10.5.15
*/
public static final Predicate<FluidStack> FLUID_EMPTY = FluidStack::isEmpty;
private static final Predicate<ChemicalStack<?>> CHEMICAL_EMPTY = ChemicalStack::isEmpty;

private static final Predicate<Object> alwaysFalse = t -> false;
private static final BiPredicate<Object, Object> alwaysFalseBi = (t, u) -> false;
private static final TriPredicate<Object, Object, Object> alwaysFalseTri = (t, u, v) -> false;
Expand Down Expand Up @@ -93,4 +111,13 @@ public static <T, U, V> TriPredicate<T, U, V> alwaysFalseTri() {
public static <T> BiPredicate<T, @NotNull AutomationType> notExternal() {
return (BiPredicate<T, @NotNull AutomationType>) notExternal;
}

/**
* Represents a predicate that checks if a chemical stack is empty.
*
* @since 10.5.15
*/
public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>> Predicate<STACK> chemicalEmpty() {
return (Predicate<STACK>) CHEMICAL_EMPTY;
}
}
@@ -1,11 +1,15 @@
package mekanism.api.recipes.cache;

import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Supplier;
import mekanism.api.annotations.NothingNullByDefault;
import mekanism.api.chemical.Chemical;
import mekanism.api.chemical.ChemicalStack;
import mekanism.api.functions.ConstantPredicates;
import mekanism.api.recipes.chemical.ChemicalChemicalToChemicalRecipe;
import mekanism.api.recipes.ingredients.ChemicalStackIngredient;
import mekanism.api.recipes.inputs.IInputHandler;
Expand All @@ -24,6 +28,11 @@ public class ChemicalChemicalToChemicalCachedRecipe<CHEMICAL extends Chemical<CH
private final IOutputHandler<@NotNull STACK> outputHandler;
private final IInputHandler<@NotNull STACK> leftInputHandler;
private final IInputHandler<@NotNull STACK> rightInputHandler;
private final BiConsumer<STACK, STACK> inputsSetter;
private final Consumer<STACK> outputSetter;
private final Supplier<INGREDIENT> leftInput;
private final Supplier<INGREDIENT> rightInput;
private final BinaryOperator<STACK> outputGetter;

//Note: These shouldn't be null in places they are actually used, but we mark them as nullable, so we don't have to initialize them
@Nullable
Expand All @@ -47,6 +56,14 @@ public ChemicalChemicalToChemicalCachedRecipe(RECIPE recipe, BooleanSupplier rec
this.leftInputHandler = Objects.requireNonNull(leftInputHandler, "Left input handler cannot be null.");
this.rightInputHandler = Objects.requireNonNull(rightInputHandler, "Right input handler cannot be null.");
this.outputHandler = Objects.requireNonNull(outputHandler, "Output handler cannot be null.");
this.leftInput = this.recipe::getLeftInput;
this.rightInput = this.recipe::getRightInput;
this.inputsSetter = (left, right) -> {
leftRecipeInput = left;
rightRecipeInput = right;
};
this.outputSetter = output -> this.output = output;
this.outputGetter = this.recipe::getOutput;
}

@Override
Expand All @@ -65,22 +82,18 @@ protected void calculateOperationsThisTick(OperationTracker tracker) {
} else {
Supplier<INGREDIENT> leftIngredient;
Supplier<INGREDIENT> rightIngredient;
INGREDIENT leftInput = recipe.getLeftInput();
INGREDIENT rightInput = recipe.getRightInput();
if (!leftInput.test(leftInputChemical) || !rightInput.test(rightInputChemical)) {
if (!recipe.getLeftInput().test(leftInputChemical) || !recipe.getRightInput().test(rightInputChemical)) {
//If one of our inputs is invalid for the side it is on, switch them so that we can check
// if they are just reversed which side they are on and there is a valid recipe for them
// if they are on the other side
leftIngredient = () -> rightInput;
rightIngredient = () -> leftInput;
leftIngredient = rightInput;
rightIngredient = leftInput;
} else {
leftIngredient = () -> leftInput;
rightIngredient = () -> rightInput;
leftIngredient = leftInput;
rightIngredient = rightInput;
}
CachedRecipeHelper.twoInputCalculateOperationsThisTick(tracker, leftInputHandler, leftIngredient, rightInputHandler, rightIngredient, (left, right) -> {
leftRecipeInput = left;
rightRecipeInput = right;
}, outputHandler, recipe::getOutput, output -> this.output = output, ChemicalStack::isEmpty, ChemicalStack::isEmpty);
CachedRecipeHelper.twoInputCalculateOperationsThisTick(tracker, leftInputHandler, leftIngredient, rightInputHandler, rightIngredient, inputsSetter,
outputHandler, outputGetter, outputSetter, ConstantPredicates.chemicalEmpty(), ConstantPredicates.chemicalEmpty());
}
}
}
Expand Down
32 changes: 18 additions & 14 deletions src/api/java/mekanism/api/recipes/cache/OneInputCachedRecipe.java
Expand Up @@ -2,6 +2,7 @@

import java.util.Objects;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
Expand Down Expand Up @@ -40,6 +41,8 @@ public class OneInputCachedRecipe<INPUT, OUTPUT, RECIPE extends MekanismRecipe &
private final Supplier<? extends InputIngredient<INPUT>> inputSupplier;
private final Function<INPUT, OUTPUT> outputGetter;
private final Predicate<OUTPUT> outputEmptyCheck;
private final Consumer<INPUT> inputSetter;
private final Consumer<OUTPUT> outputSetter;

//Note: Our input and output shouldn't be null in places they are actually used, but we mark them as nullable, so we don't have to initialize them
@Nullable
Expand Down Expand Up @@ -68,13 +71,14 @@ protected OneInputCachedRecipe(RECIPE recipe, BooleanSupplier recheckAllErrors,
this.outputGetter = Objects.requireNonNull(outputGetter, "Output getter cannot be null.");
this.inputEmptyCheck = Objects.requireNonNull(inputEmptyCheck, "Input empty check cannot be null.");
this.outputEmptyCheck = Objects.requireNonNull(outputEmptyCheck, "Output empty check cannot be null.");
this.inputSetter = input -> this.input = input;
this.outputSetter = output -> this.output = output;
}

@Override
protected void calculateOperationsThisTick(OperationTracker tracker) {
super.calculateOperationsThisTick(tracker);
CachedRecipeHelper.oneInputCalculateOperationsThisTick(tracker, inputHandler, inputSupplier, input -> this.input = input, outputHandler, outputGetter,
output -> this.output = output, inputEmptyCheck);
CachedRecipeHelper.oneInputCalculateOperationsThisTick(tracker, inputHandler, inputSupplier, inputSetter, outputHandler, outputGetter, outputSetter, inputEmptyCheck);
}

@Override
Expand Down Expand Up @@ -103,7 +107,7 @@ protected void finishProcessing(int operations) {
*/
public static OneInputCachedRecipe<@NotNull FluidStack, @NotNull ElectrolysisRecipeOutput, ElectrolysisRecipe> separating(ElectrolysisRecipe recipe,
BooleanSupplier recheckAllErrors, IInputHandler<@NotNull FluidStack> inputHandler, IOutputHandler<@NotNull ElectrolysisRecipeOutput> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, FluidStack::isEmpty,
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.FLUID_EMPTY,
ConstantPredicates.alwaysFalse());
}

Expand All @@ -118,8 +122,8 @@ protected void finishProcessing(int operations) {
*/
public static OneInputCachedRecipe<@NotNull FluidStack, @NotNull FluidStack, FluidToFluidRecipe> fluidToFluid(FluidToFluidRecipe recipe,
BooleanSupplier recheckAllErrors, IInputHandler<@NotNull FluidStack> inputHandler, IOutputHandler<@NotNull FluidStack> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, FluidStack::isEmpty,
FluidStack::isEmpty);
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.FLUID_EMPTY,
ConstantPredicates.FLUID_EMPTY);
}

/**
Expand All @@ -133,8 +137,8 @@ protected void finishProcessing(int operations) {
*/
public static OneInputCachedRecipe<@NotNull ItemStack, @NotNull ItemStack, ItemStackToItemStackRecipe> itemToItem(ItemStackToItemStackRecipe recipe,
BooleanSupplier recheckAllErrors, IInputHandler<@NotNull ItemStack> inputHandler, IOutputHandler<@NotNull ItemStack> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ItemStack::isEmpty,
ItemStack::isEmpty);
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.ITEM_EMPTY,
ConstantPredicates.ITEM_EMPTY);
}

/**
Expand All @@ -148,8 +152,8 @@ protected void finishProcessing(int operations) {
*/
public static OneInputCachedRecipe<@NotNull ItemStack, @NotNull FluidStack, ItemStackToFluidRecipe> itemToFluid(ItemStackToFluidRecipe recipe,
BooleanSupplier recheckAllErrors, IInputHandler<@NotNull ItemStack> inputHandler, IOutputHandler<@NotNull FluidStack> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ItemStack::isEmpty,
FluidStack::isEmpty);
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.ITEM_EMPTY,
ConstantPredicates.FLUID_EMPTY);
}

/**
Expand All @@ -164,8 +168,8 @@ protected void finishProcessing(int operations) {
public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>, RECIPE extends ItemStackToChemicalRecipe<CHEMICAL, STACK>>
OneInputCachedRecipe<@NotNull ItemStack, @NotNull STACK, RECIPE> itemToChemical(RECIPE recipe, BooleanSupplier recheckAllErrors,
IInputHandler<@NotNull ItemStack> inputHandler, IOutputHandler<@NotNull STACK> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ItemStack::isEmpty,
ChemicalStack::isEmpty);
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.ITEM_EMPTY,
ConstantPredicates.chemicalEmpty());
}

/**
Expand All @@ -180,8 +184,8 @@ protected void finishProcessing(int operations) {
public static <CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>, INGREDIENT extends ChemicalStackIngredient<CHEMICAL, STACK>,
RECIPE extends ChemicalToChemicalRecipe<CHEMICAL, STACK, INGREDIENT>> OneInputCachedRecipe<@NotNull STACK, @NotNull STACK, RECIPE> chemicalToChemical(
RECIPE recipe, BooleanSupplier recheckAllErrors, IInputHandler<@NotNull STACK> inputHandler, IOutputHandler<@NotNull STACK> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ChemicalStack::isEmpty,
ChemicalStack::isEmpty);
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.chemicalEmpty(),
ConstantPredicates.chemicalEmpty());
}

/**
Expand All @@ -195,7 +199,7 @@ protected void finishProcessing(int operations) {
*/
public static OneInputCachedRecipe<@NotNull ItemStack, @NotNull ChanceOutput, SawmillRecipe> sawing(SawmillRecipe recipe, BooleanSupplier recheckAllErrors,
IInputHandler<@NotNull ItemStack> inputHandler, IOutputHandler<@NotNull ChanceOutput> outputHandler) {
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ItemStack::isEmpty,
return new OneInputCachedRecipe<>(recipe, recheckAllErrors, inputHandler, outputHandler, recipe::getInput, recipe::getOutput, ConstantPredicates.ITEM_EMPTY,
ConstantPredicates.alwaysFalse());
}
}
30 changes: 26 additions & 4 deletions src/api/java/mekanism/api/recipes/cache/RotaryCachedRecipe.java
Expand Up @@ -2,9 +2,15 @@

import java.util.Objects;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import mekanism.api.annotations.NothingNullByDefault;
import mekanism.api.chemical.gas.GasStack;
import mekanism.api.functions.ConstantPredicates;
import mekanism.api.recipes.RotaryRecipe;
import mekanism.api.recipes.ingredients.ChemicalStackIngredient.GasStackIngredient;
import mekanism.api.recipes.ingredients.FluidStackIngredient;
import mekanism.api.recipes.inputs.IInputHandler;
import mekanism.api.recipes.outputs.IOutputHandler;
import net.neoforged.neoforge.fluids.FluidStack;
Expand All @@ -21,6 +27,14 @@ public class RotaryCachedRecipe extends CachedRecipe<RotaryRecipe> {
private final IInputHandler<@NotNull FluidStack> fluidInputHandler;
private final IInputHandler<@NotNull GasStack> gasInputHandler;
private final BooleanSupplier modeSupplier;
private final Consumer<FluidStack> fluidInputSetter;
private final Consumer<GasStack> gasInputSetter;
private final Consumer<FluidStack> fluidOutputSetter;
private final Consumer<GasStack> gasOutputSetter;
private final Supplier<FluidStackIngredient> fluidInputGetter;
private final Supplier<GasStackIngredient> gasInputGetter;
private final Function<GasStack, FluidStack> fluidOutputGetter;
private final Function<FluidStack, GasStack> gasOutputGetter;

private FluidStack recipeFluid = FluidStack.EMPTY;
private GasStack recipeGas = GasStack.EMPTY;
Expand All @@ -46,6 +60,14 @@ public RotaryCachedRecipe(RotaryRecipe recipe, BooleanSupplier recheckAllErrors,
this.gasOutputHandler = Objects.requireNonNull(gasOutputHandler, "Gas output handler cannot be null.");
this.fluidOutputHandler = Objects.requireNonNull(fluidOutputHandler, "Fluid output handler cannot be null.");
this.modeSupplier = Objects.requireNonNull(modeSupplier, "Mode supplier cannot be null.");
this.fluidInputSetter = input -> this.recipeFluid = input;
this.gasInputSetter = input -> this.recipeGas = input;
this.fluidOutputSetter = output -> this.fluidOutput = output;
this.gasOutputSetter = output -> this.gasOutput = output;
this.fluidInputGetter = this.recipe::getFluidInput;
this.gasInputGetter = this.recipe::getGasInput;
this.fluidOutputGetter = this.recipe::getFluidOutput;
this.gasOutputGetter = this.recipe::getGasOutput;
}

@Override
Expand All @@ -59,16 +81,16 @@ protected void calculateOperationsThisTick(OperationTracker tracker) {
tracker.mismatchedRecipe();
} else {
//Handle fluid to gas conversion
CachedRecipeHelper.oneInputCalculateOperationsThisTick(tracker, fluidInputHandler, recipe::getFluidInput, input -> recipeFluid = input,
gasOutputHandler, recipe::getGasOutput, output -> gasOutput = output, FluidStack::isEmpty);
CachedRecipeHelper.oneInputCalculateOperationsThisTick(tracker, fluidInputHandler, fluidInputGetter, fluidInputSetter,
gasOutputHandler, gasOutputGetter, gasOutputSetter, ConstantPredicates.FLUID_EMPTY);
}
} else if (!recipe.hasGasToFluid()) {
//If our recipe doesn't have a gas to fluid version, return that we cannot operate
tracker.mismatchedRecipe();
} else {
//Handle gas to fluid conversion
CachedRecipeHelper.oneInputCalculateOperationsThisTick(tracker, gasInputHandler, recipe::getGasInput, input -> recipeGas = input,
fluidOutputHandler, recipe::getFluidOutput, output -> fluidOutput = output, GasStack::isEmpty);
CachedRecipeHelper.oneInputCalculateOperationsThisTick(tracker, gasInputHandler, gasInputGetter, gasInputSetter,
fluidOutputHandler, fluidOutputGetter, fluidOutputSetter, ConstantPredicates.chemicalEmpty());
}
}
}
Expand Down

0 comments on commit 2dac808

Please sign in to comment.