Crafting is now possible ( not complete but possible )

This commit is contained in:
AlgorithmX2
2014-06-19 01:28:45 -05:00
parent 32ee57c3a9
commit b8a8f2f202
12 changed files with 455 additions and 27 deletions
@@ -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)
{
+6
View File
@@ -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
}
}
}
+30
View File
@@ -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<IAEItemStack> 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 );
}
}
+9
View File
@@ -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 );
}
}
+43 -12
View File
@@ -25,15 +25,39 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
final boolean logMissing;
final IItemList<IAEItemStack> 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<IAEItemStack>
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<IAEItemStack>
return StorageChannel.ITEMS;
}
public void moveItemsToStorage(IItemList<IAEItemStack> storage)
{
// TODO Auto-generated method stub
}
public void commit(BaseActionSource src)
{
if ( logInjections )
+57 -5
View File
@@ -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<ForgeDirection> 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<ForgeDirection> 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 )
+14
View File
@@ -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<PatternHelper>
{
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<Patter
NBTTagList outTag = encodedValue.getTagList( "out", 10 );
isCrafting = encodedValue.getBoolean( "crafting" );
patternItem = is;
aepattern = AEItemStack.create( is );
List<IAEItemStack> in = new ArrayList();
List<IAEItemStack> out = new ArrayList();
@@ -317,4 +320,15 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return ItemSorters.compareInt( o.priority, priority );
}
@Override
public int hashCode()
{
return aepattern.hashCode();
}
@Override
public boolean equals(Object obj)
{
return aepattern.equals( ((PatternHelper) obj).aepattern );
}
}
+36 -1
View File
@@ -30,10 +30,12 @@ import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.crafting.CraftingJob;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.tile.crafting.TileCraftingStorageTile;
import appeng.tile.crafting.TileCraftingTile;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class CraftingCache implements IGridCache, ICraftingProviderHelper, ICellProvider, IMEInventoryHandler
@@ -67,6 +69,9 @@ public class CraftingCache implements IGridCache, ICraftingProviderHelper, ICell
updateList = false;
updateCPUClusters();
}
for (CraftingCPUCluster cpu : cpuClusters)
cpu.updateCraftingLogic( grid, this );
}
@MENetworkEventSubscribe
@@ -111,7 +116,9 @@ public class CraftingCache implements IGridCache, ICraftingProviderHelper, ICell
for (IGridNode cst : grid.getMachines( TileCraftingStorageTile.class ))
{
TileCraftingStorageTile tile = (TileCraftingStorageTile) cst.getMachine();
cpuClusters.add( (CraftingCPUCluster) tile.getCluster() );
CraftingCPUCluster clust = (CraftingCPUCluster) tile.getCluster();
if ( clust != null )
cpuClusters.add( clust );
}
}
@@ -251,6 +258,24 @@ public class CraftingCache implements IGridCache, ICraftingProviderHelper, ICell
return false;
}
public boolean submitJob(CraftingJob job, CraftingCPUCluster target, BaseActionSource src)
{
if ( target == null )
{
// TODO real stuff...
for (CraftingCPUCluster cpu : cpuClusters)
{
target = cpu;
break;
}
}
if ( target != null && target.submitJob( grid, job, src ) )
return true;
return false;
}
@Override
public int getSlot()
{
@@ -265,4 +290,14 @@ public class CraftingCache implements IGridCache, ICraftingProviderHelper, ICell
return res;
}
public List<ICraftingMedium> getMediums(ICraftingPatternDetails key)
{
List<ICraftingMedium> o = craftingMethods.get( key );
if ( o == null )
o = ImmutableList.of();
return o;
}
}
@@ -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<TileCraftingTile> tiles = new LinkedList();
int accelerator = 0;
private LinkedList<TileCraftingTile> storage = new LinkedList<TileCraftingTile>();
private LinkedList<TileCraftingTile> status = new LinkedList<TileCraftingTile>();
/**
* crafting job info
*/
MECraftingInventory inventory = new MECraftingInventory();
IAEItemStack finalOutput;
boolean waiting = false;
Map<ICraftingPatternDetails, TaskProgress> tasks = new HashMap<ICraftingPatternDetails, TaskProgress>();
IItemList<IAEItemStack> waitingFor = AEApi.instance().storage().createItemList();
@Override
public Iterator<IGridHost> 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<ICraftingPatternDetails, TaskProgress> 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<Entry<ICraftingPatternDetails, TaskProgress>> 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<IAEItemStack> 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;
}
}
+8 -2
View File
@@ -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();
}
}
+2 -3
View File
@@ -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 );
}
}
+8 -2
View File
@@ -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();
}
}