Separated Crafting job into a worker thread.

Crafting calculation can be canceled.
Hooked up a crafting calculation launch and the confirmation GUI.
This commit is contained in:
AlgorithmX2 2014-06-18 01:23:37 -05:00
parent 0a18f2d926
commit 32ee57c3a9
11 changed files with 320 additions and 44 deletions

View file

@ -0,0 +1,46 @@
package appeng.client.gui.implementations;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
import appeng.api.storage.ITerminalHost;
import appeng.client.gui.AEBaseGui;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.core.localization.GuiText;
public class GuiCraftConfirm extends AEBaseGui
{
public GuiCraftConfirm(InventoryPlayer inventoryPlayer, ITerminalHost te) {
super( new ContainerCraftConfirm( inventoryPlayer, te ) );
}
@Override
public void initGui()
{
super.initGui();
}
@Override
protected void actionPerformed(GuiButton btn)
{
super.actionPerformed( btn );
}
@Override
public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY)
{
bindTexture( "guis/craftingreport.png" );
this.drawTexturedModalRect( offsetX, offsetY, 0, 0, xSize, ySize );
}
protected String getBackground()
{
return "guis/craftingreport.png";
}
@Override
public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY)
{
fontRendererObj.drawString( GuiText.ConfirmCrafting.getLocal(), 8, 6, 4210752 );
}
}

View file

@ -0,0 +1,98 @@
package appeng.container.implementations;
import java.util.concurrent.Future;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.ICrafting;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.World;
import appeng.api.config.SecurityPermissions;
import appeng.api.networking.IGrid;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.PlayerSource;
import appeng.api.storage.ITerminalHost;
import appeng.container.AEBaseContainer;
import appeng.core.AELog;
import appeng.crafting.CraftingJob;
import appeng.crafting.ICraftingHost;
public class ContainerCraftConfirm extends AEBaseContainer implements ICraftingHost
{
ITerminalHost priHost;
public Future<CraftingJob> job;
public CraftingJob result;
public ContainerCraftConfirm(InventoryPlayer ip, ITerminalHost te) {
super( ip, te );
priHost = te;
}
@Override
public void detectAndSendChanges()
{
super.detectAndSendChanges();
if ( job != null && job.isDone() )
{
try
{
result = job.get();
AELog.info( "Job info is ready!" );
}
catch (Throwable e)
{
getPlayerInv().player.addChatMessage( new ChatComponentText( "Error: " + e.toString() ) );
AELog.error( e );
this.isContainerValid = false;
result = null;
}
job = null;
}
verifyPermissions( SecurityPermissions.CRAFT, false );
}
@Override
public void onContainerClosed(EntityPlayer par1EntityPlayer)
{
super.onContainerClosed( par1EntityPlayer );
if ( job != null )
{
job.cancel( true );
job = null;
}
}
@Override
public void removeCraftingFromCrafters(ICrafting c)
{
super.removeCraftingFromCrafters( c );
if ( job != null )
{
job.cancel( true );
job = null;
}
}
@Override
public IGrid getGrid()
{
IActionHost h = ((IActionHost) this.getTarget());
return h.getActionableNode().getGrid();
}
@Override
public World getWorld()
{
return getPlayerInv().player.worldObj;
}
@Override
public BaseActionSource getActionSrc()
{
return new PlayerSource( getPlayerInv().player, (IActionHost) getTarget() );
}
}

View file

@ -30,7 +30,7 @@ public enum GuiText
StoredPower, MaxPower, RequiredPower, Efficiency, InWorldCrafting, inWorldFluix, inWorldPurificationCertus, inWorldPurificationNether, inWorldPurificationFluix, inWorldSingularity, ChargedQuartz, StoredPower, MaxPower, RequiredPower, Efficiency, InWorldCrafting, inWorldFluix, inWorldPurificationCertus, inWorldPurificationNether, inWorldPurificationFluix, inWorldSingularity, ChargedQuartz,
OfSecondOutput, NoSecondOutput, RFTunnel, Stores, Next, SelectAmount, Lumen, Empty; OfSecondOutput, NoSecondOutput, RFTunnel, Stores, Next, SelectAmount, Lumen, Empty, ConfirmCrafting;
String root; String root;

View file

