package gtPlusPlus.xmod.gregtech.common.helpers; import static gregtech.api.enums.Mods.Forestry; import static gtPlusPlus.core.lib.CORE.ConfigSwitches.enableTreeFarmerParticles; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; import net.minecraft.block.Block; import net.minecraft.block.BlockAir; import net.minecraft.block.IGrowable; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.network.play.server.S23PacketBlockChange; import net.minecraft.server.MinecraftServer; import net.minecraft.world.ChunkPosition; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.BonemealEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.oredict.OreDictionary; import com.google.common.collect.Lists; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; import cpw.mods.fml.common.eventhandler.Event.Result; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; import gnu.trove.set.hash.THashSet; import gregtech.api.enums.Mods; import gregtech.api.enums.OrePrefixes; import gregtech.api.enums.Textures; import gregtech.api.enums.ToolDictNames; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.items.GT_MetaGenerated_Tool; import gregtech.common.items.GT_MetaGenerated_Tool_01; import gtPlusPlus.api.objects.Logger; import gtPlusPlus.api.objects.data.AutoMap; import gtPlusPlus.api.objects.minecraft.BlockPos; import gtPlusPlus.core.lib.CORE; import gtPlusPlus.core.players.FakeFarmer; import gtPlusPlus.core.slots.SlotBuzzSaw.SAWTOOL; import gtPlusPlus.core.util.Utils; import gtPlusPlus.core.util.math.MathUtils; import gtPlusPlus.core.util.minecraft.FluidUtils; import gtPlusPlus.core.util.minecraft.ItemUtils; import gtPlusPlus.core.util.minecraft.particles.BlockBreakParticles; import gtPlusPlus.core.util.reflect.ReflectionUtils; import gtPlusPlus.xmod.gregtech.common.items.MetaGeneratedGregtechItems; public class TreeFarmHelper { public static final FluidStack fertT1 = FluidUtils.getFluidStack("fluid.fertiliser", 3); public static final FluidStack fertT2 = FluidUtils.getFluidStack("fluid.un18fertiliser", 2); public static final FluidStack fertT3 = FluidUtils.getFluidStack("fluid.un32fertiliser", 1); private static final int sawOreId = OreDictionary.getOreID(ToolDictNames.craftingToolSaw.name()); public static ITexture[][][] getTextureSet() { final ITexture[][][] rTextures = new ITexture[10][17][]; for (byte i = -1; i < 16; i++) { rTextures[0][i + 1] = TreeFarmHelper.getFront(i); rTextures[1][i + 1] = TreeFarmHelper.getBack(i); rTextures[2][i + 1] = TreeFarmHelper.getBottom(i); rTextures[3][i + 1] = TreeFarmHelper.getTop(i); rTextures[4][i + 1] = TreeFarmHelper.getSides(i); rTextures[5][i + 1] = TreeFarmHelper.getFrontActive(i); rTextures[6][i + 1] = TreeFarmHelper.getBackActive(i); rTextures[7][i + 1] = TreeFarmHelper.getBottomActive(i); rTextures[8][i + 1] = TreeFarmHelper.getTopActive(i); rTextures[9][i + 1] = TreeFarmHelper.getSidesActive(i); } return rTextures; } public static ITexture[] getFront(final byte aColor) { return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[2][aColor + 1] }; } public static ITexture[] getBack(final byte aColor) { return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[2][aColor + 1] }; } public static ITexture[] getBottom(final byte aColor) { return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[2][aColor + 1] }; } public static ITexture[] getTop(final byte aColor) { return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[2][aColor + 1] }; } public static ITexture[] getSides(final byte aColor) { return new ITexture[] { Textures.BlockIcons.MACHINE_CASINGS[2][aColor + 1] }; } public static ITexture[] getFrontActive(final byte aColor) { return getFront(aColor); } public static ITexture[] getBackActive(final byte aColor) { return getBack(aColor); } public static ITexture[] getBottomActive(final byte aColor) { return getBottom(aColor); } public static ITexture[] getTopActive(final byte aColor) { return getTop(aColor); } public static ITexture[] getSidesActive(final byte aColor) { return getSides(aColor); } public static boolean applyBonemeal(final EntityPlayer player, final World world, final int intX, final int intY, final int intZ, final short multiplier) { final Block block = world.getBlock(intX, intY, intZ); int roll; int rollNeeded; if (multiplier == 1) { roll = MathUtils.randInt(1, 15); rollNeeded = 15; } else if (multiplier == 2) { roll = MathUtils.randInt(1, 10); rollNeeded = 10; } else { roll = MathUtils.randInt(1, 5); rollNeeded = 5; } if (roll != rollNeeded) { return false; } // EntityPlayer player = FakePlayerFactory.getMinecraft((WorldServer)world); if (!world.isRemote) { if (enableTreeFarmerParticles) { world.playAuxSFX(2005, intX, intY, intZ, 0); } } final BonemealEvent event = new BonemealEvent(player, world, block, intX, intY, intZ); if (MinecraftForge.EVENT_BUS.post(event)) { Logger.MACHINE_INFO("Not sure why this returned false"); return false; } if (event.getResult() == Result.ALLOW) { if (!world.isRemote) { world.playAuxSFX(2005, intX, intY, intZ, 0); } return true; } if (block instanceof IGrowable) { final IGrowable igrowable = (IGrowable) block; if (igrowable.func_149851_a(world, intX, intY, intZ, world.isRemote)) { if (!world.isRemote) { if (igrowable.func_149852_a(world, CORE.RANDOM, intX, intY, intZ)) { igrowable.func_149853_b(world, CORE.RANDOM, intX, intY, intZ); } } return true; } } return false; } public static boolean cleanUp(final IGregTechTileEntity aBaseMetaTileEntity) { Logger.MACHINE_INFO("called cleanUp()"); int cleanedUp = 0; final int xDir = net.minecraftforge.common.util.ForgeDirection .getOrientation(aBaseMetaTileEntity.getBackFacing()).offsetX * 11; final int zDir = net.minecraftforge.common.util.ForgeDirection .getOrientation(aBaseMetaTileEntity.getBackFacing()).offsetZ * 11; for (int h = 1; h < 175; h++) { for (int i = -11; i <= 11; i++) { for (int j = -11; j <= 11; j++) { final Block testBlock = aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j); if ((((i == -8) || (i == 8)) || ((i == -9) || (i == 9)) || ((i == -10) || (i == 10)) || ((i == -11) || (i == 11))) && (((j == -8) || (j == 8)) || ((j == -9) || (j == 9)) || ((j == -10) || (j == 10)) || ((j == -11) || (j == 11)))) { if (!testBlock.getUnlocalizedName().toLowerCase().contains("air") || !testBlock.getUnlocalizedName().toLowerCase().contains("pumpkin")) { // Logger.WARNING("5:"+testBlock.getUnlocalizedName()); } else { aBaseMetaTileEntity.getWorld().setBlock( aBaseMetaTileEntity.getXCoord() + xDir + i, aBaseMetaTileEntity.getYCoord() + h, aBaseMetaTileEntity.getZCoord() + zDir + j, Blocks.bookshelf); } } // If not in the middle - don't know how else to check this one without lots of != if ((i != 7) && (i != -7) && (j != 7) && (j != -7) && (i != 6) && (i != -6) && (j != 6) && (j != -6) && (i != 5) && (i != -5) && (j != 5) && (j != -5) && (i != 4) && (i != -4) && (j != 4) && (j != -4) && (i != 3) && (i != -3) && (j != 3) && (j != -3) && (i != 2) && (i != -2) && (j != 2) && (j != -2) && (i != 1) && (i != -1) && (j != 1) && (j != -1) && (i != 0) && (j != 0)) { if (!testBlock.getUnlocalizedName().toLowerCase().contains("air") || !testBlock.getUnlocalizedName().toLowerCase().contains("pumpkin")) { // Logger.WARNING("0:"+testBlock.getUnlocalizedName()); } else { aBaseMetaTileEntity.getWorld().setBlock( aBaseMetaTileEntity.getXCoord() + xDir + i, aBaseMetaTileEntity.getYCoord() + h, aBaseMetaTileEntity.getZCoord() + zDir + j, Blocks.melon_block); } if (isLeaves(testBlock) || isWoodLog(testBlock)) { // Logger.WARNING("1:"+testBlock.getUnlocalizedName()); int posiX, posiY, posiZ; posiX = aBaseMetaTileEntity.getXCoord() + xDir + i; posiY = aBaseMetaTileEntity.getYCoord() + h; posiZ = aBaseMetaTileEntity.getZCoord() + zDir + j; // Utils.LOG_MACHINE_INFO("Cleaning Up some leftovers."); cleanedUp++; aBaseMetaTileEntity.getWorld().setBlockToAir(posiX, posiY, posiZ); new BlockBreakParticles(aBaseMetaTileEntity.getWorld(), posiX, posiY, posiZ, Blocks.dirt); } else { // Utils.LOG_WARNING("2:"+testBlock.getUnlocalizedName()); } } else { // Utils.LOG_WARNING("1"); } } } } Logger.MACHINE_INFO("cleaning up | " + cleanedUp); return true; } public static boolean isValidForGUI(final ItemStack aStack) { return isCorrectMachinePart(aStack) != SAWTOOL.NONE; } public static SAWTOOL isCorrectMachinePart(final ItemStack aStack) { if (aStack != null && aStack.getItem() instanceof GT_MetaGenerated_Tool_01) { switch (aStack.getItemDamage()) { case GT_MetaGenerated_Tool_01.SAW: return SAWTOOL.SAW; case GT_MetaGenerated_Tool_01.BUZZSAW_LV: case GT_MetaGenerated_Tool_01.BUZZSAW_MV: case GT_MetaGenerated_Tool_01.BUZZSAW_HV: return SAWTOOL.BUZZSAW; case GT_MetaGenerated_Tool_01.CHAINSAW_LV: case GT_MetaGenerated_Tool_01.CHAINSAW_MV: case GT_MetaGenerated_Tool_01.CHAINSAW_HV: return SAWTOOL.CHAINSAW; } } return SAWTOOL.NONE; } public static ToolType getPartType(final ItemStack aStack) { if (aStack != null) { // Utils.LOG_WARNING("Found "+aStack.getDisplayName()+" in the GUI slot."); if (aStack.getItem() == MetaGeneratedGregtechItems.INSTANCE) { int aDmg = aStack.getItemDamage(); if (aDmg >= 32120 && aDmg <= 32128) { return ToolType.Unbreakable; } Logger.INFO("bad Tool in Slot 2 | " + aStack.getUnlocalizedName().toLowerCase() + " | " + aDmg); return null; } if (aStack.getItem() instanceof GT_MetaGenerated_Tool) { if (Arrays.stream(OreDictionary.getOreIDs(aStack)).anyMatch(i -> i == sawOreId)) return ToolType.Breakable; } } Logger.INFO("bad Tool in Slot 4"); return null; } public static boolean isHumusLoaded = false; public static boolean isForestryLogsLoaded = false; public static boolean isForestryFenceLoaded = false; public static boolean isForestrySaplingsLoaded = false; public static boolean isForestryLeavesLoaded = false; public static Block blockHumus; public static boolean isForestryValid() { if (!Forestry.isModLoaded()) { return false; } if (ReflectionUtils.doesClassExist("forestry.core.blocks.BlockSoil")) { isHumusLoaded = true; } if (ReflectionUtils.doesClassExist("forestry.arboriculture.blocks.BlockLog")) { isForestryLogsLoaded = true; } if (ReflectionUtils.doesClassExist("forestry.arboriculture.blocks.BlockArbFence")) { isForestryFenceLoaded = true; } if (ReflectionUtils.doesClassExist("forestry.arboriculture.blocks.BlockSapling")) { isForestrySaplingsLoaded = true; } if (ReflectionUtils.doesClassExist("forestry.arboriculture.blocks.BlockForestryLeaves")) { isForestryLeavesLoaded = true; } return true; } @Optional.Method(modid = Mods.Names.FORESTRY) public static Block getHumus() { if (blockHumus != null) { return blockHumus; } else if (isHumusLoaded) { final Class humusClass = ReflectionUtils.getClass("forestry.core.blocks.BlockSoil"); final ItemStack humusStack = ItemUtils.getCorrectStacktype("Forestry:soil", 1); if (humusClass != null) { blockHumus = Block.getBlockFromItem(humusStack.getItem()); return Block.getBlockFromItem(humusStack.getItem()); } } return null; } public static boolean isWoodLog(final Block log) { final String tTool = log.getHarvestTool(0); if ((log == Blocks.log) || (log == Blocks.log2)) { return true; } // Forestry/General Compat if (log.getClass().getName().toLowerCase().contains("blocklog")) { return true; } // IC2 Rubber Tree Compat if (log.getClass().getName().toLowerCase().contains("rubwood") || log.getClass().getName().toLowerCase().contains("rubleaves")) { return true; } return (OrePrefixes.log.contains(new ItemStack(log, 1)) && ((tTool != null) && (tTool.equals("axe")))) || (log.getMaterial() != Material.wood) ? false : (OrePrefixes.fence.contains(new ItemStack(log, 1)) ? false : true); } public static boolean isLeaves(final Block log) { if (log.getUnlocalizedName().toLowerCase().contains("leaf")) { return true; } if (log.getUnlocalizedName().toLowerCase().contains("leaves")) { return true; } if (log.getLocalizedName().toLowerCase().contains("leaf")) { return true; } if (log.getLocalizedName().toLowerCase().contains("leaves")) { return true; } return OrePrefixes.leaves.contains(new ItemStack(log, 1)) || log.getMaterial() == Material.leaves || OrePrefixes.treeLeaves.contains(new ItemStack(log, 1)) || log.getMaterial() == Material.vine || OrePrefixes.mushroom.contains(new ItemStack(log, 1)) || log.getMaterial() == Material.cactus; } public static boolean isSapling(final Block log) { if (log != null) { if (OrePrefixes.sapling.contains(new ItemStack(log, 1))) { // Logger.WARNING(""+log.getLocalizedName()); } if (log.getLocalizedName().toLowerCase().contains("sapling")) { // Logger.WARNING(""+log.getLocalizedName()); return true; } } return OrePrefixes.sapling.contains(new ItemStack(log, 1)); } public static boolean isDirtBlock(final Block dirt) { return (dirt == Blocks.dirt ? true : (dirt == Blocks.grass ? true : (getHumus() == null ? false : (dirt == blockHumus ? true : false)))); } public static boolean isFenceBlock(final Block fence) { return (fence == Blocks.fence ? true : (fence == Blocks.fence_gate ? true : (fence == Blocks.nether_brick_fence ? true : (OrePrefixes.fence.contains(new ItemStack(fence, 1)) ? true : false)))); } public static boolean isAirBlock(final Block air) { if (air.getLocalizedName().toLowerCase().contains("air")) { return true; } if (air.getClass().getName().toLowerCase().contains("residual") || air.getClass().getName().toLowerCase().contains("heat")) { return true; } return (air == Blocks.air ? true : (air instanceof BlockAir ? true : false)); } /* * public static boolean isSaplingBlock(Block sapling){ return (sapling == Blocks.sapling ? true : (sapling == * Blocks.)) } */ public static BlockPos checkForLogsInGrowArea(final IGregTechTileEntity aBaseMetaTileEntity) { final int xDir = net.minecraftforge.common.util.ForgeDirection .getOrientation(aBaseMetaTileEntity.getBackFacing()).offsetX * 7; final int zDir = net.minecraftforge.common.util.ForgeDirection .getOrientation(aBaseMetaTileEntity.getBackFacing()).offsetZ * 7; for (int i = -7; i <= 7; i++) { for (int j = -7; j <= 7; j++) { for (int h = 0; h <= 1; h++) { // Farm Floor inner 14x14 if (((i != -7) && (i != 7)) && ((j != -7) && (j != 7))) { if (h == 1) { if (TreeFarmHelper.isWoodLog(aBaseMetaTileEntity.getBlockOffset(xDir + i, h, zDir + j))) { Logger.INFO("Found a Log"); return new BlockPos( aBaseMetaTileEntity.getXCoord() + xDir + i, aBaseMetaTileEntity.getYCoord() + h, aBaseMetaTileEntity.getZCoord() + zDir + j, aBaseMetaTileEntity.getWorld()); } } } } } } return null; } public static ItemStack[] findTreeFromBase(World world, BlockPos h) { int HARD_LIMIT = 10000; int mCount = 0; Logger.INFO("Finding Rest of Tree."); BlockPos mFirstSpot = h; Set mSearchedSpaces = new HashSet(); Set mTreeSet = getConnectedBlocks(world, mFirstSpot, mSearchedSpaces); Set> mTreeSet2 = new HashSet>(); Set mFinalTree = new HashSet(); Iterator it = mTreeSet.iterator(); Logger.INFO("Running first iteration."); while (it.hasNext()) { BlockPos G = it.next(); mSearchedSpaces.add(G); mTreeSet2.add(getConnectedBlocks(world, G, mSearchedSpaces)); mCount++; Logger.INFO("First Search: " + G.getLocationString()); if (mCount > HARD_LIMIT) { break; } } mCount = 0; Iterator> it2 = mTreeSet2.iterator(); Iterator it3; Logger.INFO("Running second iteration."); while (it2.hasNext()) { Set G = it2.next(); it3 = G.iterator(); while (it3.hasNext()) { BlockPos G2 = it3.next(); mSearchedSpaces.add(G2); mFinalTree.add(G2); mCount++; Logger.INFO("Second Search: " + G2.getLocationString()); if (mCount > HARD_LIMIT) { break; } } if (mCount > HARD_LIMIT) { break; } } if (mFinalTree.size() > 0) { Logger.INFO("Queuing " + mFinalTree.size() + " to Harvest Manager."); TreeCutter harvestManager = new TreeCutter(world); Iterator ith = mFinalTree.iterator(); while (ith.hasNext()) { BlockPos G = ith.next(); harvestManager.queue(G); mCount++; Logger.INFO("Queued: " + G.getLocationString()); if (mCount > HARD_LIMIT) { break; } } if (harvestManager.isValid) { ItemStack[] loot = harvestManager.getDrops(); if (loot.length > 0) { // Logger.INFO("Returning Drops from harvestManager Queue."); return loot; } } } return new ItemStack[] {}; } public static Set getConnectedBlocks(World W, BlockPos P, Set checkedSpaces) { int HARD_LIMIT = 1000; int mCount = 0; Logger.INFO("Finding blocks connected to " + P.getLocationString() + "."); Set mCheckedSpaces = checkedSpaces; Set mStartSearch = searchSixFaces(W, P, mCheckedSpaces, false); Set mSecondSearch = new HashSet(); Set mThirdSearch = new HashSet(); Iterator it = mStartSearch.iterator(); while (it.hasNext()) { Logger.INFO("Running first iteration. [II]"); BlockPos G = it.next(); mCheckedSpaces.add(G); Set mBranchSearch = searchSixFaces(W, G, mCheckedSpaces, true); Iterator it2 = mBranchSearch.iterator(); while (it2.hasNext()) { Logger.INFO("Running second iteration. [II]"); BlockPos G2 = it2.next(); mCheckedSpaces.add(G2); mSecondSearch.add(G2); mCount++; if (mCount > HARD_LIMIT) { break; } } if (mCount > HARD_LIMIT) { break; } } mCount = 0; Iterator itx = mSecondSearch.iterator(); while (itx.hasNext()) { BlockPos G = itx.next(); mCheckedSpaces.add(G); Set mBranchSearch = searchSixFaces(W, G, mCheckedSpaces, true); Iterator it2 = mBranchSearch.iterator(); while (it2.hasNext()) { BlockPos G2 = it2.next(); mCheckedSpaces.add(G2); mThirdSearch.add(G2); mCount++; if (mCount > HARD_LIMIT) { break; } } if (mCount > HARD_LIMIT) { break; } } return mThirdSearch; } public static Set searchSixFaces(World W, BlockPos P, Set checkedSpaces, boolean checkLeaves) { Set mConnected = new HashSet(); int x = P.xPos; int y = P.yPos; int z = P.zPos; if (checkLeaves) { if (isWoodLog(W.getBlock(x - 1, y, z)) || isLeaves(W.getBlock(x - 1, y, z))) { BlockPos L = new BlockPos(x - 1, y, z, W); if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); } } if (isWoodLog(W.getBlock(x + 1, y, z)) || isLeaves(W.getBlock(x + 1, y, z))) { BlockPos L = new BlockPos(x + 1, y, z, W); if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); } } if (isWoodLog(W.getBlock(x, y - 1, z)) || isLeaves(W.getBlock(x, y - 1, z))) { BlockPos L = new BlockPos(x, y - 1, z, W); if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); } } if (isWoodLog(W.getBlock(x, y + 1, z)) || isLeaves(W.getBlock(x, y + 1, z))) { BlockPos L = new BlockPos(x, y + 1, z, W); if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); } } if (isWoodLog(W.getBlock(x, y, z - 1)) || isLeaves(W.getBlock(x, y, z - 1))) { BlockPos L = new BlockPos(x, y, z - 1, W); if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); } } if (isWoodLog(W.getBlock(x, y, z + 1)) || isLeaves(W.getBlock(x, y, z + 1))) { BlockPos L = new BlockPos(x, y, z + 1, W); if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); } } } else { if (isWoodLog(W.getBlock(x - 1, y, z))) { BlockPos L = new BlockPos(x - 1, y, z, W); // if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); // } } if (isWoodLog(W.getBlock(x + 1, y, z))) { BlockPos L = new BlockPos(x + 1, y, z, W); // if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); // } } if (isWoodLog(W.getBlock(x, y - 1, z))) { BlockPos L = new BlockPos(x, y - 1, z, W); // if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); // } } if (isWoodLog(W.getBlock(x, y + 1, z))) { BlockPos L = new BlockPos(x, y + 1, z, W); // if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); // } } if (isWoodLog(W.getBlock(x, y, z - 1))) { BlockPos L = new BlockPos(x, y, z - 1, W); // if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); // } } if (isWoodLog(W.getBlock(x, y, z + 1))) { BlockPos L = new BlockPos(x, y, z + 1, W); // if (!checkedSpaces.contains(L)) { mConnected.add(L); Logger.INFO("Found Connected. [III]"); // } } } return mConnected; } public enum ToolType { Unbreakable, Breakable } /** * Tree Cutting */ public static class TreeCutter { private final World mWorld; private Map mQueue = new ConcurrentHashMap(); private AutoMap mDrops = new AutoMap(); private boolean isValid = true; public TreeCutter(World world) { this.mWorld = world; } public boolean queue(BlockPos pos) { if (isValid && pos != null) { // Logger.INFO("Queued: "+pos.getLocationString()); String hash = Utils.calculateChecksumMD5(pos); if (hash != null && !mQueue.containsKey(hash)) { mQueue.put(hash, pos); return true; } } return false; } private boolean emptyQueue() { if (isValid) { Logger.INFO("Emptying Queue."); if (this.mQueue.size() > 0) { int totalRemoved = 0; for (BlockPos h : mQueue.values()) { final Block block = mWorld.getBlock(h.xPos, h.yPos, h.zPos); if (block != null) { final int dropMeta = mWorld.getBlockMetadata(h.xPos, h.yPos, h.zPos); final ArrayList blockDrops = block .getDrops(mWorld, h.xPos, h.yPos, h.zPos, dropMeta, 0); final ItemStack[] drops = ItemUtils.getBlockDrops(blockDrops); mDrops.put(drops); // Remove drop that was added to the bus. mWorld.setBlockToAir(h.xPos, h.yPos, h.zPos); // new BlockBreakParticles(mWorld, h.xPos, h.yPos, h.zPos, block); totalRemoved++; } } if (totalRemoved > 0 && mDrops.size() > 0) { return true; } } } return false; } public ItemStack[] getDrops() { // If Queue is successfully cleared and drops are created, let us continue. if (isValid && emptyQueue()) { AutoMap mCollective = new AutoMap(); // Iterate ALL of the arrays, add output to a collective. for (ItemStack[] i : this.mDrops) { // Array is not null. if (i != null) { // Iterate this array. for (int d = 0; d < i.length; d++) { // Put Output into collective if valid if (i[d] != null && i[d].stackSize > 0) { mCollective.put(i[d]); } } } } // Build an ItemStack array. ItemStack[] drops = new ItemStack[mCollective.size()]; for (int m = 0; m < drops.length; m++) { drops[m] = mCollective.get(m); } // Return drops array if it's valid. if (drops.length > 0) { isValid = false; return drops; } } // Invalid or no drops, return empty array. isValid = false; return new ItemStack[] {}; } } /** * Farm AI */ private static EntityPlayerMP farmerAI; public EntityPlayerMP getFakePlayer(World world) { return farmerAI = checkFakePlayer(world); } public static EntityPlayerMP checkFakePlayer(World world) { if (farmerAI == null) { return new FakeFarmer(MinecraftServer.getServer().worldServerForDimension(world.provider.dimensionId)); } return farmerAI; } public static boolean onBlockStartBreak(int x, int y, int z, World world) { final Block wood = world.getBlock(x, y, z); if (wood == null) { return false; } if (wood.isWood(world, x, y, z) || wood.getMaterial() == Material.sponge) if (detectTree(world, x, y, z)) { TreeChopTask chopper = new TreeChopTask(new ChunkPosition(x, y, z), checkFakePlayer(world), 128); FMLCommonHandler.instance().bus().register(chopper); // custom block breaking code, don't call vanilla code return true; } // return onBlockStartBreak(stack, x, y, z, player); return false; } public static boolean detectTree(World world, int pX, int pY, int pZ) { ChunkPosition pos = null; Stack candidates = new Stack<>(); candidates.add(new ChunkPosition(pX, pY, pZ)); while (!candidates.isEmpty()) { ChunkPosition candidate = candidates.pop(); int curX = candidate.chunkPosX, curY = candidate.chunkPosY, curZ = candidate.chunkPosZ; Block block = world.getBlock(curX, curY, curZ); if ((pos == null || candidate.chunkPosY > pos.chunkPosY) && block.isWood(world, curX, curY, curZ)) { pos = new ChunkPosition(curX, candidate.chunkPosY + 1, curZ); // go up while (world.getBlock(curX, pos.chunkPosY, curZ).isWood(world, curX, pos.chunkPosY, curZ)) { pos = new ChunkPosition(curX, pos.chunkPosY + 1, curZ); } // check if we still have a way diagonally up candidates.add(new ChunkPosition(curX + 1, pos.chunkPosY + 1, curZ)); candidates.add(new ChunkPosition(curX, pos.chunkPosY + 1, curZ + 1)); candidates.add(new ChunkPosition(curX - 1, pos.chunkPosY + 1, curZ)); candidates.add(new ChunkPosition(curX, pos.chunkPosY + 1, curZ - 1)); } } // not even one match, so there were no logs. if (pos == null) { return false; } // check if there were enough leaves around the last position // pos now contains the block above the topmost log // we want at least 5 leaves in the surrounding 26 blocks int d = 3; int leaves = 0; for (int offX = 0; offX < d; offX++) { for (int offY = 0; offY < d; offY++) { for (int offZ = 0; offZ < d; offZ++) { int xPos = pos.chunkPosX - 1 + offX, yPos = pos.chunkPosY - 1 + offY, zPos = pos.chunkPosZ - 1 + offZ; Block leaf = world.getBlock(xPos, yPos, zPos); if (leaf != null && leaf.isLeaves(world, xPos, yPos, zPos)) { if (++leaves >= 5) { return true; } } } } } // not enough leaves. sorreh return false; } public static class TreeChopTask { public final World world; public final EntityPlayer player; public final int blocksPerTick; public Queue blocks = Lists.newLinkedList(); public Set visited = new THashSet<>(); public TreeChopTask(ChunkPosition start, EntityPlayer player, int blocksPerTick) { this.world = player.getEntityWorld(); this.player = player; this.blocksPerTick = blocksPerTick; this.blocks.add(start); } private void queueCoordinate(int x, int y, int z) { ChunkPosition pos = new ChunkPosition(x, y, z); if (!visited.contains(pos)) { blocks.add(pos); } } @SubscribeEvent public void onWorldTick(TickEvent.WorldTickEvent event) { if (event.side.isClient()) { finish(); return; } // only if same dimension if (event.world.provider.dimensionId != world.provider.dimensionId) { return; } // setup int left = blocksPerTick; // NBTTagCompound tags = stack.getTagCompound().getCompoundTag("InfiTool"); // continue running ChunkPosition pos; while (left > 0) { // completely done or can't do our job anymore?! if (blocks.isEmpty() /* || tags.getBoolean("Broken") */) { finish(); return; } pos = blocks.remove(); if (!visited.add(pos)) { continue; } int x = pos.chunkPosX, y = pos.chunkPosY, z = pos.chunkPosZ; Block block = world.getBlock(x, y, z); int meta = world.getBlockMetadata(x, y, z); // can we harvest the block and is effective? if (!block.isWood(world, x, y, z) || !isWoodLog(block)) { continue; } // save its neighbors queueCoordinate(x + 1, y, z); queueCoordinate(x, y, z + 1); queueCoordinate(x - 1, y, z); queueCoordinate(x, y, z - 1); // also add the layer above.. stupid acacia trees for (int offX = 0; offX < 3; offX++) { for (int offZ = 0; offZ < 3; offZ++) { queueCoordinate(x - 1 + offX, y + 1, z - 1 + offZ); } } // break it, wooo! breakExtraBlock(player.worldObj, x, y, z, 0, player, x, y, z); left--; } } private void finish() { // goodbye cruel world FMLCommonHandler.instance().bus().unregister(this); } } public static void breakExtraBlock(World world, int x, int y, int z, int sidehit, EntityPlayer playerEntity, int refX, int refY, int refZ) { // prevent calling that stuff for air blocks, could lead to unexpected behaviour since it fires events if (world.isAirBlock(x, y, z)) return; // what? if (!(playerEntity instanceof EntityPlayerMP)) return; EntityPlayerMP player = (EntityPlayerMP) playerEntity; // check if the block can be broken, since extra block breaks shouldn't instantly break stuff like obsidian // or precious ores you can't harvest while mining stone Block block = world.getBlock(x, y, z); int meta = world.getBlockMetadata(x, y, z); // only effective materials if (!isWoodLog(block)) return; Block refBlock = world.getBlock(refX, refY, refZ); float refStrength = ForgeHooks.blockStrength(refBlock, player, world, refX, refY, refZ); float strength = ForgeHooks.blockStrength(block, player, world, x, y, z); // only harvestable blocks that aren't impossibly slow to harvest if (!ForgeHooks.canHarvestBlock(block, player, meta) || refStrength / strength > 10f) return; // send the blockbreak event BlockEvent.BreakEvent event = ForgeHooks .onBlockBreakEvent(world, player.theItemInWorldManager.getGameType(), player, x, y, z); if (event.isCanceled()) return; if (player.capabilities.isCreativeMode) { block.onBlockHarvested(world, x, y, z, meta, player); if (block.removedByPlayer(world, player, x, y, z, false)) block.onBlockDestroyedByPlayer(world, x, y, z, meta); // send update to client if (!world.isRemote) { player.playerNetServerHandler.sendPacket(new S23PacketBlockChange(x, y, z, world)); } return; } // callback to the tool the player uses. Called on both sides. This damages the tool n stuff. player.getCurrentEquippedItem().func_150999_a(world, block, x, y, z, player); // server sided handling if (!world.isRemote) { // serverside we reproduce ItemInWorldManager.tryHarvestBlock // ItemInWorldManager.removeBlock block.onBlockHarvested(world, x, y, z, meta, player); if (block.removedByPlayer(world, player, x, y, z, true)) // boolean is if block can be harvested, checked // above { block.onBlockDestroyedByPlayer(world, x, y, z, meta); block.harvestBlock(world, player, x, y, z, meta); block.dropXpOnBlockBreak(world, x, y, z, event.getExpToDrop()); } // always send block update to client player.playerNetServerHandler.sendPacket(new S23PacketBlockChange(x, y, z, world)); } // client sided handling else { // PlayerControllerMP pcmp = Minecraft.getMinecraft().playerController; // clientside we do a "this clock has been clicked on long enough to be broken" call. This should not send // any new packets // the code above, executed on the server, sends a block-updates that give us the correct state of the block // we destroy. // following code can be found in PlayerControllerMP.onPlayerDestroyBlock world.playAuxSFX(2001, x, y, z, Block.getIdFromBlock(block) + (meta << 12)); if (block.removedByPlayer(world, player, x, y, z, true)) { block.onBlockDestroyedByPlayer(world, x, y, z, meta); } // callback to the tool ItemStack itemstack = player.getCurrentEquippedItem(); if (itemstack != null) { itemstack.func_150999_a(world, block, x, y, z, player); if (itemstack.stackSize == 0) { player.destroyCurrentEquippedItem(); } } // send an update to the server, so we get an update back // if(PHConstruct.extraBlockUpdates) // Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C07PacketPlayerDigging(2, x,y,z, // Minecraft.getMinecraft().objectMouseOver.sideHit)); } } }