Compare commits

..

22 Commits

Author SHA1 Message Date
PrototypeTrousers 058e91b7e4 v47 2021-09-18 22:11:35 -03:00
PrototypeTrousers 67bdd885d5 Revert all the energy "fixes". Will crash on concurrent modifications. 2021-09-18 21:48:53 -03:00
PrototypeTrousers 188e3a75cc simplify monitor passthrough listener logic 2021-09-18 21:45:03 -03:00
PrototypeTrousers b9f6029005 borrowed some fancy, colored, fluid rendering from gregicality
thank you @Yefancy
2021-09-18 21:42:21 -03:00
PrototypeTrousers b607e018e6 try to fix #51 2021-09-18 21:42:10 -03:00
PrototypeTrousers e6ccc24ae0 fix #49. you can now actually clear storage and conversion monitors 2021-09-18 21:41:57 -03:00
PrototypeTrousers 2cb452fd9e hash drawers handler by the amount of slots 2021-09-18 21:40:42 -03:00
PrototypeTrousers 855c6f61a9 fix JEI targeting disabled slots as valid 2021-09-18 21:40:24 -03:00
PrototypeTrousers 89a5ba46b1 fluid containers can now be drained/filled from fluid interfaces 2021-09-18 21:39:51 -03:00
PrototypeTrousers 69a3268549 small optimization to import/export busses 2021-09-18 21:39:34 -03:00
PrototypeTrousers 4b42e478f1 fix broken recipes resulting in item dupes 2021-09-18 21:38:57 -03:00
BalaM314 6d03c860c5 Fix #27
Not sure exactly what method is causing a crash, but added a catch to just say it is located in another dimension
2021-09-18 21:38:39 -03:00
Salomão 6404f26cca Merge remote-tracking branch 'origin/fluid-terminal-multiple-containers' into AE2-Omnifactory 2021-07-16 14:22:21 -03:00
Salomão ced6ad865c re-introduce time-based calculation quota
player initiated crafting calculation is not affected
2021-07-16 14:22:09 -03:00
Salomão df08ce0513 Fluid terminal is now able to fill/empty stacked tanks 2021-07-04 10:28:36 -03:00
Salomão f9c274fb48 Reduce power flickering by increasing energy polling rate
in testing 84 dense cells could sustain MAX Integer on a FE p2p pair
2021-06-27 23:17:26 -03:00
Salomão 3582582e3f fix off-by-one voiding patterns when removing expansion cards 2021-06-26 10:25:47 -03:00
Salomão 6de48f8541 fixes #34
getAllIngredients() can contain nulls
2021-06-26 07:31:16 -03:00
Salomão 5a2c2d06d3 make pattern expansion recipe shapeless 2021-06-24 22:34:21 -03:00
Salomão 98d3cafdfd Merge branch 'oredictfixes' into AE2-Omnifactory 2021-06-23 10:19:02 -03:00
Salomão 904de49543 wip
fix substitution crafting, for real this time
wip 2


wip. still has NBT issues


fix semantic changes


fix interface with free slots on interface terminal