@ -36,6 +36,7 @@ import appeng.container.implementations.ContainerCellWorkbench;
import appeng.container.implementations.ContainerChest; import appeng.container.implementations.ContainerChest;
import appeng.container.implementations.ContainerCondenser; import appeng.container.implementations.ContainerCondenser;
import appeng.container.implementations.ContainerCraftAmount; import appeng.container.implementations.ContainerCraftAmount;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.container.implementations.ContainerCraftingTerm; import appeng.container.implementations.ContainerCraftingTerm;
import appeng.container.implementations.ContainerDrive; import appeng.container.implementations.ContainerDrive;
import appeng.container.implementations.ContainerFormationPlane; import appeng.container.implementations.ContainerFormationPlane;
@ -150,7 +151,9 @@ public enum GuiBridge implements IGuiHandler
GUI_MAC(ContainerMAC.class, TileMolecularAssembler.class, WORLD, null), GUI_MAC(ContainerMAC.class, TileMolecularAssembler.class, WORLD, null),
GUI_CRAFTING_AMOUNT(ContainerCraftAmount.class, ITerminalHost.class, ITEM_OR_WORLD, SecurityPermissions.CRAFT); GUI_CRAFTING_AMOUNT(ContainerCraftAmount.class, ITerminalHost.class, ITEM_OR_WORLD, SecurityPermissions.CRAFT),
GUI_CRAFTING_CONFIRM(ContainerCraftConfirm.class, ITerminalHost.class, ITEM_OR_WORLD, SecurityPermissions.CRAFT);
private Class Tile; private Class Tile;
private Class Gui; private Class Gui;

View file

