diff --git a/container/implementations/ContainerCraftConfirm.java b/container/implementations/ContainerCraftConfirm.java index e6126730a..a321e829a 100644 --- a/container/implementations/ContainerCraftConfirm.java +++ b/container/implementations/ContainerCraftConfirm.java @@ -17,6 +17,7 @@ import appeng.container.AEBaseContainer; import appeng.core.AELog; import appeng.crafting.CraftingJob; import appeng.crafting.ICraftingHost; +import appeng.me.cache.CraftingCache; public class ContainerCraftConfirm extends AEBaseContainer implements ICraftingHost { @@ -39,7 +40,10 @@ public class ContainerCraftConfirm extends AEBaseContainer implements ICraftingH try { result = job.get(); + CraftingCache cc = getGrid().getCache( CraftingCache.class ); + cc.submitJob( result, null, getActionSrc() ); AELog.info( "Job info is ready!" ); + this.isContainerValid = false; } catch (Throwable e) { diff --git a/crafting/CraftingJob.java b/crafting/CraftingJob.java index e91c48ad3..19ec4c4ed 100644 --- a/crafting/CraftingJob.java +++ b/crafting/CraftingJob.java @@ -35,6 +35,11 @@ public class CraftingJob implements Runnable public CraftingTreeNode tree; private BaseActionSource actionSrc; + public IAEItemStack getOutput() + { + return output; + } + public CraftingJob(ICraftingHost host, NBTTagCompound data) { jobHost = host; storage = AEApi.instance().storage().createItemList(); @@ -178,4 +183,5 @@ public class CraftingJob implements Runnable } } + } diff --git a/crafting/CraftingTreeNode.java b/crafting/CraftingTreeNode.java index cf9b9291c..022354c76 100644 --- a/crafting/CraftingTreeNode.java +++ b/crafting/CraftingTreeNode.java @@ -3,12 +3,15 @@ package appeng.crafting; import java.util.ArrayList; import net.minecraft.world.World; +import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.config.FuzzyMode; import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.security.BaseActionSource; import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; import appeng.me.cache.CraftingCache; +import appeng.me.cluster.implementations.CraftingCPUCluster; public class CraftingTreeNode { @@ -29,6 +32,9 @@ public class CraftingTreeNode boolean cannotUse = false; long missing = 0; + IItemList used = AEApi.instance().storage().createItemList(); + boolean exhausted = false; + boolean sim; public CraftingTreeNode(CraftingCache cc, CraftingJob job, IAEItemStack wat, CraftingTreeProcess par, int slot, int depth) { @@ -83,6 +89,8 @@ public class CraftingTreeNode if ( available != null ) { + if ( !exhausted ) + used.add( available ); l -= available.getStackSize(); if ( l == 0 ) @@ -97,6 +105,8 @@ public class CraftingTreeNode if ( available != null ) { + if ( !exhausted ) + used.add( available ); l -= available.getStackSize(); if ( l == 0 ) @@ -104,6 +114,8 @@ public class CraftingTreeNode } } + exhausted = true; + if ( nodes.size() == 1 ) { CraftingTreeProcess pro = nodes.get( 0 ); @@ -182,8 +194,26 @@ public class CraftingTreeNode { sim = true; missing = 0; + used.resetStatus(); + exhausted = false; for (CraftingTreeProcess pro : nodes) pro.setSimulate(); } + + public void setJob(MECraftingInventory storage, CraftingCPUCluster craftingCPUCluster, BaseActionSource src) throws CraftBranchFailure + { + for (IAEItemStack i : used) + { + IAEItemStack ex = storage.extractItems( i, Actionable.MODULATE, src ); + + if ( ex == null || ex.getStackSize() != i.getStackSize() ) + throw new CraftBranchFailure( i, i.getStackSize() ); + + craftingCPUCluster.addStorage( ex ); + } + + for (CraftingTreeProcess pro : nodes) + pro.setJob( storage, craftingCPUCluster, src ); + } } diff --git a/crafting/CraftingTreeProcess.java b/crafting/CraftingTreeProcess.java index 9399293d1..a385efb59 100644 --- a/crafting/CraftingTreeProcess.java +++ b/crafting/CraftingTreeProcess.java @@ -12,6 +12,7 @@ import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.security.BaseActionSource; import appeng.api.storage.data.IAEItemStack; import appeng.me.cache.CraftingCache; +import appeng.me.cluster.implementations.CraftingCPUCluster; public class CraftingTreeProcess { @@ -140,4 +141,12 @@ public class CraftingTreeProcess for (CraftingTreeNode pro : nodes.keySet()) pro.setSimulate(); } + + public void setJob(MECraftingInventory storage, CraftingCPUCluster craftingCPUCluster, BaseActionSource src) throws CraftBranchFailure + { + craftingCPUCluster.addCrafting( details, crafts ); + + for (CraftingTreeNode pro : nodes.keySet()) + pro.setJob( storage, craftingCPUCluster, src ); + } } diff --git a/crafting/MECraftingInventory.java b/crafting/MECraftingInventory.java index d4d352dcb..ab73d9ea4 100644 --- a/crafting/MECraftingInventory.java +++ b/crafting/MECraftingInventory.java @@ -25,15 +25,39 @@ public class MECraftingInventory implements IMEInventory final boolean logMissing; final IItemList missingCache; + public MECraftingInventory() { + localCache = AEApi.instance().storage().createItemList(); + extractedCache = null; + injectedCache = null; + missingCache = null; + this.logExtracted = false; + this.logInjections = false; + this.logMissing = false; + target = null; + par = null; + } + public MECraftingInventory(MECraftingInventory parrent) { this.target = parrent; this.logExtracted = parrent.logExtracted; this.logInjections = parrent.logInjections; this.logMissing = parrent.logMissing; - missingCache = AEApi.instance().storage().createItemList(); - extractedCache = AEApi.instance().storage().createItemList(); - injectedCache = AEApi.instance().storage().createItemList(); + if ( logMissing ) + missingCache = AEApi.instance().storage().createItemList(); + else + missingCache = null; + + if ( logExtracted ) + extractedCache = AEApi.instance().storage().createItemList(); + else + extractedCache = null; + + if ( logInjections ) + injectedCache = AEApi.instance().storage().createItemList(); + else + injectedCache = null; + localCache = target.getAvailableItems( AEApi.instance().storage().createItemList() ); par = parrent; @@ -44,9 +68,22 @@ public class MECraftingInventory implements IMEInventory this.logExtracted = logExtracted; this.logInjections = logInjections; this.logMissing = logMissing; - missingCache = AEApi.instance().storage().createItemList(); - extractedCache = AEApi.instance().storage().createItemList(); - injectedCache = AEApi.instance().storage().createItemList(); + + if ( logMissing ) + missingCache = AEApi.instance().storage().createItemList(); + else + missingCache = null; + + if ( logExtracted ) + extractedCache = AEApi.instance().storage().createItemList(); + else + extractedCache = null; + + if ( logInjections ) + injectedCache = AEApi.instance().storage().createItemList(); + else + injectedCache = null; + localCache = target.getAvailableItems( AEApi.instance().storage().createItemList() ); par = null; } @@ -120,12 +157,6 @@ public class MECraftingInventory implements IMEInventory return StorageChannel.ITEMS; } - public void moveItemsToStorage(IItemList storage) - { - // TODO Auto-generated method stub - - } - public void commit(BaseActionSource src) { if ( logInjections ) diff --git a/helpers/DualityInterface.java b/helpers/DualityInterface.java index fb72b043b..58da22deb 100644 --- a/helpers/DualityInterface.java +++ b/helpers/DualityInterface.java @@ -16,10 +16,10 @@ import net.minecraftforge.common.util.ForgeDirection; import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.implementations.ICraftingPatternItem; +import appeng.api.implementations.tiles.ICraftingMachine; import appeng.api.implementations.tiles.ISegmentedInventory; import appeng.api.networking.GridFlags; import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.ICraftingMedium; import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.crafting.ICraftingProvider; import appeng.api.networking.crafting.ICraftingProviderHelper; @@ -152,6 +152,15 @@ public class DualityInterface implements IGridTickable, ISegmentedInventory, ISt waitingToSend = new LinkedList(); waitingToSend.add( is ); + + try + { + gridProxy.getTick().wakeDevice( gridProxy.getNode() ); + } + catch (GridAccessException e) + { + // :P + } } public DualityInterface(AENetworkProxy prox, IInterfaceHost ih) { @@ -554,6 +563,9 @@ public class DualityInterface implements IGridTickable, ISegmentedInventory, ISt @Override public TickRateModulation tickingRequest(IGridNode node, int TicksSinceLastCall) { + if ( hasItemsToSend() ) + pushItemsOut( EnumSet.allOf( ForgeDirection.class ) ); + boolean couldDoWork = updateStorage(); return hasWorkToDo() ? (couldDoWork ? TickRateModulation.URGENT : TickRateModulation.SLOWER) : TickRateModulation.SLEEP; } @@ -642,7 +654,45 @@ public class DualityInterface implements IGridTickable, ISegmentedInventory, ISt } @Override - public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table, ForgeDirection where) + public boolean isBusy() + { + if ( hasItemsToSend() ) + return true; + + boolean busy = false; + + if ( isBlocking() ) + { + EnumSet possibleDirections = iHost.getTargets(); + TileEntity tile = iHost.getTileEntity(); + World w = tile.getWorldObj(); + + for (ForgeDirection s : possibleDirections) + { + TileEntity te = w.getTileEntity( tile.xCoord + s.offsetX, tile.yCoord + s.offsetY, tile.zCoord + s.offsetZ ); + + InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() ); + if ( ad != null ) + { + if ( ad.simulateRemove( 1, null, null ) != null ) + { + busy = true; + break; + } + } + } + } + + return busy; + } + + private boolean isBlocking() + { + return true; + } + + @Override + public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { if ( hasItemsToSend() ) return false; @@ -654,9 +704,9 @@ public class DualityInterface implements IGridTickable, ISegmentedInventory, ISt for (ForgeDirection s : possibleDirections) { TileEntity te = w.getTileEntity( tile.xCoord + s.offsetX, tile.yCoord + s.offsetY, tile.zCoord + s.offsetZ ); - if ( te instanceof ICraftingMedium ) + if ( te instanceof ICraftingMachine ) { - if ( ((ICraftingMedium) te).pushPattern( patternDetails, table, s.getOpposite() ) ) + if ( ((ICraftingMachine) te).pushPattern( patternDetails, table, s.getOpposite() ) ) return true; } else @@ -686,7 +736,7 @@ public class DualityInterface implements IGridTickable, ISegmentedInventory, ISt private void pushItemsOut(EnumSet possibleDirections) { - if ( hasItemsToSend() ) + if ( !hasItemsToSend() ) return; TileEntity tile = iHost.getTileEntity(); @@ -700,6 +750,8 @@ public class DualityInterface implements IGridTickable, ISegmentedInventory, ISt for (ForgeDirection s : possibleDirections) { TileEntity te = w.getTileEntity( tile.xCoord + s.offsetX, tile.yCoord + s.offsetY, tile.zCoord + s.offsetZ ); + if ( te == null ) + continue; InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() ); if ( ad != null ) diff --git a/helpers/PatternHelper.java b/helpers/PatternHelper.java index 22bd14d49..8591f7f50 100644 --- a/helpers/PatternHelper.java +++ b/helpers/PatternHelper.java @@ -19,11 +19,13 @@ import appeng.api.storage.data.IAEItemStack; import appeng.container.ContainerNull; import appeng.util.ItemSorters; import appeng.util.Platform; +import appeng.util.item.AEItemStack; public class PatternHelper implements ICraftingPatternDetails, Comparable { final ItemStack patternItem; + private IAEItemStack aepattern; final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 ); final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 ); @@ -118,6 +120,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable in = new ArrayList(); List out = new ArrayList(); @@ -317,4 +320,15 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable getMediums(ICraftingPatternDetails key) + { + List o = craftingMethods.get( key ); + + if ( o == null ) + o = ImmutableList.of(); + + return o; + } + } diff --git a/me/cluster/implementations/CraftingCPUCluster.java b/me/cluster/implementations/CraftingCPUCluster.java index 421d01a1f..086aa4d0d 100644 --- a/me/cluster/implementations/CraftingCPUCluster.java +++ b/me/cluster/implementations/CraftingCPUCluster.java @@ -1,19 +1,39 @@ package appeng.me.cluster.implementations; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; +import java.util.Map; +import java.util.Map.Entry; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import appeng.api.AEApi; import appeng.api.config.Actionable; +import appeng.api.config.FuzzyMode; import appeng.api.networking.IGrid; import appeng.api.networking.IGridHost; import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingMedium; +import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.events.MENetworkCraftingCpuChange; import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.IMEInventory; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEStack; +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.MECraftingInventory; +import appeng.me.cache.CraftingCache; import appeng.me.cluster.IAECluster; import appeng.tile.crafting.TileCraftingTile; +import appeng.util.item.AEItemStack; public class CraftingCPUCluster implements IAECluster { @@ -22,12 +42,29 @@ public class CraftingCPUCluster implements IAECluster public WorldCoord max; public boolean isDestroyed = false; + class TaskProgress + { + + int value; + }; + private LinkedList tiles = new LinkedList(); int accelerator = 0; private LinkedList storage = new LinkedList(); private LinkedList status = new LinkedList(); + /** + * crafting job info + */ + MECraftingInventory inventory = new MECraftingInventory(); + + IAEItemStack finalOutput; + + boolean waiting = false; + Map tasks = new HashMap(); + IItemList waitingFor = AEApi.instance().storage().createItemList(); + @Override public Iterator getTiles() { @@ -90,7 +127,9 @@ public class CraftingCPUCluster implements IAECluster { if ( input instanceof IAEItemStack ) { - // TODO Auto-generated method stub + IAEItemStack is = waitingFor.findPrecise( (IAEItemStack) input ); + if ( is != null && is.getStackSize() > 0 ) + return true; } return false; } @@ -99,9 +138,206 @@ public class CraftingCPUCluster implements IAECluster { if ( input instanceof IAEItemStack ) { - // TODO Auto-generated method stub + IAEItemStack what = (IAEItemStack) input; + IAEItemStack is = waitingFor.findPrecise( what ); + + if ( is != null && is.getStackSize() > 0 ) + { + waiting = false; + + if ( is.getStackSize() >= input.getStackSize() ) + { + is.decStackSize( input.getStackSize() ); + + if ( finalOutput.equals( input ) ) + return input; // ignore it. + + return inventory.injectItems( what, Actionable.MODULATE, src ); + } + + IAEItemStack insert = what.copy(); + insert.setStackSize( is.getStackSize() ); + what.decStackSize( is.getStackSize() ); + is.setStackSize( 0 ); + + if ( finalOutput.equals( input ) ) + return input; // ignore it. + + inventory.injectItems( insert, Actionable.MODULATE, src ); + + return what; + } } + return input; } + private boolean canCraft(IAEItemStack[] condencedInputs) + { + for (IAEItemStack is : condencedInputs) + { + IAEItemStack avail = inventory.extractItems( is, Actionable.SIMULATE, null ); + if ( avail == null || avail.getStackSize() < is.getStackSize() ) + return false; + } + return true; + } + + public void updateCraftingLogic(IGrid grid, CraftingCache cc) + { + if ( waiting || tasks.isEmpty() ) // nothing to do here... + return; + + int remainingOperations = accelerator + 1; + boolean didsomething = false; + + for (Entry e : tasks.entrySet()) + { + if ( e.getValue().value <= 0 ) + continue; + + ICraftingPatternDetails details = e.getKey(); + if ( canCraft( details.getCondencedInputs() ) ) + { + InventoryCrafting ic = null; + + for (ICraftingMedium m : cc.getMediums( e.getKey() )) + { + if ( !m.isBusy() ) + { + if ( ic == null ) + { + ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); + + IAEItemStack[] input = details.getInputs(); + for (int x = 0; x < input.length; x++) + { + if ( input[x] != null ) + { + boolean found = true; + + if ( details.isCraftable() ) + { + for (IAEItemStack fuzz : inventory.getItemList().findFuzzy( input[x], FuzzyMode.IGNORE_ALL )) + { + IAEItemStack ais = inventory.extractItems( fuzz, Actionable.MODULATE, null ); + ItemStack is = ais == null ? null : ais.getItemStack(); + + if ( is != null && details.isValidItemForSlot( x, is, getWorld() ) ) + { + ic.setInventorySlotContents( x, is ); + found = true; + break; + } + } + } + else + { + IAEItemStack ais = inventory.extractItems( input[x].copy(), Actionable.MODULATE, null ); + ItemStack is = ais == null ? null : ais.getItemStack(); + + if ( is != null ) + { + ic.setInventorySlotContents( x, is ); + found = true; + continue; + } + } + + if ( !found ) + break; + } + } + } + + if ( m.pushPattern( details, ic ) ) + { + didsomething = true; + remainingOperations--; + + for (IAEItemStack out : details.getCondencedOutputs()) + waitingFor.add( out.copy() ); + + ic = null; // hand off complete! + + e.getValue().value--; + if ( e.getValue().value <= 0 ) + continue; + + if ( remainingOperations == 0 ) + return; + } + } + } + + if ( ic != null ) + { + // put stuff back.. + for (int x = 0; x < ic.getSizeInventory(); x++) + { + ItemStack is = ic.getStackInSlot( x ); + if ( is != null ) + inventory.injectItems( AEItemStack.create( is ), Actionable.MODULATE, null ); + } + } + } + } + + if ( remainingOperations > 0 && didsomething == false ) + waiting = true; + } + + private World getWorld() + { + return null; + } + + public boolean submitJob(IGrid g, CraftingJob job, BaseActionSource src) + { + Iterator> i = tasks.entrySet().iterator(); + while (i.hasNext()) + { + if ( i.next().getValue().value <= 0 ) + i.remove(); + } + + if ( !tasks.isEmpty() || !waitingFor.isEmpty() ) + return false; + + IStorageGrid sg = g.getCache( IStorageGrid.class ); + IMEInventory storage = sg.getItemInventory(); + MECraftingInventory ci = new MECraftingInventory( storage, true, false, false ); + + try + { + job.tree.setJob( ci, this, src ); + ci.commit( src ); + finalOutput = job.getOutput(); + waiting = false; + return true; + } + catch (CraftBranchFailure e) + { + tasks.clear(); + inventory.getItemList().resetStatus(); + AELog.error( e ); + } + + return false; + } + + public void addStorage(IAEItemStack extractItems) + { + inventory.injectItems( extractItems, Actionable.MODULATE, null ); + } + + public void addCrafting(ICraftingPatternDetails details, long crafts) + { + TaskProgress i = tasks.get( details ); + + if ( i == null ) + tasks.put( details, i = new TaskProgress() ); + + i.value += crafts; + } } diff --git a/parts/misc/PartInterface.java b/parts/misc/PartInterface.java index 89f744afb..3edced6ca 100644 --- a/parts/misc/PartInterface.java +++ b/parts/misc/PartInterface.java @@ -326,9 +326,9 @@ public class PartInterface extends PartBasicState implements IGridTickable, ISeg } @Override - public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table, ForgeDirection where) + public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { - return duality.pushPattern( patternDetails, table, where ); + return duality.pushPattern( patternDetails, table ); } @Override @@ -343,4 +343,10 @@ public class PartInterface extends PartBasicState implements IGridTickable, ISeg return EnumSet.of( side ); } + @Override + public boolean isBusy() + { + return duality.isBusy(); + } + } diff --git a/tile/crafting/TileMolecularAssembler.java b/tile/crafting/TileMolecularAssembler.java index 4add6f7a6..b1f8920e7 100644 --- a/tile/crafting/TileMolecularAssembler.java +++ b/tile/crafting/TileMolecularAssembler.java @@ -16,7 +16,6 @@ import appeng.api.config.Settings; import appeng.api.config.Upgrades; import appeng.api.implementations.IUpgradeableHost; import appeng.api.networking.IGridNode; -import appeng.api.networking.crafting.ICraftingMedium; import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.ticking.IGridTickable; import appeng.api.networking.ticking.TickRateModulation; @@ -40,7 +39,7 @@ import appeng.util.InventoryAdaptor; import appeng.util.Platform; public class TileMolecularAssembler extends AENetworkInvTile implements IAEAppEngInventory, ISidedInventory, IUpgradeableHost, IConfigManagerHost, - IGridTickable, ICraftingMedium + IGridTickable { static final int[] sides = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; @@ -58,7 +57,6 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IAEAppEn private boolean isAwake = false; private boolean forcePlan = false; - @Override public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table, ForgeDirection where) { if ( myPattern == null ) @@ -421,4 +419,5 @@ public class TileMolecularAssembler extends AENetworkInvTile implements IAEAppEn return adaptor.addItems( output ); } + } diff --git a/tile/misc/TileInterface.java b/tile/misc/TileInterface.java index 99ecb9b8f..da9238de8 100644 --- a/tile/misc/TileInterface.java +++ b/tile/misc/TileInterface.java @@ -207,9 +207,9 @@ public class TileInterface extends AENetworkInvTile implements IGridTickable, IS } @Override - public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table, ForgeDirection where) + public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { - return duality.pushPattern( patternDetails, table, where ); + return duality.pushPattern( patternDetails, table ); } @Override @@ -226,4 +226,10 @@ public class TileInterface extends AENetworkInvTile implements IGridTickable, IS return EnumSet.of( pointAt ); } + @Override + public boolean isBusy() + { + return duality.isBusy(); + } + }