Auto stash before cherry pick of "fix interface with free slots on interface terminal"
2021-06-23 10:16:59 -03:00
Salomão b0772bf94c backport 223163aa0a
fixes #32
2021-06-21 22:48:25 -03:00
31 changed files with 879 additions and 437 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ aechannel=stable
aebuild=7 aebuild=7
aegroup=appeng aegroup=appeng
aebasename=appliedenergistics2 aebasename=appliedenergistics2
trousers=omni-fixes-v43 trousers=omni-fixes-v47
######################################################### #########################################################
# Versions # # Versions #
@@ -31,6 +31,9 @@ import net.minecraft.world.World;
import appeng.api.implementations.ICraftingPatternItem; import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import java.util.Collections;
import java.util.List;
/** /**
* do not implement provided by {@link ICraftingPatternItem} * do not implement provided by {@link ICraftingPatternItem}
@@ -84,6 +87,11 @@ public interface ICraftingPatternDetails
*/ */
boolean canSubstitute(); boolean canSubstitute();
default List<IAEItemStack> getSubstituteInputs( int slot )
{
return Collections.emptyList();
}
/** /**
* Allow using this INSTANCE of the pattern details to preform the crafting action with performance enhancements. * Allow using this INSTANCE of the pattern details to preform the crafting action with performance enhancements.
* *
@@ -237,7 +237,11 @@ public class GuiInterfaceTerminal extends AEBaseGui
int interfaceDim = dimHashMap.get( guiButtonHashMap.get( this.selectedButton ) ); int interfaceDim = dimHashMap.get( guiButtonHashMap.get( this.selectedButton ) );
if( playerDim != interfaceDim ) if( playerDim != interfaceDim )
{ {
mc.player.sendStatusMessage( new TextComponentString( "Interface located at dimension: " + interfaceDim + " [" + DimensionManager.getWorld( interfaceDim ).provider.getDimensionType().getName() + "] and cant be highlighted" ), false ); try {
mc.player.sendStatusMessage( new TextComponentString( "Interface located at dimension: " + interfaceDim + " [" + DimensionManager.getWorld( interfaceDim ).provider.getDimensionType().getName() + "] and cant be highlighted" ), false );
} catch(Exception e){
mc.player.sendStatusMessage( new TextComponentString( "Interface is located in another dimension and cannot be highlighted" ), false );
}
} }
else else
{ {
@@ -418,8 +422,12 @@ public class GuiInterfaceTerminal extends AEBaseGui
// Search if the current inventory holds a pattern containing the search term. // Search if the current inventory holds a pattern containing the search term.
if( !found ) if( !found )
{ {
int slot = 0;
for( final ItemStack itemStack : entry.getInventory() ) for( final ItemStack itemStack : entry.getInventory() )
{ {
if (slot > 8 + numUpgradesMap.get(entry) * 9) {
break;
}
if( !searchFieldInputs.isEmpty() && !searchFieldOutputs.isEmpty() ) { if( !searchFieldInputs.isEmpty() && !searchFieldOutputs.isEmpty() ) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0) || this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) { if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0) || this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) {
found = true; found = true;
@@ -441,6 +449,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
// If only Interfaces with empty slots should be shown, check that here // If only Interfaces with empty slots should be shown, check that here
if(itemStack.isEmpty()) if(itemStack.isEmpty())
interfaceHasFreeSlots = true; interfaceHasFreeSlots = true;
slot++;
} }
} }
// if found, filter skipped or machine name matching the search term, add it // if found, filter skipped or machine name matching the search term, add it
@@ -270,12 +270,15 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
@Override @Override
public Rectangle getArea() public Rectangle getArea()
{ {
if( slot instanceof SlotFake ) if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{
return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 ); return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 );
else }
else if( slot instanceof GuiFluidSlot && ( (GuiFluidSlot) slot ).isSlotEnabled() )
{ {
return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 ); return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 );
} }
return new Rectangle();
} }
@Override @Override
@@ -284,7 +287,7 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
PacketInventoryAction p = null; PacketInventoryAction p = null;
try try
{ {
if( slot instanceof SlotFake ) if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{ {
if( finalItemStack.isEmpty() && finalFluidStack != null ) if( finalItemStack.isEmpty() && finalFluidStack != null )
{ {
@@ -10,9 +10,9 @@ import net.minecraft.item.ItemStack;
public abstract class GuiCustomSlot extends Gui implements ITooltip public abstract class GuiCustomSlot extends Gui implements ITooltip
{ {
private final int x; protected final int x;
private final int y; protected final int y;
private final int id; protected final int id;
public GuiCustomSlot( final int id, final int x, final int y ) public GuiCustomSlot( final int id, final int x, final int y )
{ {
@@ -22,9 +22,10 @@ package appeng.client.render;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
@@ -32,6 +33,7 @@ import appeng.api.storage.data.IAEItemStack;
import appeng.util.IWideReadableNumberConverter; import appeng.util.IWideReadableNumberConverter;
import appeng.util.ReadableNumberConverter; import appeng.util.ReadableNumberConverter;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import org.lwjgl.opengl.GL11;
/** /**
@@ -121,6 +123,49 @@ public class TesrRenderHelper
} }
} }
public static void renderFluid2d( FluidStack fluidStack, float scale )
{
if( fluidStack != null )
{
GlStateManager.pushMatrix();
int color = fluidStack.getFluid().getColor( fluidStack );
float r = ( color >> 16 & 255 ) / 255.0f;
float g = ( color >> 8 & 255 ) / 255.0f;
float b = ( color & 255 ) / 255.0f;
TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( fluidStack.getFluid().getStill( fluidStack ).toString() );
GlStateManager.enableBlend();
GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA );
GlStateManager.disableAlpha();
GlStateManager.disableLighting();
Minecraft.getMinecraft().getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
Tessellator tess = Tessellator.getInstance();
BufferBuilder buf = tess.getBuffer();
float width = 0.4f;
float height = 0.4f;
float alpha = 1.0f;
float z = 0.0001f;
float x = -0.20f;
float y = -0.25f;
buf.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR );
double uMin = sprite.getInterpolatedU( 16D - width * 16D ), uMax = sprite.getInterpolatedU( width * 16D );
double vMin = sprite.getMinV(), vMax = sprite.getInterpolatedV( height * 16D );
buf.pos( x, y, z ).tex( uMin, vMin ).color( r, g, b, alpha ).endVertex();
buf.pos( x, y + height, z ).tex( uMin, vMax ).color( r, g, b, alpha ).endVertex();
buf.pos( x + width, y + height, z ).tex( uMax, vMax ).color( r, g, b, alpha ).endVertex();
buf.pos( x + width, y, z ).tex( uMax, vMin ).color( r, g, b, alpha ).endVertex();
tess.draw();
GlStateManager.enableLighting();
GlStateManager.enableAlpha();
GlStateManager.disableBlend();
GlStateManager.color( 1F, 1F, 1F, 1F );
GlStateManager.popMatrix();
}
}
/** /**
* Render an item in 2D and the given text below it. * Render an item in 2D and the given text below it.
* *
@@ -147,9 +192,9 @@ public class TesrRenderHelper
public static void renderFluid2dWithAmount( IAEFluidStack fluidStack, float scale, float spacing ) public static void renderFluid2dWithAmount( IAEFluidStack fluidStack, float scale, float spacing )
{ {
final ItemStack renderStack = fluidStack.asItemStackRepresentation(); final FluidStack renderStack = fluidStack.getFluidStack();
TesrRenderHelper.renderItem2d( renderStack, scale ); TesrRenderHelper.renderFluid2d( renderStack, scale );
final long stackSize = fluidStack.getStackSize() / 1000; final long stackSize = fluidStack.getStackSize() / 1000;
final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B"; final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B";
@@ -245,7 +245,10 @@ public class PacketJEIRecipe extends AppEngPacket
if( out != null ) if( out != null )
{ {
out.setStackSize( recipe[x][y].getCount() ); if (!cct.useRealItems())
{
out.setStackSize( recipe[x][y].getCount() );
}
currentItem = out.createItemStack(); currentItem = out.createItemStack();
} }
} }
@@ -19,6 +19,7 @@
package appeng.core.sync.packets; package appeng.core.sync.packets;
import appeng.fluids.container.ContainerFluidInterface;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -90,5 +91,9 @@ public class PacketTargetFluidStack extends AppEngPacket
{ {
( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack ); ( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack );
} }
else if( player.openContainer instanceof ContainerFluidInterface )
{
( (ContainerFluidInterface) player.openContainer ).setTargetStack( this.stack );
}
} }
} }
+72 -3
View File
@@ -59,6 +59,7 @@ public class CraftingJob implements Runnable, ICraftingJob
private final IItemList<IAEItemStack> missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList<IAEItemStack> missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final HashMap<String, TwoIntegers> opsAndMultiplier = new HashMap<>(); private final HashMap<String, TwoIntegers> opsAndMultiplier = new HashMap<>();
private final Object monitor = new Object(); private final Object monitor = new Object();
private final Stopwatch watch = Stopwatch.createUnstarted();
private CraftingTreeNode tree; private CraftingTreeNode tree;
private final IAEItemStack output; private final IAEItemStack output;
private boolean simulate = false; private boolean simulate = false;
@@ -66,7 +67,10 @@ public class CraftingJob implements Runnable, ICraftingJob
private long bytes = 0; private long bytes = 0;
private final IActionSource actionSrc; private final IActionSource actionSrc;
private final ICraftingCallback callback; private final ICraftingCallback callback;
private boolean running = false;
private boolean done = false; private boolean done = false;
private int time;
private int incTime;
private World wrapWorld( final World w ) private World wrapWorld( final World w )
{ {
@@ -133,6 +137,7 @@ public class CraftingJob implements Runnable, ICraftingJob
try try
{ {
TickHandler.INSTANCE.registerCraftingSimulation( this.world, this ); TickHandler.INSTANCE.registerCraftingSimulation( this.world, this );
this.handlePausing();
final Stopwatch timer = Stopwatch.createStarted(); final Stopwatch timer = Stopwatch.createStarted();
@@ -214,6 +219,41 @@ public class CraftingJob implements Runnable, ICraftingJob
this.finish(); this.finish();
} }
void handlePausing() throws InterruptedException
{
if( !this.actionSrc.player().isPresent() && this.incTime > 100 )
{
this.incTime = 0;
synchronized ( this.monitor )
{
if( this.watch.elapsed( TimeUnit.MICROSECONDS ) > this.time )
{
this.running = false;
this.watch.stop();
this.monitor.notify();
}
if( !this.running )
{
AELog.craftingDebug( "crafting job will now sleep" );
while ( !this.running )
{
this.monitor.wait();
}
AELog.craftingDebug( "crafting job now active" );
}
}
if( Thread.interrupted() )
{
throw new InterruptedException();
}
}
this.incTime++;
}
private void finish() private void finish()
{ {
if( this.callback != null ) if( this.callback != null )
@@ -225,6 +265,7 @@ public class CraftingJob implements Runnable, ICraftingJob
synchronized( this.monitor ) synchronized( this.monitor )
{ {
this.running = false;
this.done = true; this.done = true;
this.monitor.notify(); this.monitor.notify();
} }
@@ -270,13 +311,41 @@ public class CraftingJob implements Runnable, ICraftingJob
/** /**
* @return true if this needs more simulation * @return true if this needs more simulation
*/ */
public boolean simulateFor() public boolean simulateFor(final int milli)
{ {
synchronized( this.monitor ) { this.time = milli;
if ( this.done ) {
synchronized ( this.monitor )
{
if( this.done )
{
return false; return false;
} }
if( !this.actionSrc.player().isPresent() )
{
this.watch.reset();
this.watch.start();
this.running = true;
AELog.craftingDebug( "main thread is now going to sleep" );
this.monitor.notify();
while ( this.running )
{
try
{
this.monitor.wait();
}
catch( final InterruptedException ignored )
{
}
}
AELog.craftingDebug( "main thread is now active" );
}
} }
return true; return true;
} }
@@ -119,7 +119,7 @@ public class CraftingTreeNode
IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing();
final List<IAEItemStack> thingsUsed = new ArrayList<>(); final List<IAEItemStack> thingsUsed = new ArrayList<>();
this.what.setStackSize( l ); this.what.setStackSize( l );
@@ -130,7 +130,12 @@ public class CraftingTreeNode
if( this.parent.details.canSubstitute() ) if( this.parent.details.canSubstitute() )
{ {
itemList = inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL ); final List<IAEItemStack> substitutes = this.parent.details.getSubstituteInputs(this.slot);
itemList = new ArrayList<>(substitutes.size());
for (IAEItemStack stack : substitutes) {
itemList.addAll(inventoryList.findFuzzy(stack, FuzzyMode.IGNORE_ALL));
}
} }
else else
{ {
@@ -185,7 +185,7 @@ public class CraftingTreeProcess
void request( final MECraftingInventory inv, final long i, final IActionSource src ) throws CraftBranchFailure, InterruptedException void request( final MECraftingInventory inv, final long i, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing();
if( this.fullSimulation ) if( this.fullSimulation )
{ {
final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
@@ -21,6 +21,9 @@ package appeng.fluids.client.gui;
import java.io.IOException; import java.io.IOException;
import appeng.api.util.IConfigManager;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.util.IConfigManagerHost;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -38,11 +41,12 @@ import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
public class GuiFluidInterface extends GuiUpgradeable public class GuiFluidInterface extends GuiUpgradeable implements IConfigManagerHost
{ {
public final static int ID_BUTTON_TANK = 222; public final static int ID_BUTTON_TANK = 222;
private final IFluidInterfaceHost host; private final IFluidInterfaceHost host;
private final ContainerFluidInterface container;
private GuiTabButton priority; private GuiTabButton priority;
public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te ) public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
@@ -50,6 +54,8 @@ public class GuiFluidInterface extends GuiUpgradeable
super( new ContainerFluidInterface( ip, te ) ); super( new ContainerFluidInterface( ip, te ) );
this.ySize = 231; this.ySize = 231;
this.host = te; this.host = te;
( this.container = (ContainerFluidInterface) this.inventorySlots ).setGui( this );
} }
@Override @Override
@@ -62,9 +68,7 @@ public class GuiFluidInterface extends GuiUpgradeable
for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i ) for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i )
{ {
final GuiFluidTank guiTank = new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, this.getGuiLeft() + 35 + 18 * i, this this.guiSlots.add( new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, 36 + 18 * i, 53, 16, 68 ) );
.getGuiTop() + 53, 16, 68 );
this.buttonList.add( guiTank );
this.guiSlots.add( new GuiFluidSlot( configFluids, i, i, 35 + 18 * i, 35 ) ); this.guiSlots.add( new GuiFluidSlot( configFluids, i, i, 35 + 18 * i, 35 ) );
} }
@@ -104,9 +108,33 @@ public class GuiFluidInterface extends GuiUpgradeable
} }
} }
@Override
protected void mouseClicked( int xCoord, int yCoord, int btn ) throws IOException
{
for( GuiCustomSlot slot : this.guiSlots )
{
if( slot instanceof GuiFluidTank )
{
if( this.isPointInRegion( slot.xPos(), slot.yPos(), slot.getWidth(), slot.getHeight(), xCoord, yCoord ) && slot.canClick( this.mc.player ) )
{
this.container.setTargetStack( ( (GuiFluidTank) slot ).getFluidStack() );
slot.slotClicked( this.mc.player.inventory.getItemStack(), btn );
return;
}
}
}
super.mouseClicked( xCoord, yCoord, btn );
}
@Override @Override
protected boolean drawUpgrades() protected boolean drawUpgrades()
{ {
return false; return false;
} }
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
}
} }
@@ -19,42 +19,50 @@
package appeng.fluids.client.gui.widgets; package appeng.fluids.client.gui.widgets;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.helpers.InventoryAction;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.util.AEColor;
import appeng.client.gui.widgets.ITooltip; import appeng.client.gui.widgets.ITooltip;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
public class GuiFluidTank extends GuiButton implements ITooltip public class GuiFluidTank extends GuiCustomSlot implements ITooltip
{ {
private final IAEFluidTank tank; private final IAEFluidTank tank;
private final int slot; private final int slot;
private final int width;
private final int height;
public GuiFluidTank( IAEFluidTank tank, int slot, int id, int x, int y, int w, int h ) public GuiFluidTank( IAEFluidTank tank, int slot, int id, int x, int y, int w, int h )
{ {
super( id, x, y, w, h, "" ); super( id, x, y );
this.tank = tank; this.tank = tank;
this.slot = slot; this.slot = slot;
this.width = w;
this.height = h;
} }
@Override @Override
public void drawButton( final Minecraft mc, final int mouseX, final int mouseY, final float partialTicks ) public void drawContent( Minecraft mc, int mouseX, int mouseY, float partialTicks )
{ {
if( this.visible ) final IAEFluidStack fs = this.getFluidStack();
if( fs != null )
{ {
GlStateManager.disableBlend(); GlStateManager.disableBlend();
GlStateManager.disableLighting(); GlStateManager.disableLighting();
drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 ); //drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 );
final IAEFluidStack fluid = this.tank.getFluidInSlot( this.slot ); final IAEFluidStack fluid = this.tank.getFluidInSlot( this.slot );
if( fluid != null && fluid.getStackSize() > 0 ) if( fluid != null && fluid.getStackSize() > 0 )
@@ -69,17 +77,16 @@ public class GuiFluidTank extends GuiButton implements ITooltip
TextureAtlasSprite sprite = mc.getTextureMapBlocks().getAtlasSprite( fluid.getFluid().getStill().toString() ); TextureAtlasSprite sprite = mc.getTextureMapBlocks().getAtlasSprite( fluid.getFluid().getStill().toString() );
final int scaledHeight = (int) ( this.height * ( (float) fluid.getStackSize() / this.tank.getTankProperties()[this.slot].getCapacity() ) ); final int scaledHeight = (int) ( this.height * ( (float) fluid.getStackSize() / this.tank.getTankProperties()[this.slot].getCapacity() ) );
int iconHeightRemainder = scaledHeight % 16; int iconHeightRemainder = scaledHeight % this.getHeight();
if( iconHeightRemainder > 0 ) if( iconHeightRemainder > 0 )
{ {
this.drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder, sprite, 16, iconHeightRemainder ); this.drawTexturedModalRect( this.xPos(), this.yPos() + this.getHeight() - iconHeightRemainder, sprite, this.getWidth(), iconHeightRemainder );
} }
for( int i = 0; i < scaledHeight / 16; i++ ) for( int i = 0; i < scaledHeight / this.getHeight(); i++ )
{ {
this.drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder - ( i + 1 ) * 16, sprite, 16, 16 ); this.drawTexturedModalRect( this.xPos(), this.yPos() + this.getHeight() - iconHeightRemainder - ( i + 1 ) * 16, sprite, this.getWidth(), this.getHeight() );
} }
} }
} }
} }
@@ -100,25 +107,25 @@ public class GuiFluidTank extends GuiButton implements ITooltip
@Override @Override
public int xPos() public int xPos()
{ {
return this.x - 2; return this.x - 1;
} }
@Override @Override
public int yPos() public int yPos()
{ {
return this.y - 2; return this.y - 1;
} }
@Override @Override
public int getWidth() public int getWidth()
{ {
return this.width + 4; return this.width;
} }
@Override @Override
public int getHeight() public int getHeight()
{ {
return this.height + 4; return this.height + 1;
} }
@Override @Override
@@ -127,4 +134,24 @@ public class GuiFluidTank extends GuiButton implements ITooltip
return true; return true;
} }
public IAEFluidStack getFluidStack()
{
return this.tank.getFluidInSlot( this.slot );
}
@Override
public void slotClicked( ItemStack clickStack, final int mouseButton )
{
if( getFluidStack() != null )
{
NetworkHandler.instance().sendToServer( new PacketInventoryAction( InventoryAction.FILL_ITEM, slot, 0 ) );
}
else
{
NetworkHandler.instance().sendToServer( new PacketInventoryAction( InventoryAction.EMPTY_ITEM, slot, 0 ) );
}
}
} }
@@ -19,9 +19,17 @@
package appeng.fluids.container; package appeng.fluids.container;
import javax.annotation.Nonnull;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketTargetFluidStack;
import appeng.fluids.util.AEFluidStack;
import appeng.helpers.InventoryAction;
import appeng.util.IConfigManagerHost;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IContainerListener; import net.minecraft.inventory.IContainerListener;
@@ -33,12 +41,19 @@ import appeng.fluids.helper.FluidSyncHelper;
import appeng.fluids.helper.IFluidInterfaceHost; import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform; import appeng.util.Platform;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
public class ContainerFluidInterface extends ContainerFluidConfigurable public class ContainerFluidInterface extends ContainerFluidConfigurable implements IConfigManagerHost
{ {
private final DualityFluidInterface myDuality; private final DualityFluidInterface myDuality;
private final FluidSyncHelper tankSync; private final FluidSyncHelper tankSync;
private IConfigManagerHost gui;
// Holds the fluid the client wishes to extract, or null for insert
private IAEFluidStack clientRequestedTargetFluid = null;
public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te ) public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
{ {
@@ -60,6 +75,15 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
return this.myDuality.getConfig(); return this.myDuality.getConfig();
} }
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
if( this.getGui() != null )
{
this.getGui().updateSetting( manager, settingName, newValue );
}
}
@Override @Override
public void detectAndSendChanges() public void detectAndSendChanges()
{ {
@@ -97,6 +121,126 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
this.tankSync.readPacket( fluids ); this.tankSync.readPacket( fluids );
} }
private IConfigManagerHost getGui()
{
return this.gui;
}
public void setGui( @Nonnull final IConfigManagerHost gui )
{
this.gui = gui;
}
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id )
{
if( action != InventoryAction.FILL_ITEM && action != InventoryAction.EMPTY_ITEM )
{
super.doAction( player, action, slot, id );
return;
}
final ItemStack held = player.inventory.getItemStack();
ItemStack heldCopy = held.copy();
heldCopy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
if( fh == null )
{
// only fluid handlers items
return;
}
if( action == InventoryAction.FILL_ITEM && this.clientRequestedTargetFluid != null )
{
final IAEFluidStack stack = this.clientRequestedTargetFluid.copy();
// Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false );
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
FluidStack extractableFluid = this.myDuality.getTanks().drain( stack.setStackSize( amountAllowed ).getFluidStack(), false );
if( extractableFluid == null || extractableFluid.amount == 0 )
{
break;
}
int fillableAmount = fh.fill( extractableFluid, false );
if( fillableAmount > 0 )
{
FluidStack extractedFluid = this.myDuality.getTanks().drain( extractableFluid, true );
fh.fill( extractedFluid, true );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
}
else if( action == InventoryAction.EMPTY_ITEM )
{
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
FluidStack drainable = fh.drain( this.myDuality.getTanks().getTankProperties()[slot].getCapacity(), false );
if( drainable != null )
{
fh.drain( drainable, true );
this.myDuality.getTanks().fill( drainable, true );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
}
this.updateHeld( player );
}
public void setTargetStack( final IAEFluidStack stack )
{
if( Platform.isClient() )
{
if( stack == null && this.clientRequestedTargetFluid == null )
{
return;
}
if( stack != null && this.clientRequestedTargetFluid != null && stack.getFluidStack().isFluidEqual( this.clientRequestedTargetFluid.getFluidStack() ) )
{
return;
}
NetworkHandler.instance().sendToServer( new PacketTargetFluidStack( (AEFluidStack) stack ) );
}
this.clientRequestedTargetFluid = stack == null ? null : stack.copy();
}
@Override @Override
protected boolean supportCapacity() protected boolean supportCapacity()
{ {
@@ -24,6 +24,9 @@ import java.nio.BufferOverflowException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.SlotPlayerHotBar;
import appeng.container.slot.SlotPlayerInv;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -70,6 +73,7 @@ import appeng.me.helpers.ChannelPowerSrc;
import appeng.util.ConfigManager; import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost; import appeng.util.IConfigManagerHost;
import appeng.util.Platform; import appeng.util.Platform;
import net.minecraftforge.items.IItemHandler;
/** /**
@@ -342,6 +346,89 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
} }
} }
@Override
public ItemStack transferStackInSlot( final EntityPlayer p, final int idx )
{
if( Platform.isClient() )
{
return ItemStack.EMPTY;
}
EntityPlayerMP player = (EntityPlayerMP) p;
if( this.inventorySlots.get( idx ) instanceof SlotPlayerInv || this.inventorySlots.get( idx ) instanceof SlotPlayerHotBar )
{
final AppEngSlot clickSlot = (AppEngSlot) this.inventorySlots.get( idx ); // require AE SLots!
ItemStack itemStack = clickSlot.getStack();
ItemStack copy = itemStack.copy();
copy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( copy );
if( fh == null )
{
// only fluid handlers items
return ItemStack.EMPTY;
}
int heldAmount = itemStack.getCount();
for( int i = 0; i < heldAmount; i++ )
{
copy = itemStack.copy();
copy.setCount( 1 );
fh = FluidUtil.getFluidHandler( copy );
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return ItemStack.EMPTY;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{
return ItemStack.EMPTY;
}
else
{
extract.amount = storable.amount;
}
}
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() );
if( spill != null && spill.getStackSize() > 0 )
{
fh.fill( spill.getFluidStack(), true );
}
}
if( notInserted == null )
{
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
clickSlot.decrStackSize( 1 );
}
}
this.detectAndSendChanges();
return ItemStack.EMPTY;
}
return super.transferStackInSlot( p, idx );
}
@Override @Override
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id ) public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id )
{ {
@@ -352,13 +439,9 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
} }
final ItemStack held = player.inventory.getItemStack(); final ItemStack held = player.inventory.getItemStack();
if( held.getCount() != 1 ) ItemStack heldCopy = held.copy();
{ heldCopy.setCount( 1 );
// only support stacksize 1 for now IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
return;
}
final IFluidHandlerItem fh = FluidUtil.getFluidHandler( held );
if( fh == null ) if( fh == null )
{ {
// only fluid handlers items // only fluid handlers items
@@ -372,88 +455,122 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
// Check how much we can store in the item // Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE ); stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false ); int amountAllowed = fh.fill( stack.getFluidStack(), false );
stack.setStackSize( amountAllowed ); int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
// Check if we can pull out of the system
final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack, this.getActionSource(), Actionable.SIMULATE );
if( canPull == null || canPull.getStackSize() < 1 )
{ {
return; ItemStack copiedFluidContainer = held.copy();
} copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
// How much could fit into the container // Check if we can pull out of the system
final int canFill = fh.fill( canPull.getFluidStack(), false ); final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( amountAllowed ), this.getActionSource(), Actionable.SIMULATE );
if( canFill == 0 ) if( canPull == null || canPull.getStackSize() < 1 )
{
return;
}
// Now actually pull out of the system
stack.setStackSize( canFill );
final IAEFluidStack pulled = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack, this.getActionSource() );
if( pulled == null || pulled.getStackSize() < 1 )
{
// Something went wrong
AELog.error( "Unable to pull fluid out of the ME system even though the simulation said yes " );
return;
}
// Actually fill
final int used = fh.fill( pulled.getFluidStack(), true );
if( used != canFill )
{
AELog.error( "Fluid item [%s] reported a different possible amount than it actually accepted.", held.getDisplayName() );
}
player.inventory.setItemStack( fh.getContainer() );
this.updateHeld( player );
}
else if( action == InventoryAction.EMPTY_ITEM )
{
// See how much we can drain from the item
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ),
this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{ {
return; return;
} }
// How much could fit into the container
final int canFill = fh.fill( canPull.getFluidStack(), false );
if( canFill == 0 )
{
return;
}
// Now actually pull out of the system
final IAEFluidStack pulled = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( canFill ), this.getActionSource() );
if( pulled == null || pulled.getStackSize() < 1 )
{
// Something went wrong
AELog.error( "Unable to pull fluid out of the ME system even though the simulation said yes " );
return;
}
// Actually fill
final int used = fh.fill( pulled.getFluidStack(), true );
if( used != canFill )
{
AELog.error( "Fluid item [%s] reported a different possible amount than it actually accepted.", held.getDisplayName() );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else else
{ {
extract.amount = storable.amount; player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
} }
} }
this.updateHeld( player );
// Actually drain }
final FluidStack drained = fh.drain( extract, true ); else if( action == InventoryAction.EMPTY_ITEM )
extract.amount = drained.amount; {
int heldAmount = held.getCount();
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), for( int i = 0; i < heldAmount; i++ )
this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{ {
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() ); ItemStack copiedFluidContainer = held.copy();
if( spill != null && spill.getStackSize() > 0 ) copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
// See how much we can drain from the item
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{ {
fh.fill( spill.getFluidStack(), true ); return;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{
return;
}
else
{
extract.amount = storable.amount;
}
}
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() );
if( spill != null && spill.getStackSize() > 0 )
{
fh.fill( spill.getFluidStack(), true );
}
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
} }
} }
player.inventory.setItemStack( fh.getContainer() );
this.updateHeld( player ); this.updateHeld( player );
} }
} }
@@ -608,14 +608,14 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
List<ItemStack> dropList = new ArrayList<>(); List<ItemStack> dropList = new ArrayList<>();
for( int invSlot = 0; invSlot < patterns.getSlots(); invSlot++ ) for( int invSlot = 0; invSlot < patterns.getSlots(); invSlot++ )
{ {
if( invSlot >= 9 + ( this.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION ) ) * 9 ) if( invSlot > 8 + this.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION ) * 9 )
{ {
ItemStack is = patterns.getStackInSlot( invSlot ); ItemStack is = patterns.getStackInSlot( invSlot );
if( is.isEmpty() ) continue; if( is.isEmpty() ) continue;
dropList.add( patterns.extractItem( invSlot, Integer.MAX_VALUE, false ) ); dropList.add( patterns.extractItem( invSlot, Integer.MAX_VALUE, false ) );
} }
} }
if( dropList.size() > 1 ) if( dropList.size() > 0 )
{ {
World world = this.getLocation().getWorld(); World world = this.getLocation().getWorld();
BlockPos blockPos = this.getLocation().getPos(); BlockPos blockPos = this.getLocation().getPos();
+114 -46
View File
@@ -19,21 +19,18 @@
package appeng.helpers; package appeng.helpers;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap; import java.util.stream.Collectors;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import net.minecraft.inventory.InventoryCrafting; import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World; import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -46,11 +43,17 @@ import appeng.core.AELog;
import appeng.core.features.AEFeature; import appeng.core.features.AEFeature;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import net.minecraftforge.common.crafting.IShapedRecipe;
public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper> public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper>
{ {
private static final int CRAFTING_GRID_DIMENSION = 3;
private static final int ALL_INPUT_LIMIT = CRAFTING_GRID_DIMENSION * CRAFTING_GRID_DIMENSION;
private static final int CRAFTING_OUTPUT_LIMIT = 1;
private static final int PROCESSING_OUTPUT_LIMIT = 3;
private final ItemStack patternItem; private final ItemStack patternItem;
private final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 ); private final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 );
private final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 ); private final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 );
@@ -60,6 +63,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
private final IAEItemStack[] condensedOutputs; private final IAEItemStack[] condensedOutputs;
private final IAEItemStack[] inputs; private final IAEItemStack[] inputs;
private final IAEItemStack[] outputs; private final IAEItemStack[] outputs;
private final Map<Integer, List<IAEItemStack>> substituteInputs;
private final boolean isCrafting; private final boolean isCrafting;
private final boolean canSubstitute; private final boolean canSubstitute;
private final Set<TestLookup> failCache = new HashSet<>(); private final Set<TestLookup> failCache = new HashSet<>();
@@ -143,9 +147,11 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
} }
} }
} }
final int outputLength = out.size();
this.outputs = out.toArray( new IAEItemStack[out.size()] ); this.inputs = in.toArray(new IAEItemStack[ALL_INPUT_LIMIT]);
this.inputs = in.toArray( new IAEItemStack[in.size()] ); this.outputs = out.toArray(new IAEItemStack[outputLength]);
this.substituteInputs = new HashMap<>(ALL_INPUT_LIMIT);
final Map<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>(); final Map<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>();
@@ -257,6 +263,14 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
this.testFrame.setInventorySlotContents( slotIndex, i ); this.testFrame.setInventorySlotContents( slotIndex, i );
// If we cannot substitute, the items must match exactly
if (!canSubstitute && slotIndex < inputs.length) {
if (!inputs[slotIndex].isSameType(i)) {
this.markItemAs(slotIndex, i, TestStatus.DECLINE);
return false;
}
}
if( this.standardRecipe.matches( this.testFrame, w ) ) if( this.standardRecipe.matches( this.testFrame, w ) )
{ {
final ItemStack testOutput = this.standardRecipe.getCraftingResult( this.testFrame ); final ItemStack testOutput = this.standardRecipe.getCraftingResult( this.testFrame );
@@ -268,25 +282,6 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return true; return true;
} }
} }
else if( AEConfig.instance().isFeatureEnabled( AEFeature.CRAFTING_MANAGER_FALLBACK ) )
{
final ItemStack testOutput = CraftingManager.findMatchingResult( this.testFrame, w );
if( Platform.itemComparisons().isSameItem( this.correctOutput, testOutput ) )
{
this.testFrame.setInventorySlotContents( slotIndex, this.crafting.getStackInSlot( slotIndex ) );
this.markItemAs( slotIndex, i, TestStatus.ACCEPT );
if( AELog.isCraftingDebugLogEnabled() )
{
this.warnAboutCraftingManager( true );
}
return true;
}
this.warnAboutCraftingManager( false );
}
this.markItemAs( slotIndex, i, TestStatus.DECLINE ); this.markItemAs( slotIndex, i, TestStatus.DECLINE );
return false; return false;
@@ -328,6 +323,97 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return this.canSubstitute; return this.canSubstitute;
} }
@Override
public List<IAEItemStack> getSubstituteInputs(int slot) {
if (this.inputs[slot] == null) {
return Collections.emptyList();
}
return this.substituteInputs.computeIfAbsent(slot, value -> {
ItemStack[] matchingStacks = getRecipeIngredient(slot).getMatchingStacks();
List<IAEItemStack> itemList = new ArrayList<>(matchingStacks.length + 1);
for (ItemStack matchingStack : matchingStacks) {
itemList.add(AEItemStack.fromItemStack(matchingStack));
}
// Ensure that the specific item put in by the user is at the beginning,
// so that it takes precedence over substitutions
itemList.add(0, this.inputs[slot]);
return itemList;
});
}
/**
* Gets the {@link Ingredient} from the actual used recipe for a given slot-index into {@link #getInputs()}.
* <p/>
* Conversion is needed for two reasons: our sparse ingredients are always organized in a 3x3 grid, while Vanilla's
* ingredient list will be condensed to the actual recipe's grid size. In addition, in our 3x3 grid, the user can
* shift the actual recipe input to the right and down.
*/
private Ingredient getRecipeIngredient(int slot) {
if (standardRecipe instanceof IShapedRecipe ) {
IShapedRecipe shapedRecipe = (IShapedRecipe) standardRecipe;
return getShapedRecipeIngredient(slot, shapedRecipe.getRecipeWidth());
} else {
return getShapelessRecipeIngredient(slot);
}
}
private Ingredient getShapedRecipeIngredient(int slot, int recipeWidth) {
// Compute the offset of the user's input vs. crafting grid origin
// Which is >0 if they have empty rows above or to the left of their input
int topOffset = 0;
if (inputs[0] == null && inputs[1] == null && inputs[2] == null) {
topOffset++; // First row is fully empty
if (inputs[3] == null && inputs[4] == null && inputs[5] == null) {
topOffset++; // Second row is fully empty
}
}
int leftOffset = 0;
if (inputs[0] == null && inputs[3] == null && inputs[6] == null) {
leftOffset++; // First column is fully empty
if (inputs[1] == null && inputs[4] == null && inputs[7] == null) {
leftOffset++; // Second column is fully empty
}
}
// Compute the x,y of the slot, as-if the recipe was anchored to 0,0
int slotX = slot % CRAFTING_GRID_DIMENSION - leftOffset;
int slotY = slot / CRAFTING_GRID_DIMENSION - topOffset;
// Compute the index into the recipe's ingredient list now
int ingredientIndex = slotY * recipeWidth + slotX;
NonNullList<Ingredient> ingredients = standardRecipe.getIngredients();
if (ingredientIndex < 0 || ingredientIndex > ingredients.size()) {
return Ingredient.EMPTY;
}
return ingredients.get(ingredientIndex);
}
private Ingredient getShapelessRecipeIngredient(int slot) {
// We map the list of *filled* sparse inputs to the shapeless (ergo unordered)
// ingredients. While these do not actually correspond to each other,
// since both lists have the same length, the mapping is at least stable.
int ingredientIndex = 0;
for (int i = 0; i < slot; i++) {
if (inputs[i] != null) {
ingredientIndex++;
}
}
NonNullList<Ingredient> ingredients = standardRecipe.getIngredients();
if (ingredientIndex < ingredients.size()) {
return ingredients.get(ingredientIndex);
}
return Ingredient.EMPTY;
}
@Override @Override
public ItemStack getOutput( final InventoryCrafting craftingInv, final World w ) public ItemStack getOutput( final InventoryCrafting craftingInv, final World w )
{ {
@@ -406,24 +492,6 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return this.pattern.hashCode(); return this.pattern.hashCode();
} }
private void warnAboutCraftingManager( boolean foundAlternative )
{
final String foundAlternativeRecipe = foundAlternative ? "Found alternative recipe." : "NOT FOUND, please report.";
final StringJoiner joinActualInputs = new StringJoiner( ", " );
for( int j = 0; j < this.testFrame.getSizeInventory(); j++ )
{
final ItemStack stack = this.testFrame.getStackInSlot( j );
if( !stack.isEmpty() )
{
joinActualInputs.add( stack.toString() );
}
}
AELog.warn( "Using CraftingManager fallback: Recipe <%s> for output <%s> rejected inputs [%s]. %s",
this.standardRecipe.getRegistryName(), this.standardRecipe.getRecipeOutput(), joinActualInputs, foundAlternativeRecipe );
}
@Override @Override
public boolean equals( final Object obj ) public boolean equals( final Object obj )
{ {
+7 -12
View File
@@ -187,20 +187,15 @@ public class TickHandler
if( ev.type == Type.WORLD && ev.phase == Phase.END ) if( ev.type == Type.WORLD && ev.phase == Phase.END )
{ {
final WorldTickEvent wte = (WorldTickEvent) ev; final WorldTickEvent wte = (WorldTickEvent) ev;
synchronized( this.craftingJobs ) synchronized ( this.craftingJobs )
{ {
final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world ); final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world );
if( !jobSet.isEmpty() ) if (!jobSet.isEmpty()) {
{ final int jobSize = jobSet.size();
final Iterator<CraftingJob> i = jobSet.iterator(); final int microSecondsPerTick = AEConfig.instance().getCraftingCalculationTimePerTick() * 1000;
while( i.hasNext() ) final int simTime = Math.max(1, microSecondsPerTick / jobSize);
{
final CraftingJob cj = i.next(); jobSet.removeIf( cj -> !cj.simulateFor( simTime ) );
if( !cj.simulateFor() )
{
i.remove();
}
}
} }
} }
} }
@@ -147,8 +147,12 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
} }
// prefer pure crystals. // prefer pure crystals.
for( ItemStack stack : ingredient.getAllIngredients() ) for ( ItemStack stack : ingredient.getAllIngredients() )
{ {
if( stack == null )
{
continue;
}
if( Platform.isRecipePrioritized( stack ) ) if( Platform.isRecipePrioritized( stack ) )
{ {
list.add( 0, stack ); list.add( 0, stack );
@@ -159,7 +163,7 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
} }
} }
for( final ItemStack is : list ) for ( final ItemStack is : list )
{ {
final NBTTagCompound tag = new NBTTagCompound(); final NBTTagCompound tag = new NBTTagCompound();
is.writeToNBT( tag ); is.writeToNBT( tag );
+25 -155
View File
@@ -30,7 +30,6 @@ import java.util.PriorityQueue;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultiset; import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset; import com.google.common.collect.Multiset;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@@ -64,9 +63,8 @@ import appeng.me.energy.EnergyWatcher;
public class EnergyGridCache implements IEnergyGrid public class EnergyGridCache implements IEnergyGrid
{ {
private static final double MAX_BUFFER_STORAGE = 800; private static final double MAX_BUFFER_STORAGE = 200;
private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = ( o1, o2 ) -> Double.compare( o2.getProviderStoredEnergy(), private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = ( o1, o2 ) -> Double.compare( o2.getProviderStoredEnergy(), o1.getProviderStoredEnergy() );
o1.getProviderStoredEnergy() );
private static final Comparator<IEnergyGridProvider> COMPARATOR_LOWEST_PERCENTAGE_FIRST = ( o1, o2 ) -> private static final Comparator<IEnergyGridProvider> COMPARATOR_LOWEST_PERCENTAGE_FIRST = ( o1, o2 ) ->
{ {
@@ -77,24 +75,9 @@ public class EnergyGridCache implements IEnergyGrid
}; };
private final NavigableSet<EnergyThreshold> interests = Sets.newTreeSet(); private final NavigableSet<EnergyThreshold> interests = Sets.newTreeSet();
// Should only be modified from the add/remove methods below to guard against
// concurrent modifications
private final double averageLength = 40.0; private final double averageLength = 40.0;
private final Set<IAEPowerStorage> providers = new LinkedHashSet<>(); private final Set<IAEPowerStorage> providers = new LinkedHashSet<>();
// Used to track whether an extraction is currently in progress, to fail fast
// when something externally
// modifies the energy grid.
private boolean ongoingExtractOperation = false;
// Should only be modified from the add/remove methods below to guard against
// concurrent modifications
private final Set<IAEPowerStorage> requesters = new LinkedHashSet<>(); private final Set<IAEPowerStorage> requesters = new LinkedHashSet<>();
// Used to track whether an injection is currently in progress, to fail fast
// when something externally
// modifies the energy grid.
private boolean ongoingInjectOperation = false;
private final Multiset<IEnergyGridProvider> energyGridProviders = HashMultiset.create(); private final Multiset<IEnergyGridProvider> energyGridProviders = HashMultiset.create();
private final IGrid myGrid; private final IGrid myGrid;
private final HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<>(); private final HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<>();
@@ -126,10 +109,6 @@ public class EnergyGridCache implements IEnergyGrid
private double lastStoredPower = -1; private double lastStoredPower = -1;
private final GridPowerStorage localStorage = new GridPowerStorage(); private final GridPowerStorage localStorage = new GridPowerStorage();
private Set<IAEPowerStorage> providerToRemove = new HashSet<>();
private Set<IAEPowerStorage> requesterToRemove = new HashSet<>();
private Set<IAEPowerStorage> providersToAdd = new HashSet<>();
private Set<IAEPowerStorage> requesterToAdd = new HashSet<>();
public EnergyGridCache( final IGrid g ) public EnergyGridCache( final IGrid g )
{ {
@@ -168,27 +147,13 @@ public class EnergyGridCache implements IEnergyGrid
case PROVIDE_POWER: case PROVIDE_POWER:
if( ev.storage.getPowerFlow() != AccessRestriction.WRITE ) if( ev.storage.getPowerFlow() != AccessRestriction.WRITE )
{ {
if( !ongoingExtractOperation ) this.providers.add( ev.storage );
{
addProvider( ev.storage );
}
else
{
this.providersToAdd.add( ev.storage );
}
} }
break; break;
case REQUEST_POWER: case REQUEST_POWER:
if( ev.storage.getPowerFlow() != AccessRestriction.READ ) if( ev.storage.getPowerFlow() != AccessRestriction.READ )
{ {
if( !ongoingInjectOperation ) this.requesters.add( ev.storage );
{
addRequester( ev.storage );
}
else
{
this.requesterToAdd.add( ev.storage );
}
} }
break; break;
} }
@@ -202,23 +167,6 @@ public class EnergyGridCache implements IEnergyGrid
@Override @Override
public void onUpdateTick() public void onUpdateTick()
{ {
if (!providerToRemove.isEmpty() && !ongoingExtractOperation) {
this.providers.removeIf( p -> providerToRemove.contains( p ) );
providerToRemove.clear();
}
if (!requesterToRemove.isEmpty() && !ongoingInjectOperation) {
this.requesters.removeIf( r -> providerToRemove.contains( r ) );
requesterToRemove.clear();
}
if (!providersToAdd.isEmpty() && !ongoingExtractOperation) {
this.providers.addAll(providersToAdd);
providersToAdd.clear();
}
if( !requesterToAdd.isEmpty() && !ongoingInjectOperation){
this.requesters.addAll(requesterToAdd);
requesterToAdd.clear();
}
if( !this.interests.isEmpty() ) if( !this.interests.isEmpty() )
{ {
final double oldPower = this.lastStoredPower; final double oldPower = this.lastStoredPower;
@@ -354,30 +302,18 @@ public class EnergyGridCache implements IEnergyGrid
final Iterator<IAEPowerStorage> it = this.providers.iterator(); final Iterator<IAEPowerStorage> it = this.providers.iterator();
ongoingExtractOperation = true; while ( extractedPower < amt && it.hasNext() )
try
{ {
while ( extractedPower < amt && it.hasNext() ) final IAEPowerStorage node = it.next();
final double req = amt - extractedPower;
final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower;
if( newPower < req && mode == Actionable.MODULATE )
{ {
final IAEPowerStorage node = it.next(); it.remove();
if ( providerToRemove.contains( node )) {
it.remove();
providerToRemove.remove( node );
continue;
}
final double req = amt - extractedPower;
final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower;
if( newPower < req && mode == Actionable.MODULATE )
{
it.remove();
}
} }
} finally {
ongoingExtractOperation = false;
} }
final double result = Math.min( extractedPower, amt ); final double result = Math.min( extractedPower, amt );
@@ -403,29 +339,15 @@ public class EnergyGridCache implements IEnergyGrid
final Iterator<IAEPowerStorage> it = this.requesters.iterator(); final Iterator<IAEPowerStorage> it = this.requesters.iterator();
ongoingInjectOperation = true; while ( amt > 0 && it.hasNext() )
try
{ {
while ( amt > 0 && it.hasNext() ) final IAEPowerStorage node = it.next();
amt = node.injectAEPower( amt, mode );
if( amt > 0 && mode == Actionable.MODULATE )
{ {
final IAEPowerStorage node = it.next(); it.remove();
if ( requesterToRemove.contains( node )) {
it.remove();
requesterToRemove.remove( node );
continue;
}
amt = node.injectAEPower( amt, mode );
if( amt > 0 && mode == Actionable.MODULATE )
{
it.remove();
}
} }
} finally
{
ongoingInjectOperation = false;
} }
final double overflow = Math.max( 0.0, amt ); final double overflow = Math.max( 0.0, amt );
@@ -505,7 +427,7 @@ public class EnergyGridCache implements IEnergyGrid
@Override @Override
public double getStoredPower() public double getStoredPower()
{ {
if( this.availableTicksSinceUpdate > 2 ) if( this.availableTicksSinceUpdate > 90 )
{ {
this.refreshPower(); this.refreshPower();
} }
@@ -582,22 +504,9 @@ public class EnergyGridCache implements IEnergyGrid
this.globalMaxPower -= ps.getAEMaxPower(); this.globalMaxPower -= ps.getAEMaxPower();
this.globalAvailablePower -= ps.getAECurrentPower(); this.globalAvailablePower -= ps.getAECurrentPower();
} }
if( !ongoingExtractOperation )
{ this.providers.remove( ps );
removeProvider( ps ); this.requesters.remove( ps );
}
else
{
this.providerToRemove.add( ps );
}
if( !ongoingInjectOperation )
{
removeRequester( ps );
}
else
{
this.requesterToRemove.add( ps );
}
} }
} }
@@ -613,31 +522,6 @@ public class EnergyGridCache implements IEnergyGrid
} }
} }
private void addRequester(IAEPowerStorage requester) {
Preconditions.checkState(!ongoingInjectOperation,
"Cannot modify energy requesters while energy is being injected.");
this.requesters.add(requester);
}
private void removeRequester(IAEPowerStorage requester) {
Preconditions.checkState(!ongoingInjectOperation,
"Cannot modify energy requesters while energy is being injected.");
this.requesters.remove(requester);
}
private void addProvider(IAEPowerStorage provider) {
Preconditions.checkState(!ongoingExtractOperation,
"Cannot modify energy providers while energy is being extracted.");
this.providers.add(provider);
}
private void removeProvider(IAEPowerStorage provider) {
Preconditions.checkState(!ongoingExtractOperation,
"Cannot modify energy providers while energy is being extracted.");
this.providers.remove(provider);
}
@Override @Override
public void addNode( final IGridNode node, final IGridHost machine ) public void addNode( final IGridNode node, final IGridHost machine )
{ {
@@ -669,26 +553,12 @@ public class EnergyGridCache implements IEnergyGrid
if( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE ) if( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE )
{ {
this.globalAvailablePower += current; this.globalAvailablePower += current;
if( !ongoingExtractOperation ) this.providers.add( ps );
{
addProvider( ps );
}
else
{
this.providersToAdd.add( ps );
}
} }
if( current < max && ps.getPowerFlow() != AccessRestriction.READ ) if( current < max && ps.getPowerFlow() != AccessRestriction.READ )
{ {
if( !ongoingInjectOperation ) this.requesters.add( ps );
{
addRequester( ps );
}
else
{
this.requesterToAdd.add( ps );
}
} }
} }
} }
@@ -494,22 +494,87 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
return null; return null;
} }
private boolean canCraft( final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs ) private boolean canCraft(final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs)
{ {
for( IAEItemStack g : condensedInputs ) if( !details.isCraftable() )
{ {
// Processing patterns are relatively easy
for ( IAEItemStack input : condensedInputs )
{
final IAEItemStack ais = this.inventory.extractItems( input.copy(), Actionable.SIMULATE,
this.machineSrc );
if( details.isCraftable() ) if( ais == null || ais.getStackSize() < input.getStackSize() )
{
return false;
}
}
}
else if( details.canSubstitute() )
{
// When substitutions are allowed, we have to keep track of which items we've reserved
IAEItemStack[] inputs = details.getInputs();
Map<IAEItemStack, Integer> consumedCount = new HashMap<>();
for ( int i = 0; i < inputs.length; i++ )
{
List<IAEItemStack> substitutes = details.getSubstituteInputs( i );
if( substitutes.isEmpty() )
{
continue;
}
boolean found = false;
for ( IAEItemStack substitute : substitutes )
{
for ( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( substitute, FuzzyMode.IGNORE_ALL ) )
{
int alreadyConsumed = consumedCount.getOrDefault( fuzz, 0 );
if( fuzz.getStackSize() - alreadyConsumed <= 0 )
{
continue; // Already fully consumed by a previous slot of this recipe
}
fuzz = fuzz.copy();
fuzz.setStackSize( 1 ); // We're iterating over non condensed inputs which means there's 1 of each needed
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE,
this.machineSrc );
if( ais != null && ais.getStackSize() > 0 )
{
// Mark 1 of the stack as consumed
consumedCount.merge( fuzz, 1, Integer::sum );
found = true;
break;
}
}
if( found )
{
break;
}
}
if( !found )
{
return false;
}
}
}
else
{
// When no substitutions can occur, we can simply check that all items are accounted since
// each type of item should only occur once
for ( IAEItemStack g : condensedInputs )
{ {
boolean found = false; boolean found = false;
for( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( g, FuzzyMode.IGNORE_ALL ) ) for ( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( g, FuzzyMode.IGNORE_ALL ) )
{ {
fuzz = fuzz.copy(); fuzz = fuzz.copy();
fuzz.setStackSize( g.getStackSize() ); fuzz.setStackSize( g.getStackSize() );
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc ); final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc );
if (ais != null && ais.getStackSize() == g.getStackSize()) if( ais != null && ais.getStackSize() >= g.getStackSize() )
{ {
found = true; found = true;
break; break;
@@ -526,15 +591,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
return false; return false;
} }
} }
else
{
final IAEItemStack ais = this.inventory.extractItems( g.copy(), Actionable.SIMULATE, this.machineSrc );
if (ais == null || ais.getStackSize() < g.getStackSize())
{
return false;
}
}
} }
return true; return true;
@@ -689,71 +746,67 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
boolean found = false; boolean found = false;
for( int x = 0; x < input.length; x++ ) for (int x = 0; x < input.length; x++) {
{ if (input[x] != null) {
if( input[x] != null )
{
found = false; found = false;
if( details.isCraftable() ) if (details.isCraftable()) {
{
final Collection<IAEItemStack> itemList; final Collection<IAEItemStack> itemList;
if( details.canSubstitute() ) if (details.canSubstitute()) {
{ final List<IAEItemStack> substitutes = details.getSubstituteInputs(x);
itemList = this.inventory.getItemList().findFuzzy( input[x], FuzzyMode.IGNORE_ALL ); itemList = new ArrayList<>(substitutes.size());
}
else
{
itemList = new ArrayList<>( 1 );
final IAEItemStack item = this.inventory.getItemList().findPrecise( input[x] ); for (IAEItemStack stack : substitutes) {
itemList.addAll(this.inventory.getItemList().findFuzzy(stack,
FuzzyMode.IGNORE_ALL));
}
} else {
itemList = new ArrayList<>(1);
if( item != null ) final IAEItemStack item = this.inventory.getItemList()
{ .findPrecise(input[x]);
itemList.add( item );
if (item != null) {
itemList.add(item);
} }
} }
for( IAEItemStack fuzz : itemList ) for (IAEItemStack fuzz : itemList) {
{
fuzz = fuzz.copy(); fuzz = fuzz.copy();
fuzz.setStackSize( input[x].getStackSize() ); fuzz.setStackSize(input[x].getStackSize());
if( details.isValidItemForSlot( x, fuzz.createItemStack(), this.getWorld() ) ) if (details.isValidItemForSlot(x, fuzz.createItemStack(),
{ this.getWorld())) {
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.MODULATE, this.machineSrc ); final IAEItemStack ais = this.inventory.extractItems(fuzz,
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack(); Actionable.MODULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY
: ais.createItemStack();
if( !is.isEmpty() ) if (!is.isEmpty()) {
{ this.postChange(AEItemStack.fromItemStack(is), this.machineSrc);
this.postChange( AEItemStack.fromItemStack( is ), this.machineSrc ); ic.setInventorySlotContents(x, is);
ic.setInventorySlotContents( x, is );
found = true; found = true;
break; break;
} }
} }
} }
} } else {
else final IAEItemStack ais = this.inventory.extractItems(input[x].copy(),
{ Actionable.MODULATE, this.machineSrc);
final IAEItemStack ais = this.inventory.extractItems( input[x].copy(), Actionable.MODULATE, this.machineSrc );
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack(); final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if( !is.isEmpty() ) if (!is.isEmpty()) {
{ this.postChange(input[x], this.machineSrc);
this.postChange( input[x], this.machineSrc ); ic.setInventorySlotContents(x, is);
ic.setInventorySlotContents( x, is ); if (is.getCount() == input[x].getStackSize()) {
if( is.getCount() == input[x].getStackSize() )
{
found = true; found = true;
continue; continue;
} }
} }
} }
if( !found ) if (!found) {
{
break; break;
} }
} }
@@ -72,7 +72,7 @@ public class MEMonitorPassThrough<T extends IAEStack<T>> extends MEPassThrough<T
final IItemList<T> after = this.getInternal() == null ? this.getWrappedChannel().createList() : this.getInternal() final IItemList<T> after = this.getInternal() == null ? this.getWrappedChannel().createList() : this.getInternal()
.getAvailableItems( new ItemListIgnoreCrafting( this.getWrappedChannel().createList() ) ); .getAvailableItems( new ItemListIgnoreCrafting( this.getWrappedChannel().createList() ) );
if( this.monitor != null ) if( this.monitor != null && this.listeners.size() > 0 )
{ {
this.monitor.addListener( this, this.monitor ); this.monitor.addListener( this, this.monitor );
} }
@@ -180,7 +180,10 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest
} }
else else
{ {
this.pushItemIntoTarget( destination, energy, inv, ais ); if( inv.getStorageList().findPrecise( ais ) != null )
{
this.pushItemIntoTarget( destination, energy, inv, ais );
}
} }
if( this.itemToSend == before && this.isCraftingEnabled() ) if( this.itemToSend == before && this.isCraftingEnabled() )
@@ -283,12 +283,12 @@ public class PartImportBus extends PartSharedItemBus implements IInventoryDestin
final ItemStack simResult; final ItemStack simResult;
if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 )
{ {
simResult = myAdaptor.simulateSimilarRemove( toSend, itemStackToImport, fzMode, this ); simResult = myAdaptor.simulateSimilarRemove( toSend, itemStackToImport, fzMode, null );
itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source ); itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source );
} }
else else
{ {
simResult = myAdaptor.simulateRemove( toSend, itemStackToImport, this ); simResult = myAdaptor.simulateRemove( toSend, itemStackToImport, null );
itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source ); itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source );
} }
@@ -434,16 +434,6 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ); return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) );
} }
if (ITEM_REPOSITORY_CAPABILITY != null && target.hasCapability( ITEM_REPOSITORY_CAPABILITY, targetSide ))
{
final IItemRepository handlerRepo = target.getCapability( ITEM_REPOSITORY_CAPABILITY, targetSide );
if( handlerRepo != null )
{
return Objects.hash( target, handlerRepo, handlerRepo.getAllItems().size() );
}
}
final IItemHandler itemHandler = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); final IItemHandler itemHandler = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide );
if( itemHandler != null ) if( itemHandler != null )
@@ -206,10 +206,17 @@ public abstract class AbstractPartMonitor extends AbstractPartDisplay implements
fluidInTank = fluidHandlerItem.drain( Integer.MAX_VALUE, false ); fluidInTank = fluidHandlerItem.drain( Integer.MAX_VALUE, false );
} }
if (fluidInTank == null) if( fluidInTank == null )
{ {
this.configuredFluid = null; this.configuredFluid = null;
this.configuredItem = AEItemStack.fromItemStack( eq ); if( !eq.isEmpty() )
{
this.configuredItem = AEItemStack.fromItemStack( eq ).setStackSize( 0 );
}
else
{
this.configuredItem = null;
}
} }
else if( fluidInTank.amount > 0 ) else if( fluidInTank.amount > 0 )
{ {
@@ -170,8 +170,7 @@ public class PartConversionMonitor extends AbstractPartMonitor
this.insertItem( player, hand, false ); this.insertItem( player, hand, false );
} }
} }
return super.onPartActivate( player, hand, pos );
return true;
} }
@Override @Override
+7 -5
View File
@@ -1246,18 +1246,20 @@ public class Platform
if( itemToAdd < input.getStackSize() ) if( itemToAdd < input.getStackSize() )
{ {
final long original = input.getStackSize(); final long original = input.getStackSize();
final T leftover = input.copy();
final T split = input.copy(); final T split = input.copy();
split.decStackSize( itemToAdd );
input.setStackSize( itemToAdd ); leftover.decStackSize(itemToAdd);
split.add( cell.injectItems( input, Actionable.MODULATE, src ) ); split.setStackSize(itemToAdd);
leftover.add(cell.injectItems(split, Actionable.MODULATE, src));
src.player().ifPresent( player -> src.player().ifPresent( player ->
{ {
final long diff = original - split.getStackSize(); final long diff = original - leftover.getStackSize();
Stats.ItemsInserted.addToPlayer( player, (int) diff ); Stats.ItemsInserted.addToPlayer( player, (int) diff );
} ); } );
return split; return leftover;
} }
final T ret = cell.injectItems( input, Actionable.MODULATE, src ); final T ret = cell.injectItems( input, Actionable.MODULATE, src );
@@ -148,7 +148,7 @@ class FuzzyItemVariantList extends ItemVariantList {
*/ */
static ItemDamageBound makeLowerBound(final ItemStack stack, final FuzzyMode fuzzy) static ItemDamageBound makeLowerBound(final ItemStack stack, final FuzzyMode fuzzy)
{ {
Preconditions.checkState( stack.getItem().isDamageable() || (Platform.isModLoaded( "gregtech" ) && stack.getItem() instanceof MetaTool), "Item#isDamageable() has to be true" ); Preconditions.checkState( stack.getItem().isDamageable() , "Item#isDamageable() has to be true" );
int damage; int damage;
if( fuzzy == FuzzyMode.IGNORE_ALL ) if( fuzzy == FuzzyMode.IGNORE_ALL )
@@ -176,7 +176,7 @@ class FuzzyItemVariantList extends ItemVariantList {
* lower number than the lower bound. It also is exclusive. * lower number than the lower bound. It also is exclusive.
*/ */
static ItemDamageBound makeUpperBound(final ItemStack stack, final FuzzyMode fuzzy) { static ItemDamageBound makeUpperBound(final ItemStack stack, final FuzzyMode fuzzy) {
Preconditions.checkState(stack.getItem().isDamageable() || (Platform.isModLoaded( "gregtech" ) && stack.getItem() instanceof MetaTool), "Item#isDamageable() has to be true"); Preconditions.checkState(stack.getItem().isDamageable() , "Item#isDamageable() has to be true");
int damage; int damage;
if (fuzzy == FuzzyMode.IGNORE_ALL) { if (fuzzy == FuzzyMode.IGNORE_ALL) {
+1 -1
View File
@@ -151,7 +151,7 @@ public final class ItemList implements IItemList<IAEItemStack> {
} }
private ItemVariantList makeRecordMap(Item item) { private ItemVariantList makeRecordMap(Item item) {
if (item.isDamageable() || (Platform.isModLoaded( "gregtech" ) && item instanceof MetaTool) ) { if (item.isDamageable() ) {
return new FuzzyItemVariantList(); return new FuzzyItemVariantList();
} else { } else {
return new NormalItemVariantList(); return new NormalItemVariantList();
@@ -18,32 +18,20 @@
"type": "appliedenergistics2:part", "type": "appliedenergistics2:part",
"part": "material.card_pattern_expansion" "part": "material.card_pattern_expansion"
}, },
"type": "appliedenergistics2:part_shaped", "type": "appliedenergistics2:part_shapeless",
"pattern": [
"ci"
],
"ingredients": [ "ingredients": [
{ {
"type": "appliedenergistics2:part", "type": "appliedenergistics2:part",
"part": "material.advanced_card" "part": "material.advanced_card"
}, },
{ [
"key": "#" {
} "item": "appliedenergistics2:interface"
], },
"key": { {
"i": [ "type": "appliedenergistics2:part",
{ "part": "part.interface"
"item": "appliedenergistics2:interface" }
}, ]
{ ]
"type": "appliedenergistics2:part",
"part": "part.interface"
}],
"c": {
"type": "appliedenergistics2:part",
"part": "material.advanced_card"
}
}
} }