@@ -967,69 +967,68 @@ public ItemStack insertItem (@NotNull ItemStack stack, boolean simulate, Predica
967967 Collection <SlotRecord > primaryRecords = drawerPrimaryLookup .getEntries (stack .getItem ());
968968 Set <Integer > checkedSlots = (simulate ) ? new HashSet <>() : null ;
969969 List <IDrawer > rebalance = new ArrayList <>();
970+ boolean needRebalance = false ;
970971
971972 int amount = stack .getCount ();
972- if (primaryRecords != null ) {
973- // First test by strict remaining capacity
973+ if (primaryRecords != null && amount >= 0 ) {
974+ record PossibleDrawer (IDrawer drawer , SlotRecord record ) {}
975+ var possibleDrawers = new ArrayList <PossibleDrawer >();
976+
977+ // This loop assumes that capacity does not affect predicates in a way
978+ // that things can strictly fit but not loosely fit.
979+ // This is currently true, and I can't think of a useful predicate that would
980+ // make it untrue, but if it becomes untrue, the set of valid drawers
981+ // would change between the first test loop and the second.
974982 for (SlotRecord record : primaryRecords ) {
975- IDrawerGroup candidateGroup = getGroupForSlotRecord (record );
976- if (candidateGroup == null )
977- continue ;
978-
979- IDrawer drawer = candidateGroup .getDrawer (record .slot );
980- if (drawer .isEmpty ())
981- continue ;
982- if (!testPredicateInsert (drawer , stack , predicate ))
983- continue ;
984- if (!hasAccess (candidateGroup , drawer ))
985- continue ;
986-
987- IDrawerAttributes attrs = drawer .getAttributes ();
988- if (attrs .isSuspended ())
989- continue ;
990- if (attrs .isBalancedFill ())
983+ IDrawer drawer = getValidDrawer (stack , predicate , record );
984+
985+ // We handle empty drawers below.
986+ if (drawer == null || drawer .isEmpty ()) continue ;
987+ possibleDrawers .add (new PossibleDrawer (drawer , record ));
988+ // If we put an item in any drawer that has balanced fill, all
989+ // the drawers with balanced fill will need to be adjusted.
990+ // We add them here, and check if we placed an item in the loops below.
991+ if (drawer .getAttributes ().isBalancedFill ())
991992 rebalance .add (drawer );
993+ }
994+ // First test by strict remaining capacity
995+ for (var possibleDrawer : possibleDrawers ) {
996+ int amountBefore = amount ;
997+ int adjusted = Math .min (amount , possibleDrawer .drawer .getRemainingCapacity ());
992998
993- if (amount == 0 )
994- continue ;
995-
996- int adjusted = Math .min (amount , drawer .getRemainingCapacity ());
997999 amount = (simulate )
998- ? Math .max (amount - drawer .getRemainingCapacity (), 0 )
999- : (amount - adjusted ) + drawer .adjustStoredItemCount (adjusted );
1000-
1001- if (amount == 0 )
1002- continue ;
1000+ ? Math .max (amount - possibleDrawer .drawer .getRemainingCapacity (), 0 )
1001+ : (amount - adjusted ) + possibleDrawer .drawer .adjustStoredItemCount (adjusted );
10031002
10041003 if (simulate )
1005- checkedSlots .add (record .index );
1004+ checkedSlots .add (possibleDrawer .record .index );
1005+
1006+ // If we placed anything in a rebalancing drawer, mark the need to rebalance
1007+ if (!needRebalance && amountBefore != amount && possibleDrawer .drawer .getAttributes ().isBalancedFill ())
1008+ needRebalance = true ;
1009+
1010+ // Once we have fit all the items, we do not need to continue.
1011+ if (amount == 0 )
1012+ break ;
10061013 }
10071014
1008- // Then relax to available capacity
1015+ // Then relax to available capacity if needed
10091016 if (amount > 0 ) {
1010- for (SlotRecord record : primaryRecords ) {
1011- IDrawerGroup candidateGroup = getGroupForSlotRecord (record );
1012- if (candidateGroup == null )
1013- continue ;
1014-
1015- IDrawer drawer = candidateGroup .getDrawer (record .slot );
1016- if (drawer .isEmpty ())
1017- continue ;
1018- if (!testPredicateInsert (drawer , stack , predicate ))
1019- continue ;
1020- if (!hasAccess (candidateGroup , drawer ))
1021- continue ;
1022-
1023- IDrawerAttributes attrs = drawer .getAttributes ();
1024- if (attrs .isSuspended ())
1025- continue ;
1026-
1017+ for (var possibleDrawer : possibleDrawers ) {
1018+ int amountBefore = amount ;
10271019 amount = (simulate )
1028- ? Math .max (amount - drawer .getAcceptingRemainingCapacity (), 0 )
1029- : drawer .adjustStoredItemCount (amount );
1020+ ? Math .max (amount - possibleDrawer . drawer .getAcceptingRemainingCapacity (), 0 )
1021+ : possibleDrawer . drawer .adjustStoredItemCount (amount );
10301022
10311023 if (simulate )
1032- checkedSlots .add (record .index );
1024+ checkedSlots .add (possibleDrawer .record .index );
1025+
1026+ if (!needRebalance && amountBefore != amount && possibleDrawer .drawer .getAttributes ().isBalancedFill ())
1027+ needRebalance = true ;
1028+
1029+ // Once we have fit all the items, we do not need to continue.
1030+ if (amount == 0 )
1031+ break ;
10331032 }
10341033 }
10351034 }
@@ -1039,19 +1038,8 @@ public ItemStack insertItem (@NotNull ItemStack stack, boolean simulate, Predica
10391038 IDrawer drawer = getDrawer (slot );
10401039 if (!drawer .isEnabled ())
10411040 continue ;
1042- if (!testPredicateInsert (drawer , stack , predicate ))
1043- continue ;
1044- if (!hasAccess (getGroupForDrawerSlot (slot ), drawer ))
1045- continue ;
1046-
1047- IDrawerGroup group = getGroupForDrawerSlot (slot );
1048- if (!hasAccess (group , drawer ))
1049- continue ;
1050-
1051- IDrawerAttributes attrs = drawer .getAttributes ();
1052- if (attrs .isSuspended ())
1041+ if (!isValidDrawer (stack , predicate , drawer , getGroupForDrawerSlot (slot )))
10531042 continue ;
1054-
10551043 if (simulate && checkedSlots .contains (slot ))
10561044 continue ;
10571045
@@ -1062,20 +1050,43 @@ public ItemStack insertItem (@NotNull ItemStack stack, boolean simulate, Predica
10621050 amount = (simulate )
10631051 ? Math .max (amount - (empty ? drawer .getAcceptingMaxCapacity (stack ) : drawer .getAcceptingRemainingCapacity ()), 0 )
10641052 : drawer .adjustStoredItemCount (amount );
1065-
1053+ // Once we have fit all the items, we do not need to continue.
10661054 if (amount == 0 )
10671055 break ;
10681056 }
10691057 }
10701058
1071- if (!rebalance .isEmpty ())
1059+ if (needRebalance && !rebalance .isEmpty ())
10721060 StorageUtil .rebalanceDrawers (rebalance .stream ());
10731061
10741062 return (amount == 0 )
10751063 ? ItemStack .EMPTY
10761064 : stackResult (stack , amount );
10771065 }
10781066
1067+ private @ Nullable IDrawer getValidDrawer (@ NotNull ItemStack stack , Predicate <ItemStack > predicate , SlotRecord record ) {
1068+ IDrawerGroup candidateGroup = getGroupForSlotRecord (record );
1069+ if (candidateGroup == null )
1070+ return null ;
1071+ IDrawer drawer = candidateGroup .getDrawer (record .slot );
1072+ if (!isValidDrawer (stack , predicate , drawer , candidateGroup )) return null ;
1073+ return drawer ;
1074+ }
1075+
1076+ private boolean isValidDrawer (@ NotNull ItemStack stack , Predicate <ItemStack > predicate , IDrawer drawer , IDrawerGroup candidateGroup ) {
1077+ if (!testPredicateInsert (drawer , stack , predicate ))
1078+ return false ;
1079+
1080+ if (!hasAccess (candidateGroup , drawer ))
1081+ return false ;
1082+
1083+ IDrawerAttributes attrs = drawer .getAttributes ();
1084+ if (attrs .isSuspended ())
1085+ return false ;
1086+
1087+ return true ;
1088+ }
1089+
10791090 @ NotNull
10801091 @ Override
10811092 public ItemStack extractItem (@ NotNull ItemStack stack , int amount , boolean simulate , Predicate <ItemStack > predicate ) {
0 commit comments