/
RecipeTransferUtil.java
174 lines (149 loc) · 6.14 KB
/
RecipeTransferUtil.java
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
package mezz.jei.transfer;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.item.ItemStack;
import mezz.jei.Internal;
import mezz.jei.api.gui.ingredient.IGuiIngredient;
import mezz.jei.api.helpers.IStackHelper;
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler;
import mezz.jei.gui.recipes.RecipeLayout;
import mezz.jei.recipes.RecipeTransferManager;
import mezz.jei.runtime.JeiRuntime;
import mezz.jei.util.ItemStackMatchable;
import mezz.jei.util.MatchingIterable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public final class RecipeTransferUtil {
private static final Logger LOGGER = LogManager.getLogger();
private RecipeTransferUtil() {
}
@Nullable
public static IRecipeTransferError getTransferRecipeError(RecipeTransferManager recipeTransferManager, Container container, RecipeLayout recipeLayout, PlayerEntity player) {
return transferRecipe(recipeTransferManager, container, recipeLayout, player, false, false);
}
public static boolean transferRecipe(RecipeTransferManager recipeTransferManager, Container container, RecipeLayout recipeLayout, PlayerEntity player, boolean maxTransfer) {
IRecipeTransferError error = transferRecipe(recipeTransferManager, container, recipeLayout, player, maxTransfer, true);
return allowsTransfer(error);
}
@Nullable
private static IRecipeTransferError transferRecipe(RecipeTransferManager recipeTransferManager, Container container, RecipeLayout recipeLayout, PlayerEntity player, boolean maxTransfer, boolean doTransfer) {
final JeiRuntime runtime = Internal.getRuntime();
if (runtime == null) {
return RecipeTransferErrorInternal.INSTANCE;
}
final IRecipeTransferHandler transferHandler = recipeTransferManager.getRecipeTransferHandler(container, recipeLayout.getRecipeCategory());
if (transferHandler == null) {
if (doTransfer) {
LOGGER.error("No Recipe Transfer handler for container {}", container.getClass());
}
return RecipeTransferErrorInternal.INSTANCE;
}
//noinspection unchecked
return transferHandler.transferRecipe(container, recipeLayout, player, maxTransfer, doTransfer);
}
public static boolean allowsTransfer(@Nullable IRecipeTransferError error) {
if (error == null) {
return true;
} else if (error.getType() == IRecipeTransferError.Type.COSMETIC) {
return true;
}
return false;
}
public static class MatchingItemsResult {
public final Map<Integer, Integer> matchingItems = new HashMap<>();
public final List<Integer> missingItems = new ArrayList<>();
}
/**
* Returns a list of items in slots that complete the recipe defined by requiredStacksList.
* Returns a result that contains missingItems if there are not enough items in availableItemStacks.
*/
public static MatchingItemsResult getMatchingItems(IStackHelper stackhelper, Map<Integer, ItemStack> availableItemStacks, Map<Integer, ? extends IGuiIngredient<ItemStack>> ingredientsMap) {
MatchingItemsResult matchingItemResult = new MatchingItemsResult();
int recipeSlotNumber = -1;
SortedSet<Integer> keys = new TreeSet<>(ingredientsMap.keySet());
for (Integer key : keys) {
IGuiIngredient<ItemStack> ingredient = ingredientsMap.get(key);
if (!ingredient.isInput()) {
continue;
}
recipeSlotNumber++;
List<ItemStack> requiredStacks = ingredient.getAllIngredients();
if (requiredStacks.isEmpty()) {
continue;
}
Integer matching = containsAnyStackIndexed(stackhelper, availableItemStacks, requiredStacks);
if (matching == null) {
matchingItemResult.missingItems.add(key);
} else {
ItemStack matchingStack = availableItemStacks.get(matching);
matchingStack.shrink(1);
if (matchingStack.getCount() == 0) {
availableItemStacks.remove(matching);
}
matchingItemResult.matchingItems.put(recipeSlotNumber, matching);
}
}
return matchingItemResult;
}
@Nullable
public static Integer containsAnyStackIndexed(IStackHelper stackhelper, Map<Integer, ItemStack> stacks, Iterable<ItemStack> contains) {
MatchingIndexed matchingStacks = new MatchingIndexed(stacks);
MatchingIterable matchingContains = new MatchingIterable(contains);
return containsStackMatchable(stackhelper, matchingStacks, matchingContains);
}
/* Returns an ItemStack from "stacks" if it isEquivalent to an ItemStack from "contains" */
@Nullable
public static <R, T> R containsStackMatchable(IStackHelper stackhelper, Iterable<ItemStackMatchable<R>> stacks, Iterable<ItemStackMatchable<T>> contains) {
for (ItemStackMatchable<?> containStack : contains) {
R matchingStack = containsStack(stackhelper, stacks, containStack);
if (matchingStack != null) {
return matchingStack;
}
}
return null;
}
/* Returns an ItemStack from "stacks" if it isEquivalent to "contains" */
@Nullable
public static <R> R containsStack(IStackHelper stackHelper, Iterable<ItemStackMatchable<R>> stacks, ItemStackMatchable<?> contains) {
for (ItemStackMatchable<R> stack : stacks) {
if (stackHelper.isEquivalent(contains.getStack(), stack.getStack())) {
return stack.getResult();
}
}
return null;
}
private static class MatchingIndexed implements Iterable<ItemStackMatchable<Integer>> {
private final Map<Integer, ItemStack> map;
public MatchingIndexed(Map<Integer, ItemStack> map) {
this.map = map;
}
@Override
public Iterator<ItemStackMatchable<Integer>> iterator() {
return new MatchingIterable.DelegateIterator<Map.Entry<Integer, ItemStack>, ItemStackMatchable<Integer>>(map.entrySet().iterator()) {
@Override
public ItemStackMatchable<Integer> next() {
final Map.Entry<Integer, ItemStack> entry = delegate.next();
return new ItemStackMatchable<Integer>() {
@Override
public ItemStack getStack() {
return entry.getValue();
}
@Override
public Integer getResult() {
return entry.getKey();
}
};
}
};
}
}
}