Applied-Energistics-2-tiler.../src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java
yueh 02ac8cf220 Refactored the logging
Using LogManager instead of FMLRelaunchLog to access the logger instance.
Added logging of the name of failed exports instead of exception.
Improved crafting log to include issuer including their location and the
requested item.
Removed superfluous FMLRelaunchLog instance.
Removed superfluous parameters for PlayerData constructor.
2016-01-01 02:55:36 +01:00

1346 lines
32 KiB
Java

/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.me.cluster.implementations;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
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 net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.config.PowerMultiplier;
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.energy.IEnergyGrid;
import appeng.api.networking.events.MENetworkCraftingCpuChange;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.security.MachineSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitorHandlerReceiver;
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.CraftingLink;
import appeng.crafting.CraftingWatcher;
import appeng.crafting.MECraftingInventory;
import appeng.me.cache.CraftingGridCache;
import appeng.me.cluster.IAECluster;
import appeng.tile.crafting.TileCraftingMonitorTile;
import appeng.tile.crafting.TileCraftingTile;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{
private static final String LOG_MARK_AS_COMPLETE = "Completed job for %s.";
private final WorldCoord min;
private final WorldCoord max;
private final int[] usedOps = new int[3];
private final Map<ICraftingPatternDetails, TaskProgress> tasks = new HashMap<ICraftingPatternDetails, TaskProgress>();
// INSTANCE sate
private final LinkedList<TileCraftingTile> tiles = new LinkedList<TileCraftingTile>();
private final LinkedList<TileCraftingTile> storage = new LinkedList<TileCraftingTile>();
private final LinkedList<TileCraftingMonitorTile> status = new LinkedList<TileCraftingMonitorTile>();
private final HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object>();
private ICraftingLink myLastLink;
private String myName = "";
private boolean isDestroyed = false;
/**
* crafting job info
*/
private MECraftingInventory inventory = new MECraftingInventory();
private IAEItemStack finalOutput;
private boolean waiting = false;
private IItemList<IAEItemStack> waitingFor = AEApi.instance().storage().createItemList();
private long availableStorage = 0;
private MachineSource machineSrc = null;
private int accelerator = 0;
private boolean isComplete = true;
private int remainingOperations;
private boolean somethingChanged;
private long lastTime;
private long elapsedTime;
private long startItemCount;
private long remainingItemCount;
public CraftingCPUCluster( final WorldCoord min, final WorldCoord max )
{
this.min = min;
this.max = max;
}
public boolean isDestroyed()
{
return this.isDestroyed;
}
public ICraftingLink getLastCraftingLink()
{
return this.myLastLink;
}
/**
* add a new Listener to the monitor, be sure to properly remove yourself when your done.
*/
@Override
public void addListener( final IMEMonitorHandlerReceiver<IAEItemStack> l, final Object verificationToken )
{
this.listeners.put( l, verificationToken );
}
/**
* remove a Listener to the monitor.
*/
@Override
public void removeListener( final IMEMonitorHandlerReceiver<IAEItemStack> l )
{
this.listeners.remove( l );
}
public IMEInventory<IAEItemStack> getInventory()
{
return this.inventory;
}
@Override
public void updateStatus( final boolean updateGrid )
{
for( final TileCraftingTile r : this.tiles )
{
r.updateMeta( true );
}
}
@Override
public void destroy()
{
if( this.isDestroyed )
{
return;
}
this.isDestroyed = true;
boolean posted = false;
for( final TileCraftingTile r : this.tiles )
{
final IGridNode n = r.getActionableNode();
if( n != null && !posted )
{
final IGrid g = n.getGrid();
if( g != null )
{
g.postEvent( new MENetworkCraftingCpuChange( n ) );
posted = true;
}
}
r.updateStatus( null );
}
}
@Override
public Iterator<IGridHost> getTiles()
{
return (Iterator) this.tiles.iterator();
}
void addTile( final TileCraftingTile te )
{
if( this.machineSrc == null || te.isCoreBlock() )
{
this.machineSrc = new MachineSource( te );
}
te.setCoreBlock( false );
te.markDirty();
this.tiles.push( te );
if( te.isStorage() )
{
this.availableStorage += te.getStorageBytes();
this.storage.add( te );
}
else if( te.isStatus() )
{
this.status.add( (TileCraftingMonitorTile) te );
}
else if( te.isAccelerator() )
{
this.accelerator++;
}
}
public boolean canAccept( final IAEStack input )
{
if( input instanceof IAEItemStack )
{
final IAEItemStack is = this.waitingFor.findPrecise( (IAEItemStack) input );
if( is != null && is.getStackSize() > 0 )
{
return true;
}
}
return false;
}
public IAEStack injectItems( final IAEStack input, final Actionable type, final BaseActionSource src )
{
if( !( input instanceof IAEItemStack ) )
{
return input;
}
final IAEItemStack what = (IAEItemStack) input.copy();
final IAEItemStack is = this.waitingFor.findPrecise( what );
if( type == Actionable.SIMULATE )// causes crafting to lock up?
{
if( is != null && is.getStackSize() > 0 )
{
if( is.getStackSize() >= what.getStackSize() )
{
if( this.finalOutput.equals( what ) )
{
if( this.myLastLink != null )
{
return ( (CraftingLink) this.myLastLink ).injectItems( what.copy(), type );
}
return what; // ignore it.
}
return null;
}
final IAEItemStack leftOver = what.copy();
leftOver.decStackSize( is.getStackSize() );
final IAEItemStack used = what.copy();
used.setStackSize( is.getStackSize() );
if( this.finalOutput.equals( what ) )
{
if( this.myLastLink != null )
{
leftOver.add( ( (CraftingLink) this.myLastLink ).injectItems( used.copy(), type ) );
return leftOver;
}
return what; // ignore it.
}
return leftOver;
}
}
else if( type == Actionable.MODULATE )
{
if( is != null && is.getStackSize() > 0 )
{
this.waiting = false;
this.postChange( what, src );
if( is.getStackSize() >= what.getStackSize() )
{
is.decStackSize( what.getStackSize() );
this.updateElapsedTime( what );
this.markDirty();
this.postCraftingStatusChange( is );
if( this.finalOutput.equals( what ) )
{
IAEStack leftover = what;
this.finalOutput.decStackSize( what.getStackSize() );
if( this.myLastLink != null )
{
leftover = ( (CraftingLink) this.myLastLink ).injectItems( what, type );
}
if( this.finalOutput.getStackSize() <= 0 )
{
this.completeJob();
}
this.updateCPU();
return leftover; // ignore it.
}
// 2000
return this.inventory.injectItems( what, type, src );
}
final IAEItemStack insert = what.copy();
insert.setStackSize( is.getStackSize() );
what.decStackSize( is.getStackSize() );
is.setStackSize( 0 );
if( this.finalOutput.equals( insert ) )
{
IAEStack leftover = input;
this.finalOutput.decStackSize( insert.getStackSize() );
if( this.myLastLink != null )
{
what.add( ( (CraftingLink) this.myLastLink ).injectItems( insert.copy(), type ) );
leftover = what;
}
if( this.finalOutput.getStackSize() <= 0 )
{
this.completeJob();
}
this.updateCPU();
this.markDirty();
return leftover; // ignore it.
}
this.inventory.injectItems( insert, type, src );
this.markDirty();
return what;
}
}
return input;
}
private void postChange( final IAEItemStack diff, final BaseActionSource src )
{
final Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.getListeners();
// protect integrity
if( i.hasNext() )
{
final ImmutableList<IAEItemStack> single = ImmutableList.of( diff.copy() );
while( i.hasNext() )
{
final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> o = i.next();
final IMEMonitorHandlerReceiver<IAEItemStack> receiver = o.getKey();
if( receiver.isValid( o.getValue() ) )
{
receiver.postChange( null, single, src );
}
else
{
i.remove();
}
}
}
}
private void markDirty()
{
this.getCore().markDirty();
}
private void postCraftingStatusChange( final IAEItemStack diff )
{
if( this.getGrid() == null )
{
return;
}
final CraftingGridCache sg = this.getGrid().getCache( ICraftingGrid.class );
if( sg.getInterestManager().containsKey( diff ) )
{
final Collection<CraftingWatcher> list = sg.getInterestManager().get( diff );
if( !list.isEmpty() )
{
for( final CraftingWatcher iw : list )
{
iw.getHost().onRequestChange( sg, diff );
}
}
}
}
private void completeJob()
{
if( this.myLastLink != null )
{
( (CraftingLink) this.myLastLink ).markDone();
}
if( AELog.isCraftingLogEnabled() )
{
final IAEItemStack logStack = this.finalOutput.copy();
logStack.setStackSize( this.startItemCount );
AELog.crafting( LOG_MARK_AS_COMPLETE, logStack );
}
this.remainingItemCount = 0;
this.startItemCount = 0;
this.lastTime = 0;
this.elapsedTime = 0;
this.isComplete = true;
}
private void updateCPU()
{
IAEItemStack send = this.finalOutput;
if( this.finalOutput != null && this.finalOutput.getStackSize() <= 0 )
{
send = null;
}
for( final TileCraftingMonitorTile t : this.status )
{
t.setJob( send );
}
}
private Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> getListeners()
{
return this.listeners.entrySet().iterator();
}
private TileCraftingTile getCore()
{
return (TileCraftingTile) this.machineSrc.via;
}
private IGrid getGrid()
{
for( final TileCraftingTile r : this.tiles )
{
final IGridNode gn = r.getActionableNode();
if( gn != null )
{
final IGrid g = gn.getGrid();
if( g != null )
{
return r.getActionableNode().getGrid();
}
}
}
return null;
}
private boolean canCraft( final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs )
{
for( IAEItemStack g : condensedInputs )
{
if( details.isCraftable() )
{
boolean found = false;
for( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( g, FuzzyMode.IGNORE_ALL ) )
{
fuzz = fuzz.copy();
fuzz.setStackSize( g.getStackSize() );
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc );
final ItemStack is = ais == null ? null : ais.getItemStack();
if( is != null && is.stackSize == g.getStackSize() )
{
found = true;
break;
}
else if( is != null )
{
g = g.copy();
g.decStackSize( is.stackSize );
}
}
if( !found )
{
return false;
}
}
else
{
final IAEItemStack ais = this.inventory.extractItems( g.copy(), Actionable.SIMULATE, this.machineSrc );
final ItemStack is = ais == null ? null : ais.getItemStack();
if( is == null || is.stackSize < g.getStackSize() )
{
return false;
}
}
}
return true;
}
public void cancel()
{
if( this.myLastLink != null )
{
this.myLastLink.cancel();
}
final IItemList<IAEItemStack> list;
this.getListOfItem( list = AEApi.instance().storage().createItemList(), CraftingItemList.ALL );
for( final IAEItemStack is : list )
{
this.postChange( is, this.machineSrc );
}
this.isComplete = true;
this.myLastLink = null;
this.tasks.clear();
final ImmutableSet<IAEItemStack> items = ImmutableSet.copyOf( this.waitingFor );
this.waitingFor.resetStatus();
for( final IAEItemStack is : items )
{
this.postCraftingStatusChange( is );
}
this.finalOutput = null;
this.updateCPU();
this.storeItems(); // marks dirty
}
public void updateCraftingLogic( final IGrid grid, final IEnergyGrid eg, final CraftingGridCache cc )
{
if( !this.getCore().isActive() )
{
return;
}
if( this.myLastLink != null )
{
if( this.myLastLink.isCanceled() )
{
this.myLastLink = null;
this.cancel();
}
}
if( this.isComplete )
{
if( this.inventory.getItemList().isEmpty() )
{
return;
}
this.storeItems();
return;
}
this.waiting = false;
if( this.waiting || this.tasks.isEmpty() ) // nothing to do here...
{
return;
}
this.remainingOperations = this.accelerator + 1 - ( this.usedOps[0] + this.usedOps[1] + this.usedOps[2] );
final int started = this.remainingOperations;
if( this.remainingOperations > 0 )
{
do
{
this.somethingChanged = false;
this.executeCrafting( eg, cc );
}
while( this.somethingChanged && this.remainingOperations > 0 );
}
this.usedOps[2] = this.usedOps[1];
this.usedOps[1] = this.usedOps[0];
this.usedOps[0] = started - this.remainingOperations;
if( this.remainingOperations > 0 && !this.somethingChanged )
{
this.waiting = true;
}
}
private void executeCrafting( final IEnergyGrid eg, final CraftingGridCache cc )
{
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while( i.hasNext() )
{
final Entry<ICraftingPatternDetails, TaskProgress> e = i.next();
if( e.getValue().value <= 0 )
{
i.remove();
continue;
}
final ICraftingPatternDetails details = e.getKey();
if( this.canCraft( details, details.getCondensedInputs() ) )
{
InventoryCrafting ic = null;
for( final ICraftingMedium m : cc.getMediums( e.getKey() ) )
{
if( e.getValue().value <= 0 )
{
continue;
}
if( !m.isBusy() )
{
if( ic == null )
{
final IAEItemStack[] input = details.getInputs();
double sum = 0;
for( final IAEItemStack anInput : input )
{
if( anInput != null )
{
sum += anInput.getStackSize();
}
}
// power...
if( eg.extractAEPower( sum, Actionable.MODULATE, PowerMultiplier.CONFIG ) < sum - 0.01 )
{
continue;
}
ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
boolean found = false;
for( int x = 0; x < input.length; x++ )
{
if( input[x] != null )
{
found = false;
if( details.isCraftable() )
{
for( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( input[x], FuzzyMode.IGNORE_ALL ) )
{
fuzz = fuzz.copy();
fuzz.setStackSize( input[x].getStackSize() );
if( details.isValidItemForSlot( x, fuzz.getItemStack(), this.getWorld() ) )
{
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.MODULATE, this.machineSrc );
final ItemStack is = ais == null ? null : ais.getItemStack();
if( is != null )
{
this.postChange( AEItemStack.create( is ), this.machineSrc );
ic.setInventorySlotContents( x, is );
found = true;
break;
}
}
}
}
else
{
final IAEItemStack ais = this.inventory.extractItems( input[x].copy(), Actionable.MODULATE, this.machineSrc );
final ItemStack is = ais == null ? null : ais.getItemStack();
if( is != null )
{
this.postChange( input[x], this.machineSrc );
ic.setInventorySlotContents( x, is );
if( is.stackSize == input[x].getStackSize() )
{
found = true;
continue;
}
}
}
if( !found )
{
break;
}
}
}
if( !found )
{
// put stuff back..
for( int x = 0; x < ic.getSizeInventory(); x++ )
{
final ItemStack is = ic.getStackInSlot( x );
if( is != null )
{
this.inventory.injectItems( AEItemStack.create( is ), Actionable.MODULATE, this.machineSrc );
}
}
ic = null;
break;
}
}
if( m.pushPattern( details, ic ) )
{
this.somethingChanged = true;
this.remainingOperations--;
for( final IAEItemStack out : details.getCondensedOutputs() )
{
this.postChange( out, this.machineSrc );
this.waitingFor.add( out.copy() );
this.postCraftingStatusChange( out.copy() );
}
if( details.isCraftable() )
{
FMLCommonHandler.instance().firePlayerCraftingEvent( Platform.getPlayer( (WorldServer) this.getWorld() ), details.getOutput( ic, this.getWorld() ), ic );
for( int x = 0; x < ic.getSizeInventory(); x++ )
{
final ItemStack output = Platform.getContainerItem( ic.getStackInSlot( x ) );
if( output != null )
{
final IAEItemStack cItem = AEItemStack.create( output );
this.postChange( cItem, this.machineSrc );
this.waitingFor.add( cItem );
this.postCraftingStatusChange( cItem );
}
}
}
ic = null; // hand off complete!
this.markDirty();
e.getValue().value--;
if( e.getValue().value <= 0 )
{
continue;
}
if( this.remainingOperations == 0 )
{
return;
}
}
}
}
if( ic != null )
{
// put stuff back..
for( int x = 0; x < ic.getSizeInventory(); x++ )
{
final ItemStack is = ic.getStackInSlot( x );
if( is != null )
{
this.inventory.injectItems( AEItemStack.create( is ), Actionable.MODULATE, this.machineSrc );
}
}
}
}
}
}
private void storeItems()
{
final IGrid g = this.getGrid();
if( g == null )
{
return;
}
final IStorageGrid sg = g.getCache( IStorageGrid.class );
final IMEInventory<IAEItemStack> ii = sg.getItemInventory();
for( IAEItemStack is : this.inventory.getItemList() )
{
is = this.inventory.extractItems( is.copy(), Actionable.MODULATE, this.machineSrc );
if( is != null )
{
this.postChange( is, this.machineSrc );
is = ii.injectItems( is, Actionable.MODULATE, this.machineSrc );
}
if( is != null )
{
this.inventory.injectItems( is, Actionable.MODULATE, this.machineSrc );
}
}
if( this.inventory.getItemList().isEmpty() )
{
this.inventory = new MECraftingInventory();
}
this.markDirty();
}
public ICraftingLink submitJob( final IGrid g, final ICraftingJob job, final BaseActionSource src, final ICraftingRequester requestingMachine )
{
if( !this.tasks.isEmpty() || !this.waitingFor.isEmpty() )
{
return null;
}
if( !( job instanceof CraftingJob ) )
{
return null;
}
if( this.isBusy() || !this.isActive() || this.availableStorage < job.getByteTotal() )
{
return null;
}
final IStorageGrid sg = g.getCache( IStorageGrid.class );
final IMEInventory<IAEItemStack> storage = sg.getItemInventory();
final MECraftingInventory ci = new MECraftingInventory( storage, true, false, false );
try
{
this.waitingFor.resetStatus();
( (CraftingJob) job ).getTree().setJob( ci, this, src );
if( ci.commit( src ) )
{
this.finalOutput = job.getOutput();
this.waiting = false;
this.isComplete = false;
this.markDirty();
this.updateCPU();
final String craftID = this.generateCraftingID();
this.myLastLink = new CraftingLink( this.generateLinkData( craftID, requestingMachine == null, false ), this );
this.prepareElapsedTime();
if( requestingMachine == null )
{
return this.myLastLink;
}
final ICraftingLink whatLink = new CraftingLink( this.generateLinkData( craftID, false, true ), requestingMachine );
this.submitLink( this.myLastLink );
this.submitLink( whatLink );
final IItemList<IAEItemStack> list = AEApi.instance().storage().createItemList();
this.getListOfItem( list, CraftingItemList.ALL );
for( final IAEItemStack ge : list )
{
this.postChange( ge, this.machineSrc );
}
return whatLink;
}
else
{
this.tasks.clear();
this.inventory.getItemList().resetStatus();
}
}
catch( final CraftBranchFailure e )
{
this.tasks.clear();
this.inventory.getItemList().resetStatus();
// AELog.error( e );
}
return null;
}
@Override
public boolean isBusy()
{
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while( i.hasNext() )
{
if( i.next().getValue().value <= 0 )
{
i.remove();
}
}
return !this.tasks.isEmpty() || !this.waitingFor.isEmpty();
}
@Override
public BaseActionSource getActionSource()
{
return this.machineSrc;
}
@Override
public long getAvailableStorage()
{
return this.availableStorage;
}
@Override
public int getCoProcessors()
{
return this.accelerator;
}
@Override
public String getName()
{
return this.myName;
}
public boolean isActive()
{
final TileCraftingTile core = this.getCore();
if( core == null )
{
return false;
}
final IGridNode node = core.getActionableNode();
if( node == null )
{
return false;
}
return node.isActive();
}
private String generateCraftingID()
{
final long now = System.currentTimeMillis();
final int hash = System.identityHashCode( this );
final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode();
return Long.toString( now, Character.MAX_RADIX ) + '-' + Integer.toString( hash, Character.MAX_RADIX ) + '-' + Integer.toString( hmm, Character.MAX_RADIX );
}
private NBTTagCompound generateLinkData( final String craftingID, final boolean standalone, final boolean req )
{
final 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 submitLink( final ICraftingLink myLastLink2 )
{
if( this.getGrid() != null )
{
final CraftingGridCache cc = this.getGrid().getCache( ICraftingGrid.class );
cc.addLink( (CraftingLink) myLastLink2 );
}
}
public void getListOfItem( final IItemList<IAEItemStack> list, final CraftingItemList whichList )
{
switch( whichList )
{
case ACTIVE:
for( final IAEItemStack ais : this.waitingFor )
{
list.add( ais );
}
break;
case PENDING:
for( final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet() )
{
for( IAEItemStack ais : t.getKey().getCondensedOutputs() )
{
ais = ais.copy();
ais.setStackSize( ais.getStackSize() * t.getValue().value );
list.add( ais );
}
}
break;
case STORAGE:
this.inventory.getAvailableItems( list );
break;
default:
case ALL:
this.inventory.getAvailableItems( list );
for( final IAEItemStack ais : this.waitingFor )
{
list.add( ais );
}
for( final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet() )
{
for( IAEItemStack ais : t.getKey().getCondensedOutputs() )
{
ais = ais.copy();
ais.setStackSize( ais.getStackSize() * t.getValue().value );
list.add( ais );
}
}
break;
}
}
public void addStorage( final IAEItemStack extractItems )
{
this.inventory.injectItems( extractItems, Actionable.MODULATE, null );
}
public void addEmitable( final IAEItemStack i )
{
this.waitingFor.add( i );
this.postCraftingStatusChange( i );
}
public void addCrafting( final ICraftingPatternDetails details, final long crafts )
{
TaskProgress i = this.tasks.get( details );
if( i == null )
{
this.tasks.put( details, i = new TaskProgress() );
}
i.value += crafts;
}
public IAEItemStack getItemStack( final IAEItemStack what, final CraftingItemList storage2 )
{
IAEItemStack is;
switch( storage2 )
{
case STORAGE:
is = this.inventory.getItemList().findPrecise( what );
break;
case ACTIVE:
is = this.waitingFor.findPrecise( what );
break;
case PENDING:
is = what.copy();
is.setStackSize( 0 );
for( final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet() )
{
for( final IAEItemStack ais : t.getKey().getCondensedOutputs() )
{
if( ais.equals( is ) )
{
is.setStackSize( is.getStackSize() + ais.getStackSize() * t.getValue().value );
}
}
}
break;
default:
case ALL:
throw new IllegalStateException( "Invalid Operation" );
}
if( is != null )
{
return is.copy();
}
is = what.copy();
is.setStackSize( 0 );
return is;
}
public void writeToNBT( final NBTTagCompound data )
{
data.setTag( "finalOutput", this.writeItem( this.finalOutput ) );
data.setTag( "inventory", this.writeList( this.inventory.getItemList() ) );
data.setBoolean( "waiting", this.waiting );
data.setBoolean( "isComplete", this.isComplete );
if( this.myLastLink != null )
{
final NBTTagCompound link = new NBTTagCompound();
this.myLastLink.writeToNBT( link );
data.setTag( "link", link );
}
final NBTTagList list = new NBTTagList();
for( final Entry<ICraftingPatternDetails, TaskProgress> e : this.tasks.entrySet() )
{
final NBTTagCompound item = this.writeItem( AEItemStack.create( e.getKey().getPattern() ) );
item.setLong( "craftingProgress", e.getValue().value );
list.appendTag( item );
}
data.setTag( "tasks", list );
data.setTag( "waitingFor", this.writeList( this.waitingFor ) );
data.setLong( "elapsedTime", this.getElapsedTime() );
data.setLong( "startItemCount", this.getStartItemCount() );
data.setLong( "remainingItemCount", this.getRemainingItemCount() );
}
private NBTTagCompound writeItem( final IAEItemStack finalOutput2 )
{
final NBTTagCompound out = new NBTTagCompound();
if( finalOutput2 != null )
{
finalOutput2.writeToNBT( out );
}
return out;
}
private NBTTagList writeList( final IItemList<IAEItemStack> myList )
{
final NBTTagList out = new NBTTagList();
for( final IAEItemStack ais : myList )
{
out.appendTag( this.writeItem( ais ) );
}
return out;
}
void done()
{
final TileCraftingTile core = this.getCore();
core.setCoreBlock( true );
if( core.getPreviousState() != null )
{
this.readFromNBT( core.getPreviousState() );
core.setPreviousState( null );
}
this.updateCPU();
this.updateName();
}
public void readFromNBT( final NBTTagCompound data )
{
this.finalOutput = AEItemStack.loadItemStackFromNBT( (NBTTagCompound) data.getTag( "finalOutput" ) );
for( final IAEItemStack ais : this.readList( (NBTTagList) data.getTag( "inventory" ) ) )
{
this.inventory.injectItems( ais, Actionable.MODULATE, this.machineSrc );
}
this.waiting = data.getBoolean( "waiting" );
this.isComplete = data.getBoolean( "isComplete" );
if( data.hasKey( "link" ) )
{
final NBTTagCompound link = data.getCompoundTag( "link" );
this.myLastLink = new CraftingLink( link, this );
this.submitLink( this.myLastLink );
}
final NBTTagList list = data.getTagList( "tasks", 10 );
for( int x = 0; x < list.tagCount(); x++ )
{
final NBTTagCompound item = list.getCompoundTagAt( x );
final IAEItemStack pattern = AEItemStack.loadItemStackFromNBT( item );
if( pattern != null && pattern.getItem() instanceof ICraftingPatternItem )
{
final ICraftingPatternItem cpi = (ICraftingPatternItem) pattern.getItem();
final ICraftingPatternDetails details = cpi.getPatternForItem( pattern.getItemStack(), this.getWorld() );
if( details != null )
{
final TaskProgress tp = new TaskProgress();
tp.value = item.getLong( "craftingProgress" );
this.tasks.put( details, tp );
}
}
}
this.waitingFor = this.readList( (NBTTagList) data.getTag( "waitingFor" ) );
for( final IAEItemStack is : this.waitingFor )
{
this.postCraftingStatusChange( is.copy() );
}
this.lastTime = System.nanoTime();
this.elapsedTime = data.getLong( "elapsedTime" );
this.startItemCount = data.getLong( "startItemCount" );
this.remainingItemCount = data.getLong( "remainingItemCount" );
}
public void updateName()
{
this.myName = "";
for( final TileCraftingTile te : this.tiles )
{
if( te.hasCustomName() )
{
if( this.myName.length() > 0 )
{
this.myName += ' ' + te.getCustomName();
}
else
{
this.myName = te.getCustomName();
}
}
}
}
private IItemList<IAEItemStack> readList( final NBTTagList tag )
{
final IItemList<IAEItemStack> out = AEApi.instance().storage().createItemList();
if( tag == null )
{
return out;
}
for( int x = 0; x < tag.tagCount(); x++ )
{
final IAEItemStack ais = AEItemStack.loadItemStackFromNBT( tag.getCompoundTagAt( x ) );
if( ais != null )
{
out.add( ais );
}
}
return out;
}
private World getWorld()
{
return this.getCore().getWorld();
}
public boolean isMaking( final IAEItemStack what )
{
final IAEItemStack wat = this.waitingFor.findPrecise( what );
return wat != null && wat.getStackSize() > 0;
}
public void breakCluster()
{
final TileCraftingTile t = this.getCore();
if( t != null )
{
t.breakCluster();
}
}
private void prepareElapsedTime()
{
this.lastTime = System.nanoTime();
this.elapsedTime = 0;
final IItemList<IAEItemStack> list = AEApi.instance().storage().createItemList();
this.getListOfItem( list, CraftingItemList.ACTIVE );
this.getListOfItem( list, CraftingItemList.PENDING );
int itemCount = 0;
for( final IAEItemStack ge : list )
{
itemCount += ge.getStackSize();
}
this.startItemCount = itemCount;
this.remainingItemCount = itemCount;
}
private void updateElapsedTime( final IAEItemStack is )
{
final long nextStartTime = System.nanoTime();
this.elapsedTime = this.getElapsedTime() + nextStartTime - this.lastTime;
this.lastTime = nextStartTime;
this.remainingItemCount = this.getRemainingItemCount() - is.getStackSize();
}
public long getElapsedTime()
{
return this.elapsedTime;
}
public long getRemainingItemCount()
{
return this.remainingItemCount;
}
public long getStartItemCount()
{
return this.startItemCount;
}
private static class TaskProgress
{
private long value;
}
}