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,
OfSecondOutput, NoSecondOutput, RFTunnel, Stores, Next, SelectAmount, Lumen, Empty;
OfSecondOutput, NoSecondOutput, RFTunnel, Stores, Next, SelectAmount, Lumen, Empty, ConfirmCrafting;
String root;

View file

@ -36,6 +36,7 @@ import appeng.container.implementations.ContainerCellWorkbench;
import appeng.container.implementations.ContainerChest;
import appeng.container.implementations.ContainerCondenser;
import appeng.container.implementations.ContainerCraftAmount;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.container.implementations.ContainerCraftingTerm;
import appeng.container.implementations.ContainerDrive;
import appeng.container.implementations.ContainerFormationPlane;
@ -150,7 +151,9 @@ public enum GuiBridge implements IGuiHandler
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 Gui;

View file

@ -4,9 +4,13 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
@ -14,18 +18,38 @@ import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.ContainerOpenContext;
import appeng.container.implementations.ContainerCraftAmount;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.core.AELog;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.GuiBridge;
import appeng.core.sync.network.INetworkInfo;
import appeng.crafting.CraftingJob;
import appeng.me.cache.CraftingCache;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class PacketCraftRequest extends AppEngPacket
{
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.
public PacketCraftRequest(ByteBuf stream) throws IOException {
@ -56,6 +80,20 @@ public class PacketCraftRequest extends AppEngPacket
{
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)
{

View file

@ -8,6 +8,7 @@ import net.minecraft.nbt.NBTTagCompound;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
@ -17,7 +18,7 @@ import appeng.util.Platform;
import com.google.common.base.Stopwatch;
public class CraftingJob
public class CraftingJob implements Runnable
{
IAEItemStack output;
@ -28,10 +29,17 @@ public class CraftingJob
ICraftingHost jobHost;
boolean simulate = false;
final MECraftingInventory original;
public CraftingTreeNode tree;
private BaseActionSource actionSrc;
public CraftingJob(ICraftingHost host, NBTTagCompound data) {
jobHost = host;
storage = AEApi.instance().storage().createItemList();
prophecies = new HashSet();
original = null;
}
public CraftingJob(ICraftingHost host, IAEItemStack what, Actionable mode) {
@ -39,41 +47,13 @@ public class CraftingJob
output = what.copy();
storage = AEApi.instance().storage().createItemList();
prophecies = new HashSet();
actionSrc = host.getActionSrc();
CraftingCache cc = host.getGrid().getCache( CraftingCache.class );
IStorageGrid sg = host.getGrid().getCache( IStorageGrid.class );
original = new MECraftingInventory( sg.getItemInventory(), false, false, false );
IItemList<IAEItemStack> missing = AEApi.instance().storage().createItemList();
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 );
}
tree = getCraftingTree( cc, 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)
{
if ( crafts > 0 )
{
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)
{
what = what.copy();
missing.add( what );
postOp( "required material: " + Platform.getItemDisplayName( what ), 1, what.getStackSize() );
}
@ -117,4 +106,76 @@ public class CraftingJob
ti.perOp = stackSize;
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;
long missing = 0;
boolean sim;
public CraftingTreeNode(CraftingCache cc, CraftingJob job, IAEItemStack wat, CraftingTreeProcess par, int slot, int depth) {
what = wat;
parent = par;
this.slot = slot;
this.world = job.jobHost.getWorld();
sim = false;
for (ICraftingPatternDetails details : cc.getCraftingFor( what ))// in order.
{
@ -62,8 +65,11 @@ public class CraftingTreeNode
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 );
if ( slot >= 0 && parent != null && parent.details.isCraftable() )
{
@ -153,9 +159,13 @@ public class CraftingTreeNode
}
}
missing += l;
return what;
// throw new CraftBranchFailure( what, l );
if ( sim )
{
missing += l;
return what;
}
throw new CraftBranchFailure( what, l );
}
public void dive(CraftingJob job)
@ -167,4 +177,13 @@ public class CraftingTreeNode
for (CraftingTreeProcess pro : nodes)
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." );
}
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...
for (Entry<CraftingTreeNode, Long> entry : nodes.entrySet())
{
@ -129,4 +132,12 @@ public class CraftingTreeProcess
for (CraftingTreeNode pro : nodes.keySet())
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;
}
public boolean isValidItemForSlot(int slotIndex, ItemStack i, World w)
synchronized public boolean isValidItemForSlot(int slotIndex, ItemStack i, World w)
{
if ( isCrafting == false )
{
throw new RuntimeException( "Only crafting recipes supported." );
}

View file

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

View file

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