2424
2525import com .cleanroommc .modularui .network .NetworkUtils ;
2626import com .cleanroommc .modularui .value .sync .SyncHandler ;
27- import it .unimi .dsi .fastutil .Hash ;
2827import it .unimi .dsi .fastutil .ints .Int2BooleanArrayMap ;
28+ import it .unimi .dsi .fastutil .ints .Int2BooleanMap ;
2929import it .unimi .dsi .fastutil .ints .Int2IntArrayMap ;
3030import it .unimi .dsi .fastutil .ints .Int2IntMap ;
3131import it .unimi .dsi .fastutil .ints .Int2IntOpenHashMap ;
3232import it .unimi .dsi .fastutil .ints .Int2ObjectArrayMap ;
3333import it .unimi .dsi .fastutil .ints .Int2ObjectMap ;
3434import it .unimi .dsi .fastutil .ints .IntArraySet ;
35+ import it .unimi .dsi .fastutil .ints .IntSet ;
3536import it .unimi .dsi .fastutil .objects .Object2BooleanMap ;
3637import it .unimi .dsi .fastutil .objects .Object2BooleanOpenCustomHashMap ;
38+ import it .unimi .dsi .fastutil .objects .Object2IntMap ;
3739import it .unimi .dsi .fastutil .objects .Object2IntOpenCustomHashMap ;
3840import it .unimi .dsi .fastutil .objects .Object2ObjectOpenCustomHashMap ;
3941
40- import java .util .*;
42+ import java .util .Collections ;
43+ import java .util .Map ;
4144
4245public 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 {
0 commit comments