Compare commits

..

3 Commits

Author SHA1 Message Date
PrototypeTrousers e3b3c8cc10 2 2022-03-03 14:31:51 -03:00
PrototypeTrousers eea5bc7c6b 1 2022-03-03 14:31:46 -03:00
PrototypeTrousers d414c458ae undo partially pattern cache rebuild optimization 2022-03-01 13:02:56 -03:00
24 changed files with 900 additions and 1327 deletions
+1 -2
View File
@@ -4,7 +4,7 @@ aebuild=7
aegroup=appeng aegroup=appeng
aebasename=appliedenergistics2 aebasename=appliedenergistics2
extended=extended_life extended=extended_life
extendedversion=v52b extendedversion=v50g
######################################################### #########################################################
# Versions # # Versions #
######################################################### #########################################################
@@ -26,7 +26,6 @@ cofhcore_version=1.12.2-4.5.2.19
crafttweaker_version=4.1.8.9 crafttweaker_version=4.1.8.9
inventorytweaks_version=1.63 inventorytweaks_version=1.63
ctm_version=MC1.12.2-0.3.1.16 ctm_version=MC1.12.2-0.3.1.16
forestry_version=5.8.2.387
######################################################### #########################################################
# Deployment # # Deployment #
######################################################### #########################################################
-2
View File
@@ -97,8 +97,6 @@ dependencies {
compileOnly "inventory-tweaks:InventoryTweaks:${inventorytweaks_version}:api" compileOnly "inventory-tweaks:InventoryTweaks:${inventorytweaks_version}:api"
compileOnly "team.chisel.ctm:CTM:${ctm_version}" compileOnly "team.chisel.ctm:CTM:${ctm_version}"
compileOnly "de.ellpeck.actuallyadditions:ActuallyAdditions:1.12.2-r152.16:api" compileOnly "de.ellpeck.actuallyadditions:ActuallyAdditions:1.12.2-r152.16:api"
deobfCompile "net.sengir.forestry:forestry_${minecraft_version}:$forestry_version"
// at runtime, use the full JEI jar // at runtime, use the full JEI jar
runtime "mezz.jei:jei_${minecraft_version}:${jei_version}" runtime "mezz.jei:jei_${minecraft_version}:${jei_version}"
+37 -24
View File
@@ -33,7 +33,6 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import appeng.container.slot.*; import appeng.container.slot.*;
import appeng.util.Platform;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -160,7 +159,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
final List<Slot> slots = this.getInventorySlots(); final List<Slot> slots = this.getInventorySlots();
final Iterator<Slot> i = slots.iterator(); final Iterator<Slot> i = slots.iterator();
while ( i.hasNext() ) while( i.hasNext() )
{ {
if( i.next() instanceof SlotME ) if( i.next() instanceof SlotME )
{ {
@@ -209,17 +208,13 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
} }
} }
GlStateManager.enableDepth(); GlStateManager.enableDepth();
if( Platform.isModLoaded( "jei" ) ) bookmarkedJEIghostItem(mouseX,mouseY);
{
bookmarkedJEIghostItem( mouseX, mouseY );
}
GlStateManager.disableDepth(); GlStateManager.disableDepth();
} }
@Optional.Method( modid = "jei" ) void bookmarkedJEIghostItem(final int mouseX, final int mouseY) {
void bookmarkedJEIghostItem( final int mouseX, final int mouseY )
{ if (!isJeiGhostItem)
if( !isJeiGhostItem )
{ {
bookmarkedIngredient = runtime.getBookmarkOverlay().getIngredientUnderMouse(); bookmarkedIngredient = runtime.getBookmarkOverlay().getIngredientUnderMouse();
} }
@@ -253,9 +248,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
} }
} }
} }
private void drawTargets(int mouseX, int mouseY) {
private void drawTargets( int mouseX, int mouseY )
{
GlStateManager.disableLighting(); GlStateManager.disableLighting();
for( IGhostIngredientHandler.Target target : hoveredIngredientTargets ) for( IGhostIngredientHandler.Target target : hoveredIngredientTargets )
{ {
@@ -384,13 +377,17 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
final AppEngSlot aeSlot = (AppEngSlot) slot; final AppEngSlot aeSlot = (AppEngSlot) slot;
if( aeSlot.isSlotEnabled() ) if( aeSlot.isSlotEnabled() )
{ {
this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1, 18, 18 ); this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1,
18,
18 );
} }
else else
{ {
GlStateManager.color( 1.0F, 1.0F, 1.0F, 0.4F ); GlStateManager.color( 1.0F, 1.0F, 1.0F, 0.4F );
GlStateManager.enableBlend(); GlStateManager.enableBlend();
this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1, 18, 18 ); this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1,
18,
18 );
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
} }
} }
@@ -509,7 +506,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
{ {
final EntityPlayer player = Minecraft.getMinecraft().player; final EntityPlayer player = Minecraft.getMinecraft().player;
if( this.isJeiGhostItem && isDraggingJeiGhostItem ) if( this.isJeiGhostItem && isDraggingJeiGhostItem)
{ {
for( IGhostIngredientHandler.Target target : hoveredIngredientTargets ) for( IGhostIngredientHandler.Target target : hoveredIngredientTargets )
{ {
@@ -762,8 +759,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
this.disableShiftClick = false; this.disableShiftClick = false;
} }
if( clickType == ClickType.PICKUP && isJeiGhostItem && !isDraggingJeiGhostItem ) if (clickType == ClickType.PICKUP && isJeiGhostItem && !isDraggingJeiGhostItem) {
{
this.isDraggingJeiGhostItem = true; this.isDraggingJeiGhostItem = true;
return; return;
} }
@@ -883,7 +879,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
if( stack != ItemStack.EMPTY ) if( stack != ItemStack.EMPTY )
{ {
InventoryAction direction = wheel > 0 ? InventoryAction.PLACE_SINGLE : InventoryAction.PICKUP_SINGLE; InventoryAction direction = wheel > 0 ? InventoryAction.PLACE_SINGLE : InventoryAction.PICKUP_SINGLE;
final PacketInventoryAction p = new PacketInventoryAction( direction, slot.slotNumber, 0 ); final PacketInventoryAction p = new PacketInventoryAction( direction , slot.slotNumber , 0);
NetworkHandler.instance().sendToServer( p ); NetworkHandler.instance().sendToServer( p );
} }
} }
@@ -1036,11 +1032,27 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
final float f1 = 0.00390625F; final float f1 = 0.00390625F;
final float f = 0.00390625F; final float f = 0.00390625F;
final float par6 = 16; final float par6 = 16;
vb.pos( par1 + 0, par2 + par6, this.zLevel ).tex( ( par3 + 0 ) * f, ( par4 + par6 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex(); vb.pos( par1 + 0, par2 + par6, this.zLevel )
.tex( ( par3 + 0 ) * f, ( par4 + par6 ) * f1 )
.color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
final float par5 = 16; final float par5 = 16;
vb.pos( par1 + par5, par2 + par6, this.zLevel ).tex( ( par3 + par5 ) * f, ( par4 + par6 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex(); vb.pos( par1 + par5, par2 + par6, this.zLevel )
vb.pos( par1 + par5, par2 + 0, this.zLevel ).tex( ( par3 + par5 ) * f, ( par4 + 0 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex(); .tex( ( par3 + par5 ) * f, ( par4 + par6 ) * f1 )
vb.pos( par1 + 0, par2 + 0, this.zLevel ).tex( ( par3 + 0 ) * f, ( par4 + 0 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex(); .color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
vb.pos( par1 + par5, par2 + 0, this.zLevel )
.tex( ( par3 + par5 ) * f, ( par4 + 0 ) * f1 )
.color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
vb.pos( par1 + 0, par2 + 0, this.zLevel )
.tex( ( par3 + 0 ) * f, ( par4 + 0 ) * f1 )
.color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
tessellator.draw(); tessellator.draw();
} }
@@ -1054,7 +1066,8 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
{ {
if( ( (AppEngSlot) s ).getIsValid() == hasCalculatedValidness.NotAvailable ) if( ( (AppEngSlot) s ).getIsValid() == hasCalculatedValidness.NotAvailable )
{ {
boolean isValid = s.isItemValid( is ) || s instanceof SlotOutput || s instanceof AppEngCraftingSlot || s instanceof SlotDisabled || s instanceof SlotInaccessible || s instanceof SlotFake || s instanceof SlotRestrictedInput || s instanceof SlotDisconnected; boolean isValid = s.isItemValid(
is ) || s instanceof SlotOutput || s instanceof AppEngCraftingSlot || s instanceof SlotDisabled || s instanceof SlotInaccessible || s instanceof SlotFake || s instanceof SlotRestrictedInput || s instanceof SlotDisconnected;
if( isValid && s instanceof SlotRestrictedInput ) if( isValid && s instanceof SlotRestrictedInput )
{ {
try try
-3
View File
@@ -25,7 +25,6 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import appeng.helpers.NonBlockingItems;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -239,8 +238,6 @@ public final class AppEng
AppEng.proxy.postInit(); AppEng.proxy.postInit();
AEConfig.instance().save(); AEConfig.instance().save();
NonBlockingItems.INSTANCE.init();
NetworkRegistry.INSTANCE.registerGuiHandler( this, GuiBridge.GUI_Handler ); NetworkRegistry.INSTANCE.registerGuiHandler( this, GuiBridge.GUI_Handler );
NetworkHandler.init( "AE2" ); NetworkHandler.init( "AE2" );
@@ -24,9 +24,34 @@ import java.lang.reflect.InvocationTargetException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import appeng.core.sync.packets.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import appeng.core.sync.packets.PacketAssemblerAnimation;
import appeng.core.sync.packets.PacketClick;
import appeng.core.sync.packets.PacketCompassRequest;
import appeng.core.sync.packets.PacketCompassResponse;
import appeng.core.sync.packets.PacketCompressedNBT;
import appeng.core.sync.packets.PacketConfigButton;
import appeng.core.sync.packets.PacketCraftRequest;
import appeng.core.sync.packets.PacketFluidSlot;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.core.sync.packets.PacketJEIRecipe;
import appeng.core.sync.packets.PacketLightning;
import appeng.core.sync.packets.PacketMEFluidInventoryUpdate;
import appeng.core.sync.packets.PacketMEInventoryUpdate;
import appeng.core.sync.packets.PacketMatterCannon;
import appeng.core.sync.packets.PacketMockExplosion;
import appeng.core.sync.packets.PacketPaintedEntity;
import appeng.core.sync.packets.PacketPartPlacement;
import appeng.core.sync.packets.PacketPatternSlot;
import appeng.core.sync.packets.PacketProgressBar;
import appeng.core.sync.packets.PacketSwapSlots;
import appeng.core.sync.packets.PacketSwitchGuis;
import appeng.core.sync.packets.PacketTargetFluidStack;
import appeng.core.sync.packets.PacketTargetItemStack;
import appeng.core.sync.packets.PacketTransitionEffect;
import appeng.core.sync.packets.PacketValueConfig;
public class AppEngPacketHandlerBase public class AppEngPacketHandlerBase
{ {
@@ -82,10 +107,7 @@ public class AppEngPacketHandlerBase
PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ), PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ),
PACKET_FLUID_TANK( PacketFluidSlot.class ), PACKET_FLUID_TANK( PacketFluidSlot.class );
PACKET_INFORM_PLAYER( PacketInformPlayer.class );
private final Class<? extends AppEngPacket> packetClass; private final Class<? extends AppEngPacket> packetClass;
private final Constructor<? extends AppEngPacket> packetConstructor; private final Constructor<? extends AppEngPacket> packetConstructor;
@@ -1,89 +0,0 @@
package appeng.core.sync.packets;
import appeng.api.storage.data.IAEItemStack;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.util.item.AEItemStack;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.text.TextComponentString;
import java.io.IOException;
public class PacketInformPlayer extends AppEngPacket
{
private IAEItemStack actualItem = null;
private IAEItemStack reportedItem = null;
private final InfoType type;
public PacketInformPlayer( ByteBuf stream ) throws IOException
{
this.type = InfoType.values()[stream.readInt()];
if( type == InfoType.PARTIAL_ITEM_EXTRACTION )
{
this.reportedItem = AEItemStack.fromPacket( stream );
this.actualItem = AEItemStack.fromPacket( stream );
}
else if( type == InfoType.NO_ITEMS_EXTRACTED )
{
this.reportedItem = AEItemStack.fromPacket( stream );
}
}
public PacketInformPlayer( final IAEItemStack iaeItemStack ) throws IOException
{
this( iaeItemStack, null );
}
public PacketInformPlayer( IAEItemStack extra, IAEItemStack result ) throws IOException
{
this.reportedItem = extra;
this.actualItem = result;
if( actualItem == null )
{
this.type = InfoType.NO_ITEMS_EXTRACTED;
}
else
{
this.type = InfoType.PARTIAL_ITEM_EXTRACTION;
}
final ByteBuf data = Unpooled.buffer();
data.writeInt( this.getPacketID() );
data.writeInt( type.ordinal() );
reportedItem.writeToPacket( data );
if( actualItem != null )
{
actualItem.writeToPacket( data );
}
this.configureWrite( data );
}
@Override
public void clientPacketData( final INetworkInfo network, final AppEngPacket packet, final EntityPlayer player )
{
TextComponentString msg = null;
if( this.type == InfoType.PARTIAL_ITEM_EXTRACTION )
{
AppEng.proxy.getPlayers().get( 0 ).sendStatusMessage( new TextComponentString( "System reported " + reportedItem.getStackSize() + " " + reportedItem.getItem().getItemStackDisplayName( reportedItem.getDefinition() ) + " available but could only extract" + actualItem.getStackSize() ), false );
}
else if( this.type == InfoType.NO_ITEMS_EXTRACTED )
{
AppEng.proxy.getPlayers().get( 0 ).sendStatusMessage( new TextComponentString( "System reported " + reportedItem.getStackSize() + " " + reportedItem.getItem().getItemStackDisplayName( reportedItem.getDefinition() ) + " available but could not extract anything" ), false );
}
}
public enum InfoType
{
PARTIAL_ITEM_EXTRACTION,
NO_ITEMS_EXTRACTED
}
}
@@ -30,6 +30,7 @@ import java.util.List;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
import appeng.container.implementations.ContainerExpandedProcessingPatternTerm; import appeng.container.implementations.ContainerExpandedProcessingPatternTerm;
import appeng.container.implementations.ContainerPatternTerm; import appeng.container.implementations.ContainerPatternTerm;
import gregtech.common.items.MetaTool;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -40,7 +41,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.fml.common.Optional;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -175,8 +175,7 @@ public class PacketJEIRecipe extends AppEngPacket
{ {
ItemStack currentItem = craftMatrix.getStackInSlot( x ); ItemStack currentItem = craftMatrix.getStackInSlot( x );
if( x >= this.recipe.size() ) if (x >= this.recipe.size()) {
{
currentItem = ItemStack.EMPTY; currentItem = ItemStack.EMPTY;
} }
@@ -229,7 +228,7 @@ public class PacketJEIRecipe extends AppEngPacket
out = Platform.poweredExtraction( energy, storage, request, cct.getActionSource() ); out = Platform.poweredExtraction( energy, storage, request, cct.getActionSource() );
if( out == null ) if( out == null )
{ {
if( request.getItem().isDamageable() || Platform.isGTDamageableItem( request.getItem() ) ) if( request.getItem().isDamageable() || ( Platform.isModLoaded( "gregtech" ) && request.getItem() instanceof MetaTool ) )
{ {
Collection<IAEItemStack> outList = inv.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findFuzzy( request, FuzzyMode.IGNORE_ALL ); Collection<IAEItemStack> outList = inv.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findFuzzy( request, FuzzyMode.IGNORE_ALL );
for( IAEItemStack is : outList ) for( IAEItemStack is : outList )
@@ -262,7 +261,7 @@ public class PacketJEIRecipe extends AppEngPacket
if( out != null ) if( out != null )
{ {
if( !cct.useRealItems() ) if (!cct.useRealItems())
{ {
out.setStackSize( recipe.get( x )[y].getCount() ); out.setStackSize( recipe.get( x )[y].getCount() );
} }
@@ -286,7 +285,7 @@ public class PacketJEIRecipe extends AppEngPacket
} }
} }
} }
if( !cct.useRealItems() ) if (!cct.useRealItems())
{ {
if( currentItem.isEmpty() && recipe.size() > x && this.recipe.get( x ) != null ) if( currentItem.isEmpty() && recipe.size() > x && this.recipe.get( x ) != null )
{ {
@@ -299,28 +298,25 @@ public class PacketJEIRecipe extends AppEngPacket
con.onCraftMatrixChanged( new WrapperInvItemHandler( craftMatrix ) ); con.onCraftMatrixChanged( new WrapperInvItemHandler( craftMatrix ) );
if( this.output != null && ( ( con instanceof ContainerPatternTerm && !( (ContainerPatternTerm) con ).isCraftingMode() ) || con instanceof ContainerExpandedProcessingPatternTerm ) ) if( this.output != null && ( ( con instanceof ContainerPatternTerm && !( (ContainerPatternTerm) con ).isCraftingMode() ) || con instanceof ContainerExpandedProcessingPatternTerm ) ) {
{ IItemHandler outputSlots = cct.getInventoryByName("output");
IItemHandler outputSlots = cct.getInventoryByName( "output" ); for (int i = 0; i < outputSlots.getSlots(); ++i) {
for( int i = 0; i < outputSlots.getSlots(); ++i ) ItemHandlerUtil.setStackInSlot(outputSlots, i, ItemStack.EMPTY);
{ }
ItemHandlerUtil.setStackInSlot( outputSlots, i, ItemStack.EMPTY ); for (int i = 0; i < this.output.size() && i < outputSlots.getSlots(); ++i) {
} if (this.output.get(i) == null || this.output.get(i) == ItemStack.EMPTY) {
for( int i = 0; i < this.output.size() && i < outputSlots.getSlots(); ++i ) continue;
{ }
if( this.output.get( i ) == null || this.output.get( i ) == ItemStack.EMPTY ) ItemHandlerUtil.setStackInSlot(outputSlots, i, this.output.get(i));
{ }
continue;
}
ItemHandlerUtil.setStackInSlot( outputSlots, i, this.output.get( i ) );
}
} }
} }
} }
/** /**
*
* @param slot * @param slot
* @param is itemstack * @param is itemstack
* @return is if it can be used, else EMPTY * @return is if it can be used, else EMPTY
*/ */
private ItemStack canUseInSlot( int slot, ItemStack is ) private ItemStack canUseInSlot( int slot, ItemStack is )
+50 -59
View File
@@ -19,6 +19,15 @@
package appeng.crafting; package appeng.crafting;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Stopwatch;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
@@ -27,6 +36,7 @@ import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingCallback; import appeng.api.networking.crafting.ICraftingCallback;
import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingJob; import appeng.api.networking.crafting.ICraftingJob;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStorageGrid; import appeng.api.networking.storage.IStorageGrid;
@@ -36,14 +46,6 @@ import appeng.api.storage.data.IItemList;
import appeng.api.util.DimensionalCoord; import appeng.api.util.DimensionalCoord;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.hooks.TickHandler; import appeng.hooks.TickHandler;
import appeng.me.cache.GridStorageCache;
import com.google.common.base.Stopwatch;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
public class CraftingJob implements Runnable, ICraftingJob public class CraftingJob implements Runnable, ICraftingJob
@@ -55,45 +57,48 @@ public class CraftingJob implements Runnable, ICraftingJob
private final World world; private final World world;
private final IItemList<IAEItemStack> crafting = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList<IAEItemStack> crafting = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
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 IItemList<IAEItemStack> neededForLoop = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList<IAEItemStack> usedWhileBuilding = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final Object2ObjectOpenHashMap<CraftingTreeNode, IAEItemStack> reserved = new Object2ObjectOpenHashMap<>(); private final IItemList<IAEItemStack> uniques = 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 tickSpreadingWatch = Stopwatch.createUnstarted(); private final Stopwatch tickSpreadingWatch = Stopwatch.createUnstarted();
private final Stopwatch craftingTreeWatch = Stopwatch.createUnstarted(); private final Stopwatch craftingTreeWatch = Stopwatch.createUnstarted();
private final IAEItemStack output;
private final IActionSource actionSrc;
private final ICraftingCallback callback;
private CraftingTreeNode tree; private CraftingTreeNode tree;
private final IAEItemStack output;
private boolean simulate = false; private boolean simulate = false;
private MECraftingInventory availableCheck; private MECraftingInventory availableCheck;
private long bytes = 0; private long bytes = 0;
private final IActionSource actionSrc;
private final ICraftingCallback callback;
private boolean running = false; private boolean running = false;
private boolean done = false; private boolean done = false;
private int time; private int time;
private int incTime; private int incTime;
private World wrapWorld( final World w )
{
return w;
}
public CraftingJob( final World w, final IGrid grid, final IActionSource actionSrc, final IAEItemStack what, final ICraftingCallback callback ) public CraftingJob( final World w, final IGrid grid, final IActionSource actionSrc, final IAEItemStack what, final ICraftingCallback callback )
{ {
this.world = w; this.world = this.wrapWorld( w );
this.output = what.copy(); this.output = what.copy();
this.actionSrc = actionSrc; this.actionSrc = actionSrc;
this.callback = callback; this.callback = callback;
final ICraftingGrid cc = grid.getCache( ICraftingGrid.class );
final IStorageGrid sg = grid.getCache( IStorageGrid.class );
this.original = new MECraftingInventory( sg.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), actionSrc, false, false, false );
ICraftingGrid cc = grid.getCache( ICraftingGrid.class );
final GridStorageCache sg = grid.getCache( IStorageGrid.class );
this.original = sg.getExtractableList( actionSrc );
this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.setTree( this.getCraftingTree( cc, what ) ); this.setTree( this.getCraftingTree( cc, what ) );
this.availableCheck = null; this.availableCheck = null;
} }
private CraftingTreeNode getCraftingTree( final ICraftingGrid cc, final IAEItemStack what ) private CraftingTreeNode getCraftingTree( final ICraftingGrid cc, final IAEItemStack what )
{ {
return new CraftingTreeNode( cc, this, what, what.getStackSize(), null, -1 ); return new CraftingTreeNode( cc, this, what, null, -1, 0 );
} }
void refund( final IAEItemStack o ) void refund( final IAEItemStack o )
@@ -101,17 +106,27 @@ public class CraftingJob implements Runnable, ICraftingJob
this.availableCheck.injectItems( o, Actionable.MODULATE, this.actionSrc ); this.availableCheck.injectItems( o, Actionable.MODULATE, this.actionSrc );
} }
public IItemList<IAEItemStack> getUsedWhileBuilding()
{
return usedWhileBuilding;
}
public IItemList<IAEItemStack> getUniques()
{
return uniques;
}
IAEItemStack checkUse( final IAEItemStack available ) IAEItemStack checkUse( final IAEItemStack available )
{ {
return this.availableCheck.extractItems( available, Actionable.MODULATE, this.actionSrc ); return this.availableCheck.extractItems( available, Actionable.MODULATE, this.actionSrc );
} }
IAEItemStack checkAvailable( final IAEItemStack available ) public void writeToNBT( final NBTTagCompound out )
{ {
return this.availableCheck.extractItems( available, Actionable.SIMULATE, this.actionSrc );
} }
void addTask( IAEItemStack what, final long crafts ) void addTask( IAEItemStack what, final long crafts, final ICraftingPatternDetails details, final int depth )
{ {
if( crafts > 0 ) if( crafts > 0 )
{ {
@@ -127,22 +142,6 @@ public class CraftingJob implements Runnable, ICraftingJob
this.missing.add( what ); this.missing.add( what );
} }
public void reserve( CraftingTreeNode node, IAEItemStack stack )
{
this.checkUse( stack );
reserved.put( node, stack );
}
public IItemList<IAEItemStack> getNeededForLoop()
{
return neededForLoop;
}
public Object2ObjectOpenHashMap<CraftingTreeNode, IAEItemStack> getReserved()
{
return reserved;
}
@Override @Override
public void run() public void run()
{ {
@@ -153,15 +152,13 @@ public class CraftingJob implements Runnable, ICraftingJob
TickHandler.INSTANCE.registerCraftingSimulation( this.world, this ); TickHandler.INSTANCE.registerCraftingSimulation( this.world, this );
this.handlePausing(); this.handlePausing();
craftingTreeWatch.start();
final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true ); final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true );
craftingInventory.ignore( this.output );
this.availableCheck = new MECraftingInventory( this.original, false, false, false ); this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.reserved.values().forEach( availableCheck::reserve );
this.reserved.values().forEach( craftingInventory::reserve );
craftingTreeWatch.start();
this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc ); this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc );
craftingTreeWatch.stop();
this.getTree().dive( this ); this.getTree().dive( this );
for( final String s : this.opsAndMultiplier.keySet() ) for( final String s : this.opsAndMultiplier.keySet() )
@@ -170,14 +167,8 @@ public class CraftingJob implements Runnable, ICraftingJob
AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) ); AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) );
} }
if( actionSrc.player().isPresent() ) craftingTreeWatch.stop();
{ this.logCraftingJob( "real, success", craftingTreeWatch );
this.logCraftingJob( "simulated, success", craftingTreeWatch );
}
else
{
this.logCraftingJob( "real, success", craftingTreeWatch );
}
} }
catch( final CraftBranchFailure e ) catch( final CraftBranchFailure e )
{ {
@@ -187,16 +178,14 @@ public class CraftingJob implements Runnable, ICraftingJob
{ {
if( actionSrc.player().isPresent() ) if( actionSrc.player().isPresent() )
{ {
craftingTreeWatch.reset().start();
final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true ); final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true );
this.getTree().setSimulate(); craftingInventory.ignore( this.output );
this.availableCheck = new MECraftingInventory( this.original, false, false, false ); this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.reserved.values().forEach( availableCheck::reserve );
this.reserved.values().forEach( craftingInventory::reserve );
craftingTreeWatch.reset().start(); this.getTree().setSimulate();
this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc ); this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc );
craftingTreeWatch.stop();
this.getTree().dive( this ); this.getTree().dive( this );
for( final String s : this.opsAndMultiplier.keySet() ) for( final String s : this.opsAndMultiplier.keySet() )
@@ -205,10 +194,12 @@ public class CraftingJob implements Runnable, ICraftingJob
AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) ); AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) );
} }
this.logCraftingJob( "simulated, failed", craftingTreeWatch ); craftingTreeWatch.stop();
this.logCraftingJob( "simulate", craftingTreeWatch );
} }
else else
{ {
craftingTreeWatch.stop();
this.logCraftingJob( "real, failed", craftingTreeWatch ); this.logCraftingJob( "real, failed", craftingTreeWatch );
} }
} }
@@ -277,7 +268,7 @@ public class CraftingJob implements Runnable, ICraftingJob
} }
} }
} }
if( Thread.interrupted() ) if( Thread.interrupted() )
{ {
throw new InterruptedException(); throw new InterruptedException();
@@ -19,6 +19,15 @@
package appeng.crafting; package appeng.crafting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
@@ -28,22 +37,9 @@ import appeng.api.networking.security.IActionSource;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInformPlayer;
import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.util.Platform;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Optional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@Optional.Interface( iface = "gregtech.api.items.IToolItem", modid = "gregtech" )
public class CraftingTreeNode public class CraftingTreeNode
{ {
@@ -58,20 +54,22 @@ public class CraftingTreeNode
private final IAEItemStack what; private final IAEItemStack what;
// what are the crafting patterns for this? // what are the crafting patterns for this?
private final ArrayList<CraftingTreeProcess> nodes = new ArrayList<>(); private final ArrayList<CraftingTreeProcess> nodes = new ArrayList<>();
private final boolean canEmit;
private CraftingTreeNode loopHead;
private int bytes = 0; private int bytes = 0;
private boolean canEmit = false;
private long missing = 0; private long missing = 0;
private long howManyEmitted = 0; private long howManyEmitted = 0;
private boolean exhausted = false; private boolean exhausted = false;
public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, long amount, final CraftingTreeProcess par, final int slot ) private boolean sim;
public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, final CraftingTreeProcess par, final int slot, final int depth )
{ {
this.what = wat; this.what = wat;
this.parent = par; this.parent = par;
this.slot = slot; this.slot = slot;
this.world = job.getWorld(); this.world = job.getWorld();
this.job = job; this.job = job;
this.sim = false;
this.canEmit = cc.canEmitFor( this.what ); this.canEmit = cc.canEmitFor( this.what );
@@ -83,136 +81,114 @@ public class CraftingTreeNode
for( final ICraftingPatternDetails details : cc.getCraftingFor( this.what, this.parent == null ? null : this.parent.details, slot, this.world ) )// in for( final ICraftingPatternDetails details : cc.getCraftingFor( this.what, this.parent == null ? null : this.parent.details, slot, this.world ) )// in
// order. // order.
{ {
int times = 1; if( this.parent == null || this.parent.notRecursive() )
for( IAEItemStack o : details.getCondensedOutputs() )
{ {
if( what.equals( o ) ) this.nodes.add( new CraftingTreeProcess( cc, job, details, this, depth + 1 ) );
{
times = (int) ( amount / o.getStackSize() + ( amount % o.getStackSize() != 0 ? 1 : 0 ) );
}
}
if( this.parent == null )
{
this.nodes.add( new CraftingTreeProcess( cc, job, details, times, this ) );
continue;
}
if( details == parent.details )
{
continue;
}
CraftingTreeNode recursive = recursiveNode( this );
if( recursive == null )
{
this.nodes.add( new CraftingTreeProcess( cc, job, details, times, this ) );
}
else
{
reserveForNode();
} }
} }
} }
void reserveForNode() public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, final CraftingTreeProcess par, final int slot, final int depth, boolean available )
{ {
if( this.equals( loopHead ) ) this.what = wat;
this.parent = par;
this.slot = slot;
this.world = job.getWorld();
this.job = job;
this.sim = false;
this.canEmit = cc.canEmitFor( this.what );
if( this.canEmit )
{ {
return; return; // if you can emit for something, you can't make it with patterns.
} }
IAEItemStack available = job.checkAvailable( this.what );
if( available != null && available.getStackSize() >= this.what.getStackSize() ) if( !available )
{ {
this.job.reserve( this, this.what.copy() ); for( final ICraftingPatternDetails details : cc.getCraftingFor( this.what, this.parent == null ? null : this.parent.details, slot, this.world ) )// in
// order.
{
if( this.parent == null || this.parent.notRecursive() )
{
this.nodes.add( new CraftingTreeProcess( cc, job, details, this, depth + 1 ) );
}
}
} }
else }
boolean notRecursive( final ICraftingPatternDetails details )
{
IAEItemStack[] o = details.getCondensedOutputs();
for( final IAEItemStack i : o )
{ {
parent.reserveForNode(); if( i.equals( this.what ) )
{
return false;
}
} }
o = details.getCondensedInputs();
for( final IAEItemStack i : o )
{
if( i.equals( this.what ) )
{
return false;
}
}
if( this.parent == null )
{
return true;
}
return this.parent.notRecursive();
} }
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(); this.job.handlePausing();
if( this.canEmit )
{
final IAEItemStack wat = this.what.copy();
wat.setStackSize( l );
this.howManyEmitted = wat.getStackSize();
this.bytes += wat.getStackSize();
return wat;
}
final IItemList<IAEItemStack> inventoryList = inv.getItemList();
IAEItemStack reserved = job.getReserved().get( this );
final List<IAEItemStack> thingsUsed = new ArrayList<>(); final List<IAEItemStack> thingsUsed = new ArrayList<>();
this.what.setStackSize( l ); this.what.setStackSize( l );
if( this.getSlot() >= 0 && this.parent != null && this.parent.details.isCraftable() ) if( this.getSlot() >= 0 && this.parent != null && this.parent.details.isCraftable() )
{ {
Collection<IAEItemStack> itemList = new HashSet<>(); final Collection<IAEItemStack> itemList;
final IItemList<IAEItemStack> inventoryList = inv.getItemList();
if( this.what.getItem().isDamageable() || Platform.isGTDamageableItem( this.what.getItem() ) ) if( this.parent.details.canSubstitute() )
{ {
itemList.addAll( inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL ) ); final List<IAEItemStack> substitutes = this.parent.details.getSubstituteInputs( this.slot );
itemList = new ArrayList<>( substitutes.size() );
if( this.parent.details.canSubstitute() ) for( IAEItemStack stack : substitutes )
{ {
for( IAEItemStack is : inventoryList ) itemList.addAll( inventoryList.findFuzzy( stack, FuzzyMode.IGNORE_ALL ) );
{
if( is.fuzzyComparison( this.what, FuzzyMode.IGNORE_ALL ) )
{
itemList.add( is );
}
}
} }
} }
else else
{ {
itemList = Lists.newArrayList();
final IAEItemStack item = inventoryList.findPrecise( this.what ); final IAEItemStack item = inventoryList.findPrecise( this.what );
if( item != null ) if( item != null )
{ {
itemList.add( item ); itemList.add( item );
} }
if( this.parent.details.canSubstitute() )
{
for( IAEItemStack s : parent.details.getSubstituteInputs( this.slot ) )
{
if( s != null )
{
for( IAEItemStack ss : inventoryList.findFuzzy( s, FuzzyMode.IGNORE_ALL ) )
{
if( ss != null )
{
itemList.add( ss );
}
}
}
}
}
} }
for( IAEItemStack fuzz : itemList ) for( IAEItemStack fuzz : itemList )
{ {
if( this.parent.details.isValidItemForSlot( this.getSlot(), fuzz.getDefinition(), this.world ) ) if( this.parent.details.isValidItemForSlot( this.getSlot(), fuzz.copy().getCachedItemStack( 1 ), this.world ) )
{ {
fuzz = fuzz.copy(); fuzz = fuzz.copy();
fuzz.setStackSize( l ); fuzz.setStackSize( l );
final IAEItemStack available; final IAEItemStack available = inv.extractItems( fuzz, Actionable.MODULATE, src );
if( reserved != null )
{
available = reserved;
}
else
{
available = inv.extractItems( fuzz, Actionable.MODULATE, src );
}
if( available != null ) if( available != null )
{ {
@@ -225,11 +201,6 @@ public class CraftingTreeNode
thingsUsed.add( is.copy() ); thingsUsed.add( is.copy() );
this.used.add( is ); this.used.add( is );
} }
else if( reserved != null )
{
thingsUsed.add( reserved.copy() );
this.used.add( reserved );
}
} }
this.bytes += available.getStackSize(); this.bytes += available.getStackSize();
@@ -245,20 +216,7 @@ public class CraftingTreeNode
} }
else else
{ {
final IAEItemStack available; final IAEItemStack available = inv.extractItems( this.what, Actionable.MODULATE, src );
if( parent == null && this.what.equals( job.getOutput() ) )
{
available = null;
}
else if( reserved != null )
{
available = reserved;
}
else
{
available = inv.extractItems( this.what, Actionable.MODULATE, src );
}
if( available != null ) if( available != null )
{ {
@@ -271,11 +229,6 @@ public class CraftingTreeNode
thingsUsed.add( is.copy() ); thingsUsed.add( is.copy() );
this.used.add( is ); this.used.add( is );
} }
else if( reserved != null )
{
thingsUsed.add( reserved.copy() );
this.used.add( reserved );
}
} }
this.bytes += available.getStackSize(); this.bytes += available.getStackSize();
@@ -288,6 +241,17 @@ public class CraftingTreeNode
} }
} }
if( this.canEmit )
{
final IAEItemStack wat = this.what.copy();
wat.setStackSize( l );
this.howManyEmitted = wat.getStackSize();
this.bytes += wat.getStackSize();
return wat;
}
this.exhausted = true; this.exhausted = true;
if( this.nodes.size() == 1 ) if( this.nodes.size() == 1 )
@@ -301,6 +265,7 @@ public class CraftingTreeNode
pro.request( inv, pro.getTimes( l, madeWhat.getStackSize() ), src ); pro.request( inv, pro.getTimes( l, madeWhat.getStackSize() ), src );
madeWhat.setStackSize( l ); madeWhat.setStackSize( l );
final IAEItemStack available = inv.extractItems( madeWhat, Actionable.MODULATE, src ); final IAEItemStack available = inv.extractItems( madeWhat, Actionable.MODULATE, src );
if( available != null ) if( available != null )
@@ -328,9 +293,7 @@ public class CraftingTreeNode
while ( pro.possible && l > 0 ) while ( pro.possible && l > 0 )
{ {
final MECraftingInventory subInv = new MECraftingInventory( inv, true, true, true ); final MECraftingInventory subInv = new MECraftingInventory( inv, true, true, true );
final IAEItemStack madeWhat = pro.getAmountCrafted( this.what ); pro.request( subInv, 1, src );
pro.request( subInv, pro.getTimes( l, madeWhat.getStackSize() ), src );
this.what.setStackSize( l ); this.what.setStackSize( l );
final IAEItemStack available = subInv.extractItems( this.what, Actionable.MODULATE, src ); final IAEItemStack available = subInv.extractItems( this.what, Actionable.MODULATE, src );
@@ -363,10 +326,10 @@ public class CraftingTreeNode
} }
} }
if( job.isSimulation() ) if( this.sim )
{ {
this.bytes += l;
this.missing += l; this.missing += l;
this.bytes += l;
final IAEItemStack rv = this.what.copy(); final IAEItemStack rv = this.what.copy();
rv.setStackSize( l ); rv.setStackSize( l );
return rv; return rv;
@@ -382,24 +345,9 @@ public class CraftingTreeNode
throw new CraftBranchFailure( this.what, l ); throw new CraftBranchFailure( this.what, l );
} }
CraftingTreeNode recursiveNode( CraftingTreeNode node ) boolean notRecursive()
{ {
if( this.parent == null ) return job.getUniques().findPrecise( this.what ) == null || this.parent == null;
{
return null;
}
if( node != this )
{
if( node.what.equals( this.what ) )
{
if( node.what.getStackSize() == this.what.getStackSize() )
{
loopHead = this;
return node;
}
}
}
return this.parent.notRecursive( node );
} }
void dive( final CraftingJob job ) void dive( final CraftingJob job )
@@ -427,6 +375,7 @@ public class CraftingTreeNode
void setSimulate() void setSimulate()
{ {
this.sim = true;
this.missing = 0; this.missing = 0;
this.bytes = 0; this.bytes = 0;
this.used.resetStatus(); this.used.resetStatus();
@@ -448,21 +397,7 @@ public class CraftingTreeNode
{ {
if( src.player().isPresent() ) if( src.player().isPresent() )
{ {
try src.player().get().sendStatusMessage( new TextComponentString( "System reported " + i.getStackSize() + " " + i.getDefinition().getItem().getItemStackDisplayName( i.getDefinition() ) + " available but could not extract anything" ), false );
{
if( ex == null )
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( i ), (EntityPlayerMP) src.player().get() );
}
else
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( ex, i ), (EntityPlayerMP) src.player().get() );
}
}
catch( IOException e )
{
e.printStackTrace();
}
} }
throw new CraftBranchFailure( i, i.getStackSize() ); throw new CraftBranchFailure( i, i.getStackSize() );
} }
@@ -19,122 +19,86 @@
package appeng.crafting; package appeng.crafting;
import appeng.api.config.Actionable; import java.util.Map.Entry;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.IActionSource;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import com.google.common.collect.ImmutableCollection;
import it.unimi.dsi.fastutil.objects.Object2LongArrayMap; import it.unimi.dsi.fastutil.objects.Object2LongArrayMap;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.ArrayList; import appeng.api.AEApi;
import java.util.List; import appeng.api.config.Actionable;
import java.util.Map.Entry; import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.IActionSource;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.util.Platform;
public class CraftingTreeProcess public class CraftingTreeProcess
{ {
final ICraftingPatternDetails details;
private final CraftingTreeNode parent; private final CraftingTreeNode parent;
final ICraftingPatternDetails details;
private final CraftingJob job; private final CraftingJob job;
private final Object2LongArrayMap<CraftingTreeNode> nodes = new Object2LongArrayMap<>(); private final Object2LongArrayMap<CraftingTreeNode> nodes = new Object2LongArrayMap<>();
private final int depth;
boolean possible = true; boolean possible = true;
private long crafts = 0; private long crafts = 0;
private IItemList<IAEItemStack> containerItems;
private boolean limitQty;
private long bytes = 0; private long bytes = 0;
private boolean hasContainerItem = false;
public CraftingTreeProcess( final ICraftingGrid cc, final CraftingJob job, final ICraftingPatternDetails details, int times, final CraftingTreeNode craftingTreeNode ) public CraftingTreeProcess( final ICraftingGrid cc, final CraftingJob job, final ICraftingPatternDetails details, final CraftingTreeNode craftingTreeNode, final int depth )
{ {
this.parent = craftingTreeNode; this.parent = craftingTreeNode;
this.details = details; this.details = details;
this.job = job; this.job = job;
World world = job.getWorld(); this.depth = depth;
final World world = job.getWorld();
final IAEItemStack[] list = details.getInputs(); final IAEItemStack[] list = details.getInputs();
// this is minor different then below, this slot uses the pattern, but kinda fudges it. for( final IAEItemStack part : details.getCondensedInputs() )
for( IAEItemStack part : details.getCondensedInputs() )
{ {
if( part == null ) if( part.getItem().hasContainerItem( part.getDefinition() ) )
{ {
if( containerItems == null )
{
containerItems = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
}
containerItems.add( part );
this.limitQty = true;
}
}
// this is minor different then below, this slot uses the pattern, but kinda fudges it.
for( IAEItemStack part : details.getCondensedInputs() ) {
if (part == null) {
continue; continue;
} }
for( int x = 0; x < list.length; x++ ) for (int x = 0; x < list.length; x++) {
{
final IAEItemStack comparePart = list[x]; final IAEItemStack comparePart = list[x];
if( part.equals( comparePart ) ) if (part.equals(comparePart)) {
{ if (isContainerItem(part)) {
boolean isPartContainer = false;
if( part.getItem().hasContainerItem( part.getDefinition() ) )
{
part = list[x]; part = list[x];
isPartContainer = true;
this.hasContainerItem = true;
} }
this.nodes.put(new CraftingTreeNode(cc, job, part.copy(), this, x, depth + 1), part.getStackSize());
long wantedSize = isPartContainer ? part.getStackSize() : part.getStackSize() * times; if (details.canSubstitute()) {
for ()
if( details.canSubstitute() && cc.getCraftingFor( part, details, x, world ).isEmpty() )
{
for( IAEItemStack subs : details.getSubstituteInputs( x ) )
{
if( subs.fuzzyComparison( part, FuzzyMode.IGNORE_ALL ) )
{
this.nodes.put( new CraftingTreeNode( cc, job, subs.copy(), wantedSize, this, x ), part.getStackSize() / times );
wantedSize = 0;
break;
}
}
//try to order the crafting of a substitute
ICraftingPatternDetails prioritizedPattern = null;
IAEItemStack prioritizedIAE = null;
for( IAEItemStack subs : details.getSubstituteInputs( x ) )
{
if( subs.equals( part ) )
{
continue;
}
ImmutableCollection<ICraftingPatternDetails> detailCollection = cc.getCraftingFor( subs, details, x, world );
for( ICraftingPatternDetails sp : detailCollection )
{
if( prioritizedPattern == null )
{
prioritizedPattern = sp;
prioritizedIAE = subs;
}
else
{
if( sp.getPriority() > prioritizedPattern.getPriority() )
{
prioritizedPattern = sp;
}
}
}
if( prioritizedIAE != null )
{
this.nodes.put( new CraftingTreeNode( cc, job, prioritizedIAE.copy(), wantedSize, this, x ), part.getStackSize() / times );
wantedSize = 0;
break;
}
}
} }
if( wantedSize > 0 ) break;
{ }
part = part.copy().setStackSize( wantedSize ); }
// use the first slot... }
this.nodes.put( new CraftingTreeNode( cc, job, part.copy(), wantedSize, this, x ), part.getStackSize() / times );
wantedSize = 0; if(!this.limitQty) {
} for (final IAEItemStack part : details.getCondensedOutputs()) {
if( !isPartContainer && wantedSize == 0 ) for (final IAEItemStack o : details.getCondensedInputs()) {
{ if (part.equals(o)) {
this.limitQty = true;
break; break;
} }
} }
@@ -142,18 +106,18 @@ public class CraftingTreeProcess
} }
} }
CraftingTreeNode notRecursive( CraftingTreeNode node ) boolean isContainerItem(IAEItemStack iaeItemStack) {
return (containerItems != null && !containerItems.findFuzzy(iaeItemStack, FuzzyMode.IGNORE_ALL).isEmpty());
}
boolean notRecursive()
{ {
if( parent == null ) return this.parent == null || this.parent.notRecursive();
{
return null;
}
return this.parent.recursiveNode( node );
} }
long getTimes( final long remaining, final long stackSize ) long getTimes( final long remaining, final long stackSize )
{ {
if( hasContainerItem ) if( this.limitQty )
{ {
return 1; return 1;
} }
@@ -163,43 +127,25 @@ public class CraftingTreeProcess
void request( final MECraftingInventory inv, final long amountOfTimes, final IActionSource src ) throws CraftBranchFailure, InterruptedException void request( final MECraftingInventory inv, final long amountOfTimes, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing(); this.job.handlePausing();
List<IAEItemStack> containerItems = null;
// request and remove inputs... // request and remove inputs...
for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() ) for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
final IAEItemStack stack = entry.getKey().request( inv, details.isCraftable() && hasContainerItem ? 1 : entry.getValue() * amountOfTimes, src ); final IAEItemStack craftableStack = entry.getKey().getStack( entry.getValue() );
final IAEItemStack stack = entry.getKey().request( inv, craftableStack.getStackSize() * amountOfTimes, src );
if( stack.equals( job.getOutput() ) ) if( containerItems != null && !this.containerItems.findFuzzy( stack, FuzzyMode.IGNORE_ALL ).isEmpty() )
{
job.getNeededForLoop().add( stack.copy() );
}
if( details.isCraftable() && stack.getItem().hasContainerItem( stack.getDefinition() ) )
{ {
final ItemStack is = Platform.getContainerItem( stack.createItemStack() ); final ItemStack is = Platform.getContainerItem( stack.createItemStack() );
final IAEItemStack o = AEItemStack.fromItemStack( is ); final IAEItemStack o = AEItemStack.fromItemStack( is );
if( o != null ) if( o != null )
{ {
if( containerItems == null )
{
containerItems = new ArrayList<>();
}
this.bytes++; this.bytes++;
o.setCachedItemStack( is ); inv.injectItems( o, Actionable.MODULATE, src );
containerItems.add( o );
}
if( containerItems != null )
{
for( IAEItemStack i : containerItems )
{
inv.injectItems( i, Actionable.MODULATE, src );
}
} }
} }
} }
// assume its possible. // assume its possible.
// add crafting results.. // add crafting results..
@@ -214,7 +160,7 @@ public class CraftingTreeProcess
void dive( final CraftingJob job ) void dive( final CraftingJob job )
{ {
job.addTask( this.getAmountCrafted( this.parent.getStack( 1 ) ), this.crafts ); job.addTask( this.getAmountCrafted( this.parent.getStack( 1 ) ), this.crafts, this.details, this.depth );
for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() ) for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
entry.getKey().dive( job ); entry.getKey().dive( job );
@@ -284,9 +230,4 @@ public class CraftingTreeProcess
entry.getKey().getPlan( plan ); entry.getKey().getPlan( plan );
} }
} }
public void reserveForNode()
{
parent.reserveForNode();
}
} }
@@ -28,14 +28,10 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.core.sync.network.NetworkHandler; import appeng.me.helpers.PlayerSource;
import appeng.core.sync.packets.PacketInformPlayer;
import appeng.util.inv.ItemListIgnoreCrafting; import appeng.util.inv.ItemListIgnoreCrafting;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import java.io.IOException;
public class MECraftingInventory implements IMEInventory<IAEItemStack> public class MECraftingInventory implements IMEInventory<IAEItemStack>
{ {
@@ -314,20 +310,13 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
{ {
if( src.player().isPresent() ) if( src.player().isPresent() )
{ {
try if( result == null )
{ {
if( result == null ) src.player().get().sendStatusMessage( new TextComponentString( "System reported " + extra.getStackSize() + " " + extra.getDefinition().getItem().getItemStackDisplayName( extra.getDefinition() ) + " available but could not extract anything" ), false );
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( extra ), (EntityPlayerMP) src.player().get() );
}
else
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( extra, result ), (EntityPlayerMP) src.player().get() );
}
} }
catch( IOException e ) else
{ {
e.printStackTrace(); src.player().get().sendStatusMessage( new TextComponentString( "System reported " + extra.getStackSize() + " " + extra.getDefinition().getItem().getItemStackDisplayName( extra.getDefinition() ) + " available but could only extract " + result.getStackSize() ), false );
} }
} }
failed = true; failed = true;
@@ -361,6 +350,11 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
return true; return true;
} }
private void addMissing( final IAEItemStack extra )
{
this.missingCache.add( extra );
}
void ignore( final IAEItemStack what ) void ignore( final IAEItemStack what )
{ {
final IAEItemStack list = this.localCache.findPrecise( what ); final IAEItemStack list = this.localCache.findPrecise( what );
@@ -369,18 +363,4 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
list.setStackSize( 0 ); list.setStackSize( 0 );
} }
} }
void reserve( final IAEItemStack what )
{
final IAEItemStack list = this.localCache.findPrecise( what );
if( list != null )
{
list.decStackSize( what.getStackSize() );
}
}
private void addMissing( final IAEItemStack extra )
{
this.missingCache.add( extra );
}
} }
@@ -414,7 +414,7 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
} }
} }
if( notInserted == null || notInserted.getStackSize() == 0 ) if( notInserted == null )
{ {
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) ) if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{ {
@@ -19,58 +19,15 @@
package appeng.helpers; package appeng.helpers;
import appeng.api.AEApi; import java.util.*;
import appeng.api.config.Actionable;
import appeng.api.config.Settings; import javax.annotation.Nullable;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo; import appeng.util.inv.BlockingInventoryAdaptor;
import appeng.api.implementations.ICraftingPatternItem; import appeng.util.*;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.implementations.tiles.ICraftingMachine;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.crafting.ICraftingProviderHelper;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.events.MENetworkCraftingPatternChange;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPart;
import appeng.api.storage.*;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.api.util.IConfigManager;
import appeng.capabilities.Capabilities;
import appeng.core.settings.TickRates;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
import appeng.me.helpers.MachineSource;
import appeng.me.storage.MEMonitorIInventory;
import appeng.me.storage.MEMonitorPassThrough;
import appeng.me.storage.NullInventory;
import appeng.parts.automation.StackUpgradeInventory;
import appeng.parts.automation.UpgradeInventory;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.inv.*; import appeng.util.inv.*;
import appeng.util.item.AEItemStack;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import de.ellpeck.actuallyadditions.api.tile.IPhantomTile; import de.ellpeck.actuallyadditions.api.tile.IPhantomTile;
import gregtech.api.block.machines.BlockMachine; import gregtech.api.block.machines.BlockMachine;
@@ -95,8 +52,56 @@ import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.RangedWrapper; import net.minecraftforge.items.wrapper.RangedWrapper;
import javax.annotation.Nullable; import appeng.api.AEApi;
import java.util.*; import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.implementations.tiles.ICraftingMachine;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.crafting.ICraftingProviderHelper;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.events.MENetworkCraftingPatternChange;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPart;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.IStorageMonitorableAccessor;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.api.util.IConfigManager;
import appeng.capabilities.Capabilities;
import appeng.core.settings.TickRates;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
import appeng.me.helpers.MachineSource;
import appeng.me.storage.MEMonitorIInventory;
import appeng.me.storage.MEMonitorPassThrough;
import appeng.me.storage.NullInventory;
import appeng.parts.automation.StackUpgradeInventory;
import appeng.parts.automation.UpgradeInventory;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.item.AEItemStack;
import static gregtech.api.block.machines.BlockMachine.getMetaTileEntity; import static gregtech.api.block.machines.BlockMachine.getMetaTileEntity;
@@ -108,7 +113,9 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
public static final int NUMBER_OF_PATTERN_SLOTS = 36; public static final int NUMBER_OF_PATTERN_SLOTS = 36;
private static final Collection<Block> BAD_BLOCKS = new HashSet<>( 100 ); private static final Collection<Block> BAD_BLOCKS = new HashSet<>( 100 );
private final IAEItemStack[] requireWork = {null, null, null, null, null, null, null, null, null}; private final IAEItemStack[] requireWork = {
null, null, null, null, null, null, null, null, null
};
private final MultiCraftingTracker craftingTracker; private final MultiCraftingTracker craftingTracker;
private final AENetworkProxy gridProxy; private final AENetworkProxy gridProxy;
private final IInterfaceHost iHost; private final IInterfaceHost iHost;
@@ -121,13 +128,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) );
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) );
private final UpgradeInventory upgrades; private final UpgradeInventory upgrades;
private final Accessor accessor = new Accessor();
private boolean hasConfig = false; private boolean hasConfig = false;
private int priority; private int priority;
private List<ICraftingPatternDetails> craftingList = null; private List<ICraftingPatternDetails> craftingList = null;
private List<ItemStack> waitingToSend = null; private List<ItemStack> waitingToSend = null;
private IMEInventory<IAEItemStack> destination; private IMEInventory<IAEItemStack> destination;
private int isWorking = -1; private int isWorking = -1;
private final Accessor accessor = new Accessor();
private EnumSet<EnumFacing> visitedFaces = EnumSet.noneOf( EnumFacing.class ); private EnumSet<EnumFacing> visitedFaces = EnumSet.noneOf( EnumFacing.class );
private EnumMap<EnumFacing, List<ItemStack>> waitingToSendFacing = new EnumMap<>( EnumFacing.class ); private EnumMap<EnumFacing, List<ItemStack>> waitingToSendFacing = new EnumMap<>( EnumFacing.class );
private boolean resetConfigCache = true; private boolean resetConfigCache = true;
@@ -153,11 +160,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.interfaceRequestSource = new InterfaceRequestSource( this.iHost ); this.interfaceRequestSource = new InterfaceRequestSource( this.iHost );
} }
private static boolean invIsCustomBlocking( BlockingInventoryAdaptor inv )
{
return ( inv.containsBlockingItems() );
}
@Override @Override
public void saveChanges() public void saveChanges()
{ {
@@ -279,7 +281,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final NBTTagCompound waitingListSided = data.getCompoundTag( "sidedWaitList" ); final NBTTagCompound waitingListSided = data.getCompoundTag( "sidedWaitList" );
for( EnumFacing s : EnumFacing.values() ) for( EnumFacing s : EnumFacing.values() )
{
if( waitingListSided.hasKey( s.name() ) ) if( waitingListSided.hasKey( s.name() ) )
{ {
NBTTagList w = waitingListSided.getTagList( s.name(), 10 ); NBTTagList w = waitingListSided.getTagList( s.name(), 10 );
@@ -293,7 +294,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
} }
}
this.craftingTracker.readFromNBT( data ); this.craftingTracker.readFromNBT( data );
@@ -464,7 +464,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
try try
{ {
this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) ); this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) );
} }
catch( GridAccessException e ) catch( GridAccessException e )
{ {
@@ -909,6 +909,10 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
changed = true; changed = true;
throw new GridAccessException(); throw new GridAccessException();
} }
else
{
itemStack.setCachedItemStack( inputStack );
}
IAEItemStack storedStack = this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findPrecise( itemStack ); IAEItemStack storedStack = this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findPrecise( itemStack );
if( storedStack != null ) if( storedStack != null )
@@ -926,13 +930,8 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
else if( storedStack.isCraftable() ) else if( storedStack.isCraftable() )
{ {
itemStack.setCachedItemStack( inputStack );
changed = this.handleCrafting( x, adaptor, itemStack ) || changed; changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
} }
if( acquired == null )
{
itemStack.setCachedItemStack( inputStack );
}
} }
} }
// else wtf? // else wtf?
@@ -1105,6 +1104,11 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return ( inv.containsItems() ); return ( inv.containsItems() );
} }
private static boolean invIsCustomBlocking( BlockingInventoryAdaptor inv )
{
return ( inv.containsBlockingItems() );
}
@Override @Override
public boolean pushPattern( final ICraftingPatternDetails patternDetails, final InventoryCrafting table ) public boolean pushPattern( final ICraftingPatternDetails patternDetails, final InventoryCrafting table )
{ {
@@ -1154,7 +1158,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() ); final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
if( ad != null ) if( ad != null )
{ {
if( this.isBlocking() ) if( this.isBlocking() )
@@ -1166,7 +1170,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if( phantomTE.hasBoundPosition() ) if( phantomTE.hasBoundPosition() )
{ {
TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() ); TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() );
if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( phantomTE.getBoundPosition() ).getBlock().getRegistryName().getResourceDomain() ) ) if( NonBlockingItems.INSTANCE.getMap().containsKey( phantom.getBlockType().getRegistryName().getResourceDomain() ) )
{ {
if( isCustomInvBlocking( phantom, s ) ) if( isCustomInvBlocking( phantom, s ) )
{ {
@@ -1176,7 +1180,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
} }
else if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( tile.getPos().offset( s ) ).getBlock().getRegistryName().getResourceDomain() ) ) else if( NonBlockingItems.INSTANCE.getMap().containsKey( te.getBlockType().getRegistryName().getResourceDomain() ) )
{ {
if( isCustomInvBlocking( te, s ) ) if( isCustomInvBlocking( te, s ) )
{ {
@@ -1184,6 +1188,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
continue; continue;
} }
} }
else if( invIsBlocked( ad ) ) else if( invIsBlocked( ad ) )
{ {
visitedFaces.remove( s ); visitedFaces.remove( s );
@@ -1243,7 +1248,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if( phantomTE.hasBoundPosition() ) if( phantomTE.hasBoundPosition() )
{ {
TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() ); TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() );
if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( phantomTE.getBoundPosition() ).getBlock().getRegistryName().getResourceDomain() ) ) if( NonBlockingItems.INSTANCE.getMap().containsKey( phantom.getBlockType().getRegistryName().getResourceDomain() ) )
{ {
if( !isCustomInvBlocking( phantom, s ) ) if( !isCustomInvBlocking( phantom, s ) )
{ {
@@ -1253,7 +1258,8 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
} }
else if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( tile.getPos().offset( s ) ).getBlock().getRegistryName().getResourceDomain() ) )
else if( NonBlockingItems.INSTANCE.getMap().containsKey( te.getBlockType().getRegistryName().getResourceDomain() ) )
{ {
if( !isCustomInvBlocking( te, s ) ) if( !isCustomInvBlocking( te, s ) )
{ {
@@ -1261,13 +1267,11 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
break; break;
} }
} }
else
else if( !invIsBlocked( ad ) )
{ {
if( !invIsBlocked( ad ) ) allAreBusy = false;
{ break;
allAreBusy = false;
break;
}
} }
} }
} }
@@ -1593,7 +1597,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
private class InterfaceRequestContext implements Comparable<Integer> private class InterfaceRequestContext implements Comparable<Integer>
{ {
@@ -1604,7 +1607,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
private class InterfaceInventory extends MEMonitorIInventory private class InterfaceInventory extends MEMonitorIInventory
{ {
@@ -1642,7 +1644,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
private class Accessor implements IStorageMonitorableAccessor private class Accessor implements IStorageMonitorableAccessor
{ {
@@ -2,7 +2,6 @@ package appeng.helpers;
import appeng.core.AEConfig; import appeng.core.AEConfig;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.util.Platform;
import gregtech.api.items.metaitem.MetaItem; import gregtech.api.items.metaitem.MetaItem;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
@@ -51,19 +50,16 @@ public class NonBlockingItems
continue; continue;
} }
if( ModItemMeta[0].equals( "gregtech" ) && Platform.isModLoaded( "gregtech" ) ) if( ModItemMeta[0].equals( "gregtech" ) )
{ {
boolean found = false;
for( MetaItem<?> metaItem : MetaItem.getMetaItems() ) for( MetaItem<?> metaItem : MetaItem.getMetaItems() )
{ {
MetaItem<?>.MetaValueItem metaItem2 = metaItem.getItem( ModItemMeta[1] ); MetaItem<?>.MetaValueItem metaItem2 = metaItem.getItem( ModItemMeta[1] );
if( metaItem.getItem( ModItemMeta[1] ) != null ) if( metaItem.getItem( ModItemMeta[1] ) != null )
{ {
found = true;
ItemStack itemStack = metaItem2.getStackForm(); ItemStack itemStack = metaItem2.getStackForm();
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() ); NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> {
{
intSet.add( itemStack.getItemDamage() ); intSet.add( itemStack.getItemDamage() );
return intSet; return intSet;
} ); } );
@@ -74,30 +70,28 @@ public class NonBlockingItems
if( !itemStack.isEmpty() ) if( !itemStack.isEmpty() )
{ {
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() ); NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> {
{
intSet.add( itemStack.getItemDamage() ); intSet.add( itemStack.getItemDamage() );
return intSet; return intSet;
} ); } );
} }
else
{
AELog.error( "Item not found on nonBlocking config: " + s );
}
} }
} break;
if( !found )
{
AELog.error( "Item not found on nonBlocking config: " + s );
} }
} }
else if( ModItemMeta[0].equals( "ore" ) ) else if( ModItemMeta[0].equals( "ore" ) )
{ {
OreDictionary.getOres( ModItemMeta[1] ).forEach( itemStack -> OreDictionary.getOres( ModItemMeta[1] ).forEach( itemStack -> {
{ NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() ); NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> {
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> intSet.add( itemStack.getItemDamage() );
{ return intSet;
intSet.add( itemStack.getItemDamage() ); } );
return intSet; } );
} );
} );
} }
else else
{ {
@@ -105,8 +99,7 @@ public class NonBlockingItems
if( !itemStack.isEmpty() ) if( !itemStack.isEmpty() )
{ {
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() ); NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) -> {
{
intSet.add( itemStack.getItemDamage() ); intSet.add( itemStack.getItemDamage() );
return intSet; return intSet;
} ); } );
@@ -126,8 +119,4 @@ public class NonBlockingItems
{ {
return NON_BLOCKING_MAP; return NON_BLOCKING_MAP;
} }
public void init()
{
}
} }
+32 -54
View File
@@ -40,7 +40,6 @@ import appeng.container.ContainerNull;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import net.minecraftforge.common.crafting.IShapedRecipe; import net.minecraftforge.common.crafting.IShapedRecipe;
import net.minecraftforge.fml.common.Optional;
public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper> public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper>
@@ -248,7 +247,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
final TestStatus result = this.getStatus( slotIndex, i ); final TestStatus result = this.getStatus( slotIndex, i );
switch ( result ) switch( result )
{ {
case ACCEPT: case ACCEPT:
return true; return true;
@@ -267,11 +266,9 @@ 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 we cannot substitute, the items must match exactly
if( ( !( i.getItem().isDamageable() || Platform.isGTDamageableItem( i.getItem() ) ) && !canSubstitute ) && slotIndex < inputs.length ) if (!canSubstitute && slotIndex < inputs.length) {
{ if (!inputs[slotIndex].isSameType(i)) {
if( !inputs[slotIndex].isSameType( i ) ) this.markItemAs(slotIndex, i, TestStatus.DECLINE);
{
this.markItemAs( slotIndex, i, TestStatus.DECLINE );
return false; return false;
} }
} }
@@ -329,26 +326,23 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
} }
@Override @Override
public List<IAEItemStack> getSubstituteInputs( int slot ) public List<IAEItemStack> getSubstituteInputs(int slot) {
{ if (this.inputs[slot] == null) {
if( this.inputs[slot] == null )
{
return Collections.emptyList(); return Collections.emptyList();
} }
return this.substituteInputs.computeIfAbsent( slot, value -> { return this.substituteInputs.computeIfAbsent(slot, value -> {
ItemStack[] matchingStacks = getRecipeIngredient( slot ).getMatchingStacks(); ItemStack[] matchingStacks = getRecipeIngredient(slot).getMatchingStacks();
List<IAEItemStack> itemList = new ArrayList<>( matchingStacks.length + 1 ); List<IAEItemStack> itemList = new ArrayList<>(matchingStacks.length + 1);
for( ItemStack matchingStack : matchingStacks ) for (ItemStack matchingStack : matchingStacks) {
{ itemList.add(AEItemStack.fromItemStack(matchingStack));
itemList.add( AEItemStack.fromItemStack( matchingStack ) );
} }
// Ensure that the specific item put in by the user is at the beginning, // Ensure that the specific item put in by the user is at the beginning,
// so that it takes precedence over substitutions // so that it takes precedence over substitutions
itemList.add( 0, this.inputs[slot] ); itemList.add(0, this.inputs[slot]);
return itemList; return itemList;
} ); });
} }
/** /**
@@ -358,40 +352,31 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
* ingredient list will be condensed to the actual recipe's grid size. In addition, in our 3x3 grid, the user can * 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. * shift the actual recipe input to the right and down.
*/ */
private Ingredient getRecipeIngredient( int slot ) private Ingredient getRecipeIngredient(int slot) {
{
if( standardRecipe instanceof IShapedRecipe ) if (standardRecipe instanceof IShapedRecipe ) {
{
IShapedRecipe shapedRecipe = (IShapedRecipe) standardRecipe; IShapedRecipe shapedRecipe = (IShapedRecipe) standardRecipe;
return getShapedRecipeIngredient( slot, shapedRecipe.getRecipeWidth() ); return getShapedRecipeIngredient(slot, shapedRecipe.getRecipeWidth());
} } else {
else return getShapelessRecipeIngredient(slot);
{
return getShapelessRecipeIngredient( slot );
} }
} }
private Ingredient getShapedRecipeIngredient( int slot, int recipeWidth ) private Ingredient getShapedRecipeIngredient(int slot, int recipeWidth) {
{
// Compute the offset of the user's input vs. crafting grid origin // 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 // Which is >0 if they have empty rows above or to the left of their input
int topOffset = 0; int topOffset = 0;
if( inputs[0] == null && inputs[1] == null && inputs[2] == null ) if (inputs[0] == null && inputs[1] == null && inputs[2] == null) {
{
topOffset++; // First row is fully empty topOffset++; // First row is fully empty
if( inputs[3] == null && inputs[4] == null && inputs[5] == null ) if (inputs[3] == null && inputs[4] == null && inputs[5] == null) {
{
topOffset++; // Second row is fully empty topOffset++; // Second row is fully empty
} }
} }
int leftOffset = 0; int leftOffset = 0;
if( inputs[0] == null && inputs[3] == null && inputs[6] == null ) if (inputs[0] == null && inputs[3] == null && inputs[6] == null) {
{
leftOffset++; // First column is fully empty leftOffset++; // First column is fully empty
if( inputs[1] == null && inputs[4] == null && inputs[7] == null ) if (inputs[1] == null && inputs[4] == null && inputs[7] == null) {
{
leftOffset++; // Second column is fully empty leftOffset++; // Second column is fully empty
} }
} }
@@ -405,37 +390,32 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
NonNullList<Ingredient> ingredients = standardRecipe.getIngredients(); NonNullList<Ingredient> ingredients = standardRecipe.getIngredients();
if( ingredientIndex < 0 || ingredientIndex > ingredients.size() ) if (ingredientIndex < 0 || ingredientIndex > ingredients.size()) {
{
return Ingredient.EMPTY; return Ingredient.EMPTY;
} }
return ingredients.get( ingredientIndex ); return ingredients.get(ingredientIndex);
} }
private Ingredient getShapelessRecipeIngredient( int slot ) private Ingredient getShapelessRecipeIngredient(int slot) {
{
// We map the list of *filled* sparse inputs to the shapeless (ergo unordered) // We map the list of *filled* sparse inputs to the shapeless (ergo unordered)
// ingredients. While these do not actually correspond to each other, // ingredients. While these do not actually correspond to each other,
// since both lists have the same length, the mapping is at least stable. // since both lists have the same length, the mapping is at least stable.
int ingredientIndex = 0; int ingredientIndex = 0;
for( int i = 0; i < slot; i++ ) for (int i = 0; i < slot; i++) {
{ if (inputs[i] != null) {
if( inputs[i] != null )
{
ingredientIndex++; ingredientIndex++;
} }
} }
NonNullList<Ingredient> ingredients = standardRecipe.getIngredients(); NonNullList<Ingredient> ingredients = standardRecipe.getIngredients();
if( ingredientIndex < ingredients.size() ) if (ingredientIndex < ingredients.size()) {
{ return ingredients.get(ingredientIndex);
return ingredients.get( ingredientIndex );
} }
return Ingredient.EMPTY; return Ingredient.EMPTY;
} }
@Override @Override
public ItemStack getOutput( final InventoryCrafting craftingInv, final World w ) public ItemStack getOutput( final InventoryCrafting craftingInv, final World w )
{ {
@@ -537,9 +517,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
private enum TestStatus private enum TestStatus
{ {
ACCEPT, ACCEPT, DECLINE, TEST
DECLINE,
TEST
} }
private static final class TestLookup private static final class TestLookup
+8 -34
View File
@@ -19,12 +19,13 @@
package appeng.me.cache; package appeng.me.cache;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.crafting.MECraftingInventory;
import appeng.helpers.IInterfaceHost;
import appeng.helpers.IPriorityHost;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
@@ -54,8 +55,6 @@ import appeng.me.helpers.GenericInterestManager;
import appeng.me.helpers.MachineSource; import appeng.me.helpers.MachineSource;
import appeng.me.storage.ItemWatcher; import appeng.me.storage.ItemWatcher;
import appeng.me.storage.NetworkInventoryHandler; import appeng.me.storage.NetworkInventoryHandler;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class GridStorageCache implements IStorageGrid public class GridStorageCache implements IStorageGrid
@@ -69,8 +68,6 @@ public class GridStorageCache implements IStorageGrid
private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>(); private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>();
private final Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks; private final Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks;
private final Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors; private final Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors;
private MECraftingInventory localCache = null;
private final Int2ObjectMap<MECraftingInventory> extractableItemPriorityMap = new Int2ObjectOpenHashMap<>();
private int localDepth; private int localDepth;
public GridStorageCache( final IGrid g ) public GridStorageCache( final IGrid g )
@@ -85,8 +82,6 @@ public class GridStorageCache implements IStorageGrid
@Override @Override
public void onUpdateTick() public void onUpdateTick()
{ {
this.localCache = null;
this.extractableItemPriorityMap.clear();
this.storageMonitors.forEach( ( channel, monitor ) -> monitor.onTick() ); this.storageMonitors.forEach( ( channel, monitor ) -> monitor.onTick() );
} }
@@ -174,28 +169,6 @@ public class GridStorageCache implements IStorageGrid
return (IMEMonitor<T>) this.storageMonitors.get( channel ); return (IMEMonitor<T>) this.storageMonitors.get( channel );
} }
public MECraftingInventory getExtractableList( IActionSource src )
{
if( src instanceof MachineSource )
{
if( src.machine().isPresent() )
{
IActionHost machine = src.machine().get();
if( machine instanceof IInterfaceHost )
{
extractableItemPriorityMap.putIfAbsent( ( (IPriorityHost) machine ).getPriority(), new MECraftingInventory( getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), src, false, false, false ) );
return extractableItemPriorityMap.get( ( (IPriorityHost) machine ).getPriority() );
}
}
}
if( localCache == null )
{
localCache = new MECraftingInventory( getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), src, false, false, false );
}
return localCache;
}
private CellChangeTracker addCellProvider( final ICellProvider cc, final CellChangeTracker tracker ) private CellChangeTracker addCellProvider( final ICellProvider cc, final CellChangeTracker tracker )
{ {
if( this.inactiveCellProviders.contains( cc ) ) if( this.inactiveCellProviders.contains( cc ) )
@@ -225,7 +198,8 @@ public class GridStorageCache implements IStorageGrid
final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource(); final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource();
this.storageMonitors.forEach( ( channel, monitor ) -> { this.storageMonitors.forEach( ( channel, monitor ) ->
{
for( final IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( channel ) ) for( final IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( channel ) )
{ {
tracker.postChanges( channel, -1, h, actionSrc ); tracker.postChanges( channel, -1, h, actionSrc );
@@ -19,6 +19,22 @@
package appeng.me.cluster.implementations; package appeng.me.cluster.implementations;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import appeng.api.config.Upgrades;
import appeng.helpers.DualityInterface;
import appeng.helpers.PatternHelper;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
@@ -27,7 +43,14 @@ import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost; import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.*; import appeng.api.networking.crafting.CraftingItemList;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingJob;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingMedium;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingRequester;
import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.events.MENetworkCraftingCpuChange; import appeng.api.networking.events.MENetworkCraftingCpuChange;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
@@ -40,8 +63,11 @@ import appeng.api.storage.data.IItemList;
import appeng.api.util.WorldCoord; import appeng.api.util.WorldCoord;
import appeng.container.ContainerNull; import appeng.container.ContainerNull;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.crafting.*; import appeng.crafting.CraftBranchFailure;
import appeng.helpers.PatternHelper; import appeng.crafting.CraftingJob;
import appeng.crafting.CraftingLink;
import appeng.crafting.CraftingWatcher;
import appeng.crafting.MECraftingInventory;
import appeng.me.cache.CraftingGridCache; import appeng.me.cache.CraftingGridCache;
import appeng.me.cluster.IAECluster; import appeng.me.cluster.IAECluster;
import appeng.me.helpers.MachineSource; import appeng.me.helpers.MachineSource;
@@ -49,17 +75,6 @@ import appeng.tile.crafting.TileCraftingMonitorTile;
import appeng.tile.crafting.TileCraftingTile; import appeng.tile.crafting.TileCraftingTile;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public final class CraftingCPUCluster implements IAECluster, ICraftingCPU public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
@@ -87,7 +102,6 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
private IAEItemStack finalOutput; private IAEItemStack finalOutput;
private boolean waiting = false; private boolean waiting = false;
private IItemList<IAEItemStack> waitingFor = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private IItemList<IAEItemStack> waitingFor = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private IItemList<IAEItemStack> neededForLoop = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private long availableStorage = 0; private long availableStorage = 0;
private MachineSource machineSrc = null; private MachineSource machineSrc = null;
private int accelerator = 0; private int accelerator = 0;
@@ -210,10 +224,13 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
public boolean canAccept( final IAEItemStack input ) public boolean canAccept( final IAEItemStack input )
{ {
if( input != null ) if( input instanceof IAEItemStack )
{ {
final IAEItemStack is = this.waitingFor.findPrecise( input ); final IAEItemStack is = this.waitingFor.findPrecise( input );
return is != null && is.getStackSize() > 0; if( is != null && is.getStackSize() > 0 )
{
return true;
}
} }
return false; return false;
} }
@@ -222,8 +239,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
// also stop accepting items when the job is complete, i.e. to prevent re-insertion when pushing out // also stop accepting items when the job is complete, i.e. to prevent re-insertion when pushing out
// items during storeItems // items during storeItems
if( input == null || isComplete ) if (input == null || isComplete) {
{
return input; return input;
} }
@@ -287,28 +303,9 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
if( this.finalOutput.equals( what ) ) if( this.finalOutput.equals( what ) )
{ {
IAEItemStack isLoop = neededForLoop.findPrecise( finalOutput );
IAEItemStack leftover = what; IAEItemStack leftover = what;
if( isLoop != null && isLoop.getStackSize() > 0 ) this.finalOutput.decStackSize( what.getStackSize() );
{
if( isLoop.getStackSize() >= what.getStackSize() )
{
leftover = this.inventory.injectItems( what.copy(), type, src );
isLoop.decStackSize( what.getStackSize() );
}
else
{
leftover = this.inventory.injectItems( what.copy().setStackSize( what.getStackSize() - isLoop.getStackSize() ), type, src );
isLoop.decStackSize( what.getStackSize() - isLoop.getStackSize() );
}
if( leftover == null )
{
return null;
}
}
this.finalOutput.decStackSize( leftover.getStackSize() );
if( this.myLastLink != null ) if( this.myLastLink != null )
{ {
@@ -338,28 +335,9 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
if( this.finalOutput.equals( insert ) ) if( this.finalOutput.equals( insert ) )
{ {
IAEItemStack isLoop = neededForLoop.findPrecise( finalOutput );
IAEItemStack leftover = input; IAEItemStack leftover = input;
if( isLoop != null && isLoop.getStackSize() > 0 ) this.finalOutput.decStackSize( insert.getStackSize() );
{
if( isLoop.getStackSize() >= insert.getStackSize() )
{
leftover = this.inventory.injectItems( insert.copy(), type, src );
isLoop.decStackSize( insert.getStackSize() );
}
else
{
leftover = this.inventory.injectItems( insert.copy().setStackSize( insert.getStackSize() - isLoop.getStackSize() ), type, src );
isLoop.decStackSize( insert.getStackSize() - isLoop.getStackSize() );
}
if( leftover == null )
{
return null;
}
}
this.finalOutput.decStackSize( leftover.getStackSize() );
if( this.myLastLink != null ) if( this.myLastLink != null )
{ {
@@ -397,7 +375,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
final ImmutableList<IAEItemStack> single = ImmutableList.of( diff.copy() ); final ImmutableList<IAEItemStack> single = ImmutableList.of( diff.copy() );
while ( i.hasNext() ) while( i.hasNext() )
{ {
final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> o = i.next(); final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> o = i.next();
final IMEMonitorHandlerReceiver<IAEItemStack> receiver = o.getKey(); final IMEMonitorHandlerReceiver<IAEItemStack> receiver = o.getKey();
@@ -517,14 +495,15 @@ 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)
{ {
if( !details.isCraftable() ) if( !details.isCraftable() )
{ {
// Processing patterns are relatively easy // Processing patterns are relatively easy
for( IAEItemStack input : condensedInputs ) for ( IAEItemStack input : condensedInputs )
{ {
final IAEItemStack ais = this.inventory.extractItems( input.copy(), Actionable.SIMULATE, this.machineSrc ); final IAEItemStack ais = this.inventory.extractItems( input.copy(), Actionable.SIMULATE,
this.machineSrc );
if( ais == null || ais.getStackSize() < input.getStackSize() ) if( ais == null || ais.getStackSize() < input.getStackSize() )
{ {
@@ -537,7 +516,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
// When substitutions are allowed, we have to keep track of which items we've reserved // When substitutions are allowed, we have to keep track of which items we've reserved
IAEItemStack[] inputs = details.getInputs(); IAEItemStack[] inputs = details.getInputs();
Map<IAEItemStack, Integer> consumedCount = new HashMap<>(); Map<IAEItemStack, Integer> consumedCount = new HashMap<>();
for( int i = 0; i < inputs.length; i++ ) for ( int i = 0; i < inputs.length; i++ )
{ {
List<IAEItemStack> substitutes = details.getSubstituteInputs( i ); List<IAEItemStack> substitutes = details.getSubstituteInputs( i );
if( substitutes.isEmpty() ) if( substitutes.isEmpty() )
@@ -546,9 +525,9 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
} }
boolean found = false; boolean found = false;
for( IAEItemStack substitute : substitutes ) for ( IAEItemStack substitute : substitutes )
{ {
for( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( substitute, FuzzyMode.IGNORE_ALL ) ) for ( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( substitute, FuzzyMode.IGNORE_ALL ) )
{ {
int alreadyConsumed = consumedCount.getOrDefault( fuzz, 0 ); int alreadyConsumed = consumedCount.getOrDefault( fuzz, 0 );
if( fuzz.getStackSize() - alreadyConsumed <= 0 ) if( fuzz.getStackSize() - alreadyConsumed <= 0 )
@@ -558,7 +537,8 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
fuzz = fuzz.copy(); fuzz = fuzz.copy();
fuzz.setStackSize( 1 ); // We're iterating over non condensed inputs which means there's 1 of each needed 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 ); final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE,
this.machineSrc );
if( ais != null && ais.getStackSize() > 0 ) if( ais != null && ais.getStackSize() > 0 )
{ {
@@ -585,11 +565,11 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
// When no substitutions can occur, we can simply check that all items are accounted since // When no substitutions can occur, we can simply check that all items are accounted since
// each type of item should only occur once // each type of item should only occur once
for( IAEItemStack g : condensedInputs ) 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() );
@@ -695,7 +675,8 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
this.somethingChanged = false; this.somethingChanged = false;
this.executeCrafting( eg, cc ); this.executeCrafting( eg, cc );
} while ( this.somethingChanged && this.remainingOperations > 0 ); }
while( this.somethingChanged && this.remainingOperations > 0 );
} }
this.usedOps[2] = this.usedOps[1]; this.usedOps[2] = this.usedOps[1];
this.usedOps[1] = this.usedOps[0]; this.usedOps[1] = this.usedOps[0];
@@ -711,7 +692,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator(); final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while ( i.hasNext() ) while( i.hasNext() )
{ {
final Entry<ICraftingPatternDetails, TaskProgress> e = i.next(); final Entry<ICraftingPatternDetails, TaskProgress> e = i.next();
@@ -727,12 +708,12 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
InventoryCrafting ic = null; InventoryCrafting ic = null;
if( !visitedMediums.containsKey( details ) || visitedMediums.get( details ).isEmpty() ) if (!visitedMediums.containsKey( details ) || visitedMediums.get( details ).isEmpty())
{ {
visitedMediums.put( details, new ArrayDeque<>( cc.getMediums( details ).stream().filter( Objects::nonNull ).collect( Collectors.toList() ) ) ); visitedMediums.put( details, new ArrayDeque<>( cc.getMediums( details ).stream().filter( Objects::nonNull ).collect( Collectors.toList()) ) );
} }
while ( !visitedMediums.get( details ).isEmpty() ) while (!visitedMediums.get( details ).isEmpty())
{ {
ICraftingMedium m = visitedMediums.get( details ).poll(); ICraftingMedium m = visitedMediums.get( details ).poll();
@@ -792,58 +773,52 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
itemList.addAll( this.inventory.getItemList().findFuzzy( stack, FuzzyMode.IGNORE_ALL ) ); itemList.addAll( this.inventory.getItemList().findFuzzy( stack, FuzzyMode.IGNORE_ALL ) );
} }
} } else {
else itemList = new ArrayList<>(1);
{
itemList = new ArrayList<>( 1 );
final IAEItemStack item = this.inventory.getItemList().findPrecise( input[x] ); final IAEItemStack item = this.inventory.getItemList()
.findPrecise(input[x]);
if( item != null ) if (item != null) {
{ itemList.add(item);
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;
} }
} }
@@ -927,7 +902,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
private void storeItems() private void storeItems()
{ {
Preconditions.checkState( isComplete, "CPU should be complete to prevent re-insertion when dumping items" ); Preconditions.checkState(isComplete, "CPU should be complete to prevent re-insertion when dumping items");
final IGrid g = this.getGrid(); final IGrid g = this.getGrid();
if( g == null ) if( g == null )
@@ -987,12 +962,10 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
try try
{ {
this.waitingFor.resetStatus(); this.waitingFor.resetStatus();
this.neededForLoop.resetStatus();
( (CraftingJob) job ).getTree().setJob( ci, this, src ); ( (CraftingJob) job ).getTree().setJob( ci, this, src );
if( ci.commit( src ) ) if( ci.commit( src ) )
{ {
this.finalOutput = job.getOutput(); this.finalOutput = job.getOutput();
this.neededForLoop = ( (CraftingJob) job ).getNeededForLoop();
this.waiting = false; this.waiting = false;
this.isComplete = false; this.isComplete = false;
this.markDirty(); this.markDirty();
@@ -1043,7 +1016,8 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
public boolean isBusy() public boolean isBusy()
{ {
this.tasks.entrySet().removeIf( taskProgressEntry -> taskProgressEntry.getValue().value <= 0 ); this.tasks.entrySet().removeIf(
taskProgressEntry -> taskProgressEntry.getValue().value <= 0 );
if( !this.waitingFor.isEmpty() || !this.tasks.isEmpty() ) if( !this.waitingFor.isEmpty() || !this.tasks.isEmpty() )
{ {
@@ -1101,7 +1075,8 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
final int hash = System.identityHashCode( this ); final int hash = System.identityHashCode( this );
final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode(); final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode();
return Long.toString( now, Character.MAX_RADIX ) + '-' + Integer.toString( hash, Character.MAX_RADIX ) + '-' + Integer.toString( hmm, Character.MAX_RADIX ); return Long.toString( now, Character.MAX_RADIX ) + '-' + Integer.toString( hash, Character.MAX_RADIX ) + '-' + Integer.toString( hmm,
Character.MAX_RADIX );
} }
private NBTTagCompound generateLinkData( final String craftingID, final boolean standalone, final boolean req ) private NBTTagCompound generateLinkData( final String craftingID, final boolean standalone, final boolean req )
@@ -1128,7 +1103,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
public void getListOfItem( final IItemList<IAEItemStack> list, final CraftingItemList whichList ) public void getListOfItem( final IItemList<IAEItemStack> list, final CraftingItemList whichList )
{ {
switch ( whichList ) switch( whichList )
{ {
case ACTIVE: case ACTIVE:
for( final IAEItemStack ais : this.waitingFor ) for( final IAEItemStack ais : this.waitingFor )
@@ -1199,7 +1174,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
IAEItemStack is; IAEItemStack is;
switch ( storage2 ) switch( storage2 )
{ {
case STORAGE: case STORAGE:
is = this.inventory.getItemList().findPrecise( what ); is = this.inventory.getItemList().findPrecise( what );
@@ -19,6 +19,7 @@
package appeng.parts.misc; package appeng.parts.misc;
import javax.annotation.Nullable;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.AccessRestriction; import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@@ -146,7 +147,6 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
} }
ItemStack extracted; ItemStack extracted;
int stackSizeCurrentSlot = stackInInventorySlot.getCount(); int stackSizeCurrentSlot = stackInInventorySlot.getCount();
int remainingCurrentSlot = Math.min( remainingSize, stackSizeCurrentSlot ); int remainingCurrentSlot = Math.min( remainingSize, stackSizeCurrentSlot );
@@ -155,17 +155,9 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
do do
{ {
extracted = this.itemHandler.extractItem( i, remainingCurrentSlot, simulate ); extracted = this.itemHandler.extractItem( i, remainingCurrentSlot, simulate );
if( !extracted.isEmpty() ) if( !extracted.isEmpty() )
{ {
// In order to guard against broken IItemHandler implementations, we'll try to guess if the returned
// stack (especially in simulate mode) is the same that was returned by getStackInSlot. This is
// obviously not a precise science, but it would catch the previous Forge bug:
// https://github.com/MinecraftForge/MinecraftForge/pull/6580
if( extracted == stackInInventorySlot )
{
extracted = extracted.copy();
}
if( extracted.getCount() > remainingCurrentSlot ) if( extracted.getCount() > remainingCurrentSlot )
{ {
// Something broke. It should never return more than we requested... // Something broke. It should never return more than we requested...
@@ -174,17 +166,12 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
extracted.setCount( remainingCurrentSlot ); extracted.setCount( remainingCurrentSlot );
} }
// Heuristic for simulation: looping in case of simulations is pointless, since the state of the // We're just gonna use the first stack we get our hands on as the template for the rest.
// underlying inventory does not change after a simulated extraction. To still support inventories // In case some stupid itemhandler (aka forge) returns an internal state we have to do a second
// that report stacks that are larger than maxStackSize, we use this heuristic // expensive copy again.
if( simulate && extracted.getCount() == extracted.getMaxStackSize() && remainingCurrentSlot > extracted.getMaxStackSize() )
{
extracted.setCount( remainingCurrentSlot );
}
if( gathered.isEmpty() ) if( gathered.isEmpty() )
{ {
gathered = extracted; gathered = extracted.copy();
} }
else else
{ {
@@ -192,9 +179,11 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
} }
remainingCurrentSlot -= extracted.getCount(); remainingCurrentSlot -= extracted.getCount();
} }
} while ( !simulate && !extracted.isEmpty() && remainingCurrentSlot > 0 ); } while ( !extracted.isEmpty() && remainingCurrentSlot > 0 );
remainingSize -= stackSizeCurrentSlot - remainingCurrentSlot; remainingSize -= stackSizeCurrentSlot - remainingCurrentSlot;
// Done?
if( remainingSize <= 0 ) if( remainingSize <= 0 )
{ {
break; break;
@@ -128,7 +128,7 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
public TileChest() public TileChest()
{ {
this.setInternalMaxPower( PowerMultiplier.CONFIG.multiply( 128 ) ); this.setInternalMaxPower( PowerMultiplier.CONFIG.multiply( 40 ) );
this.getProxy().setFlags( GridFlags.REQUIRE_CHANNEL ); this.getProxy().setFlags( GridFlags.REQUIRE_CHANNEL );
this.config.registerSetting( Settings.SORT_BY, SortOrder.NAME ); this.config.registerSetting( Settings.SORT_BY, SortOrder.NAME );
this.config.registerSetting( Settings.VIEW_MODE, ViewItems.ALL ); this.config.registerSetting( Settings.VIEW_MODE, ViewItems.ALL );
@@ -541,7 +541,7 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
if( this.cellHandler != null && this.cellHandler.getChannel() == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) if( this.cellHandler != null && this.cellHandler.getChannel() == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{ {
final IAEItemStack returns = Platform.poweredInsert( this, this.cellHandler, final IAEItemStack returns = Platform.poweredInsert( this, this.cellHandler,
AEItemStack.fromItemStack( this.inputInventory.getStackInSlot( 0 ) ), this.mySrc ); AEItemStack.fromItemStack( this.inputInventory.getStackInSlot( 0 ) ), this.mySrc );
if( returns == null ) if( returns == null )
{ {
@@ -698,8 +698,7 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
{ {
TileChest.this.getProxy().getStorage().postAlterationOfStoredItems( this.chan, change, TileChest.this.mySrc ); TileChest.this.getProxy().getStorage().postAlterationOfStoredItems( this.chan, change, TileChest.this.mySrc );
} }
} } catch ( final GridAccessException e )
catch( final GridAccessException e )
{ {
// :( // :(
} }
@@ -739,11 +738,11 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
return input; return input;
} }
T injected = super.injectItems( input, mode, src ); T injected = super.injectItems( input, mode, src );
if( mode == Actionable.MODULATE && ( injected == null || injected.getStackSize() != input.getStackSize() ) ) if (mode == Actionable.MODULATE && ( injected == null || injected.getStackSize() != input.getStackSize() ))
{ {
if( TileChest.this.isPowered() && this.getInternalHandler().getCellInv() != null ) if( TileChest.this.getProxy().isActive() && this.getInternalHandler().getCellInv() != null )
{ {
TileChest.this.cellHandler.postChangesToListeners( Collections.singletonList( input.copy().setStackSize( input.getStackSize() - ( injected == null ? 0 : injected.getStackSize() ) ) ), TileChest.this.mySrc ); TileChest.this.cellHandler.postChangesToListeners(Collections.singletonList( input.copy().setStackSize( input.getStackSize() - ( injected == null ? 0 : injected.getStackSize() ) ) ), TileChest.this.mySrc );
} }
} }
return injected; return injected;
@@ -793,9 +792,9 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
T extracted = super.extractItems( request, mode, src ); T extracted = super.extractItems( request, mode, src );
if( mode == Actionable.MODULATE && extracted != null ) if( mode == Actionable.MODULATE && extracted != null )
{ {
if( TileChest.this.isPowered() && this.getInternalHandler().getCellInv() != null ) if( TileChest.this.getProxy().isActive() && this.getInternalHandler().getCellInv() != null )
{ {
TileChest.this.cellHandler.postChangesToListeners( Collections.singletonList( request.copy().setStackSize( -extracted.getStackSize() ) ), TileChest.this.mySrc ); TileChest.this.cellHandler.postChangesToListeners(Collections.singletonList( request.copy().setStackSize( -extracted.getStackSize() ) ), TileChest.this.mySrc );
} }
} }
return extracted; return extracted;
@@ -849,7 +848,7 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
private class FluidHandler implements IFluidHandler private class FluidHandler implements IFluidHandler
{ {
private final IFluidTankProperties[] TANK_PROPS = new IFluidTankProperties[]{new FluidTankProperties( null, Fluid.BUCKET_VOLUME )}; private final IFluidTankProperties[] TANK_PROPS = new IFluidTankProperties[] { new FluidTankProperties( null, Fluid.BUCKET_VOLUME ) };
@Override @Override
public int fill( final FluidStack resource, final boolean doFill ) public int fill( final FluidStack resource, final boolean doFill )
@@ -859,7 +858,7 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
.getChannel() == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) .getChannel() == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{ {
final IAEFluidStack results = Platform.poweredInsert( TileChest.this, TileChest.this.cellHandler, AEFluidStack.fromFluidStack( resource ), final IAEFluidStack results = Platform.poweredInsert( TileChest.this, TileChest.this.cellHandler, AEFluidStack.fromFluidStack( resource ),
TileChest.this.mySrc, doFill ? Actionable.MODULATE : Actionable.SIMULATE ); TileChest.this.mySrc, doFill ? Actionable.MODULATE : Actionable.SIMULATE );
if( results == null ) if( results == null )
{ {
+51 -60
View File
@@ -36,9 +36,6 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import gregtech.api.items.IToolItem;
import ic2.api.item.IC2Items;
import ic2.api.item.ICustomDamageItem;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -76,7 +73,6 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.Optional;
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 net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.OreDictionary;
@@ -138,8 +134,6 @@ import appeng.util.prioritylist.IPartitionList;
* @version rv2 * @version rv2
* @since rv0 * @since rv0
*/ */
@Optional.Interface( iface = "gregtech.api.items.IToolItem", modid = "gregtech" )
@Optional.Interface( iface = "ic2.api.item.ICustomDamageItem", modid = "IC2" )
public class Platform public class Platform
{ {
@@ -182,8 +176,9 @@ public class Platform
/** /**
* This displays the value for encoded longs ( double *100 ) * This displays the value for encoded longs ( double *100 )
* *
* @param n to be formatted long value * @param n to be formatted long value
* @param isRate if true it adds a /t to the formatted string * @param isRate if true it adds a /t to the formatted string
*
* @return formatted long value * @return formatted long value
*/ */
public static String formatPowerLong( final long n, final boolean isRate ) public static String formatPowerLong( final long n, final boolean isRate )
@@ -193,14 +188,12 @@ public class Platform
final PowerUnits displayUnits = AEConfig.instance().selectedPowerUnit(); final PowerUnits displayUnits = AEConfig.instance().selectedPowerUnit();
p = PowerUnits.AE.convertTo( displayUnits, p ); p = PowerUnits.AE.convertTo( displayUnits, p );
final String[] preFixes = { final String[] preFixes = { "k", "M", "G", "T", "P", "T", "P", "E", "Z", "Y" };
"k", "M", "G", "T", "P", "T", "P", "E", "Z", "Y"
};
String unitName = displayUnits.name(); String unitName = displayUnits.name();
String level = ""; String level = "";
int offset = 0; int offset = 0;
while ( p > 1000 && offset < preFixes.length ) while( p > 1000 && offset < preFixes.length )
{ {
p /= 1000; p /= 1000;
level = preFixes[offset]; level = preFixes[offset];
@@ -217,7 +210,7 @@ public class Platform
final int west_y = forward.zOffset * up.xOffset - forward.xOffset * up.zOffset; final int west_y = forward.zOffset * up.xOffset - forward.xOffset * up.zOffset;
final int west_z = forward.xOffset * up.yOffset - forward.yOffset * up.xOffset; final int west_z = forward.xOffset * up.yOffset - forward.yOffset * up.xOffset;
switch ( west_x + west_y * 2 + west_z * 3 ) switch( west_x + west_y * 2 + west_z * 3 )
{ {
case 1: case 1:
return AEPartLocation.EAST; return AEPartLocation.EAST;
@@ -244,7 +237,7 @@ public class Platform
final int west_y = forward.getFrontOffsetZ() * up.getFrontOffsetX() - forward.getFrontOffsetX() * up.getFrontOffsetZ(); final int west_y = forward.getFrontOffsetZ() * up.getFrontOffsetX() - forward.getFrontOffsetX() * up.getFrontOffsetZ();
final int west_z = forward.getFrontOffsetX() * up.getFrontOffsetY() - forward.getFrontOffsetY() * up.getFrontOffsetX(); final int west_z = forward.getFrontOffsetX() * up.getFrontOffsetY() - forward.getFrontOffsetY() * up.getFrontOffsetX();
switch ( west_x + west_y * 2 + west_z * 3 ) switch( west_x + west_y * 2 + west_z * 3 )
{ {
case 1: case 1:
return EnumFacing.EAST; return EnumFacing.EAST;
@@ -278,7 +271,8 @@ public class Platform
{ {
ce = nextEnum( ce ); ce = nextEnum( ce );
} }
} while ( !validOptions.contains( ce ) || isNotValidSetting( ce ) ); }
while( !validOptions.contains( ce ) || isNotValidSetting( ce ) );
return ce; return ce;
} }
@@ -452,7 +446,7 @@ public class Platform
{ {
if( upAndDown ) if( upAndDown )
{ {
switch ( dir ) switch( dir )
{ {
case NORTH: case NORTH:
return AEPartLocation.SOUTH; return AEPartLocation.SOUTH;
@@ -472,7 +466,7 @@ public class Platform
} }
else else
{ {
switch ( dir ) switch( dir )
{ {
case UP: case UP:
return AEPartLocation.DOWN; return AEPartLocation.DOWN;
@@ -525,7 +519,8 @@ public class Platform
final double offset_x = ( getRandomInt() % 32 - 16 ) / 82; final double offset_x = ( getRandomInt() % 32 - 16 ) / 82;
final double offset_y = ( getRandomInt() % 32 - 16 ) / 82; final double offset_y = ( getRandomInt() % 32 - 16 ) / 82;
final double offset_z = ( getRandomInt() % 32 - 16 ) / 82; final double offset_z = ( getRandomInt() % 32 - 16 ) / 82;
final EntityItem ei = new EntityItem( w, 0.5 + offset_x + pos.getX(), 0.5 + offset_y + pos.getY(), 0.2 + offset_z + pos.getZ(), i.copy() ); final EntityItem ei = new EntityItem( w, 0.5 + offset_x + pos.getX(), 0.5 + offset_y + pos.getY(), 0.2 + offset_z + pos.getZ(), i
.copy() );
w.spawnEntity( ei ); w.spawnEntity( ei );
} }
} }
@@ -597,7 +592,8 @@ public class Platform
try try
{ {
ITooltipFlag.TooltipFlags tooltipFlag = Minecraft.getMinecraft().gameSettings.advancedItemTooltips ? ITooltipFlag.TooltipFlags.ADVANCED : ITooltipFlag.TooltipFlags.NORMAL; ITooltipFlag.TooltipFlags tooltipFlag = Minecraft
.getMinecraft().gameSettings.advancedItemTooltips ? ITooltipFlag.TooltipFlags.ADVANCED : ITooltipFlag.TooltipFlags.NORMAL;
return itemStack.getTooltip( Minecraft.getMinecraft().player, tooltipFlag ); return itemStack.getTooltip( Minecraft.getMinecraft().player, tooltipFlag );
} }
catch( final Exception errB ) catch( final Exception errB )
@@ -768,7 +764,7 @@ public class Platform
public static int MC2MEColor( final int color ) public static int MC2MEColor( final int color )
{ {
switch ( color ) switch( color )
{ {
case 4: // "blue" case 4: // "blue"
return 0; return 0;
@@ -846,10 +842,10 @@ public class Platform
return forward; return forward;
} }
switch ( forward ) switch( forward )
{ {
case DOWN: case DOWN:
switch ( axis ) switch( axis )
{ {
case DOWN: case DOWN:
return forward; return forward;
@@ -868,7 +864,7 @@ public class Platform
} }
break; break;
case UP: case UP:
switch ( axis ) switch( axis )
{ {
case NORTH: case NORTH:
return AEPartLocation.WEST; return AEPartLocation.WEST;
@@ -883,7 +879,7 @@ public class Platform
} }
break; break;
case NORTH: case NORTH:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return AEPartLocation.WEST; return AEPartLocation.WEST;
@@ -898,7 +894,7 @@ public class Platform
} }
break; break;
case SOUTH: case SOUTH:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return AEPartLocation.EAST; return AEPartLocation.EAST;
@@ -913,7 +909,7 @@ public class Platform
} }
break; break;
case EAST: case EAST:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return AEPartLocation.NORTH; return AEPartLocation.NORTH;
@@ -927,7 +923,7 @@ public class Platform
break; break;
} }
case WEST: case WEST:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return AEPartLocation.SOUTH; return AEPartLocation.SOUTH;
@@ -948,10 +944,10 @@ public class Platform
public static EnumFacing rotateAround( final EnumFacing forward, final EnumFacing axis ) public static EnumFacing rotateAround( final EnumFacing forward, final EnumFacing axis )
{ {
switch ( forward ) switch( forward )
{ {
case DOWN: case DOWN:
switch ( axis ) switch( axis )
{ {
case DOWN: case DOWN:
return forward; return forward;
@@ -970,7 +966,7 @@ public class Platform
} }
break; break;
case UP: case UP:
switch ( axis ) switch( axis )
{ {
case NORTH: case NORTH:
return EnumFacing.WEST; return EnumFacing.WEST;
@@ -985,7 +981,7 @@ public class Platform
} }
break; break;
case NORTH: case NORTH:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return EnumFacing.WEST; return EnumFacing.WEST;
@@ -1000,7 +996,7 @@ public class Platform
} }
break; break;
case SOUTH: case SOUTH:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return EnumFacing.EAST; return EnumFacing.EAST;
@@ -1015,7 +1011,7 @@ public class Platform
} }
break; break;
case EAST: case EAST:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return EnumFacing.NORTH; return EnumFacing.NORTH;
@@ -1029,7 +1025,7 @@ public class Platform
break; break;
} }
case WEST: case WEST:
switch ( axis ) switch( axis )
{ {
case UP: case UP:
return EnumFacing.SOUTH; return EnumFacing.SOUTH;
@@ -1105,7 +1101,9 @@ public class Platform
final Vec3d vec31 = vec3.addVector( f7 * d3, f6 * d3, f8 * d3 ); final Vec3d vec31 = vec3.addVector( f7 * d3, f6 * d3, f8 * d3 );
final AxisAlignedBB bb = new AxisAlignedBB( Math.min( vec3.x, vec31.x ), Math.min( vec3.y, vec31.y ), Math.min( vec3.z, vec31.z ), Math.max( vec3.x, vec31.x ), Math.max( vec3.y, vec31.y ), Math.max( vec3.z, vec31.z ) ).grow( 16, 16, 16 ); final AxisAlignedBB bb = new AxisAlignedBB( Math.min( vec3.x, vec31.x ), Math.min( vec3.y, vec31.y ), Math.min( vec3.z,
vec31.z ), Math.max( vec3.x, vec31.x ), Math.max( vec3.y, vec31.y ), Math.max( vec3.z, vec31.z ) ).grow(
16, 16, 16 );
Entity entity = null; Entity entity = null;
double closest = 9999999.0D; double closest = 9999999.0D;
@@ -1251,15 +1249,15 @@ public class Platform
final T leftover = input.copy(); final T leftover = input.copy();
final T split = input.copy(); final T split = input.copy();
leftover.decStackSize( itemToAdd ); leftover.decStackSize(itemToAdd);
split.setStackSize( itemToAdd ); split.setStackSize(itemToAdd);
leftover.add( cell.injectItems( split, Actionable.MODULATE, src ) ); leftover.add(cell.injectItems(split, Actionable.MODULATE, src));
src.player().ifPresent( player -> src.player().ifPresent( player ->
{ {
final long diff = original - leftover.getStackSize(); final long diff = original - leftover.getStackSize();
Stats.ItemsInserted.addToPlayer( player, (int) diff ); Stats.ItemsInserted.addToPlayer( player, (int) diff );
} ); } );
return leftover; return leftover;
} }
@@ -1267,10 +1265,10 @@ public class Platform
final T ret = cell.injectItems( input, Actionable.MODULATE, src ); final T ret = cell.injectItems( input, Actionable.MODULATE, src );
src.player().ifPresent( player -> src.player().ifPresent( player ->
{ {
final long diff = ret == null ? input.getStackSize() : input.getStackSize() - ret.getStackSize(); final long diff = ret == null ? input.getStackSize() : input.getStackSize() - ret.getStackSize();
Stats.ItemsInserted.addToPlayer( player, (int) diff ); Stats.ItemsInserted.addToPlayer( player, (int) diff );
} ); } );
return ret; return ret;
} }
@@ -1284,7 +1282,7 @@ public class Platform
return input; return input;
} }
@SuppressWarnings( {"rawtypes", "unchecked"} ) @SuppressWarnings( { "rawtypes", "unchecked" } )
public static void postChanges( final IStorageGrid gs, final ItemStack removed, final ItemStack added, final IActionSource src ) public static void postChanges( final IStorageGrid gs, final ItemStack removed, final ItemStack added, final IActionSource src )
{ {
for( final IStorageChannel<?> chan : AEApi.instance().storage().storageChannels() ) for( final IStorageChannel<?> chan : AEApi.instance().storage().storageChannels() )
@@ -1363,7 +1361,8 @@ public class Platform
final String locationA = a.getGridBlock().isWorldAccessible() ? a.getGridBlock().getLocation().toString() : "notInWorld"; final String locationA = a.getGridBlock().isWorldAccessible() ? a.getGridBlock().getLocation().toString() : "notInWorld";
final String locationB = b.getGridBlock().isWorldAccessible() ? b.getGridBlock().getLocation().toString() : "notInWorld"; final String locationB = b.getGridBlock().isWorldAccessible() ? b.getGridBlock().getLocation().toString() : "notInWorld";
AELog.info( "Audit: Node A [isSecure=%b, key=%d, playerID=%d, location={%s}] vs Node B[isSecure=%b, key=%d, playerID=%d, location={%s}]", a_isSecure, a.getLastSecurityKey(), a.getPlayerID(), locationA, b_isSecure, b.getLastSecurityKey(), b.getPlayerID(), locationB ); AELog.info( "Audit: Node A [isSecure=%b, key=%d, playerID=%d, location={%s}] vs Node B[isSecure=%b, key=%d, playerID=%d, location={%s}]",
a_isSecure, a.getLastSecurityKey(), a.getPlayerID(), locationA, b_isSecure, b.getLastSecurityKey(), b.getPlayerID(), locationB );
} }
// can't do that son... // can't do that son...
@@ -1424,7 +1423,7 @@ public class Platform
float yaw = 0.0f; float yaw = 0.0f;
// player.yOffset = 1.8f; // player.yOffset = 1.8f;
switch ( side ) switch( side )
{ {
case DOWN: case DOWN:
pitch = 90.0f; pitch = 90.0f;
@@ -1514,14 +1513,16 @@ public class Platform
} }
} }
final boolean checkFuzzy = ae_req.getOre().isPresent() || providedTemplate.getItemDamage() == OreDictionary.WILDCARD_VALUE || providedTemplate.hasTagCompound() || providedTemplate.isItemStackDamageable(); final boolean checkFuzzy = ae_req.getOre().isPresent() || providedTemplate.getItemDamage() == OreDictionary.WILDCARD_VALUE || providedTemplate
.hasTagCompound() || providedTemplate.isItemStackDamageable();
if( items != null && checkFuzzy ) if( items != null && checkFuzzy )
{ {
for( final IAEItemStack x : items ) for( final IAEItemStack x : items )
{ {
final ItemStack sh = x.getDefinition(); final ItemStack sh = x.getDefinition();
if( ( Platform.itemComparisons().isEqualItemType( providedTemplate, sh ) || ae_req.sameOre( x ) ) && !ItemStack.areItemsEqual( sh, output ) ) if( ( Platform.itemComparisons().isEqualItemType( providedTemplate, sh ) || ae_req.sameOre( x ) ) && !ItemStack.areItemsEqual( sh,
output ) )
{ // Platform.isSameItemType( sh, providedTemplate ) { // Platform.isSameItemType( sh, providedTemplate )
final ItemStack cp = sh.copy(); final ItemStack cp = sh.copy();
cp.setCount( 1 ); cp.setCount( 1 );
@@ -1680,14 +1681,4 @@ public class Platform
return isPurified; return isPurified;
} }
public static boolean isGTDamageableItem( Item item )
{
return ( isModLoaded( "gregtech" ) && item instanceof IToolItem );
}
public static boolean isIC2DamageableItem( Item item )
{
return ( isModLoaded( "IC2" ) && item instanceof ICustomDamageItem );
}
} }
@@ -1,12 +1,20 @@
package appeng.util.inv; package appeng.util.inv;
import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.helpers.NonBlockingItems; import appeng.helpers.NonBlockingItems;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
import gregtech.common.items.MetaTool;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
+24 -50
View File
@@ -18,6 +18,7 @@
package appeng.util.item; package appeng.util.item;
import java.lang.ref.WeakReference;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@@ -26,8 +27,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import gregtech.api.items.IToolItem;
import ic2.api.item.ICustomDamageItem;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -45,7 +44,7 @@ import appeng.core.Api;
import appeng.util.Platform; import appeng.util.Platform;
public class AEItemStack extends AEStack<IAEItemStack> implements IAEItemStack public final class AEItemStack extends AEStack<IAEItemStack> implements IAEItemStack
{ {
private static final String NBT_STACKSIZE = "Cnt"; private static final String NBT_STACKSIZE = "Cnt";
private static final String NBT_REQUESTABLE = "Req"; private static final String NBT_REQUESTABLE = "Req";
@@ -281,17 +280,26 @@ public class AEItemStack extends AEStack<IAEItemStack> implements IAEItemStack
@Override @Override
public ItemStack getCachedItemStack( long stackSize ) public ItemStack getCachedItemStack( long stackSize )
{ {
ItemStack currentCached = null;
if( this.cachedItemStack != null ) if( this.cachedItemStack != null )
{ {
if( Platform.itemComparisons().isSameItem( this.getDefinition(), this.cachedItemStack ) ) currentCached = this.cachedItemStack;
{
ItemStack currentCached = this.cachedItemStack;
this.cachedItemStack = null;
currentCached.setCount( Ints.saturatedCast( stackSize ) );
return currentCached;
}
} }
return ItemHandlerHelper.copyStackWithSize( this.getDefinition(), Ints.saturatedCast( stackSize ) );
ItemStack itemStack;
if( currentCached != null )
{
// Cache is suitable, just update the count
itemStack = currentCached;
currentCached.setCount( Ints.saturatedCast( stackSize ) );
}
else
{
// We need a new stack :-(
itemStack = this.createItemStack();
}
return itemStack;
} }
@Override @Override
@@ -362,53 +370,20 @@ public class AEItemStack extends AEStack<IAEItemStack> implements IAEItemStack
private boolean fuzzyItemStackComparison( ItemStack a, ItemStack b, FuzzyMode mode ) private boolean fuzzyItemStackComparison( ItemStack a, ItemStack b, FuzzyMode mode )
{ {
if( a.getItem() == b.getItem() && ( a.getItem().isDamageable() || Platform.isGTDamageableItem( a.getItem() ) ) ) if( a.getItem() == b.getItem() && a.getItem().isDamageable() )
{ {
if( mode == FuzzyMode.IGNORE_ALL ) if( mode == FuzzyMode.IGNORE_ALL )
{ {
if( a.getItem().isDamageable() ) return true;
{
return true;
}
else if( Platform.isGTDamageableItem( a.getItem() ) )
{
return a.getItemDamage() == b.getItemDamage();
}
} }
else if( mode == FuzzyMode.PERCENT_99 ) else if( mode == FuzzyMode.PERCENT_99 )
{ {
if( Platform.isIC2DamageableItem( a.getItem() ) ) return a.getItemDamage() > 1 == b.getItemDamage() > 1;
{
return ( (ICustomDamageItem) a.getItem() ).getCustomDamage( a ) > 1 == ( (ICustomDamageItem) b.getItem() ).getCustomDamage( b ) > 1;
}
else if( a.getItem().isDamageable() )
{
return a.getItemDamage() > 1 == b.getItemDamage() > 1;
}
else if( Platform.isGTDamageableItem( a.getItem() ) )
{
return ( (IToolItem) a.getItem() ).getItemDamage( a ) > 1 == ( (IToolItem) b.getItem() ).getItemDamage( b ) > 1;
}
} }
else else
{ {
float percentDamageOfA = 0; final float percentDamageOfA = (float) a.getItemDamage() / a.getMaxDamage();
float percentDamageOfB = 0; final float percentDamageOfB = (float) b.getItemDamage() / b.getMaxDamage();
if( Platform.isIC2DamageableItem( a.getItem() ) )
{
percentDamageOfA = (float) ( (ICustomDamageItem) a.getItem() ).getCustomDamage( a ) / ( (ICustomDamageItem) a.getItem() ).getMaxCustomDamage( a );
percentDamageOfB = (float) ( (ICustomDamageItem) b.getItem() ).getCustomDamage( b ) / ( (ICustomDamageItem) b.getItem() ).getMaxCustomDamage( b );
}
else if( a.getItem().isDamageable() )
{
percentDamageOfA = (float) a.getItemDamage() / a.getMaxDamage();
percentDamageOfB = (float) b.getItemDamage() / b.getMaxDamage();
}
else if( Platform.isGTDamageableItem( a.getItem() ) )
{
percentDamageOfA = (float) ( (IToolItem) a.getItem() ).getItemDamage( a ) / ( (IToolItem) a.getItem() ).getMaxItemDamage( a );
percentDamageOfB = (float) ( (IToolItem) b.getItem() ).getItemDamage( b ) / ( (IToolItem) b.getItem() ).getMaxItemDamage( b );
}
return percentDamageOfA > mode.breakPoint == percentDamageOfB > mode.breakPoint; return percentDamageOfA > mode.breakPoint == percentDamageOfB > mode.breakPoint;
} }
@@ -416,5 +391,4 @@ public class AEItemStack extends AEStack<IAEItemStack> implements IAEItemStack
return false; return false;
} }
} }
@@ -25,8 +25,7 @@ import java.util.Map;
import appeng.util.Platform; import appeng.util.Platform;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import gregtech.api.items.IToolItem; import gregtech.common.items.MetaTool;
import ic2.api.item.ICustomDamageItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap; import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap;
@@ -35,210 +34,159 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
/** /**
* This variant list is optimized for damageable items, and supports selecting durability ranges with * This variant list is optimized for damageable items, and supports selecting durability ranges with
* {@link #findFuzzy(IAEItemStack, FuzzyMode)}. * {@link #findFuzzy(IAEItemStack, FuzzyMode)}.
*/ */
class FuzzyItemVariantList extends ItemVariantList class FuzzyItemVariantList extends ItemVariantList {
{
static final SharedStackComparator COMPARATOR = new SharedStackComparator(); static final SharedStackComparator COMPARATOR = new SharedStackComparator();
// NOTE: We only use Object as they key here so we can pass our special DamageBounds to the subMap method. // NOTE: We only use Object as they key here so we can pass our special DamageBounds to the subMap method.
// We NEVER put any keys in this map that are not AESharedItemStacks. // We NEVER put any keys in this map that are not AESharedItemStacks.
private final Object2ObjectSortedMap<Object, IAEItemStack> records = new Object2ObjectAVLTreeMap<>( COMPARATOR ); private final Object2ObjectSortedMap<Object, IAEItemStack> records = new Object2ObjectAVLTreeMap<>(COMPARATOR);
@Override @Override
public Collection<IAEItemStack> findFuzzy( final IAEItemStack filter, final FuzzyMode fuzzy ) public Collection<IAEItemStack> findFuzzy(final IAEItemStack filter, final FuzzyMode fuzzy) {
{ ItemStack itemStack = filter.getDefinition();
ItemStack itemStack = filter.getDefinition();
ItemDamageBound lowerBound = makeLowerBound( itemStack, fuzzy ); ItemDamageBound lowerBound = makeLowerBound(itemStack, fuzzy);
ItemDamageBound upperBound = makeUpperBound( itemStack, fuzzy ); ItemDamageBound upperBound = makeUpperBound(itemStack, fuzzy);
Preconditions.checkState( lowerBound.itemDamage > upperBound.itemDamage ); Preconditions.checkState(lowerBound.itemDamage > upperBound.itemDamage);
return this.records.subMap( lowerBound, upperBound ).values(); return this.records.subMap(lowerBound, upperBound).values();
} }
@SuppressWarnings( "unchecked" ) @SuppressWarnings("unchecked")
@Override @Override
Map<AESharedItemStack, IAEItemStack> getRecords() Map<AESharedItemStack, IAEItemStack> getRecords() {
{ // We ensure on our end that we NEVER use anything but AESharedItemStack as the key in this map
// We ensure on our end that we NEVER use anything but AESharedItemStack as the key in this map return (Map<AESharedItemStack, IAEItemStack>) (Object) this.records;
return (Map<AESharedItemStack, IAEItemStack>) (Object) this.records; }
}
static class ItemDamageBound static class ItemDamageBound {
{ final int itemDamage;
final int itemDamage;
public ItemDamageBound( int itemDamage ) public ItemDamageBound(int itemDamage) {
{ this.itemDamage = itemDamage;
this.itemDamage = itemDamage; }
} }
}
/** /**
* This comparator creates a strict and total ordering over all {@link AESharedItemStack} of the same item. To * This comparator creates a strict and total ordering over all {@link AESharedItemStack} of the same item. To
* support selecting ranges of durability, it is defined for type {@link Object} and also accepts * support selecting ranges of durability, it is defined for type {@link Object} and also accepts
* {@link ItemDamageBound} as an argument to compare against. * {@link ItemDamageBound} as an argument to compare against.
*/ */
static class SharedStackComparator implements Comparator<Object> static class SharedStackComparator implements Comparator<Object> {
{ @Override
@Override public int compare(Object a, Object b) {
public int compare( Object a, Object b ) // Either argument can either be a damage bound or a shared item stack
{ // Since we never put damage bounds into the map as keys, only one
// Either argument can either be a damage bound or a shared item stack // of the two arguments can possibly be a bound
// Since we never put damage bounds into the map as keys, only one ItemDamageBound boundA = null;
// of the two arguments can possibly be a bound AESharedItemStack stackA = null;
ItemDamageBound boundA = null; int itemDamageA;
AESharedItemStack stackA = null; if (a instanceof ItemDamageBound) {
int itemDamageA; boundA = (ItemDamageBound) a;
if( a instanceof ItemDamageBound ) itemDamageA = boundA.itemDamage;
{ } else {
boundA = (ItemDamageBound) a; stackA = (AESharedItemStack) a;
itemDamageA = boundA.itemDamage; itemDamageA = stackA.getItemDamage();
} }
else ItemDamageBound boundB = null;
{ AESharedItemStack stackB = null;
stackA = (AESharedItemStack) a; int itemDamageB;
itemDamageA = stackA.getItemDamage(); if (b instanceof ItemDamageBound) {
} boundB = (ItemDamageBound) b;
ItemDamageBound boundB = null; itemDamageB = boundB.itemDamage;
AESharedItemStack stackB = null; } else {
int itemDamageB; stackB = (AESharedItemStack) b;
if( b instanceof ItemDamageBound ) itemDamageB = stackB.getItemDamage();
{ }
boundB = (ItemDamageBound) b;
itemDamageB = boundB.itemDamage;
}
else
{
stackB = (AESharedItemStack) b;
itemDamageB = stackB.getItemDamage();
}
// When either argument is a damage bound, we just compare the damage values because it is used // When either argument is a damage bound, we just compare the damage values because it is used
// only to get a certain damage range out of the map. // only to get a certain damage range out of the map.
if( boundA != null || boundB != null ) if (boundA != null || boundB != null) {
{ return Integer.compare(itemDamageB, itemDamageA);
return Integer.compare( itemDamageB, itemDamageA ); }
}
ItemStack itemStackA = stackA.getDefinition(); ItemStack itemStackA = stackA.getDefinition();
ItemStack itemStackB = stackB.getDefinition(); ItemStack itemStackB = stackB.getDefinition();
Preconditions.checkState( itemStackA.getCount() == 1, "ItemStack#getCount() has to be 1" ); Preconditions.checkState(itemStackA.getCount() == 1, "ItemStack#getCount() has to be 1");
Preconditions.checkArgument( itemStackB.getCount() == 1, "ItemStack#getCount() has to be 1" ); Preconditions.checkArgument(itemStackB.getCount() == 1, "ItemStack#getCount() has to be 1");
if( itemStackA == itemStackB ) if (itemStackA == itemStackB) {
{ return 0;
return 0; }
}
// Damaged items are sorted before undamaged items // Damaged items are sorted before undamaged items
final int damageValue = Integer.compare( itemDamageB, itemDamageA ); final int damageValue = Integer.compare(itemDamageB, itemDamageA);
if( damageValue != 0 ) if (damageValue != 0) {
{ return damageValue;
return damageValue; }
}
// As a final tie breaker, order by the object identity of the item stack // As a final tie breaker, order by the object identity of the item stack
// While this will order seemingly at random, we only need the order of // While this will order seemingly at random, we only need the order of
// damage values to be predictable, while still having to satisfy the // damage values to be predictable, while still having to satisfy the
// complete order requirements of the sorted map // complete order requirements of the sorted map
return Long.compare( System.identityHashCode( itemStackA ), System.identityHashCode( itemStackB ) ); return Long.compare(System.identityHashCode(itemStackA), System.identityHashCode(itemStackB));
} }
} }
/** /**
* Minecraft reverses the damage values. So anything with a damage of 0 is undamaged and increases the more damaged * Minecraft reverses the damage values. So anything with a damage of 0 is undamaged and increases the more damaged
* the item is. * the item is.
* <p> * <p>
* Further the used subMap follows [MAX_DAMAGE, MIN_DAMAGE), so to include undamaged items, we have to start with a * Further the used subMap follows [MAX_DAMAGE, MIN_DAMAGE), so to include undamaged items, we have to start with a
* lower damage value than 0, while it is fine to use {@link ItemStack#getMaxDamage()} for the upper bound. * lower damage value than 0, while it is fine to use {@link ItemStack#getMaxDamage()} for the upper bound.
*/ */
private static final int MIN_DAMAGE_VALUE = -1; private static final int MIN_DAMAGE_VALUE = -1;
/* /*
* Keep in mind that the stack order is from most damaged to least damaged, so this lower bound will actually be a * Keep in mind that the stack order is from most damaged to least damaged, so this lower bound will actually be a
* higher number than the upper bound. * higher number than the upper bound.
*/ */
static ItemDamageBound makeLowerBound( final ItemStack stack, final FuzzyMode fuzzy ) static ItemDamageBound makeLowerBound(final ItemStack stack, final FuzzyMode fuzzy)
{ {
Preconditions.checkState( stack.getItem().isDamageable() || ( Platform.isGTDamageableItem( stack.getItem() ) ), "Item#isDamageable() has to be true" ); Preconditions.checkState( stack.getItem().isDamageable() , "Item#isDamageable() has to be true" );
int damage; int damage;
int maxDamage; if( fuzzy == FuzzyMode.IGNORE_ALL )
if( Platform.isIC2DamageableItem( stack.getItem() ) ) {
{ if( stack.getMaxDamage() == 0 )
maxDamage = ( (ICustomDamageItem) stack.getItem() ).getMaxCustomDamage( stack ); {
damage = ( (ICustomDamageItem) stack.getItem() ).getCustomDamage( stack ); damage = stack.getItemDamage();
} }
else if( Platform.isGTDamageableItem( stack.getItem() ) ) else
{ {
maxDamage = ( (IToolItem) stack.getItem() ).getMaxItemDamage( stack ); damage = stack.getMaxDamage();
damage = ( (IToolItem) stack.getItem() ).getItemDamage( stack ); }
} }
else else
{ {
maxDamage = stack.getMaxDamage(); final int breakpoint = fuzzy.calculateBreakPoint( stack.getMaxDamage() );
damage = stack.getItemDamage(); damage = stack.getItemDamage() <= breakpoint ? breakpoint : stack.getMaxDamage();
} }
if( fuzzy == FuzzyMode.IGNORE_ALL ) return new ItemDamageBound( damage );
{ }
if( maxDamage != 0 )
{
damage = maxDamage;
}
}
else
{
final int breakpoint = fuzzy.calculateBreakPoint( maxDamage );
damage = damage <= breakpoint ? breakpoint : maxDamage;
}
return new ItemDamageBound( damage ); /*
} * Keep in mind that the stack order is from most damaged to least damaged, so this upper bound will actually be a
* lower number than the lower bound. It also is exclusive.
*/
static ItemDamageBound makeUpperBound(final ItemStack stack, final FuzzyMode fuzzy) {
Preconditions.checkState(stack.getItem().isDamageable() , "Item#isDamageable() has to be true");
/* int damage;
* Keep in mind that the stack order is from most damaged to least damaged, so this upper bound will actually be a if (fuzzy == FuzzyMode.IGNORE_ALL) {
* lower number than the lower bound. It also is exclusive. damage = MIN_DAMAGE_VALUE;
*/ } else {
static ItemDamageBound makeUpperBound( final ItemStack stack, final FuzzyMode fuzzy ) final int breakpoint = fuzzy.calculateBreakPoint(stack.getMaxDamage());
{ damage = stack.getItemDamage() <= breakpoint ? MIN_DAMAGE_VALUE : breakpoint;
Preconditions.checkState( stack.getItem().isDamageable() || ( Platform.isGTDamageableItem( stack.getItem() ) ), "Item#isDamageable() has to be true" ); }
int damage; return new ItemDamageBound(damage);
if( fuzzy == FuzzyMode.IGNORE_ALL ) }
{
damage = MIN_DAMAGE_VALUE;
}
else
{
int maxDamage;
if( Platform.isIC2DamageableItem( stack.getItem() ) )
{
maxDamage = ( (ICustomDamageItem) stack.getItem() ).getMaxCustomDamage( stack );
damage = ( (ICustomDamageItem) stack.getItem() ).getCustomDamage( stack );
}
else if( Platform.isGTDamageableItem( stack.getItem() ) )
{
maxDamage = ( (IToolItem) stack.getItem() ).getMaxItemDamage( stack );
damage = ( (IToolItem) stack.getItem() ).getItemDamage( stack );
}
else
{
maxDamage = stack.getMaxDamage();
damage = stack.getItemDamage();
}
final int breakpoint = fuzzy.calculateBreakPoint( maxDamage );
damage = damage <= breakpoint ? MIN_DAMAGE_VALUE : breakpoint;
}
return new ItemDamageBound( damage );
}
} }
+141 -177
View File
@@ -26,6 +26,7 @@ import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import appeng.util.Platform; import appeng.util.Platform;
import gregtech.common.items.MetaTool;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
@@ -35,217 +36,180 @@ import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
public final class ItemList implements IItemList<IAEItemStack> {
public final class ItemList implements IItemList<IAEItemStack> private final Reference2ObjectMap<Item, ItemVariantList> records = new Reference2ObjectOpenHashMap<>();
{ /**
* We increment this version field everytime an attempt to mutate this item list (or potentially one of its
* sub-lists) is made. Iterators will copy the version when they are created and compare it against the current
* version whenever they advance to trigger a {@link ConcurrentModificationException}.
*/
private final AtomicInteger version = new AtomicInteger(0);
private final Reference2ObjectMap<Item, ItemVariantList> records = new Reference2ObjectOpenHashMap<>(); @Override
/** public IAEItemStack findPrecise(final IAEItemStack itemStack) {
* We increment this version field everytime an attempt to mutate this item list (or potentially one of its if (itemStack == null) {
* sub-lists) is made. Iterators will copy the version when they are created and compare it against the current return null;
* version whenever they advance to trigger a {@link ConcurrentModificationException}. }
*/
private final AtomicInteger version = new AtomicInteger( 0 );
@Override ItemVariantList record = this.records.get(itemStack.getItem());
public IAEItemStack findPrecise( final IAEItemStack itemStack ) return record != null ? record.findPrecise(itemStack) : null;
{ }
if( itemStack == null )
{
return null;
}
ItemVariantList record = this.records.get( itemStack.getItem() ); @Override
return record != null ? record.findPrecise( itemStack ) : null; public Collection<IAEItemStack> findFuzzy(final IAEItemStack filter, final FuzzyMode fuzzy) {
} if (filter == null) {
return Collections.emptyList();
}
@Override ItemVariantList record = this.records.get(filter.getItem());
public Collection<IAEItemStack> findFuzzy( final IAEItemStack filter, final FuzzyMode fuzzy ) return record != null ? record.findFuzzy(filter, fuzzy) : Collections.emptyList();
{ }
if( filter == null )
{
return Collections.emptyList();
}
ItemVariantList record = this.records.get( filter.getItem() ); @Override
return record != null ? record.findFuzzy( filter, fuzzy ) : Collections.emptyList(); public boolean isEmpty() {
} return !this.iterator().hasNext();
}
@Override @Override
public boolean isEmpty() public void add(final IAEItemStack itemStack) {
{ version.incrementAndGet();
return !this.iterator().hasNext();
}
@Override if (itemStack == null) {
public void add( final IAEItemStack itemStack ) return;
{ }
version.incrementAndGet();
if( itemStack == null ) this.getOrCreateRecord(itemStack.getItem()).add(itemStack);
{ }
return;
}
this.getOrCreateRecord( itemStack.getItem() ).add( itemStack ); @Override
} public void addStorage(final IAEItemStack itemStack) {
version.incrementAndGet();
@Override if (itemStack == null) {
public void addStorage( final IAEItemStack itemStack ) return;
{ }
version.incrementAndGet();
if( itemStack == null ) this.getOrCreateRecord(itemStack.getItem()).addStorage(itemStack);
{ }
return;
}
this.getOrCreateRecord( itemStack.getItem() ).addStorage( itemStack ); @Override
} public void addCrafting(final IAEItemStack itemStack) {
version.incrementAndGet();
@Override if (itemStack == null) {
public void addCrafting( final IAEItemStack itemStack ) return;
{ }
version.incrementAndGet();
if( itemStack == null ) this.getOrCreateRecord(itemStack.getItem()).addCrafting(itemStack);
{ }
return;
}
this.getOrCreateRecord( itemStack.getItem() ).addCrafting( itemStack ); @Override
} public void addRequestable(final IAEItemStack itemStack) {
version.incrementAndGet();
@Override if (itemStack == null) {
public void addRequestable( final IAEItemStack itemStack ) return;
{ }
version.incrementAndGet();
if( itemStack == null ) this.getOrCreateRecord(itemStack.getItem()).addRequestable(itemStack);
{ }
return;
}
this.getOrCreateRecord( itemStack.getItem() ).addRequestable( itemStack ); @Override
} public IAEItemStack getFirstItem() {
for (final IAEItemStack stackType : this) {
return stackType;
}
@Override return null;
public IAEItemStack getFirstItem() }
{
for( final IAEItemStack stackType : this )
{
return stackType;
}
return null; @Override
} public int size() {
int size = 0;
for (ItemVariantList entry : records.values()) {
size += entry.size();
}
@Override return size;
public int size() }
{
int size = 0;
for( ItemVariantList entry : records.values() )
{
size += entry.size();
}
return size; @Override
} public Iterator<IAEItemStack> iterator() {
return new ChainedIterator(this.records.values().iterator(), version);
}
@Override @Override
public Iterator<IAEItemStack> iterator() public void resetStatus() {
{ for (final IAEItemStack i : this) {
return new ChainedIterator( this.records.values().iterator(), version ); i.reset();
} }
}
@Override private ItemVariantList getOrCreateRecord(Item item) {
public void resetStatus() return this.records.computeIfAbsent(item, this::makeRecordMap);
{ }
for( final IAEItemStack i : this )
{
i.reset();
}
}
private ItemVariantList getOrCreateRecord( Item item ) private ItemVariantList makeRecordMap(Item item) {
{ if (item.isDamageable() ) {
return this.records.computeIfAbsent( item, this::makeRecordMap ); return new FuzzyItemVariantList();
} } else {
return new NormalItemVariantList();
}
}
private ItemVariantList makeRecordMap( Item item ) /**
{ * Iterates over multiple item lists as if they were one list.
if( item.isDamageable() || Platform.isGTDamageableItem( item ) ) */
{ private static class ChainedIterator implements Iterator<IAEItemStack> {
return new FuzzyItemVariantList();
}
else
{
return new NormalItemVariantList();
}
}
/** private final AtomicInteger parentVersion;
* Iterates over multiple item lists as if they were one list. private final int version;
*/ private final Iterator<ItemVariantList> parent;
private static class ChainedIterator implements Iterator<IAEItemStack> private Iterator<IAEItemStack> next;
{
private final AtomicInteger parentVersion; public ChainedIterator(Iterator<ItemVariantList> iterator, AtomicInteger parentVersion) {
private final int version; this.parent = iterator;
private final Iterator<ItemVariantList> parent; this.parentVersion = parentVersion;
private Iterator<IAEItemStack> next; this.version = parentVersion.get();
this.ensureItems();
}
public ChainedIterator( Iterator<ItemVariantList> iterator, AtomicInteger parentVersion ) @Override
{ public boolean hasNext() {
this.parent = iterator; return next != null && next.hasNext();
this.parentVersion = parentVersion; }
this.version = parentVersion.get();
this.ensureItems();
}
@Override @Override
public boolean hasNext() public IAEItemStack next() {
{ if (this.next == null) {
return next != null && next.hasNext(); throw new NoSuchElementException();
} }
if (this.version != this.parentVersion.get()) {
throw new ConcurrentModificationException();
}
@Override IAEItemStack result = this.next.next();
public IAEItemStack next() this.ensureItems();
{ return result;
if( this.next == null ) }
{
throw new NoSuchElementException();
}
if( this.version != this.parentVersion.get() )
{
throw new ConcurrentModificationException();
}
IAEItemStack result = this.next.next(); private void ensureItems() {
this.ensureItems(); if (hasNext()) {
return result; return; // Still items left in the current one
} }
private void ensureItems() // Find the next iterator willing to return some items...
{ while (this.parent.hasNext()) {
if( hasNext() ) this.next = this.parent.next().iterator();
{
return; // Still items left in the current one
}
// Find the next iterator willing to return some items... if (this.next.hasNext()) {
while ( this.parent.hasNext() ) return; // Found one!
{ }
this.next = this.parent.next().iterator(); }
if( this.next.hasNext() ) // No more items
{ this.next = null;
return; // Found one! }
} }
}
// No more items
this.next = null;
}
}
} }