diff --git a/container/implementations/ContainerCraftConfirm.java b/container/implementations/ContainerCraftConfirm.java index 94a4d10b..d12c5486 100644 --- a/container/implementations/ContainerCraftConfirm.java +++ b/container/implementations/ContainerCraftConfirm.java @@ -162,7 +162,7 @@ public class ContainerCraftConfirm extends AEBaseContainer if ( result != null && simulation == false ) { ICraftingGrid cc = getGrid().getCache( ICraftingGrid.class ); - cc.submitJob( result, null, getActionSrc() ); + cc.submitJob( result, null, null, getActionSrc() ); this.isContainerValid = false; } } diff --git a/core/api/ApiStorage.java b/core/api/ApiStorage.java index b9f6f646..c30817bf 100644 --- a/core/api/ApiStorage.java +++ b/core/api/ApiStorage.java @@ -5,7 +5,10 @@ import io.netty.buffer.ByteBuf; import java.io.IOException; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fluids.FluidStack; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingRequester; import appeng.api.networking.energy.IEnergySource; import appeng.api.networking.security.BaseActionSource; import appeng.api.storage.IMEInventory; @@ -13,6 +16,7 @@ import appeng.api.storage.IStorageHelper; import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; +import appeng.crafting.CraftingLink; import appeng.util.Platform; import appeng.util.item.AEFluidStack; import appeng.util.item.AEItemStack; @@ -36,13 +40,13 @@ public class ApiStorage implements IStorageHelper @Override public IItemList createItemList() { - return new ItemList( IAEItemStack.class); + return new ItemList( IAEItemStack.class ); } @Override public IItemList createFluidList() { - return new ItemList( IAEFluidStack.class); + return new ItemList( IAEFluidStack.class ); } @Override @@ -68,4 +72,10 @@ public class ApiStorage implements IStorageHelper { return AEFluidStack.loadFluidStackFromPacket( input ); } + + @Override + public ICraftingLink loadCraftingLink(NBTTagCompound data, ICraftingRequester req) + { + return new CraftingLink( data, req ); + } } diff --git a/crafting/CraftingLink.java b/crafting/CraftingLink.java new file mode 100644 index 00000000..7729655d --- /dev/null +++ b/crafting/CraftingLink.java @@ -0,0 +1,146 @@ +package appeng.crafting; + +import net.minecraft.nbt.NBTTagCompound; +import appeng.api.networking.crafting.ICraftingCPU; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.storage.data.IAEItemStack; + +public class CraftingLink implements ICraftingLink +{ + + boolean canceled = false; + boolean done = false; + + CraftingLinkNexus tie; + + final ICraftingRequester req; + final ICraftingCPU cpu; + + final String CraftID; + final boolean standalone; + + public CraftingLink(NBTTagCompound data, ICraftingRequester req) { + CraftID = data.getString( "CraftID" ); + canceled = data.getBoolean( "canceled" ); + done = data.getBoolean( "done" ); + standalone = data.getBoolean( "standalone" ); + + if ( !data.hasKey( "req" ) || data.getBoolean( "req" ) != true ) + throw new RuntimeException( "Invalid Crafting Link for Object" ); + + this.req = req; + cpu = null; + } + + public CraftingLink(NBTTagCompound data, ICraftingCPU cpu) { + CraftID = data.getString( "CraftID" ); + canceled = data.getBoolean( "canceled" ); + done = data.getBoolean( "done" ); + standalone = data.getBoolean( "standalone" ); + + if ( !data.hasKey( "req" ) || data.getBoolean( "req" ) == true ) + throw new RuntimeException( "Invalid Crafting Link for Object" ); + + this.cpu = cpu; + req = null; + } + + @Override + public boolean isCanceled() + { + if ( canceled ) + return true; + + if ( done ) + return false; + + if ( tie == null ) + return false; + + return tie.isCanceled(); + } + + @Override + public boolean isDone() + { + if ( done ) + return true; + + if ( canceled ) + return false; + + if ( tie == null ) + return false; + + return tie.isDone(); + } + + @Override + public void cancel() + { + if ( done ) + return; + + canceled = true; + + if ( tie != null ) + tie.cancel(); + + tie = null; + } + + @Override + public void writeToNBT(NBTTagCompound tag) + { + tag.setString( "CraftID", CraftID ); + tag.setBoolean( "canceled", canceled ); + tag.setBoolean( "done", done ); + tag.setBoolean( "standalone", standalone ); + tag.setBoolean( "req", req != null ); + } + + public void setNextus(CraftingLinkNexus n) + { + if ( tie != null ) + tie.remove( this ); + + if ( canceled && n != null ) + { + n.cancel(); + tie = null; + return; + } + + tie = n; + + if ( n != null ) + n.add( this ); + } + + @Override + public String getCraftingID() + { + return CraftID; + } + + @Override + public boolean isStandalone() + { + return standalone; + } + + public IAEItemStack injectItems(IAEItemStack input) + { + if ( tie == null || tie.req == null || tie.req.req == null ) + return input; + + return tie.req.req.injectCratedItems( tie.req, input ); + } + + public void markDone() + { + if ( tie != null ) + tie.markDone(); + } +} diff --git a/crafting/CraftingLinkNexus.java b/crafting/CraftingLinkNexus.java new file mode 100644 index 00000000..6906a84a --- /dev/null +++ b/crafting/CraftingLinkNexus.java @@ -0,0 +1,121 @@ +package appeng.crafting; + +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.me.cache.CraftingGridCache; + +public class CraftingLinkNexus +{ + + public CraftingLinkNexus(String craftID) { + this.CraftID = craftID; + } + + public final String CraftID; + + boolean canceled = false; + boolean done = false; + + int tickOfDeath = 0; + + CraftingLink req; + CraftingLink cpu; + + public boolean isDead(IGrid g, CraftingGridCache craftingGridCache) + { + if ( isCanceled() || isDone() ) + return true; + + if ( req == null || cpu == null ) + tickOfDeath++; + else + { + boolean hasCpu = craftingGridCache.hasCpu( cpu.cpu ); + boolean hasMachine = req.req.getActionableNode().getGrid() == g; + + if ( hasCpu && hasMachine ) + tickOfDeath = 0; + else + tickOfDeath += 60; + } + + if ( tickOfDeath > 60 ) + { + cancel(); + return true; + } + + return false; + } + + public void remove(CraftingLink craftingLink) + { + if ( req == craftingLink ) + req = null; + else if ( cpu == craftingLink ) + cpu = null; + } + + public void add(CraftingLink craftingLink) + { + if ( craftingLink.cpu != null ) + cpu = craftingLink; + else if ( craftingLink.req != null ) + req = craftingLink; + } + + public boolean isCanceled() + { + return canceled; + } + + public boolean isDone() + { + return done; + } + + public void markDone() + { + done = true; + + if ( req != null ) + { + req.done = true; + if ( req.req != null ) + req.req.jobStateChange( req ); + } + + if ( cpu != null ) + cpu.done = true; + } + + public void cancel() + { + canceled = true; + + if ( req != null ) + { + req.canceled = true; + if ( req.req != null ) + req.req.jobStateChange( req ); + } + + if ( cpu != null ) + cpu.canceled = true; + } + + public boolean isMachine(IGridHost machine) + { + return req == machine; + } + + public void removeNode() + { + if ( req != null ) + req.setNextus( null ); + + req = null; + tickOfDeath = 0; + } + +} diff --git a/me/cache/CraftingGridCache.java b/me/cache/CraftingGridCache.java index c46ea0d4..9039c8e5 100644 --- a/me/cache/CraftingGridCache.java +++ b/me/cache/CraftingGridCache.java @@ -3,6 +3,7 @@ package appeng.me.cache; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Set; @@ -23,10 +24,12 @@ import appeng.api.networking.crafting.ICraftingCPU; import appeng.api.networking.crafting.ICraftingCallback; 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.ICraftingProvider; import appeng.api.networking.crafting.ICraftingProviderHelper; +import appeng.api.networking.crafting.ICraftingRequester; import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.events.MENetworkCraftingCpuChange; import appeng.api.networking.events.MENetworkCraftingPatternChange; @@ -41,6 +44,8 @@ import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IItemList; import appeng.crafting.CraftingJob; +import appeng.crafting.CraftingLink; +import appeng.crafting.CraftingLinkNexus; import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.tile.crafting.TileCraftingStorageTile; import appeng.tile.crafting.TileCraftingTile; @@ -61,6 +66,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper HashMap> craftingMethods = new HashMap(); HashMap> craftableItems = new HashMap(); + HashMap links = new HashMap(); boolean updateList = false; @@ -77,6 +83,18 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper sg.registerCellProvider( this ); } + public void addLink(CraftingLink l) + { + if ( l.isStandalone() ) + return; + + CraftingLinkNexus n = links.get( l.getCraftingID() ); + if ( n == null ) + links.put( l.getCraftingID(), n = new CraftingLinkNexus( l.getCraftingID() ) ); + + l.setNextus( n ); + } + @Override public void onUpdateTick() { @@ -86,6 +104,13 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper updateCPUClusters(); } + Iterator i = links.values().iterator(); + while (i.hasNext()) + { + if ( i.next().isDead( grid, this ) ) + i.remove(); + } + for (CraftingCPUCluster cpu : cpuClusters) cpu.updateCraftingLogic( grid, eg, this ); } @@ -105,6 +130,17 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper @Override public void removeNode(IGridNode gridNode, IGridHost machine) { + if ( machine instanceof ICraftingRequester ) + { + Iterator nex = links.values().iterator(); + while (nex.hasNext()) + { + CraftingLinkNexus n = nex.next(); + if ( n.isMachine( machine ) ) + n.removeNode(); + } + } + if ( machine instanceof TileCraftingTile ) updateList = true; if ( machine instanceof ICraftingProvider ) @@ -117,6 +153,15 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper @Override public void addNode(IGridNode gridNode, IGridHost machine) { + if ( machine instanceof ICraftingRequester ) + { + for (ICraftingLink l : ((ICraftingRequester) machine).getRequestedJobs()) + { + if ( l instanceof CraftingLink ) + addLink( (CraftingLink) l ); + } + } + if ( machine instanceof TileCraftingTile ) updateList = true; if ( machine instanceof ICraftingProvider ) @@ -134,7 +179,12 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper TileCraftingStorageTile tile = (TileCraftingStorageTile) cst.getMachine(); CraftingCPUCluster clust = (CraftingCPUCluster) tile.getCluster(); if ( clust != null ) + { cpuClusters.add( clust ); + + if ( clust.myLastLink != null ) + addLink( (CraftingLink) clust.myLastLink ); + } } } @@ -283,10 +333,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper return false; } - public boolean submitJob(ICraftingJob job, ICraftingCPU target, BaseActionSource src) + @Override + public ICraftingLink submitJob(ICraftingJob job, ICraftingRequester requestingMachine, ICraftingCPU target, BaseActionSource src) { if ( job.isSimulation() ) - return false; + return null; CraftingCPUCluster cpuClust = null; @@ -306,10 +357,10 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper } } - if ( cpuClust != null && cpuClust.submitJob( grid, job, src ) ) - return true; + if ( cpuClust != null ) + return cpuClust.submitJob( grid, job, src, requestingMachine ); - return false; + return null; } @Override @@ -362,8 +413,16 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper @Override public Future beginCraftingJob(World world, IGrid grid, BaseActionSource actionSrc, IAEItemStack slotItem, ICraftingCallback cb) { + if ( world == null || grid == null || actionSrc == null || slotItem == null ) + throw new RuntimeException( "Invalid Craftinb Job Request" ); + CraftingJob cj = new CraftingJob( world, grid, actionSrc, slotItem, cb ); return craftingPool.submit( cj, (ICraftingJob) cj ); } + public boolean hasCpu(ICraftingCPU cpu) + { + return cpuClusters.contains( cpu ); + } + } diff --git a/me/cluster/implementations/CraftingCPUCluster.java b/me/cluster/implementations/CraftingCPUCluster.java index dc87ab70..ae4d7836 100644 --- a/me/cluster/implementations/CraftingCPUCluster.java +++ b/me/cluster/implementations/CraftingCPUCluster.java @@ -22,9 +22,12 @@ 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.energy.IEnergyGrid; import appeng.api.networking.events.MENetworkCraftingCpuChange; import appeng.api.networking.security.BaseActionSource; @@ -40,6 +43,7 @@ import appeng.container.ContainerNull; import appeng.core.AELog; import appeng.crafting.CraftBranchFailure; import appeng.crafting.CraftingJob; +import appeng.crafting.CraftingLink; import appeng.crafting.MECraftingInventory; import appeng.me.cache.CraftingGridCache; import appeng.me.cluster.IAECluster; @@ -75,6 +79,7 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU private LinkedList status = new LinkedList(); long availableStorage = 0; + public ICraftingLink myLastLink; MachineSource machineSrc = null; @@ -284,6 +289,9 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU if ( finalOutput.getStackSize() <= 0 ) completeJob(); + if ( myLastLink != null ) + return ((CraftingLink) myLastLink).injectItems( (IAEItemStack) input ); + return input; // ignore it. } @@ -307,6 +315,9 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU if ( finalOutput.getStackSize() <= 0 ) completeJob(); + if ( myLastLink != null ) + return ((CraftingLink) myLastLink).injectItems( (IAEItemStack) input ); + return input; // ignore it. } @@ -338,6 +349,9 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU private void completeJob() { + if ( myLastLink != null ) + ((CraftingLink) myLastLink).markDone(); + AELog.info( "marking job as complete" ); isComplete = true; } @@ -383,7 +397,11 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU public void cancel() { + if ( myLastLink != null ) + myLastLink.cancel(); + isComplete = true; + myLastLink = null; tasks.clear(); waitingFor.resetStatus(); storeItems(); // marks dirty @@ -391,6 +409,15 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU public void updateCraftingLogic(IGrid grid, IEnergyGrid eg, CraftingGridCache cc) { + if ( myLastLink != null ) + { + if ( myLastLink.isCanceled() ) + { + myLastLink = null; + cancel(); + } + } + if ( isComplete ) { if ( inventory.getItemList().isEmpty() ) @@ -579,16 +606,16 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU private World getWorld() { - return null; + return getCore().getWorldObj(); } - public boolean submitJob(IGrid g, ICraftingJob job, BaseActionSource src) + public ICraftingLink submitJob(IGrid g, ICraftingJob job, BaseActionSource src, ICraftingRequester requestingMachine) { if ( !tasks.isEmpty() || !waitingFor.isEmpty() ) - return false; + return null; if ( !(job instanceof CraftingJob) ) - return false; + return null; IStorageGrid sg = g.getCache( IStorageGrid.class ); IMEInventory storage = sg.getItemInventory(); @@ -603,7 +630,20 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU waiting = false; isComplete = false; markDirty(); - return true; + + String craftID = generateCraftingID(); + + myLastLink = new CraftingLink( generateLinkData( craftID, requestingMachine == null, false ), this ); + + if ( requestingMachine == null ) + return myLastLink; + + ICraftingLink whatLink = new CraftingLink( generateLinkData( craftID, requestingMachine == null, true ), requestingMachine ); + + submitLink( myLastLink ); + submitLink( whatLink ); + + return whatLink; } catch (CraftBranchFailure e) { @@ -612,7 +652,39 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU AELog.error( e ); } - return false; + return null; + } + + private void submitLink(ICraftingLink myLastLink2) + { + if ( getGrid() != null ) + { + CraftingGridCache cc = getGrid().getCache( ICraftingGrid.class ); + cc.addLink( (CraftingLink) myLastLink2 ); + } + } + + private String generateCraftingID() + { + long now = System.currentTimeMillis(); + int hash = System.identityHashCode( this ); + int hmm = finalOutput == null ? 0 : finalOutput.hashCode(); + + return Long.toString( now, Character.MAX_RADIX ) + "-" + Integer.toString( hash, Character.MAX_RADIX ) + "-" + + Integer.toString( hmm, Character.MAX_RADIX ); + } + + private NBTTagCompound generateLinkData(String craftingID, boolean standalone, boolean req) + { + NBTTagCompound tag = new NBTTagCompound(); + + tag.setString( "CraftID", craftingID ); + tag.setBoolean( "canceled", false ); + tag.setBoolean( "done", false ); + tag.setBoolean( "standalone", standalone ); + tag.setBoolean( "req", req ); + + return tag; } private void markDirty() @@ -701,6 +773,13 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU waiting = data.getBoolean( "waiting" ); isComplete = data.getBoolean( "isComplete" ); + if ( data.hasKey( "link" ) ) + { + NBTTagCompound link = data.getCompoundTag( "link" ); + myLastLink = new CraftingLink( link, this ); + submitLink( myLastLink ); + } + NBTTagList list = data.getTagList( "tasks", 10 ); for (int x = 0; x < list.tagCount(); x++) { @@ -729,6 +808,13 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU data.setBoolean( "waiting", waiting ); data.setBoolean( "isComplete", isComplete ); + if ( myLastLink != null ) + { + NBTTagCompound link = new NBTTagCompound(); + myLastLink.writeToNBT( link ); + data.setTag( "link", link ); + } + NBTTagList list = new NBTTagList(); for (Entry e : tasks.entrySet()) { @@ -744,6 +830,8 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU private IItemList readList(NBTTagList tag) { IItemList out = AEApi.instance().storage().createItemList(); + if ( tag == null ) + return out; for (int x = 0; x < tag.tagCount(); x++) { diff --git a/me/helpers/AENetworkProxy.java b/me/helpers/AENetworkProxy.java index 23b0a24a..e7b3f692 100644 --- a/me/helpers/AENetworkProxy.java +++ b/me/helpers/AENetworkProxy.java @@ -13,6 +13,7 @@ import appeng.api.networking.IGrid; import appeng.api.networking.IGridBlock; import appeng.api.networking.IGridHost; import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.events.MENetworkPowerIdleChange; import appeng.api.networking.pathing.IPathingGrid; @@ -57,12 +58,12 @@ public class AENetworkProxy implements IGridBlock { return myRepInstance; } - - public void setVisualRepresentation( ItemStack is ) + + public void setVisualRepresentation(ItemStack is) { myRepInstance = is; } - + public AENetworkProxy(IGridProxyable te, String nbtName, ItemStack visual, boolean inWorld) { this.gp = te; this.nbtName = nbtName; @@ -276,6 +277,20 @@ public class AENetworkProxy implements IGridBlock return sg; } + public ICraftingGrid getCrafting() throws GridAccessException + { + IGrid grid = getGrid(); + if ( grid == null ) + throw new GridAccessException(); + + ICraftingGrid sg = grid.getCache( ICraftingGrid.class ); + + if ( sg == null ) + throw new GridAccessException(); + + return sg; + } + @Override public boolean isWorldAccessable() { diff --git a/parts/automation/NonNullArrayIterator.java b/parts/automation/NonNullArrayIterator.java new file mode 100644 index 00000000..3f7bad0d --- /dev/null +++ b/parts/automation/NonNullArrayIterator.java @@ -0,0 +1,38 @@ +package appeng.parts.automation; + +import java.util.Iterator; + +import scala.NotImplementedError; + +public class NonNullArrayIterator implements Iterator +{ + + int offset = 0; + final E[] g; + + public NonNullArrayIterator(E[] o) { + g = o; + } + + @Override + public boolean hasNext() + { + while (offset < g.length && g[offset] == null) + offset++; + + return offset != g.length; + } + + @Override + public E next() + { + return g[offset++]; + } + + @Override + public void remove() + { + throw new NotImplementedError(); + } + +} diff --git a/parts/automation/PartExportBus.java b/parts/automation/PartExportBus.java index 82a15de1..35e0844f 100644 --- a/parts/automation/PartExportBus.java +++ b/parts/automation/PartExportBus.java @@ -1,15 +1,25 @@ package appeng.parts.automation; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.Vec3; +import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.config.FuzzyMode; +import appeng.api.config.PowerMultiplier; import appeng.api.config.RedstoneMode; import appeng.api.config.Settings; import appeng.api.config.Upgrades; import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingGrid; +import appeng.api.networking.crafting.ICraftingJob; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingRequester; import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.security.BaseActionSource; import appeng.api.networking.security.MachineSource; @@ -22,22 +32,28 @@ import appeng.api.storage.IMEInventory; import appeng.api.storage.IMEMonitor; import appeng.api.storage.data.IAEItemStack; import appeng.client.texture.CableBusTextures; +import appeng.core.AELog; import appeng.core.settings.TickRates; import appeng.core.sync.GuiBridge; import appeng.me.GridAccessException; import appeng.util.InventoryAdaptor; import appeng.util.Platform; +import appeng.util.item.AEItemStack; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -public class PartExportBus extends PartSharedItemBus implements IGridTickable +public class PartExportBus extends PartSharedItemBus implements IGridTickable, ICraftingRequester { BaseActionSource mySrc; + Future calculatingJob = null; + ICraftingLink[] links = null; + public PartExportBus(ItemStack is) { super( PartExportBus.class, is ); settings.registerSetting( Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE ); @@ -45,6 +61,36 @@ public class PartExportBus extends PartSharedItemBus implements IGridTickable mySrc = new MachineSource( this ); } + @Override + public void readFromNBT(NBTTagCompound extra) + { + super.readFromNBT( extra ); + + for (int x = 0; x < 9; x++) + { + NBTTagCompound link = extra.getCompoundTag( "links-" + x ); + if ( link != null && !link.hasNoTags() ) + setLink( x, AEApi.instance().storage().loadCraftingLink( link, this ) ); + } + } + + @Override + public void writeToNBT(NBTTagCompound extra) + { + super.writeToNBT( extra ); + + for (int x = 0; x < 9; x++) + { + ICraftingLink link = getLink( x ); + if ( link != null ) + { + NBTTagCompound ln = new NBTTagCompound(); + link.writeToNBT( ln ); + extra.setTag( "links-" + x, ln ); + } + } + } + @Override public boolean onPartActivate(EntityPlayer player, Vec3 pos) { @@ -164,20 +210,67 @@ public class PartExportBus extends PartSharedItemBus implements IGridTickable for (int x = 0; x < availableSlots() && itemToSend > 0; x++) { IAEItemStack ais = config.getAEStackInSlot( x ); - if ( ais == null || itemToSend <= 0 ) + if ( ais == null || itemToSend <= 0 || craftOnly() ) + { + if ( isCraftingEnabled() && ais != null && d.simulateAdd( ais.getItemStack() ) == null ) + { + ICraftingGrid cg = proxy.getCrafting(); + + if ( getLink( x ) != null ) + { + continue; + } + else if ( calculatingJob != null ) + { + ICraftingJob job = null; + try + { + if ( calculatingJob.isDone() ) + job = calculatingJob.get(); + else if ( calculatingJob.isCancelled() ) + calculatingJob = null; + + if ( job != null ) + { + calculatingJob = null; + setLink( x, cg.submitJob( job, this, null, mySrc ) ); + didSomething = true; + } + } + catch (InterruptedException e) + { + // :P + } + catch (ExecutionException e) + { + // :P + } + } + else + { + if ( getLink( x ) == null ) + { + IAEItemStack aisC = ais.copy(); + aisC.setStackSize( itemToSend ); + calculatingJob = cg.beginCraftingJob( getTile().getWorldObj(), proxy.getGrid(), mySrc, aisC, null ); + } + } + } + continue; + } if ( getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) { for (IAEItemStack o : ImmutableList.copyOf( inv.getStorageList().findFuzzy( ais, fzMode ) )) { - pushItemIntoTarget( d, energy, fzMode, inv, o ); + pushItemIntoTarget( d, energy, inv, o ); if ( itemToSend <= 0 ) break; } } else - pushItemIntoTarget( d, energy, fzMode, inv, ais ); + pushItemIntoTarget( d, energy, inv, ais ); } } @@ -190,7 +283,17 @@ public class PartExportBus extends PartSharedItemBus implements IGridTickable return didSomething ? TickRateModulation.FASTER : TickRateModulation.SLOWER; } - private void pushItemIntoTarget(InventoryAdaptor d, IEnergyGrid energy, FuzzyMode fzMode, IMEInventory inv, IAEItemStack ais) + private boolean craftOnly() + { + return true; + } + + private boolean isCraftingEnabled() + { + return getInstalledUpgrades( Upgrades.CRAFTING ) > 0; + } + + private void pushItemIntoTarget(InventoryAdaptor d, IEnergyGrid energy, IMEInventory inv, IAEItemStack ais) { ItemStack is = ais.getItemStack(); is.stackSize = (int) itemToSend; @@ -243,4 +346,85 @@ public class PartExportBus extends PartSharedItemBus implements IGridTickable { return new TickingRequest( TickRates.ExportBus.min, TickRates.ExportBus.max, isSleeping(), false ); } + + ICraftingLink getLink(int slot) + { + if ( links == null ) + return null; + + return links[slot]; + } + + void setLink(int slot, ICraftingLink l) + { + if ( links == null ) + links = new ICraftingLink[9]; + + links[slot] = l; + + boolean hasStuff = false; + for (int x = 0; x < links.length; x++) + { + ICraftingLink g = links[x]; + + if ( g == null || g.isCanceled() || g.isDone() ) + links[x] = null; + else + hasStuff = true; + } + + if ( hasStuff == false ) + links = null; + } + + @Override + public ImmutableSet getRequestedJobs() + { + if ( links == null ) + return ImmutableSet.of(); + + return ImmutableSet.copyOf( new NonNullArrayIterator( links ) ); + } + + @Override + public IAEItemStack injectCratedItems(ICraftingLink link, IAEItemStack items) + { + InventoryAdaptor d = getHandler(); + + try + { + if ( proxy.isActive() ) + { + IEnergyGrid energy = proxy.getEnergy(); + + double power = items.getStackSize(); + if ( energy.extractAEPower( power, Actionable.MODULATE, PowerMultiplier.CONFIG ) > power - 0.01 ) + { + return AEItemStack.create( d.addItems( items.getItemStack() ) ); + } + } + } + catch (GridAccessException e) + { + AELog.error( e ); + } + + return items; + } + + @Override + public void jobStateChange(ICraftingLink link) + { + if ( links != null ) + { + for (int x = 0; x < links.length; x++) + { + if ( links[x] == link ) + { + setLink( x, null ); + return; + } + } + } + } }