package com.jaquadro.minecraft.gardencore.block; import com.jaquadro.minecraft.gardencore.GardenCore; import com.jaquadro.minecraft.gardencore.api.GardenCoreAPI; import com.jaquadro.minecraft.gardencore.api.IBonemealHandler; import com.jaquadro.minecraft.gardencore.api.IPlantProxy; import com.jaquadro.minecraft.gardencore.block.tile.TileEntityGarden; import com.jaquadro.minecraft.gardencore.core.ClientProxy; import com.jaquadro.minecraft.gardencore.core.ModItems; import com.jaquadro.minecraft.gardencore.util.BindingStack; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.client.particle.EntityDiggingFX; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.IIcon; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.IPlantable; import java.util.ArrayList; import java.util.List; import java.util.Random; public class BlockGardenProxy extends Block implements IPlantProxy { @SideOnly(Side.CLIENT) private IIcon transpIcon; // Scratch State private boolean applyingBonemeal; // Reentrant Flags private int reeLightValue; public BlockGardenProxy (String blockName) { super(Material.plants); setHardness(0); setLightOpacity(0); setBlockName(blockName); //setTickRandomly(true); } public float getPlantOffsetX (IBlockAccess blockAccess, int x, int y, int z, int slot) { BlockGarden gardenBlock = getGardenBlock(blockAccess, x, y, z); if (gardenBlock == null) return 0; return gardenBlock.getSlotProfile().getPlantOffsetX(blockAccess, x, getBaseBlockYCoord(blockAccess, x, y, z), z, slot); } public float getPlantOffsetY (IBlockAccess blockAccess, int x, int y, int z, int slot) { BlockGarden gardenBlock = getGardenBlock(blockAccess, x, y, z); if (gardenBlock == null) return 0; return gardenBlock.getSlotProfile().getPlantOffsetY(blockAccess, x, getBaseBlockYCoord(blockAccess, x, y, z), z, slot); } public float getPlantOffsetZ (IBlockAccess blockAccess, int x, int y, int z, int slot) { BlockGarden gardenBlock = getGardenBlock(blockAccess, x, y, z); if (gardenBlock == null) return 0; return gardenBlock.getSlotProfile().getPlantOffsetZ(blockAccess, x, getBaseBlockYCoord(blockAccess, x, y, z), z, slot); } public void bindSlot (World world, int x, int y, int z, TileEntityGarden te, int slot) { int data = 0; if (getPlantBlock(te, slot) != null) data = getPlantData(te, slot); GardenCore.proxy.getBindingStack(world, this).bind(world, x, y, z, slot, data); } public void unbindSlot (World world, int x, int y, int z, TileEntityGarden te) { GardenCore.proxy.getBindingStack(world, this).unbind(world, x, y, z); } @Override public boolean isOpaqueCube () { return false; } @Override public boolean renderAsNormalBlock () { return false; } @Override public int getRenderType () { return ClientProxy.gardenProxyRenderID; } @Override public AxisAlignedBB getCollisionBoundingBoxFromPool (World world, int x, int y, int z) { TileEntityGarden te = getGardenEntity(world, x, y, z); if (te == null) return null; BlockGarden garden = getGardenBlock(world, x, y, z); if (garden == null) return null; int baseY = getBaseBlockYCoord(world, x, y, z); AxisAlignedBB aabb = null; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { AxisAlignedBB sub = block.getCollisionBoundingBoxFromPool(world, x, y, z); if (sub == null) continue; float offsetX = garden.getSlotProfile().getPlantOffsetX(world, x, baseY, z, slot); float offsetY = garden.getSlotProfile().getPlantOffsetY(world, x, baseY, z, slot); float offsetZ = garden.getSlotProfile().getPlantOffsetZ(world, x, baseY, z, slot); sub.offset(offsetX, offsetY, offsetZ); if (aabb == null) aabb = sub; else aabb = aabb.func_111270_a(sub); // Union } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } return aabb; } @Override public AxisAlignedBB getSelectedBoundingBoxFromPool (World world, int x, int y, int z) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return super.getSelectedBoundingBoxFromPool(world, x, y, z); int baseY = getBaseBlockYCoord(world, x, y, z); AxisAlignedBB aabb = null; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { AxisAlignedBB sub = block.getSelectedBoundingBoxFromPool(world, x, y, z); if (sub == null) continue; float offsetX = garden.getSlotProfile().getPlantOffsetX(world, x, baseY, z, slot); float offsetY = garden.getSlotProfile().getPlantOffsetY(world, x, baseY, z, slot); float offsetZ = garden.getSlotProfile().getPlantOffsetZ(world, x, baseY, z, slot); sub.offset(offsetX, offsetY, offsetZ); if (aabb == null) aabb = sub; else aabb = aabb.func_111270_a(sub); // Union } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } if (aabb == null) aabb = super.getSelectedBoundingBoxFromPool(world, x, y, z); return aabb; } /* All plants that derive from BlockBush will do a check-and-drop. updateTick may be too unpredictable to support @Override public void updateTick (World world, int x, int y, int z, Random random) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); int data = getPlantData(te, slot); if (block == null || !block.getTickRandomly()) continue; try { bindSlot(world, x, y, z, te, slot); block.updateTick(world, x, y, z, random); int postTickData = world.getBlockMetadata(x, y, z); if (data != postTickData) setPlantData(te, slot, postTickData); } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } }*/ @Override public void addCollisionBoxesToList (World world, int x, int y, int z, AxisAlignedBB mask, List list, Entity colliding) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) { super.addCollisionBoxesToList(world, x, y, z, mask, list, colliding); return; } int baseY = getBaseBlockYCoord(world, x, y, z); for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { AxisAlignedBB sub = block.getCollisionBoundingBoxFromPool(world, x, y, z); if (sub == null) continue; float offsetX = garden.getSlotProfile().getPlantOffsetX(world, x, baseY, z, slot); float offsetY = garden.getSlotProfile().getPlantOffsetY(world, x, baseY, z, slot); float offsetZ = garden.getSlotProfile().getPlantOffsetZ(world, x, baseY, z, slot); sub.offset(offsetX, offsetY, offsetZ); if (mask.intersectsWith(sub)) list.add(sub); } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } if (list.isEmpty()) super.addCollisionBoxesToList(world, x, y, z, mask, list, colliding); } @Override public MovingObjectPosition collisionRayTrace (World world, int x, int y, int z, Vec3 startVec, Vec3 endVec) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return super.collisionRayTrace(world, x, y, z, startVec, endVec); int baseY = getBaseBlockYCoord(world, x, y, z); MovingObjectPosition mop = null; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { float offsetX = garden.getSlotProfile().getPlantOffsetX(world, x, baseY, z, slot); float offsetY = garden.getSlotProfile().getPlantOffsetY(world, x, baseY, z, slot); float offsetZ = garden.getSlotProfile().getPlantOffsetZ(world, x, baseY, z, slot); Vec3 slotStartVec = Vec3.createVectorHelper(startVec.xCoord - offsetX, startVec.yCoord - offsetY, startVec.zCoord - offsetZ); Vec3 slotEndVec = Vec3.createVectorHelper(endVec.xCoord - offsetX, endVec.yCoord - offsetY, endVec.zCoord - offsetZ); MovingObjectPosition sub = block.collisionRayTrace(world, x, y, z, slotStartVec, slotEndVec); if (mop == null || slotStartVec.squareDistanceTo(mop.hitVec) > slotStartVec.squareDistanceTo(sub.hitVec)) mop = sub; } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } return mop; } @Override public void onNeighborBlockChange (World world, int x, int y, int z, Block block) { TileEntityGarden te = getGardenEntity(world, x, y, z); if (te != null) BlockGarden.validateBlockState(te); else world.setBlockToAir(x, y, z); } @Override public boolean onBlockActivated (World world, int x, int y, int z, EntityPlayer player, int side, float vx, float vy, float vz) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return false; boolean flag = false; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { flag |= block.onBlockActivated(world, x, y, z, player, side, vx, vy, vz); } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } if (flag) return true; BlockGarden block = getGardenBlock(world, x, y, z); if (block != null) { y = getBaseBlockYCoord(world, x, y, z); return block.applyItemToGarden(world, x, y, z, player, null); } return false; } /*public boolean applyTestKit (World world, int x, int y, int z, ItemStack testKit) { BlockGarden block = getGardenBlock(world, x, y, z); if (block == null) return false; y = getBaseBlockYCoord(world, x, y, z); return block.applyTestKit(world, x, y, z, testKit); }*/ public boolean applyBonemeal (World world, int x, int y, int z) { BlockGarden block = getGardenBlock(world, x, y, z); if (block == null) return false; y = getBaseBlockYCoord(world, x, y, z); TileEntityGarden te = block.getTileEntity(world, x, y, z); boolean handled = false; for (int slot : block.getSlotProfile().getPlantSlots()) { for (IBonemealHandler handler : GardenCoreAPI.instance().getBonemealHandlers()) { if (handler.applyBonemeal(world, x, y, z, block, slot)) { handled = true; break; } } } return handled; } @Override public void onBlockHarvested (World world, int x, int y, int z, int p_149681_5_, EntityPlayer player) { super.onBlockHarvested(world, x, y, z, p_149681_5_, player); if (player.capabilities.isCreativeMode) { TileEntityGarden te = getGardenEntity(world, x, y, z); if (te != null) te.clearPlantedContents(); } } @Override public void breakBlock (World world, int x, int y, int z, Block block, int data) { if (hasValidUnderBlock(world, x, y, z) && !isApplyingBonemealTo(x, y, z)) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te != null && block != null) { for (int slot : garden.getSlotProfile().getPlantSlots()) { ItemStack item = te.getPlantInSlot(slot); if (item != null) dropBlockAsItem(world, x, y, z, item); } te.clearPlantedContents(); } } world.notifyBlockOfNeighborChange(x, y + 1, z, block); world.notifyBlockOfNeighborChange(x, y - 1, z, block); if (!isApplyingBonemealTo(x, y, z)) { if (world.getBlock(x, y - 1, z) == this) world.setBlockToAir(x, y - 1, z); } super.breakBlock(world, x, y, z, block, data); } @Override public ArrayList<ItemStack> getDrops (World world, int x, int y, int z, int metadata, int fortune) { ArrayList<ItemStack> drops = new ArrayList<ItemStack>(); return drops; } @Override public int getLightValue (IBlockAccess world, int x, int y, int z) { if (reeLightValue > 0) return -1; reeLightValue++; int value = 0; TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) value = super.getLightValue(world, x, y, z); else { for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(te.getWorldObj(), x, y, z, te, slot); try { int sub = block.getLightValue(world, x, y, z); if (sub == -1) sub = block.getLightValue(); if (sub == -1) sub = getLightValue(); if (sub > value) value = sub; } catch (Exception e) { continue; } finally { unbindSlot(te.getWorldObj(), x, y, z, te); } } } reeLightValue--; return value; } @Override public void onEntityCollidedWithBlock (World world, int x, int y, int z, Entity entity) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { block.onEntityCollidedWithBlock(world, x, y, z, entity); } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } } @Override public void randomDisplayTick (World world, int x, int y, int z, Random random) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { block.randomDisplayTick(world, x, y, z, random); } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } } @SideOnly(Side.CLIENT) @Override public int colorMultiplier (IBlockAccess blockAccess, int x, int y, int z) { int slot = GardenCore.proxy.getClientBindingStack(this).getSlot(); TileEntityGarden te = getGardenEntity(blockAccess, x, y, z); if (te == null || slot == -1) return super.colorMultiplier(blockAccess, x, y, z); Block block = getPlantBlockRestricted(te, slot); if (block == null) return super.colorMultiplier(blockAccess, x, y, z); try { return block.colorMultiplier(blockAccess, x, y, z); } catch (Exception e) { return super.colorMultiplier(blockAccess, x, y, z); } } @SideOnly(Side.CLIENT) @Override public IIcon getIcon (IBlockAccess blockAccess, int x, int y, int z, int side) { int slot = GardenCore.proxy.getClientBindingStack(this).getSlot(); TileEntityGarden te = getGardenEntity(blockAccess, x, y, z); if (te == null || slot == -1) return super.getIcon(blockAccess, x, y, z, side); Block block = getPlantBlockRestricted(te, slot); if (block == null) return super.getIcon(blockAccess, x, y, z, side); try { return block.getIcon(blockAccess, x, y, z, side); } catch (Exception e) { return super.getIcon(blockAccess, x, y, z, side); } } @SideOnly(Side.CLIENT) @Override public IIcon getIcon (int side, int data) { return transpIcon; } @SideOnly(Side.CLIENT) @Override public boolean addDestroyEffects (World world, int x, int y, int z, int meta, EffectRenderer effectRenderer) { TileEntityGarden te = getGardenEntity(world, x, y, z); BlockGarden garden = getGardenBlock(world, x, y, z); if (te == null || garden == null) return true; for (int slot : garden.getSlotProfile().getPlantSlots()) { Block block = getPlantBlock(te, slot); int blockData = getPlantData(te, slot); if (block == null) continue; bindSlot(world, x, y, z, te, slot); try { byte count = 4; for (int ix = 0; ix < count; ++ix) { for (int iy = 0; iy < count; ++iy) { for (int iz = 0; iz < count; ++iz) { double xOff = (double)x + ((double)ix + 0.5D) / (double)count; double yOff = (double)y + ((double)iy + 0.5D) / (double)count; double zOff = (double)z + ((double)iz + 0.5D) / (double)count; EntityDiggingFX fx = new EntityDiggingFX(world, xOff, yOff, zOff, xOff - (double) x - 0.5D, yOff - (double) y - 0.5D, zOff - (double) z - 0.5D, this, meta); fx.setParticleIcon(block.getIcon(world.rand.nextInt(6), blockData)); effectRenderer.addEffect(fx.applyColourMultiplier(x, y, z)); } } } } catch (Exception e) { continue; } finally { unbindSlot(world, x, y, z, te); } } return true; } @SideOnly(Side.CLIENT) @Override public void registerBlockIcons (IIconRegister iconRegister) { transpIcon = iconRegister.registerIcon(GardenCore.MOD_ID + ":proxy_transp"); } private boolean hasValidUnderBlock (IBlockAccess world, int x, int y, int z) { if (y == 0) return false; Block underBlock = world.getBlock(x, y - 1, z); return underBlock instanceof BlockGarden || underBlock instanceof IPlantProxy; } private int getBaseBlockYCoord (IBlockAccess world, int x, int y, int z) { if (y == 0) return 0; Block underBlock = world.getBlock(x, --y, z); while (y > 0 && underBlock instanceof IPlantProxy) underBlock = world.getBlock(x, --y, z); return y; } public BlockGarden getGardenBlock (IBlockAccess world, int x, int y, int z) { if (y == 0) return null; y = getBaseBlockYCoord(world, x, y, z); Block underBlock = world.getBlock(x, y, z); if (!(underBlock instanceof BlockGarden)) return null; return (BlockGarden) underBlock; } public TileEntityGarden getGardenEntity (IBlockAccess world, int x, int y, int z) { y = getBaseBlockYCoord(world, x, y, z); TileEntity tileEntity = world.getTileEntity(x, y, z); if (!(tileEntity instanceof TileEntityGarden)) return null; return (TileEntityGarden) tileEntity; } public Block getPlantBlock (TileEntityGarden tileEntity, int slot) { ItemStack itemStack = tileEntity.getPlantInSlot(slot); if (itemStack == null) return null; return getPlantBlock(tileEntity, itemStack.getItem()); } public Block getPlantBlockRestricted (TileEntityGarden tileEntity, int slot) { ItemStack itemStack = tileEntity.getStackInSlotIsolated(slot); if (itemStack == null) return null; return getPlantBlock(tileEntity, itemStack.getItem()); } private Block getPlantBlock (TileEntityGarden tileEntity, Item item) { if (item == null) return null; if (item instanceof IPlantable) return ((IPlantable)item).getPlant(tileEntity.getWorldObj(), tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); if (item instanceof ItemBlock) return Block.getBlockFromItem(item); return null; } public int getPlantData (TileEntityGarden tileEntity, int slot) { ItemStack itemStack = tileEntity.getPlantInSlot(slot); if (itemStack == null) return 0; return itemStack.getItemDamage(); } private void setPlantData (TileEntityGarden tileEntity, int slot, int data) { ItemStack itemStack = tileEntity.getPlantInSlot(slot); if (itemStack != null) { itemStack.setItemDamage(data); tileEntity.setInventorySlotContents(slot, itemStack); } } private boolean isApplyingBonemealTo (int x, int y, int z) { return applyingBonemeal; } }