Skip to content

Commit ff44d7f

Browse files
authored
Fix Crafting Station Partial Dupe Bug (#2885)
1 parent 875d79a commit ff44d7f

File tree

2 files changed

+55
-39
lines changed

2 files changed

+55
-39
lines changed

src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeLogic.java

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,23 @@
2424

2525
import com.cleanroommc.modularui.network.NetworkUtils;
2626
import com.cleanroommc.modularui.value.sync.SyncHandler;
27-
import it.unimi.dsi.fastutil.Hash;
2827
import it.unimi.dsi.fastutil.ints.Int2BooleanArrayMap;
28+
import it.unimi.dsi.fastutil.ints.Int2BooleanMap;
2929
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
3030
import it.unimi.dsi.fastutil.ints.Int2IntMap;
3131
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
3232
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
3333
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
3434
import it.unimi.dsi.fastutil.ints.IntArraySet;
35+
import it.unimi.dsi.fastutil.ints.IntSet;
3536
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
3637
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenCustomHashMap;
38+
import it.unimi.dsi.fastutil.objects.Object2IntMap;
3739
import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap;
3840
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
3941

40-
import java.util.*;
42+
import java.util.Collections;
43+
import java.util.Map;
4144

4245
public class CraftingRecipeLogic extends SyncHandler {
4346

@@ -51,7 +54,7 @@ public class CraftingRecipeLogic extends SyncHandler {
5154

5255
private final World world;
5356
private IItemHandlerModifiable availableHandlers;
54-
private final Hash.Strategy<ItemStack> strategy = ItemStackHashStrategy.builder()
57+
private final ItemStackHashStrategy strategy = ItemStackHashStrategy.builder()
5558
.compareItem(true)
5659
.compareMetadata(true)
5760
.build();
@@ -60,13 +63,13 @@ public class CraftingRecipeLogic extends SyncHandler {
6063
* Used to lookup a list of slots for a given stack
6164
* filled by {@link CraftingRecipeLogic#refreshStackMap()}
6265
**/
63-
private final Map<ItemStack, Set<Integer>> stackLookupMap = new Object2ObjectOpenCustomHashMap<>(this.strategy);
66+
private final Map<ItemStack, IntSet> stackLookupMap = new Object2ObjectOpenCustomHashMap<>(this.strategy);
6467

6568
/**
6669
* List of items needed to complete the crafting recipe, filled by
6770
* {@link CraftingRecipeLogic#detectAndSendChanges(boolean)} )}
6871
**/
69-
private final Map<ItemStack, Integer> requiredItems = new Object2IntOpenCustomHashMap<>(
72+
private final Object2IntMap<ItemStack> requiredItems = new Object2IntOpenCustomHashMap<>(
7073
this.strategy);
7174

7275
private final Int2IntMap compactedIndexes = new Int2IntArrayMap(9);
@@ -147,45 +150,42 @@ protected boolean consumeRecipeItems() {
147150
if (requiredItems.isEmpty()) {
148151
return false;
149152
}
150-
Map<Integer, Integer> gatheredItems = new Int2IntOpenHashMap();
153+
Int2IntMap gatheredItems = new Int2IntOpenHashMap();
151154

152155
for (var entry : requiredItems.entrySet()) {
153156
ItemStack stack = entry.getKey();
154157
int requestedAmount = entry.getValue();
155158
var slotList = stackLookupMap.get(stack);
156159

157-
int extractedAmount = 0;
158160
for (int slot : slotList) {
159161
var extracted = availableHandlers.extractItem(slot, requestedAmount, true);
160162
gatheredItems.put(slot, extracted.getCount());
161-
extractedAmount += extracted.getCount();
162163
requestedAmount -= extracted.getCount();
163-
if (requestedAmount == 0) break;
164164
}
165-
if (extractedAmount < requestedAmount) return false;
165+
// not enough to satisfy the recipe, return false
166+
if (requestedAmount > 0) return false;
166167
}
167168

168-
boolean extracted = false;
169169
for (var gathered : gatheredItems.entrySet()) {
170170
int slot = gathered.getKey(), amount = gathered.getValue();
171171
var stack = availableHandlers.getStackInSlot(slot);
172172
boolean hasContainer = stack.getItem().hasContainerItem(stack);
173173

174-
if (hasContainer && stack.getCount() > 1) {
175-
var useStack = stack.splitStack(1);
176-
var newStack = ForgeHooks.getContainerItem(useStack);
177-
if (newStack.isEmpty()) return false;
178-
179-
GTTransferUtils.insertItem(this.availableHandlers, newStack, false);
180-
} else if (hasContainer) {
181-
var usedStack = ForgeHooks.getContainerItem(stack);
182-
availableHandlers.setStackInSlot(slot, usedStack);
183-
} else {
174+
if (!hasContainer) {
175+
// not a transmutable item (damagable tool, etc), extract normally
184176
availableHandlers.extractItem(slot, amount, false);
177+
} else if (stack.getCount() > 1) {
178+
// only some stacks are transmuted, try insert non-empty stacks
179+
ItemStack newStack = ForgeHooks.getContainerItem(stack.splitStack(1));
180+
if (!newStack.isEmpty())
181+
GTTransferUtils.insertItem(this.availableHandlers, newStack, false);
182+
} else {
183+
// all stacks are transmuted, just replace
184+
availableHandlers.setStackInSlot(slot, ForgeHooks.getContainerItem(stack));
185185
}
186-
extracted = true;
187186
}
188-
return extracted;
187+
// we've checked everything, return true
188+
return true;
189189
}
190190

191191
/**
@@ -330,13 +330,34 @@ public void detectAndSendChanges(boolean init) {
330330
return;
331331
}
332332

333+
Int2BooleanMap map = updateInputSlots();
334+
335+
// only sync when something has changed
336+
if (!map.isEmpty()) {
337+
syncToClient(UPDATE_INGREDIENTS, buffer -> {
338+
buffer.writeByte(map.size());
339+
for (var set : map.entrySet()) {
340+
buffer.writeByte(set.getKey());
341+
buffer.writeBoolean(set.getValue());
342+
}
343+
});
344+
}
345+
}
346+
347+
/**
348+
* Updates each input slot for if a valid item exists for that slot
349+
*
350+
* @return a map of slots that has changed since last time, if any
351+
*/
352+
private Int2BooleanMap updateInputSlots() {
333353
compactedIndexes.clear();
334354
requiredItems.clear();
335355
refreshStackMap();
336-
final Map<Integer, Boolean> map = new Int2BooleanArrayMap();
356+
357+
Int2BooleanMap map = new Int2BooleanArrayMap();
337358
int next = 0;
338359
for (CraftingInputSlot slot : this.inputSlots) {
339-
final boolean hadIngredients = slot.hasIngredients;
360+
boolean hadIngredients = slot.hasIngredients;
340361

341362
// check if existing stack works
342363
var slotStack = slot.getStack();
@@ -367,17 +388,7 @@ public void detectAndSendChanges(boolean init) {
367388
if (hadIngredients != slot.hasIngredients)
368389
map.put(slot.getIndex(), slot.hasIngredients);
369390
}
370-
371-
// only sync when something has changed
372-
if (!map.isEmpty()) {
373-
syncToClient(UPDATE_INGREDIENTS, buffer -> {
374-
buffer.writeByte(map.size());
375-
for (var set : map.entrySet()) {
376-
buffer.writeByte(set.getKey());
377-
buffer.writeBoolean(set.getValue());
378-
}
379-
});
380-
}
391+
return map;
381392
}
382393

383394
/**
@@ -392,7 +403,7 @@ public void refreshStackMap() {
392403
var curStack = this.availableHandlers.getStackInSlot(i);
393404
if (curStack.isEmpty()) continue;
394405

395-
Set<Integer> slots;
406+
IntSet slots;
396407
if (stackLookupMap.containsKey(curStack)) {
397408
slots = stackLookupMap.get(curStack);
398409
} else {

src/main/java/gregtech/common/mui/widget/workbench/CraftingOutputSlot.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ public void readOnServer(int id, PacketBuffer buf) {
139139
if (data.shift) {
140140
ItemStack finalStack = outputStack.copy();
141141
while (quickTransfer(finalStack, true) &&
142-
finalStack.getCount() < outputStack.getMaxStackSize()) {
143-
if (!recipeLogic.performRecipe()) break;
142+
canStack(finalStack, outputStack) &&
143+
recipeLogic.performRecipe()) {
144144
finalStack.setCount(finalStack.getCount() + outputStack.getCount());
145145
handleItemCraft(outputStack, player);
146146
}
@@ -154,6 +154,11 @@ public void readOnServer(int id, PacketBuffer buf) {
154154
}
155155
}
156156

157+
private static boolean canStack(ItemStack a, ItemStack b) {
158+
return ItemHandlerHelper.canItemStacksStackRelaxed(a, b) &&
159+
a.getCount() + b.getCount() < b.getMaxStackSize();
160+
}
161+
157162
private boolean insertStack(ItemStack fromStack, ModularSlot toSlot, boolean simulate) {
158163
ItemStack toStack = toSlot.getStack().copy();
159164
if (ItemHandlerHelper.canItemStacksStack(fromStack, toStack)) {

0 commit comments

Comments
 (0)