From 8cc29734a2e909266ed1d41b4c7bc27d50f30aa0 Mon Sep 17 00:00:00 2001 From: PrototypeTrousers Date: Fri, 25 Mar 2022 21:09:52 -0300 Subject: [PATCH] positive loop support --- .../java/appeng/crafting/CraftingJob.java | 60 +++--- .../appeng/crafting/CraftingTreeNode.java | 132 +++++++++--- .../appeng/crafting/CraftingTreeProcess.java | 195 +++++------------- .../appeng/crafting/MECraftingInventory.java | 9 - .../implementations/CraftingCPUCluster.java | 69 ++++--- 5 files changed, 224 insertions(+), 241 deletions(-) diff --git a/src/main/java/appeng/crafting/CraftingJob.java b/src/main/java/appeng/crafting/CraftingJob.java index 469a0da72..c60b43b92 100644 --- a/src/main/java/appeng/crafting/CraftingJob.java +++ b/src/main/java/appeng/crafting/CraftingJob.java @@ -19,16 +19,6 @@ package appeng.crafting; -import java.util.HashMap; -import java.util.concurrent.TimeUnit; - -import appeng.me.cache.GridStorageCache; -import com.google.common.base.Stopwatch; - -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.World; - import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.networking.IGrid; @@ -37,7 +27,6 @@ import appeng.api.networking.IGridNode; import appeng.api.networking.crafting.ICraftingCallback; import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingJob; -import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.IActionSource; import appeng.api.networking.storage.IStorageGrid; @@ -47,6 +36,14 @@ import appeng.api.storage.data.IItemList; import appeng.api.util.DimensionalCoord; import appeng.core.AELog; import appeng.hooks.TickHandler; +import appeng.me.cache.GridStorageCache; +import com.google.common.base.Stopwatch; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import java.util.HashMap; +import java.util.concurrent.TimeUnit; public class CraftingJob implements Runnable, ICraftingJob @@ -58,48 +55,45 @@ public class CraftingJob implements Runnable, ICraftingJob private final World world; private final IItemList crafting = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + private final IItemList neededForLoop = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + private final Object2ObjectOpenHashMap reserved = new Object2ObjectOpenHashMap<>(); private final HashMap opsAndMultiplier = new HashMap<>(); private final Object monitor = new Object(); private final Stopwatch tickSpreadingWatch = Stopwatch.createUnstarted(); private final Stopwatch craftingTreeWatch = Stopwatch.createUnstarted(); - private final ICraftingGrid cc; - private CraftingTreeNode tree; private final IAEItemStack output; + private final IActionSource actionSrc; + private final ICraftingCallback callback; + private CraftingTreeNode tree; private boolean simulate = false; private MECraftingInventory availableCheck; private long bytes = 0; - private final IActionSource actionSrc; - private final ICraftingCallback callback; private boolean running = false; private boolean done = false; private int time; private int incTime; - private World wrapWorld( final World w ) - { - return w; - } - public CraftingJob( final World w, final IGrid grid, final IActionSource actionSrc, final IAEItemStack what, final ICraftingCallback callback ) { - this.world = this.wrapWorld( w ); + this.world = w; this.output = what.copy(); this.actionSrc = actionSrc; this.callback = callback; - this.cc = grid.getCache( ICraftingGrid.class ); + ICraftingGrid cc = grid.getCache( ICraftingGrid.class ); final GridStorageCache sg = grid.getCache( IStorageGrid.class ); this.original = sg.getExtractableList( actionSrc ); + this.availableCheck = new MECraftingInventory( this.original, false, false, false ); this.setTree( this.getCraftingTree( cc, what ) ); this.availableCheck = null; } private CraftingTreeNode getCraftingTree( final ICraftingGrid cc, final IAEItemStack what ) { - return new CraftingTreeNode( cc, this, what, null, -1, 0 ); + return new CraftingTreeNode( cc, this, what, null, -1 ); } void refund( final IAEItemStack o ) @@ -117,7 +111,7 @@ public class CraftingJob implements Runnable, ICraftingJob return this.availableCheck.extractItems( available, Actionable.SIMULATE, this.actionSrc ); } - void addTask( IAEItemStack what, final long crafts, final ICraftingPatternDetails details, final int depth ) + void addTask( IAEItemStack what, final long crafts ) { if( crafts > 0 ) { @@ -133,6 +127,22 @@ public class CraftingJob implements Runnable, ICraftingJob this.missing.add( what ); } + public void reserve( CraftingTreeNode node, IAEItemStack stack ) + { + checkUse( stack ); + reserved.put( node, stack ); + } + + public IItemList getNeededForLoop() + { + return neededForLoop; + } + + public Object2ObjectOpenHashMap getReserved() + { + return reserved; + } + @Override public void run() { @@ -144,7 +154,6 @@ public class CraftingJob implements Runnable, ICraftingJob this.handlePausing(); final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true ); - craftingInventory.ignore( this.output ); this.availableCheck = new MECraftingInventory( this.original, false, false, false ); craftingTreeWatch.start(); @@ -176,7 +185,6 @@ public class CraftingJob implements Runnable, ICraftingJob if( actionSrc.player().isPresent() ) { final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true ); - craftingInventory.ignore( this.output ); this.getTree().setSimulate(); this.availableCheck = new MECraftingInventory( this.original, false, false, false ); diff --git a/src/main/java/appeng/crafting/CraftingTreeNode.java b/src/main/java/appeng/crafting/CraftingTreeNode.java index a3fcf094b..48c6ac2fa 100644 --- a/src/main/java/appeng/crafting/CraftingTreeNode.java +++ b/src/main/java/appeng/crafting/CraftingTreeNode.java @@ -19,17 +19,9 @@ package appeng.crafting; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import appeng.api.config.FuzzyMode; -import appeng.util.Platform; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.world.World; - import appeng.api.AEApi; import appeng.api.config.Actionable; +import appeng.api.config.FuzzyMode; import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.security.IActionSource; @@ -37,8 +29,15 @@ import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import appeng.me.cluster.implementations.CraftingCPUCluster; +import appeng.util.Platform; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.World; import net.minecraftforge.fml.common.Optional; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + @Optional.Interface( iface = "gregtech.api.items.IToolItem", modid = "gregtech" ) public class CraftingTreeNode @@ -55,33 +54,22 @@ public class CraftingTreeNode private final IAEItemStack what; // what are the crafting patterns for this? private final ArrayList nodes = new ArrayList<>(); - private final ICraftingGrid cc; - private final int depth; + private final boolean canEmit; + private CraftingTreeNode loopHead; private int bytes = 0; - private boolean canEmit = false; private long missing = 0; private long howManyEmitted = 0; private boolean exhausted = false; - public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, final CraftingTreeProcess par, final int slot, final int depth ) + public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, final CraftingTreeProcess par, final int slot ) { this.what = wat; this.parent = par; this.slot = slot; this.world = job.getWorld(); this.job = job; - this.cc = cc; - this.depth = depth; this.canEmit = cc.canEmitFor( this.what ); - } - - public void addNode() - { - if( !nodes.isEmpty() ) - { - return; - } if( this.canEmit ) { @@ -91,16 +79,59 @@ public class CraftingTreeNode for( final ICraftingPatternDetails details : cc.getCraftingFor( this.what, this.parent == null ? null : this.parent.details, slot, this.world ) )// in // order. { - if( this.parent == null || notRecursive( details ) && this.parent.details != details ) + int times = 1; + for( IAEItemStack o : details.getCondensedOutputs() ) { - this.nodes.add( new CraftingTreeProcess( cc, job, details, this, depth + 1 ) ); + if( what.equals( o ) ) + { + times = (int) ( what.getStackSize() / o.getStackSize() + ( what.getStackSize() % o.getStackSize() != 0 ? 1 : 0 ) ); + } } + + for( IAEItemStack i : details.getCondensedInputs() ) + { + if( i.equals( job.getOutput() ) ) + { + job.getNeededForLoop().add( i.copy().setStackSize( i.getStackSize() * times ) ); + } + } + + if( this.parent == null ) + { + this.nodes.add( new CraftingTreeProcess( cc, job, details, times, this ) ); + continue; + } + CraftingTreeNode recursive = recursiveNode( this ); + if( recursive == null ) + { + this.nodes.add( new CraftingTreeProcess( cc, job, details, times, this ) ); + } + else + { + reserveForNode(); + } + } + } + + void reserveForNode() + { + if( loopHead == this ) + { + return; + } + IAEItemStack available = job.checkAvailable( this.what ); + if( available != null && available.getStackSize() >= this.what.getStackSize() ) + { + this.job.reserve( this, this.what.copy() ); + } + else + { + parent.reserverForNode(); } } IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException { - addNode(); this.job.handlePausing(); if( this.canEmit ) { @@ -114,6 +145,9 @@ public class CraftingTreeNode } final IItemList inventoryList = inv.getItemList(); + + IAEItemStack reserved = job.getReserved().get( this ); + final List thingsUsed = new ArrayList<>(); this.what.setStackSize( l ); @@ -146,7 +180,19 @@ public class CraftingTreeNode } if( this.parent.details.canSubstitute() ) { - itemList.addAll( inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL ) ); + for( IAEItemStack s : parent.details.getSubstituteInputs( this.slot ) ) + { + if( s != null ) + { + for( IAEItemStack ss : inventoryList.findFuzzy( s, FuzzyMode.IGNORE_ALL ) ) + { + if( ss != null && !itemList.contains( ss ) ) + { + itemList.add( ss ); + } + } + } + } } } @@ -191,7 +237,16 @@ public class CraftingTreeNode { if( !this.exhausted ) { - final IAEItemStack is = this.job.checkUse( available ); + IAEItemStack is; + + if( reserved != null ) + { + is = reserved; + } + else + { + is = this.job.checkUse( available ); + } if( is != null ) { @@ -249,7 +304,9 @@ public class CraftingTreeNode while ( pro.possible && l > 0 ) { final MECraftingInventory subInv = new MECraftingInventory( inv, true, true, true ); - pro.request( subInv, 1, src ); + final IAEItemStack madeWhat = pro.getAmountCrafted( this.what ); + + pro.request( subInv, pro.getTimes( l, madeWhat.getStackSize() ), src ); this.what.setStackSize( l ); final IAEItemStack available = subInv.extractItems( this.what, Actionable.MODULATE, src ); @@ -301,17 +358,24 @@ public class CraftingTreeNode throw new CraftBranchFailure( this.what, l ); } - boolean notRecursive( ICraftingPatternDetails details ) + CraftingTreeNode recursiveNode( CraftingTreeNode node ) { if( this.parent == null ) { - return true; + return null; } - if( this.parent.details == details ) + if( node != this ) { - return false; + if( node.what.equals( this.what ) ) + { + if( node.what.getStackSize() == this.what.getStackSize() ) + { + loopHead = this; + return node; + } + } } - return this.parent.notRecursive( details ); + return this.parent.notRecursive( node ); } void dive( final CraftingJob job ) diff --git a/src/main/java/appeng/crafting/CraftingTreeProcess.java b/src/main/java/appeng/crafting/CraftingTreeProcess.java index 025af3d43..d0d9a1cdd 100644 --- a/src/main/java/appeng/crafting/CraftingTreeProcess.java +++ b/src/main/java/appeng/crafting/CraftingTreeProcess.java @@ -19,18 +19,8 @@ package appeng.crafting; -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; - -import appeng.api.config.FuzzyMode; -import appeng.util.item.AEItemStack; -import com.google.common.collect.ImmutableCollection; -import it.unimi.dsi.fastutil.objects.Object2LongArrayMap; -import net.minecraft.item.ItemStack; -import net.minecraft.world.World; - import appeng.api.config.Actionable; +import appeng.api.config.FuzzyMode; import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.security.IActionSource; @@ -38,37 +28,34 @@ import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.util.Platform; +import appeng.util.item.AEItemStack; +import com.google.common.collect.ImmutableCollection; +import it.unimi.dsi.fastutil.objects.Object2LongArrayMap; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; public class CraftingTreeProcess { - private final CraftingTreeNode parent; final ICraftingPatternDetails details; + private final CraftingTreeNode parent; private final CraftingJob job; private final Object2LongArrayMap nodes = new Object2LongArrayMap<>(); - private final int depth; - private final ICraftingGrid cc; - private final World world; boolean possible = true; private long crafts = 0; private long bytes = 0; + private boolean hasContainerItem = false; - public CraftingTreeProcess( final ICraftingGrid cc, final CraftingJob job, final ICraftingPatternDetails details, final CraftingTreeNode craftingTreeNode, final int depth ) + public CraftingTreeProcess( final ICraftingGrid cc, final CraftingJob job, final ICraftingPatternDetails details, int times, final CraftingTreeNode craftingTreeNode ) { this.parent = craftingTreeNode; this.details = details; this.job = job; - this.depth = depth; - this.cc = cc; - this.world = job.getWorld(); - } - - public void addProcess() - { - if( !nodes.isEmpty() ) - { - return; - } + World world = job.getWorld(); final IAEItemStack[] list = details.getInputs(); @@ -89,131 +76,61 @@ public class CraftingTreeProcess { part = list[x]; isPartContainer = true; + this.hasContainerItem = true; } - long wantedSize = part.getStackSize(); - IAEItemStack found; - long remaining = 0; - long requestAmount = 0; + long wantedSize = isPartContainer ? part.getStackSize() : part.getStackSize() * times; - if( wantedSize > 0 ) + if( details.canSubstitute() && cc.getCraftingFor( part, details, x, world ).isEmpty() ) { - if( details.canSubstitute() ) + for( IAEItemStack subs : details.getSubstituteInputs( x ) ) { - for( IAEItemStack subs : details.getSubstituteInputs( x ) ) + if( subs.fuzzyComparison( part, FuzzyMode.IGNORE_ALL ) ) { - found = job.checkAvailable( subs ); - - if( found != null ) - { - remaining = found.getStackSize(); - } - - if( remaining > 0 ) - { - if( remaining >= wantedSize ) - { - requestAmount = wantedSize; - wantedSize = 0; - //we have the items - } - else - { - requestAmount = remaining; - wantedSize -= remaining; - } - subs = subs.copy().setStackSize( requestAmount ); - this.nodes.put( new CraftingTreeNode( cc, job, subs, this, x, depth + 1 ), requestAmount ); - if( wantedSize == 0 ) - { - break; - } - } + this.nodes.put( new CraftingTreeNode( cc, job, subs.copy().setStackSize( wantedSize ), this, x ), wantedSize ); + wantedSize = 0; + break; } } - else + //try to order the crafting of a substitute + ICraftingPatternDetails prioritizedPattern = null; + IAEItemStack prioritizedIAE = null; + for( IAEItemStack subs : details.getSubstituteInputs( x ) ) { - found = job.checkAvailable( part ); - - if( found != null ) + if( subs.equals( part ) ) { - remaining = found.getStackSize(); + continue; } + ImmutableCollection detailCollection = cc.getCraftingFor( subs, details, x, world ); - if( remaining > 0 ) + for( ICraftingPatternDetails sp : detailCollection ) { - if( remaining >= wantedSize ) + if( prioritizedPattern == null ) { - requestAmount = wantedSize; - wantedSize = 0; - //we have the items + prioritizedPattern = sp; + prioritizedIAE = subs; } else { - requestAmount = remaining; - wantedSize -= remaining; - } - part = part.copy().setStackSize( requestAmount ); - this.nodes.put( new CraftingTreeNode( cc, job, part, this, x, depth + 1 ), requestAmount ); - } - } - } - if( wantedSize > 0 ) - { - if( details.canSubstitute() && cc.getCraftingFor( part, details, x, world ).isEmpty() ) - { - for( IAEItemStack subs : details.getSubstituteInputs( x ) ) - { - if( subs.fuzzyComparison( part, FuzzyMode.IGNORE_ALL ) ) - { - wantedSize -= 1; - this.nodes.put( new CraftingTreeNode( cc, job, subs.copy().setStackSize( 1 ), this, x, depth + 1 ), 1 ); - if( wantedSize == 0 ) - { - break; - } - } - } - //try to order the crafting of a substitute - ICraftingPatternDetails prioritizedPattern = null; - IAEItemStack prioritizedIAE = null; - for( IAEItemStack subs : details.getSubstituteInputs( x ) ) - { - if( subs.equals( part ) ) - { - continue; - } - ImmutableCollection detailCollection = cc.getCraftingFor( subs, details, x, world ); - - for( ICraftingPatternDetails sp : detailCollection ) - { - if( prioritizedPattern == null ) + if( sp.getPriority() > prioritizedPattern.getPriority() ) { prioritizedPattern = sp; - prioritizedIAE = subs; - } - else - { - if( sp.getPriority() > prioritizedPattern.getPriority() ) - { - prioritizedPattern = sp; - } } } - if( prioritizedIAE != null ) - { - this.nodes.put( new CraftingTreeNode( cc, job, prioritizedIAE.copy(), this, x, depth + 1 ), wantedSize ); - wantedSize = 0; - break; - } + } + if( prioritizedIAE != null ) + { + this.nodes.put( new CraftingTreeNode( cc, job, prioritizedIAE.copy().setStackSize( wantedSize ), this, x ), wantedSize ); + wantedSize = 0; + break; } } } if( wantedSize > 0 ) { - part = part.copy(); + part = part.copy().setStackSize( wantedSize ); // use the first slot... - this.nodes.put( new CraftingTreeNode( cc, job, part, this, x, depth + 1 ), wantedSize ); + this.nodes.put( new CraftingTreeNode( cc, job, part, this, x ), wantedSize ); wantedSize = 0; } if( !isPartContainer && wantedSize == 0 ) @@ -225,36 +142,33 @@ public class CraftingTreeProcess } } - boolean notRecursive( ICraftingPatternDetails details ) + CraftingTreeNode notRecursive( CraftingTreeNode node ) { - return this.parent == null || this.parent.notRecursive( details ); + if( parent == null ) + { + return null; + } + return this.parent.recursiveNode( node ); } long getTimes( final long remaining, final long stackSize ) { - for( final IAEItemStack part : details.getCondensedOutputs() ) + if( hasContainerItem ) { - for( final IAEItemStack o : details.getCondensedInputs() ) - { - if( part.equals( o ) || o.getItem().hasContainerItem( part.getDefinition() ) ) - { - return 1; - } - } + return 1; } return ( remaining / stackSize ) + ( remaining % stackSize != 0 ? 1 : 0 ); } void request( final MECraftingInventory inv, final long amountOfTimes, final IActionSource src ) throws CraftBranchFailure, InterruptedException { - addProcess(); this.job.handlePausing(); List containerItems = null; // request and remove inputs... for( final Entry entry : this.nodes.object2LongEntrySet() ) { - final IAEItemStack stack = entry.getKey().request( inv, entry.getValue() * amountOfTimes, src ); + final IAEItemStack stack = entry.getKey().request( inv, hasContainerItem ? 1 : entry.getValue(), src ); if( stack.getItem().hasContainerItem( stack.getDefinition() ) ) { @@ -295,7 +209,7 @@ public class CraftingTreeProcess void dive( final CraftingJob job ) { - job.addTask( this.getAmountCrafted( this.parent.getStack( 1 ) ), this.crafts, this.details, this.depth ); + job.addTask( this.getAmountCrafted( this.parent.getStack( 1 ) ), this.crafts ); for( final Entry entry : this.nodes.object2LongEntrySet() ) { entry.getKey().dive( job ); @@ -365,4 +279,9 @@ public class CraftingTreeProcess entry.getKey().getPlan( plan ); } } + + public void reserverForNode() + { + parent.reserveForNode(); + } } diff --git a/src/main/java/appeng/crafting/MECraftingInventory.java b/src/main/java/appeng/crafting/MECraftingInventory.java index 379937498..c61fb5d91 100644 --- a/src/main/java/appeng/crafting/MECraftingInventory.java +++ b/src/main/java/appeng/crafting/MECraftingInventory.java @@ -353,13 +353,4 @@ public class MECraftingInventory implements IMEInventory { this.missingCache.add( extra ); } - - void ignore( final IAEItemStack what ) - { - final IAEItemStack list = this.localCache.findPrecise( what ); - if( list != null ) - { - list.setStackSize( 0 ); - } - } } diff --git a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java index fa7ccb23b..ae57be47c 100644 --- a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java @@ -19,22 +19,6 @@ package appeng.me.cluster.implementations; -import java.util.*; -import java.util.Map.Entry; -import java.util.stream.Collectors; - -import appeng.api.config.Upgrades; -import appeng.helpers.DualityInterface; -import appeng.helpers.PatternHelper; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; - -import net.minecraft.inventory.InventoryCrafting; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.world.World; - import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.config.FuzzyMode; @@ -43,14 +27,7 @@ import appeng.api.implementations.ICraftingPatternItem; import appeng.api.networking.IGrid; import appeng.api.networking.IGridHost; import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.CraftingItemList; -import appeng.api.networking.crafting.ICraftingCPU; -import appeng.api.networking.crafting.ICraftingGrid; -import appeng.api.networking.crafting.ICraftingJob; -import appeng.api.networking.crafting.ICraftingLink; -import appeng.api.networking.crafting.ICraftingMedium; -import appeng.api.networking.crafting.ICraftingPatternDetails; -import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.networking.crafting.*; import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.events.MENetworkCraftingCpuChange; import appeng.api.networking.security.IActionSource; @@ -63,11 +40,8 @@ import appeng.api.storage.data.IItemList; import appeng.api.util.WorldCoord; import appeng.container.ContainerNull; import appeng.core.AELog; -import appeng.crafting.CraftBranchFailure; -import appeng.crafting.CraftingJob; -import appeng.crafting.CraftingLink; -import appeng.crafting.CraftingWatcher; -import appeng.crafting.MECraftingInventory; +import appeng.crafting.*; +import appeng.helpers.PatternHelper; import appeng.me.cache.CraftingGridCache; import appeng.me.cluster.IAECluster; import appeng.me.helpers.MachineSource; @@ -75,6 +49,17 @@ import appeng.tile.crafting.TileCraftingMonitorTile; import appeng.tile.crafting.TileCraftingTile; import appeng.util.Platform; import appeng.util.item.AEItemStack; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; public final class CraftingCPUCluster implements IAECluster, ICraftingCPU @@ -102,6 +87,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU private IAEItemStack finalOutput; private boolean waiting = false; private IItemList waitingFor = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + private IItemList neededForLoop = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private long availableStorage = 0; private MachineSource machineSrc = null; private int accelerator = 0; @@ -224,13 +210,10 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU public boolean canAccept( final IAEItemStack input ) { - if( input instanceof IAEItemStack ) + if( input != null ) { final IAEItemStack is = this.waitingFor.findPrecise( input ); - if( is != null && is.getStackSize() > 0 ) - { - return true; - } + return is != null && is.getStackSize() > 0; } return false; } @@ -304,6 +287,14 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU if( this.finalOutput.equals( what ) ) { + + IAEItemStack isLoop = neededForLoop.findPrecise( finalOutput ); + if( isLoop != null && isLoop.getStackSize() > 0 ) + { + isLoop.decStackSize( what.getStackSize() ); + return this.inventory.injectItems( what, type, src ); + } + IAEItemStack leftover = what; this.finalOutput.decStackSize( what.getStackSize() ); @@ -336,6 +327,14 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU if( this.finalOutput.equals( insert ) ) { + + IAEItemStack isLoop = neededForLoop.findPrecise( finalOutput ); + if( isLoop != null && isLoop.getStackSize() > 0 ) + { + isLoop.decStackSize( insert.getStackSize() ); + return this.inventory.injectItems( insert, type, src ); + } + IAEItemStack leftover = input; this.finalOutput.decStackSize( insert.getStackSize() ); @@ -966,10 +965,12 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU try { this.waitingFor.resetStatus(); + this.neededForLoop.resetStatus(); ( (CraftingJob) job ).getTree().setJob( ci, this, src ); if( ci.commit( src ) ) { this.finalOutput = job.getOutput(); + this.neededForLoop = ( (CraftingJob) job ).getNeededForLoop(); this.waiting = false; this.isComplete = false; this.markDirty();