package openblocks.common.tileentity; import com.google.common.collect.Lists; import java.util.Collections; import java.util.List; import net.minecraft.block.Block; import net.minecraft.command.IEntitySelector; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidHandler; import openblocks.OpenBlocks; import openblocks.client.gui.GuiVacuumHopper; import openblocks.common.LiquidXpUtils; import openblocks.common.container.ContainerVacuumHopper; import openblocks.common.entity.EntityItemProjectile; import openmods.OpenMods; import openmods.api.IActivateAwareTile; import openmods.api.IHasGui; import openmods.api.INeighbourAwareTile; import openmods.api.IValueProvider; import openmods.include.IncludeInterface; import openmods.inventory.GenericInventory; import openmods.inventory.IInventoryProvider; import openmods.inventory.TileEntityInventory; import openmods.inventory.legacy.ItemDistribution; import openmods.liquids.SidedFluidHandler; import openmods.sync.SyncableBoolean; import openmods.sync.SyncableSides; import openmods.sync.SyncableTank; import openmods.tileentity.SyncedTileEntity; import openmods.utils.EnchantmentUtils; import openmods.utils.SidedInventoryAdapter; import openmods.utils.bitmap.BitMapUtils; import openmods.utils.bitmap.IReadableBitMap; import openmods.utils.bitmap.IRpcDirectionBitMap; import openmods.utils.bitmap.IWriteableBitMap; public class TileEntityVacuumHopper extends SyncedTileEntity implements IInventoryProvider, IActivateAwareTile, IHasGui, IEntitySelector, INeighbourAwareTile { public static final int TANK_CAPACITY = LiquidXpUtils.xpToLiquidRatio(EnchantmentUtils.getExperienceForLevel(5)); private SyncableTank tank; public SyncableSides xpOutputs; public SyncableSides itemOutputs; public SyncableBoolean vacuumDisabled; private boolean needsTankUpdate; private final GenericInventory inventory = registerInventoryCallback(new TileEntityInventory(this, "vacuumhopper", true, 10)); @IncludeInterface(ISidedInventory.class) private final SidedInventoryAdapter sided = new SidedInventoryAdapter(inventory); @IncludeInterface private final IFluidHandler tankWrapper = new SidedFluidHandler.Source(xpOutputs, tank); @Override protected void createSyncedFields() { tank = new SyncableTank(TANK_CAPACITY, OpenBlocks.Fluids.xpJuice); xpOutputs = new SyncableSides(); itemOutputs = new SyncableSides(); vacuumDisabled = new SyncableBoolean(); } public TileEntityVacuumHopper() { sided.registerAllSlots(itemOutputs, false, true); } public IReadableBitMap<ForgeDirection> getReadableXpOutputs() { return xpOutputs; } public IWriteableBitMap<ForgeDirection> getWriteableXpOutputs() { return BitMapUtils.createRpcAdapter(createRpcProxy(xpOutputs, IRpcDirectionBitMap.class)); } public IReadableBitMap<ForgeDirection> getReadableItemOutputs() { return itemOutputs; } public IWriteableBitMap<ForgeDirection> getWriteableItemOutputs() { return BitMapUtils.createRpcAdapter(createRpcProxy(itemOutputs, IRpcDirectionBitMap.class)); } public IValueProvider<FluidStack> getFluidProvider() { return tank; } @Override public boolean isEntityApplicable(Entity entity) { if (entity.isDead) return false; if (entity instanceof EntityItemProjectile) return entity.motionY < 0.01; if (entity instanceof EntityItem) { ItemStack stack = ((EntityItem)entity).getEntityItem(); return ItemDistribution.testInventoryInsertion(inventory, stack) > 0; } if (entity instanceof EntityXPOrb) return tank.getSpace() > 0; return false; } @Override public void updateEntity() { super.updateEntity(); if (vacuumDisabled.get()) return; if (worldObj.isRemote) { worldObj.spawnParticle("portal", xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, worldObj.rand.nextDouble() - 0.5, worldObj.rand.nextDouble() - 1.0, worldObj.rand.nextDouble() - 0.5); } @SuppressWarnings("unchecked") List<Entity> interestingItems = worldObj.selectEntitiesWithinAABB(Entity.class, getBB().expand(3, 3, 3), this); boolean needsSync = false; for (Entity entity : interestingItems) { double x = (xCoord + 0.5D - entity.posX); double y = (yCoord + 0.5D - entity.posY); double z = (zCoord + 0.5D - entity.posZ); double distance = Math.sqrt(x * x + y * y + z * z); if (distance < 1.1) { needsSync |= onEntityCollidedWithBlock(entity); } else { double var11 = 1.0 - distance / 15.0; if (var11 > 0.0D) { var11 *= var11; entity.motionX += x / distance * var11 * 0.05; entity.motionY += y / distance * var11 * 0.2; entity.motionZ += z / distance * var11 * 0.05; } } } if (!worldObj.isRemote) { needsSync |= outputToNeighbors(); if (needsSync) sync(); } } private boolean outputToNeighbors() { if (OpenMods.proxy.getTicks(worldObj) % 10 == 0) { if (needsTankUpdate) { tank.updateNeighbours(worldObj, getPosition()); needsTankUpdate = false; } tank.distributeToSides(50, worldObj, getPosition(), xpOutputs.getValue()); autoInventoryOutput(); return true; } return false; } private void autoInventoryOutput() { for (int i = 0; i < inventory.getSizeInventory(); i++) { if (inventory.getStackInSlot(i) != null) { getItemOutOfSlot(i); break; } } } private void getItemOutOfSlot(int slot) { final List<ForgeDirection> outputSides = Lists.newArrayList(itemOutputs.getValue()); Collections.shuffle(outputSides); for (ForgeDirection output : outputSides) { TileEntity tileOnSurface = getTileInDirection(output); if (ItemDistribution.moveItemInto(inventory, slot, tileOnSurface, output, 64, true) > 0) return; } } @Override public Object getServerGui(EntityPlayer player) { return new ContainerVacuumHopper(player.inventory, this); } @Override public Object getClientGui(EntityPlayer player) { return new GuiVacuumHopper(new ContainerVacuumHopper(player.inventory, this)); } @Override public boolean canOpenGui(EntityPlayer player) { return true; } @Override public boolean onBlockActivated(EntityPlayer player, int side, float hitX, float hitY, float hitZ) { if (player.isSneaking()) { if (player.inventory.getStackInSlot(player.inventory.currentItem) == null) { vacuumDisabled.toggle(); return true; } } return false; } public boolean onEntityCollidedWithBlock(Entity entity) { if (!worldObj.isRemote) { if (entity instanceof EntityItem && !entity.isDead) { EntityItem item = (EntityItem)entity; ItemStack stack = item.getEntityItem().copy(); ItemDistribution.insertItemIntoInventory(inventory, stack); if (stack.stackSize == 0) { item.setDead(); } else { item.setEntityItemStack(stack); } return true; } else if (entity instanceof EntityXPOrb) { if (tank.getSpace() > 0) { EntityXPOrb orb = (EntityXPOrb)entity; int xpAmount = LiquidXpUtils.xpToLiquidRatio(orb.getXpValue()); FluidStack newFluid = new FluidStack(OpenBlocks.Fluids.xpJuice, xpAmount); tank.fill(newFluid, true); entity.setDead(); return true; } } } return false; } @Override public IInventory getInventory() { return inventory; } @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); inventory.writeToNBT(tag); } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); inventory.readFromNBT(tag); } @Override public void validate() { super.validate(); this.needsTankUpdate = true; } @Override public void onNeighbourChanged(Block block) { this.needsTankUpdate = true; } }