1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
package gregtech.api.recipe;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import gregtech.api.util.GTRecipe;
import gregtech.api.util.MethodsReturnNonnullByDefault;
// spotless:off spotless likes formatting @code to @code
/**
* Helper class for searching recipe. Retrieve instance with {@link RecipeMap#findRecipeQuery}.
* <p>
* It features fluent API, so you can find recipes like this:
*
* <pre>
* {@code
* GTRecipe recipe = recipeMap.findRecipeQuery()
* .items(inputItems)
* .fluids(inputFluids)
* .find();
* }
* </pre>
*/
// spotless:on
@SuppressWarnings("unused")
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public final class FindRecipeQuery {
private static final Predicate<GTRecipe> ALWAYS = r -> true;
private final RecipeMap<?> recipeMap;
@Nullable
private ItemStack[] items;
@Nullable
private FluidStack[] fluids;
@Nullable
private ItemStack specialSlot;
private Predicate<GTRecipe> filter = ALWAYS;
private long voltage = Integer.MAX_VALUE;
@Nullable
private GTRecipe cachedRecipe;
private boolean notUnificated;
private boolean dontCheckStackSizes;
private boolean forCollisionCheck;
FindRecipeQuery(RecipeMap<?> recipeMap) {
this.recipeMap = recipeMap;
}
// region executors
/**
* @return The first matched recipe, or null if not found.
*/
@Nullable
public GTRecipe find() {
return findAll().findFirst()
.orElse(null);
}
/**
* @return All the matched recipes in the form of Stream.
*/
public Stream<GTRecipe> findAll() {
if (items == null) {
items = new ItemStack[0];
}
if (fluids == null) {
fluids = new FluidStack[0];
}
return recipeMap.getBackend()
.matchRecipeStream(
items,
fluids,
specialSlot,
cachedRecipe,
notUnificated,
dontCheckStackSizes,
forCollisionCheck)
.filter(recipe -> voltage * recipeMap.getAmperage() >= recipe.mEUt && filter.test(recipe));
}
/**
* Checks if given inputs conflict with already registered recipes.
*
* @return True if collision is found.
*/
public boolean checkCollision() {
dontCheckStackSizes = true;
forCollisionCheck = true;
return findAll().findAny()
.isPresent();
}
// endregion
// region setters
/**
* @param items Item inputs.
*/
public FindRecipeQuery items(@Nullable ItemStack... items) {
this.items = items;
return this;
}
/**
* @param fluids Fluid inputs.
*/
public FindRecipeQuery fluids(@Nullable FluidStack... fluids) {
this.fluids = fluids;
return this;
}
/**
* @param specialSlot Content of the special slot. Normal recipemaps don't need this, but some do.
* Set {@link RecipeMapBuilder#specialSlotSensitive} to make it actually functional.
* Alternatively overriding {@link RecipeMapBackend#filterFindRecipe} will also work.
*/
public FindRecipeQuery specialSlot(@Nullable ItemStack specialSlot) {
this.specialSlot = specialSlot;
return this;
}
/**
* @param filter Matched recipe will be tested by this function. If it returns false, the query will attempt to
* find next recipe.
*/
public FindRecipeQuery filter(Predicate<GTRecipe> filter) {
this.filter = filter;
return this;
}
/**
* @param voltage Recipes that exceed this voltage won't match. It will be automatically multiplied by amperage
* of the recipemap. By default, voltage is set to max Integer, meaning no voltage check.
*/
public FindRecipeQuery voltage(long voltage) {
this.voltage = voltage;
return this;
}
/**
* @param cachedRecipe If this is not null, the query tests it before all other recipes.
*/
public FindRecipeQuery cachedRecipe(@Nullable GTRecipe cachedRecipe) {
this.cachedRecipe = cachedRecipe;
return this;
}
/**
* @param notUnificated If this is set to true, item inputs will be unificated.
*/
public FindRecipeQuery notUnificated(boolean notUnificated) {
this.notUnificated = notUnificated;
return this;
}
/**
* @param dontCheckStackSizes If this is set to true, the query won't check item count and fluid amount
* for the matched recipe.
*/
public FindRecipeQuery dontCheckStackSizes(boolean dontCheckStackSizes) {
this.dontCheckStackSizes = dontCheckStackSizes;
return this;
}
// endregion
}
|