/** * This class was created by <Vazkii>. It's distributed as * part of the Botania Mod. Get the Source Code in github: * https://github.com/Vazkii/Botania * * Botania is Open Source and distributed under the * Botania License: http://botaniamod.net/license.php * * File Created @ [Mar 20, 2014, 5:54:39 PM (GMT)] */ package vazkii.botania.common.block.subtile.functional; import java.util.ArrayList; import java.util.List; import org.lwjgl.opengl.GL11; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.item.EntityItemFrame; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; import vazkii.botania.api.corporea.InvWithLocation; import vazkii.botania.api.lexicon.LexiconEntry; import vazkii.botania.api.mana.IManaItem; import vazkii.botania.api.subtile.RadiusDescriptor; import vazkii.botania.api.subtile.SubTileFunctional; import vazkii.botania.common.core.handler.MethodHandles; import vazkii.botania.common.core.helper.InventoryHelper; import vazkii.botania.common.lexicon.LexiconData; public class SubTileHopperhock extends SubTileFunctional { private static final String TAG_FILTER_TYPE = "filterType"; private static final int RANGE_MANA = 10; private static final int RANGE = 6; private static final int RANGE_MANA_MINI = 2; private static final int RANGE_MINI = 1; private int filterType = 0; @Override public void onUpdate() { super.onUpdate(); if(supertile.getWorld().isRemote || redstoneSignal > 0) return; boolean pulledAny = false; int range = getRange(); BlockPos pos = supertile.getPos(); List<EntityItem> items = supertile.getWorld().getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(pos.add(-range, -range, -range), pos.add(range + 1, range + 1, range + 1))); int slowdown = getSlowdownFactor(); for(EntityItem item : items) { int age; try { age = (int) MethodHandles.itemAge_getter.invokeExact(item); } catch (Throwable t) { continue; } if(age < 60 + slowdown || age >= 105 && age < 110 || item.isDead || item.getEntityItem().isEmpty()) continue; ItemStack stack = item.getEntityItem(); IItemHandler invToPutItemIn = null; boolean priorityInv = false; int amountToPutIn = 0; for(EnumFacing dir : EnumFacing.VALUES) { BlockPos pos_ = pos.offset(dir); InvWithLocation inv = InventoryHelper.getInventoryWithLocation(supertile.getWorld(), pos_, dir); if(inv != null) { List<ItemStack> filter = getFilterForInventory(pos_, true); boolean canAccept = canAcceptItem(stack, filter, filterType); ItemStack simulate = ItemHandlerHelper.insertItem(inv.handler, stack.copy(), true); int availablePut = stack.getCount() - simulate.getCount(); canAccept &= availablePut > 0; if(canAccept) { boolean priority = !filter.isEmpty(); setInv : { if(priorityInv && !priority) break setInv; invToPutItemIn = inv.handler; priorityInv = priority; amountToPutIn = availablePut; } } } } if(invToPutItemIn != null && !item.isDead) { SubTileSpectranthemum.spawnExplosionParticles(item, 3); ItemHandlerHelper.insertItem(invToPutItemIn, stack.splitStack(amountToPutIn), false); item.setEntityItemStack(stack); // Just in case someone subclasses EntityItem and changes something important. pulledAny = true; } } if(pulledAny && mana > 1) mana--; } public boolean canAcceptItem(ItemStack stack, List<ItemStack> filter, int filterType) { if(stack.isEmpty()) return false; if(filter.isEmpty()) return true; switch(filterType) { case 0 : { // Accept items in frames only boolean anyFilter = false; for(ItemStack filterEntry : filter) { if(filterEntry == null) continue; anyFilter = true; boolean itemEqual = stack.getItem() == filterEntry.getItem(); boolean damageEqual = stack.getItemDamage() == filterEntry.getItemDamage(); boolean nbtEqual = ItemStack.areItemStackTagsEqual(filterEntry, stack); if(itemEqual && damageEqual && nbtEqual) return true; if(!stack.getHasSubtypes() && stack.isItemStackDamageable() && stack.getMaxStackSize() == 1 && itemEqual && nbtEqual) return true; if(stack.getItem() instanceof IManaItem && itemEqual) return true; } return !anyFilter; } case 1 : return !canAcceptItem(stack, filter, 0); // Accept items not in frames only default : return true; // Accept all items } } public List<ItemStack> getFilterForInventory(BlockPos pos, boolean recursiveForDoubleChests) { List<ItemStack> filter = new ArrayList<>(); if(recursiveForDoubleChests) { TileEntity tileEntity = supertile.getWorld().getTileEntity(pos); Block chest = supertile.getWorld().getBlockState(pos).getBlock(); if(tileEntity instanceof TileEntityChest) for(EnumFacing dir : EnumFacing.HORIZONTALS) if(supertile.getWorld().getBlockState(pos.offset(dir)).getBlock() == chest) { filter.addAll(getFilterForInventory(pos.offset(dir), false)); break; } } for(EnumFacing dir : EnumFacing.HORIZONTALS) { AxisAlignedBB aabb = new AxisAlignedBB(pos.offset(dir), pos.offset(dir).add(1, 1, 1)); List<EntityItemFrame> frames = supertile.getWorld().getEntitiesWithinAABB(EntityItemFrame.class, aabb); for(EntityItemFrame frame : frames) { if(frame.facingDirection == dir) filter.add(frame.getDisplayedItem()); } } return filter; } @Override public boolean acceptsRedstone() { return true; } @Override public boolean onWanded(EntityPlayer player, ItemStack wand) { if(player == null) return false; if(player.isSneaking()) { filterType = filterType == 2 ? 0 : filterType + 1; sync(); return true; } else return super.onWanded(player, wand); } @Override public RadiusDescriptor getRadius() { return new RadiusDescriptor.Square(toBlockPos(), getRange()); } public int getRange() { return mana > 0 ? RANGE_MANA : RANGE; } @Override public void writeToPacketNBT(NBTTagCompound cmp) { super.writeToPacketNBT(cmp); cmp.setInteger(TAG_FILTER_TYPE, filterType); } @Override public void readFromPacketNBT(NBTTagCompound cmp) { super.readFromPacketNBT(cmp); filterType = cmp.getInteger(TAG_FILTER_TYPE); } @SideOnly(Side.CLIENT) @Override public void renderHUD(Minecraft mc, ScaledResolution res) { super.renderHUD(mc, res); int color = getColor(); String filter = I18n.format("botaniamisc.filter" + filterType); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); int x = res.getScaledWidth() / 2 - mc.fontRendererObj.getStringWidth(filter) / 2; int y = res.getScaledHeight() / 2 + 30; mc.fontRendererObj.drawStringWithShadow(filter, x, y, color); GlStateManager.disableBlend(); } @Override public LexiconEntry getEntry() { return LexiconData.hopperhock; } @Override public int getMaxMana() { return 20; } @Override public int getColor() { return 0x3F3F3F; } public static class Mini extends SubTileHopperhock { @Override public int getRange() { return mana > 0 ? RANGE_MANA_MINI : RANGE_MINI; } } }