package gtPlusPlus.xmod.gregtech.common.helpers; import static gtPlusPlus.core.lib.CORE.ConfigSwitches.enableTreeFarmerParticles; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import com.google.common.collect.Lists; import gnu.trove.set.hash.THashSet; 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 gregtech.api.enums.*; 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 gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.items.GT_MetaGenerated_Tool; import gregtech.common.items.GT_MetaGenerated_Item_02; 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.lib.LoadedMods; 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; 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; 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){ //Utils.LOG_WARNING("Found "+aStack.getDisplayName()+" in the GUI slot."); if ((aStack.getItem() instanceof GT_MetaGenerated_Item_02) || (aStack.getItem() instanceof GT_MetaGenerated_Tool)){ if (OrePrefixes.craftingTool.contains(aStack)){ if (aStack.getDisplayName().toLowerCase().contains("saw") || aStack.getDisplayName().toLowerCase().contains("gt.metatool.01")){ if (aStack.getItemDamage() == 10){ return SAWTOOL.SAW; } else if (aStack.getItemDamage() == 140 || aStack.getDisplayName().toLowerCase().contains("gt.metatool.01.140")){ return SAWTOOL.BUZZSAW; } else if (aStack.getItemDamage() == 110 || aStack.getDisplayName().toLowerCase().contains("gt.metatool.01.110")){ return SAWTOOL.CHAINSAW; } else if (aStack.getItemDamage() == 112 || aStack.getDisplayName().toLowerCase().contains("gt.metatool.01.112")){ return SAWTOOL.CHAINSAW; } else if (aStack.getItemDamage() == 114 || aStack.getDisplayName().toLowerCase().contains("gt.metatool.01.114")){ return SAWTOOL.CHAINSAW; } else { return SAWTOOL.NONE; } } } } } 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 (!LoadedMods.Forestry){ 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 = "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 0) { mCollective.put(i[d]); } } } } //Build an ItemStack array. ItemStack[] drops = new ItemStack[mCollective.size()]; for (int m=0;m 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)); } } }