@ -4,9 +4,13 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.common.util.ForgeDirection;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@ -14,18 +18,38 @@ import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost; import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.container.ContainerOpenContext;
import appeng.container.implementations.ContainerCraftAmount; import appeng.container.implementations.ContainerCraftAmount;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.core.sync.AppEngPacket; import appeng.core.sync.AppEngPacket;
import appeng.core.sync.GuiBridge;
import appeng.core.sync.network.INetworkInfo; import appeng.core.sync.network.INetworkInfo;
import appeng.crafting.CraftingJob; import appeng.crafting.CraftingJob;
import appeng.me.cache.CraftingCache; import appeng.me.cache.CraftingCache;
import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
public class PacketCraftRequest extends AppEngPacket public class PacketCraftRequest extends AppEngPacket
{ {
final public IAEItemStack slotItem; final public IAEItemStack slotItem;
final public static ExecutorService craftingPool;
static
{
ThreadFactory factory = new ThreadFactory() {
@Override
public Thread newThread(Runnable ar)
{
return new Thread( ar, "AE Crafting Calculator" );
}
};
craftingPool = Executors.newCachedThreadPool( factory );
}
// automatic. // automatic.
public PacketCraftRequest(ByteBuf stream) throws IOException { public PacketCraftRequest(ByteBuf stream) throws IOException {
@ -56,6 +80,20 @@ public class PacketCraftRequest extends AppEngPacket
{ {
CraftingJob cj = new CraftingJob( cca, slotItem, Actionable.SIMULATE ); CraftingJob cj = new CraftingJob( cca, slotItem, Actionable.SIMULATE );
ContainerOpenContext context = cca.openContext;
if ( context != null )
{
TileEntity te = context.w.getTileEntity( context.x, context.y, context.z );
Platform.openGUI( player, te, cca.openContext.side, GuiBridge.GUI_CRAFTING_CONFIRM );
if ( player.openContainer instanceof ContainerCraftConfirm )
{
ContainerCraftConfirm ccc = (ContainerCraftConfirm) player.openContainer;
ccc.job = craftingPool.submit( cj, cj );
cca.detectAndSendChanges();
}
}
} }
catch (Throwable e) catch (Throwable e)
{ {

View file

@ -8,6 +8,7 @@ import net.minecraft.nbt.NBTTagCompound;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.storage.IStorageGrid; import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
@ -17,7 +18,7 @@ import appeng.util.Platform;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
public class CraftingJob public class CraftingJob implements Runnable
{ {
IAEItemStack output; IAEItemStack output;
@ -28,10 +29,17 @@ public class CraftingJob
ICraftingHost jobHost; ICraftingHost jobHost;
boolean simulate = false;
final MECraftingInventory original;
public CraftingTreeNode tree;
private BaseActionSource actionSrc;
public CraftingJob(ICraftingHost host, NBTTagCompound data) { public CraftingJob(ICraftingHost host, NBTTagCompound data) {
jobHost = host; jobHost = host;
storage = AEApi.instance().storage().createItemList(); storage = AEApi.instance().storage().createItemList();
prophecies = new HashSet(); prophecies = new HashSet();
original = null;
} }
public CraftingJob(ICraftingHost host, IAEItemStack what, Actionable mode) { public CraftingJob(ICraftingHost host, IAEItemStack what, Actionable mode) {
@ -39,41 +47,13 @@ public class CraftingJob
output = what.copy(); output = what.copy();
storage = AEApi.instance().storage().createItemList(); storage = AEApi.instance().storage().createItemList();
prophecies = new HashSet(); prophecies = new HashSet();
actionSrc = host.getActionSrc();
CraftingCache cc = host.getGrid().getCache( CraftingCache.class ); CraftingCache cc = host.getGrid().getCache( CraftingCache.class );
IStorageGrid sg = host.getGrid().getCache( IStorageGrid.class ); IStorageGrid sg = host.getGrid().getCache( IStorageGrid.class );
original = new MECraftingInventory( sg.getItemInventory(), false, false, false );
IItemList<IAEItemStack> missing = AEApi.instance().storage().createItemList(); tree = getCraftingTree( cc, what );
MECraftingInventory meci = new MECraftingInventory( sg.getItemInventory(), true, false, true );
meci.ignore( what );
CraftingTreeNode tree = getCraftingTree( cc, what );
try
{
Stopwatch timer = Stopwatch.createStarted();
tree.request( meci, what.getStackSize(), host.getActionSrc() );
tree.dive( this );
for (String s : opsAndMultiplier.keySet())
{
twoIntegers ti = opsAndMultiplier.get( s );
AELog.info( s + " * " + ti.times + " = " + (ti.perOp * ti.times) );
}
AELog.info( "-------------" + timer.elapsed( TimeUnit.MILLISECONDS ) + "ms" );
// if ( mode == Actionable.MODULATE )
// meci.moveItemsToStorage( storage );
}
catch (CraftBranchFailure e)
{
AELog.error( e );
}
catch (CraftingCalculationFailure f)
{
AELog.error( f );
}
} }
private CraftingTreeNode getCraftingTree(CraftingCache cc, IAEItemStack what) private CraftingTreeNode getCraftingTree(CraftingCache cc, IAEItemStack what)
@ -86,16 +66,25 @@ public class CraftingJob
} }
IItemList<IAEItemStack> crafting = AEApi.instance().storage().createItemList();
IItemList<IAEItemStack> missing = AEApi.instance().storage().createItemList();
public void addTask(IAEItemStack what, long crafts, ICraftingPatternDetails details, int depth) public void addTask(IAEItemStack what, long crafts, ICraftingPatternDetails details, int depth)
{ {
if ( crafts > 0 ) if ( crafts > 0 )
{ {
postOp( "new task: " + Platform.getItemDisplayName( what ) + " x " + what.getStackSize(), what.getStackSize(), crafts ); postOp( "new task: " + Platform.getItemDisplayName( what ) + " x " + what.getStackSize(), what.getStackSize(), crafts );
what = what.copy();
what.setStackSize( what.getStackSize() * crafts );
crafting.add( what );
} }
} }
public void addMissing(IAEItemStack what) public void addMissing(IAEItemStack what)
{ {
what = what.copy();
missing.add( what );
postOp( "required material: " + Platform.getItemDisplayName( what ), 1, what.getStackSize() ); postOp( "required material: " + Platform.getItemDisplayName( what ), 1, what.getStackSize() );
} }
@ -117,4 +106,76 @@ public class CraftingJob
ti.perOp = stackSize; ti.perOp = stackSize;
ti.times += crafts; ti.times += crafts;
} }
@Override
public void run()
{
try
{
Stopwatch timer = Stopwatch.createStarted();
MECraftingInventory meci = new MECraftingInventory( original, true, false, true );
meci.ignore( output );
tree.request( meci, output.getStackSize(), actionSrc );
tree.dive( this );
for (String s : opsAndMultiplier.keySet())
{
twoIntegers ti = opsAndMultiplier.get( s );
AELog.info( s + " * " + ti.times + " = " + (ti.perOp * ti.times) );
}
AELog.info( "------------- real" + timer.elapsed( TimeUnit.MILLISECONDS ) + "ms" );
// if ( mode == Actionable.MODULATE )
// meci.moveItemsToStorage( storage );
}
catch (CraftBranchFailure e)
{
simulate = true;
try
{
Stopwatch timer = Stopwatch.createStarted();
MECraftingInventory meci = new MECraftingInventory( original, true, false, true );
meci.ignore( output );
tree.setSimulate();
tree.request( meci, output.getStackSize(), actionSrc );
tree.dive( this );
for (String s : opsAndMultiplier.keySet())
{
twoIntegers ti = opsAndMultiplier.get( s );
AELog.info( s + " * " + ti.times + " = " + (ti.perOp * ti.times) );
}
AELog.info( "------------- simulate" + timer.elapsed( TimeUnit.MILLISECONDS ) + "ms" );
}
catch (CraftBranchFailure e1)
{
AELog.error( e1 );
}
catch (CraftingCalculationFailure f)
{
AELog.error( f );
}
catch (InterruptedException e1)
{
AELog.info( "Crafting calculation canceled." );
return;
}
}
catch (CraftingCalculationFailure f)
{
AELog.error( f );
}
catch (InterruptedException e1)
{
AELog.info( "Crafting calculation canceled." );
return;
}
}
} }

View file

@ -29,11 +29,14 @@ public class CraftingTreeNode
boolean cannotUse = false; boolean cannotUse = false;
long missing = 0; long missing = 0;
boolean sim;
public CraftingTreeNode(CraftingCache cc, CraftingJob job, IAEItemStack wat, CraftingTreeProcess par, int slot, int depth) { public CraftingTreeNode(CraftingCache cc, CraftingJob job, IAEItemStack wat, CraftingTreeProcess par, int slot, int depth) {
what = wat; what = wat;
parent = par; parent = par;
this.slot = slot; this.slot = slot;
this.world = job.jobHost.getWorld(); this.world = job.jobHost.getWorld();
sim = false;
for (ICraftingPatternDetails details : cc.getCraftingFor( what ))// in order. for (ICraftingPatternDetails details : cc.getCraftingFor( what ))// in order.
{ {
@ -62,8 +65,11 @@ public class CraftingTreeNode
return parent.notRecurive( details ); return parent.notRecurive( details );
} }
public IAEItemStack request(MECraftingInventory inv, long l, BaseActionSource src) throws CraftBranchFailure public IAEItemStack request(MECraftingInventory inv, long l, BaseActionSource src) throws CraftBranchFailure, InterruptedException
{ {
if ( Thread.interrupted() )
throw new InterruptedException();
what.setStackSize( l ); what.setStackSize( l );
if ( slot >= 0 && parent != null && parent.details.isCraftable() ) if ( slot >= 0 && parent != null && parent.details.isCraftable() )
{ {
@ -153,9 +159,13 @@ public class CraftingTreeNode
} }
} }
if ( sim )
{
missing += l; missing += l;
return what; return what;
// throw new CraftBranchFailure( what, l ); }
throw new CraftBranchFailure( what, l );
} }
public void dive(CraftingJob job) public void dive(CraftingJob job)
@ -167,4 +177,13 @@ public class CraftingTreeNode
for (CraftingTreeProcess pro : nodes) for (CraftingTreeProcess pro : nodes)
pro.dive( job ); pro.dive( job );
} }
public void setSimulate()
{
sim = true;
missing = 0;
for (CraftingTreeProcess pro : nodes)
pro.setSimulate();
}
} }

