1010import java .util .Map .Entry ;
1111import java .util .Set ;
1212import java .util .function .BooleanSupplier ;
13- import java .util .function .IntSupplier ;
13+ import java .util .function .ToIntBiFunction ;
1414import mekanism .api .Action ;
1515import mekanism .api .IContentsListener ;
1616import mekanism .api .NBTConstants ;
6969import net .minecraft .world .level .block .Block ;
7070import net .minecraft .world .level .block .state .BlockState ;
7171import net .neoforged .neoforge .attachment .AttachmentType ;
72+ import org .jetbrains .annotations .Contract ;
7273import org .jetbrains .annotations .NotNull ;
7374import org .jetbrains .annotations .Nullable ;
7475
@@ -279,6 +280,7 @@ public boolean inputProducesOutput(int process, @NotNull ItemStack fallbackInput
279280 return outputSlot .isEmpty () || getRecipeForInput (process , fallbackInput , outputSlot , secondaryOutputSlot , updateCache ) != null ;
280281 }
281282
283+ @ Contract ("null, _ -> false" )
282284 protected abstract boolean isCachedRecipeValid (@ Nullable CachedRecipe <RECIPE > cached , @ NotNull ItemStack stack );
283285
284286 @ Nullable
@@ -287,7 +289,7 @@ protected RECIPE getRecipeForInput(int process, @NotNull ItemStack fallbackInput
287289 if (!CommonWorldTickHandler .flushTagAndRecipeCaches ) {
288290 //If our recipe caches are valid, grab our cached recipe and see if it is still valid
289291 CachedRecipe <RECIPE > cached = getCachedRecipe (process );
290- if (cached != null && isCachedRecipeValid (cached , fallbackInput )) {
292+ if (isCachedRecipeValid (cached , fallbackInput )) {
291293 //Our input matches the recipe we have cached for this slot
292294 return cached .getRecipe ();
293295 }
@@ -526,7 +528,7 @@ ItemStack getOutput(int process) throws ComputerException {
526528 //End methods IComputerTile
527529
528530 private void sortInventory () {
529- Map <HashedItem , RecipeProcessInfo > processes = new HashMap <>();
531+ Map <HashedItem , RecipeProcessInfo < RECIPE > > processes = new HashMap <>();
530532 List <ProcessInfo > emptyProcesses = new ArrayList <>();
531533 for (ProcessInfo processInfo : processInfoSlots ) {
532534 IInventorySlot inputSlot = processInfo .inputSlot ();
@@ -535,18 +537,20 @@ private void sortInventory() {
535537 } else {
536538 ItemStack inputStack = inputSlot .getStack ();
537539 HashedItem item = HashedItem .raw (inputStack );
538- RecipeProcessInfo recipeProcessInfo = processes .computeIfAbsent (item , i -> new RecipeProcessInfo ());
540+ RecipeProcessInfo < RECIPE > recipeProcessInfo = processes .computeIfAbsent (item , i -> new RecipeProcessInfo <> ());
539541 recipeProcessInfo .processes .add (processInfo );
540542 recipeProcessInfo .totalCount += inputStack .getCount ();
541543 if (recipeProcessInfo .lazyMinPerSlot == null && !CommonWorldTickHandler .flushTagAndRecipeCaches ) {
542544 //If we don't have a lazily initialized min per slot calculation set for it yet
543545 // and our cache is not invalid/out of date due to a reload
544546 CachedRecipe <RECIPE > cachedRecipe = getCachedRecipe (processInfo .process ());
545547 if (isCachedRecipeValid (cachedRecipe , inputStack )) {
548+ recipeProcessInfo .item = inputStack ;
549+ recipeProcessInfo .recipe = cachedRecipe .getRecipe ();
546550 // And our current process has a cached recipe then set the lazily initialized per slot value
547551 // Note: If something goes wrong, and we end up with zero as how much we need as an input
548552 // we just bump the value up to one to make sure we properly handle it
549- recipeProcessInfo .lazyMinPerSlot = () -> Math . max ( 1 , getNeededInput (cachedRecipe . getRecipe (), inputStack ) );
553+ recipeProcessInfo .lazyMinPerSlot = (info , factory ) -> factory . getNeededInput (info . recipe , ( ItemStack ) info . item );
550554 }
551555 }
552556 }
@@ -555,23 +559,24 @@ private void sortInventory() {
555559 //If all input slots are empty, just exit
556560 return ;
557561 }
558- for (Entry <HashedItem , RecipeProcessInfo > entry : processes .entrySet ()) {
559- RecipeProcessInfo recipeProcessInfo = entry .getValue ();
562+ for (Entry <HashedItem , RecipeProcessInfo < RECIPE > > entry : processes .entrySet ()) {
563+ RecipeProcessInfo < RECIPE > recipeProcessInfo = entry .getValue ();
560564 if (recipeProcessInfo .lazyMinPerSlot == null ) {
565+ recipeProcessInfo .item = entry .getKey ();
561566 //If we don't have a lazy initializer for our minPerSlot setup, that means that there is
562567 // no valid cached recipe for any of the slots of this type currently, so we want to try and
563568 // get the recipe we will have for the first slot, once we end up with more items in the stack
564- recipeProcessInfo .lazyMinPerSlot = () -> {
569+ recipeProcessInfo .lazyMinPerSlot = (info , factory ) -> {
565570 //Note: We put all of this logic in the lazy init, so that we don't actually call any of this
566571 // until it is needed. That way if we have no empty slots and all our input slots are filled
567572 // we don't do any extra processing here, and can properly short circuit
568- HashedItem item = entry . getKey () ;
569- ItemStack largerInput = item .createStack (Math .min (item .getMaxStackSize (), recipeProcessInfo .totalCount ));
570- ProcessInfo processInfo = recipeProcessInfo .processes .get (0 );
573+ HashedItem item = ( HashedItem ) info . item ;
574+ ItemStack largerInput = item .createStack (Math .min (item .getMaxStackSize (), info .totalCount ));
575+ ProcessInfo processInfo = info .processes .get (0 );
571576 //Try getting a recipe for our input with a larger size, and update the cache if we find one
572- RECIPE recipe = getRecipeForInput (processInfo .process (), largerInput , processInfo .outputSlot (), processInfo .secondaryOutputSlot (), true );
573- if (recipe != null ) {
574- return Math . max ( 1 , getNeededInput (recipe , largerInput ) );
577+ info . recipe = factory . getRecipeForInput (processInfo .process (), largerInput , processInfo .outputSlot (), processInfo .secondaryOutputSlot (), true );
578+ if (info . recipe != null ) {
579+ return factory . getNeededInput (info . recipe , largerInput );
575580 }
576581 return 1 ;
577582 };
@@ -587,10 +592,10 @@ private void sortInventory() {
587592 distributeItems (processes );
588593 }
589594
590- private void addEmptySlotsAsTargets (Map <HashedItem , RecipeProcessInfo > processes , List <ProcessInfo > emptyProcesses ) {
591- for (Entry <HashedItem , RecipeProcessInfo > entry : processes .entrySet ()) {
592- RecipeProcessInfo recipeProcessInfo = entry .getValue ();
593- int minPerSlot = recipeProcessInfo .getMinPerSlot ();
595+ private void addEmptySlotsAsTargets (Map <HashedItem , RecipeProcessInfo < RECIPE > > processes , List <ProcessInfo > emptyProcesses ) {
596+ for (Entry <HashedItem , RecipeProcessInfo < RECIPE > > entry : processes .entrySet ()) {
597+ RecipeProcessInfo < RECIPE > recipeProcessInfo = entry .getValue ();
598+ int minPerSlot = recipeProcessInfo .getMinPerSlot (this );
594599 int maxSlots = recipeProcessInfo .totalCount / minPerSlot ;
595600 if (maxSlots <= 1 ) {
596601 //If we don't have enough to even fill the input for a slot for a single recipe; skip
@@ -630,9 +635,9 @@ private void addEmptySlotsAsTargets(Map<HashedItem, RecipeProcessInfo> processes
630635 }
631636 }
632637
633- private void distributeItems (Map <HashedItem , RecipeProcessInfo > processes ) {
634- for (Entry <HashedItem , RecipeProcessInfo > entry : processes .entrySet ()) {
635- RecipeProcessInfo recipeProcessInfo = entry .getValue ();
638+ private void distributeItems (Map <HashedItem , RecipeProcessInfo < RECIPE > > processes ) {
639+ for (Entry <HashedItem , RecipeProcessInfo < RECIPE > > entry : processes .entrySet ()) {
640+ RecipeProcessInfo < RECIPE > recipeProcessInfo = entry .getValue ();
636641 int processCount = recipeProcessInfo .processes .size ();
637642 if (processCount == 1 ) {
638643 //If there is only one process with the item in it; short-circuit, no balancing is needed
@@ -647,7 +652,7 @@ private void distributeItems(Map<HashedItem, RecipeProcessInfo> processes) {
647652 continue ;
648653 }
649654 int remainder = recipeProcessInfo .totalCount % processCount ;
650- int minPerSlot = recipeProcessInfo .getMinPerSlot ();
655+ int minPerSlot = recipeProcessInfo .getMinPerSlot (this );
651656 if (minPerSlot > 1 ) {
652657 int perSlotRemainder = numberPerSlot % minPerSlot ;
653658 if (perSlotRemainder > 0 ) {
@@ -732,18 +737,20 @@ public record ProcessInfo(int process, @NotNull FactoryInputInventorySlot inputS
732737 @ Nullable IInventorySlot secondaryOutputSlot ) {
733738 }
734739
735- private static class RecipeProcessInfo {
740+ private static class RecipeProcessInfo < RECIPE extends MekanismRecipe > {
736741
737742 private final List <ProcessInfo > processes = new ArrayList <>();
738743 @ Nullable
739- private IntSupplier lazyMinPerSlot ;
744+ private ToIntBiFunction <RecipeProcessInfo <RECIPE >, TileEntityFactory <RECIPE >> lazyMinPerSlot ;
745+ private Object item ;
746+ private RECIPE recipe ;
740747 private int minPerSlot = 1 ;
741748 private int totalCount ;
742749
743- public int getMinPerSlot () {
750+ public int getMinPerSlot (TileEntityFactory < RECIPE > factory ) {
744751 if (lazyMinPerSlot != null ) {
745752 //Get the value lazily
746- minPerSlot = lazyMinPerSlot .getAsInt ( );
753+ minPerSlot = Math . max ( 1 , lazyMinPerSlot .applyAsInt ( this , factory ) );
747754 lazyMinPerSlot = null ;
748755 }
749756 return minPerSlot ;
0 commit comments