Skip to content

Commit 13fc4aa

Browse files
committed
Remove fluid and item multi ingredients in favor of using just using compound ingredients as the internal ingredient
1 parent 620196d commit 13fc4aa

27 files changed

+485
-954
lines changed

src/api/java/mekanism/api/recipes/ingredients/ChemicalStackIngredient.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* Base implementation for how Mekanism handle's ChemicalStack Ingredients.
2222
*/
2323
public interface ChemicalStackIngredient<CHEMICAL extends Chemical<CHEMICAL>, STACK extends ChemicalStack<CHEMICAL>> extends InputIngredient<@NotNull STACK>,
24-
IEmptyStackProvider<CHEMICAL, STACK> {
24+
IEmptyStackProvider<CHEMICAL, STACK> {//TODO - 1.20.5: Rewrite this to be more like neo's fluid ingredient system
2525

2626
/**
2727
* Evaluates this predicate on the given argument, ignoring any size data.
@@ -32,6 +32,15 @@ public interface ChemicalStackIngredient<CHEMICAL extends Chemical<CHEMICAL>, ST
3232
*/
3333
boolean testType(@NotNull CHEMICAL chemical);
3434

35+
/**
36+
* Gets the implementation type of this ingredient. For the most part this won't matter to consumers, as we just use this as part of the codec implementations.
37+
*
38+
* @return Size/Implementation Type of this ingredient.
39+
*
40+
* @since 10.6.0
41+
*/
42+
IngredientType getType();
43+
3544
/**
3645
* Base implementation for how Mekanism handle's GasStack Ingredients.
3746
* <p>
Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,134 @@
11
package mekanism.api.recipes.ingredients;
22

3+
import com.mojang.serialization.Codec;
4+
import java.util.List;
5+
import java.util.Objects;
6+
import mekanism.api.annotations.NothingNullByDefault;
7+
import net.minecraft.network.RegistryFriendlyByteBuf;
8+
import net.minecraft.network.codec.StreamCodec;
39
import net.neoforged.neoforge.fluids.FluidStack;
10+
import net.neoforged.neoforge.fluids.crafting.SizedFluidIngredient;
11+
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
12+
import org.jetbrains.annotations.ApiStatus.Internal;
413
import org.jetbrains.annotations.NotNull;
14+
import org.jetbrains.annotations.Nullable;
515

616
/**
7-
* Base implementation for how Mekanism handle's FluidStack Ingredients.
17+
* Implementation for how Mekanism handle's FluidStack Ingredients.
818
* <p>
919
* Create instances of this using {@link mekanism.api.recipes.ingredients.creator.IngredientCreatorAccess#fluid()}.
20+
*
21+
* @implNote This is a wrapper around {@link SizedFluidIngredient}
1022
*/
11-
public abstract class FluidStackIngredient implements InputIngredient<@NotNull FluidStack> {
23+
@NothingNullByDefault
24+
public final class FluidStackIngredient implements InputIngredient<@NotNull FluidStack> {
25+
26+
/**
27+
* A codec which can (de)encode fluid stack ingredients.
28+
*
29+
* @implNote This must be a lazily initialized so that this class can be loaded in tests
30+
* @since 10.6.0
31+
*/
32+
public static final Codec<FluidStackIngredient> CODEC = Codec.lazyInitialized(() -> SizedFluidIngredient.FLAT_CODEC.xmap(
33+
FluidStackIngredient::new, FluidStackIngredient::ingredient
34+
));
35+
/**
36+
* A stream codec which can be used to encode and decode fluid stack ingredients over the network.
37+
*
38+
* @implNote This must be a lazily initialized so that this class can be loaded in tests
39+
* @since 10.6.0
40+
*/
41+
public static final StreamCodec<RegistryFriendlyByteBuf, FluidStackIngredient> STREAM_CODEC = NeoForgeStreamCodecs.lazy(() ->
42+
SizedFluidIngredient.STREAM_CODEC.map(FluidStackIngredient::new, FluidStackIngredient::ingredient)
43+
);
44+
45+
/**
46+
* Creates a Fluid Stack Ingredient that matches a given ingredient and amount. Prefer calling via
47+
* {@link mekanism.api.recipes.ingredients.creator.IngredientCreatorAccess#fluid()} and
48+
* {@link mekanism.api.recipes.ingredients.creator.IFluidStackIngredientCreator#from(SizedFluidIngredient)}.
49+
*
50+
* @param ingredient Sized ingredient to match.
51+
*
52+
* @throws NullPointerException if the given instance is null.
53+
* @throws IllegalArgumentException if the given instance is empty.
54+
* @since 10.6.0
55+
*/
56+
public static FluidStackIngredient of(SizedFluidIngredient ingredient) {
57+
Objects.requireNonNull(ingredient, "FluidStackIngredients cannot be created from a null ingredient.");
58+
if (ingredient.ingredient().isEmpty()) {
59+
throw new IllegalArgumentException("FluidStackIngredients cannot be created using the empty ingredient.");
60+
}
61+
return new FluidStackIngredient(ingredient);
62+
}
63+
64+
private final SizedFluidIngredient ingredient;
65+
@Nullable
66+
private List<FluidStack> representations;
67+
68+
private FluidStackIngredient(SizedFluidIngredient ingredient) {
69+
this.ingredient = ingredient;
70+
}
71+
72+
@Override
73+
public boolean test(FluidStack stack) {
74+
Objects.requireNonNull(stack);
75+
return ingredient.test(stack);
76+
}
77+
78+
@Override
79+
public boolean testType(FluidStack stack) {
80+
Objects.requireNonNull(stack);
81+
return ingredient.ingredient().test(stack);
82+
}
83+
84+
@Override
85+
public FluidStack getMatchingInstance(FluidStack stack) {
86+
return test(stack) ? stack.copyWithAmount(ingredient.amount()) : FluidStack.EMPTY;
87+
}
88+
89+
@Override
90+
public long getNeededAmount(FluidStack stack) {
91+
return testType(stack) ? ingredient.amount() : 0;
92+
}
93+
94+
@Override
95+
public boolean hasNoMatchingInstances() {
96+
return ingredient.ingredient().hasNoFluids();
97+
}
98+
99+
@Override
100+
public List<@NotNull FluidStack> getRepresentations() {
101+
if (this.representations == null) {
102+
this.representations = List.of(ingredient.getFluids());
103+
}
104+
return representations;
105+
}
106+
107+
/**
108+
* For use in recipe input caching. Gets the internal NeoSized Fluid Ingredient.
109+
*
110+
* @since 10.6.0
111+
*/
112+
@Internal
113+
public SizedFluidIngredient ingredient() {
114+
return ingredient;
115+
}
116+
117+
@Override
118+
public boolean equals(Object o) {
119+
if (this == o) {
120+
return true;
121+
} else if (o == null || getClass() != o.getClass()) {
122+
return false;
123+
}
124+
FluidStackIngredient other = (FluidStackIngredient) o;
125+
//TODO - 1.20.5: Replace this once sized ingredient implements equals and hashcode
126+
return ingredient.amount() == other.ingredient.amount() && ingredient.ingredient().equals(other.ingredient.ingredient());
127+
}
128+
129+
@Override
130+
public int hashCode() {
131+
//return ingredient.hashCode();
132+
return Objects.hash(ingredient.amount(), ingredient.ingredient());
133+
}
12134
}

src/api/java/mekanism/api/recipes/ingredients/InputIngredient.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,4 @@ default boolean hasNoMatchingInstances() {
5757
* @apiNote Do not modify any of the values returned by the representations
5858
*/
5959
List<TYPE> getRepresentations();
60-
61-
/**
62-
* Gets the implementation type of this ingredient. For the most part this won't matter to consumers, as we just use this as part of the codec implementations.
63-
*
64-
* @return Size/Implementation Type of this ingredient.
65-
*
66-
* @since 10.6.0
67-
*/
68-
IngredientType getType();
6960
}
Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,136 @@
11
package mekanism.api.recipes.ingredients;
22

3+
import com.mojang.serialization.Codec;
4+
import java.util.List;
5+
import java.util.Objects;
6+
import mekanism.api.annotations.NothingNullByDefault;
7+
import net.minecraft.network.RegistryFriendlyByteBuf;
8+
import net.minecraft.network.codec.StreamCodec;
39
import net.minecraft.world.item.ItemStack;
10+
import net.neoforged.neoforge.common.crafting.SizedIngredient;
11+
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
12+
import org.jetbrains.annotations.ApiStatus.Internal;
413
import org.jetbrains.annotations.NotNull;
14+
import org.jetbrains.annotations.Nullable;
515

616
/**
717
* Base implementation for how Mekanism handle's ItemStack Ingredients.
818
* <p>
919
* Create instances of this using {@link mekanism.api.recipes.ingredients.creator.IngredientCreatorAccess#item()}.
20+
*
21+
* @implNote This is a wrapper around {@link SizedIngredient}
1022
*/
11-
public abstract class ItemStackIngredient implements InputIngredient<@NotNull ItemStack> {
23+
@NothingNullByDefault
24+
public final class ItemStackIngredient implements InputIngredient<@NotNull ItemStack> {
25+
26+
/**
27+
* A codec which can (de)encode item stack ingredients.
28+
*
29+
* @implNote This must be a lazily initialized so that this class can be loaded in tests
30+
* @since 10.6.0
31+
*/
32+
public static final Codec<ItemStackIngredient> CODEC = Codec.lazyInitialized(() -> SizedIngredient.FLAT_CODEC.xmap(
33+
ItemStackIngredient::new, ItemStackIngredient::ingredient
34+
));
35+
/**
36+
* A stream codec which can be used to encode and decode item stack ingredients over the network.
37+
*
38+
* @implNote This must be a lazily initialized so that this class can be loaded in tests
39+
* @since 10.6.0
40+
*/
41+
public static final StreamCodec<RegistryFriendlyByteBuf, ItemStackIngredient> STREAM_CODEC = NeoForgeStreamCodecs.lazy(() ->
42+
SizedIngredient.STREAM_CODEC.map(ItemStackIngredient::new, ItemStackIngredient::ingredient)
43+
);
44+
45+
/**
46+
* Creates an Item Stack Ingredient that matches a given ingredient and amount. Prefer calling via
47+
* {@link mekanism.api.recipes.ingredients.creator.IngredientCreatorAccess#item()} and
48+
* {@link mekanism.api.recipes.ingredients.creator.IItemStackIngredientCreator#from(SizedIngredient)}.
49+
*
50+
* @param ingredient Sized ingredient to match.
51+
*
52+
* @throws NullPointerException if the given instance is null.
53+
* @throws IllegalArgumentException if the given instance is empty.
54+
* @since 10.6.0
55+
*/
56+
public static ItemStackIngredient of(SizedIngredient ingredient) {
57+
Objects.requireNonNull(ingredient, "ItemStackIngredients cannot be created from a null ingredient.");
58+
if (ingredient.ingredient().isEmpty()) {
59+
throw new IllegalArgumentException("ItemStackIngredients cannot be created using the empty ingredient.");
60+
}
61+
return new ItemStackIngredient(ingredient);
62+
}
63+
64+
private final SizedIngredient ingredient;
65+
@Nullable
66+
private List<ItemStack> representations;
67+
68+
private ItemStackIngredient(SizedIngredient ingredient) {
69+
this.ingredient = ingredient;
70+
}
71+
72+
@Override
73+
public boolean test(ItemStack stack) {
74+
Objects.requireNonNull(stack);
75+
return ingredient.test(stack);
76+
}
77+
78+
@Override
79+
public boolean testType(ItemStack stack) {
80+
Objects.requireNonNull(stack);
81+
return ingredient.ingredient().test(stack);
82+
}
83+
84+
@Override
85+
public ItemStack getMatchingInstance(ItemStack stack) {
86+
return test(stack) ? stack.copyWithCount(ingredient.count()) : ItemStack.EMPTY;
87+
}
88+
89+
@Override
90+
public long getNeededAmount(ItemStack stack) {
91+
return testType(stack) ? ingredient.count() : 0;
92+
}
93+
94+
@Override
95+
public boolean hasNoMatchingInstances() {
96+
return ingredient.ingredient().hasNoItems();
97+
}
98+
99+
@Override
100+
public List<@NotNull ItemStack> getRepresentations() {
101+
if (this.representations == null) {
102+
//TODO: See if quark or whatever mods used to occasionally have empty stacks in their ingredients still do
103+
// if so we probably should filter them out of this
104+
this.representations = List.of(ingredient.getItems());
105+
}
106+
return representations;
107+
}
108+
109+
/**
110+
* For use in recipe input caching. Gets the internal Neo Sized Ingredient.
111+
*
112+
* @since 10.6.0
113+
*/
114+
@Internal
115+
public SizedIngredient ingredient() {
116+
return ingredient;
117+
}
118+
119+
@Override
120+
public boolean equals(Object o) {
121+
if (this == o) {
122+
return true;
123+
} else if (o == null || getClass() != o.getClass()) {
124+
return false;
125+
}
126+
ItemStackIngredient other = (ItemStackIngredient) o;
127+
//TODO - 1.20.5: Replace this once sized ingredient implements equals and hashcode
128+
return ingredient.count() == other.ingredient.count() && ingredient.ingredient().equals(other.ingredient.ingredient());
129+
}
130+
131+
@Override
132+
public int hashCode() {
133+
//return ingredient.hashCode();
134+
return Objects.hash(ingredient.count(), ingredient.ingredient());
135+
}
12136
}

src/api/java/mekanism/api/recipes/ingredients/creator/IChemicalStackIngredientCreator.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mekanism.api.recipes.ingredients.creator;
22

33
import java.util.Objects;
4+
import java.util.stream.Stream;
45
import mekanism.api.annotations.NothingNullByDefault;
56
import mekanism.api.chemical.Chemical;
67
import mekanism.api.chemical.ChemicalStack;
@@ -64,4 +65,29 @@ default INGREDIENT from(TagKey<CHEMICAL> tag, int amount) {
6465
* @throws IllegalArgumentException if the given amount smaller than one.
6566
*/
6667
INGREDIENT from(TagKey<CHEMICAL> tag, long amount);
68+
69+
/**
70+
* Combines multiple Ingredients into a single Ingredient.
71+
*
72+
* @param ingredients Ingredients to combine.
73+
*
74+
* @return Combined Ingredient.
75+
*
76+
* @throws NullPointerException if the given array is null.
77+
* @throws IllegalArgumentException if the given array is empty.
78+
*/
79+
@SuppressWarnings("unchecked")
80+
INGREDIENT createMulti(INGREDIENT... ingredients);
81+
82+
/**
83+
* Creates an Ingredient out of a stream of Ingredients.
84+
*
85+
* @param ingredients Ingredient(s) to combine.
86+
*
87+
* @return Given Ingredient or Combined Ingredient if multiple were in the stream.
88+
*
89+
* @throws NullPointerException if the given stream is null.
90+
* @throws IllegalArgumentException if the given stream is empty.
91+
*/
92+
INGREDIENT from(Stream<INGREDIENT> ingredients);
6793
}

src/api/java/mekanism/api/recipes/ingredients/creator/IFluidStackIngredientCreator.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ default FluidStackIngredient from(Fluid instance, int amount) {
3636

3737
@Override
3838
default FluidStackIngredient from(FluidStack instance) {
39+
//TODO - 1.20.5: Helper for this and item stack ingredient creator to create compound ingredients?
40+
// Maybe by having a var-arg variant of this?
3941
Objects.requireNonNull(instance, "FluidStackIngredients cannot be created from a null FluidStack.");
4042
if (instance.isEmpty()) {
4143
throw new IllegalArgumentException("FluidStackIngredients cannot be created using the empty stack.");
@@ -81,5 +83,7 @@ default FluidStackIngredient from(FluidIngredient ingredient, int amount) {
8183
* @throws IllegalArgumentException if the given instance is empty.
8284
* @since 10.6.0
8385
*/
84-
FluidStackIngredient from(SizedFluidIngredient ingredient);
86+
default FluidStackIngredient from(SizedFluidIngredient ingredient) {
87+
return FluidStackIngredient.of(ingredient);
88+
}
8589
}

0 commit comments

Comments
 (0)