View file

@ -86,8 +86,11 @@ public class CraftingTreeProcess
throw new RuntimeException( "Crafting Tree construction failed." ); throw new RuntimeException( "Crafting Tree construction failed." );
} }
public void request(MECraftingInventory inv, long i, BaseActionSource src) throws CraftBranchFailure public void request(MECraftingInventory inv, long i, BaseActionSource src) throws CraftBranchFailure, InterruptedException
{ {
if ( Thread.interrupted() )
throw new InterruptedException();
// request and remove inputs... // request and remove inputs...
for (Entry<CraftingTreeNode, Long> entry : nodes.entrySet()) for (Entry<CraftingTreeNode, Long> entry : nodes.entrySet())
{ {
@ -129,4 +132,12 @@ public class CraftingTreeProcess
for (CraftingTreeNode pro : nodes.keySet()) for (CraftingTreeNode pro : nodes.keySet())
pro.dive( job ); pro.dive( job );
} }
public void setSimulate()
{
crafts = 0;
for (CraftingTreeNode pro : nodes.keySet())
pro.setSimulate();
}
} }

View file

@ -195,11 +195,10 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
condencedOutputs[offset++] = io; condencedOutputs[offset++] = io;
} }
public boolean isValidItemForSlot(int slotIndex, ItemStack i, World w) synchronized public boolean isValidItemForSlot(int slotIndex, ItemStack i, World w)
{ {
if ( isCrafting == false ) if ( isCrafting == false )
{ {
throw new RuntimeException( "Only crafting recipes supported." ); throw new RuntimeException( "Only crafting recipes supported." );
} }

View file

@ -90,7 +90,7 @@ public class CraftingCPUCalculator extends MBCalculator
@Override @Override
public void disconnect() public void disconnect()
{ {
tqb.disconnect(); tqb.disconnect( true );
} }
@Override @Override

View file

@ -62,11 +62,12 @@ public class TileCraftingTile extends AENetworkTile implements IAEMultiBlock, IP
} }
@Override @Override
public void disconnect() public void disconnect(boolean update)
{ {
if ( clust != null ) if ( clust != null )
{ {
clust.destroy(); clust.destroy();
if ( update )
updateMeta(); updateMeta();
} }
} }