aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java')
-rw-r--r--src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java1033
1 files changed, 1033 insertions, 0 deletions
diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java
new file mode 100644
index 0000000000..2ff2712952
--- /dev/null
+++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java
@@ -0,0 +1,1033 @@
+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 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<BlockPos> mSearchedSpaces = new HashSet<BlockPos>();
+ Set<BlockPos> mTreeSet = getConnectedBlocks(world, mFirstSpot, mSearchedSpaces);
+ Set<Set<BlockPos>> mTreeSet2 = new HashSet<Set<BlockPos>>();
+ Set<BlockPos> mFinalTree = new HashSet<BlockPos>();
+ Iterator<BlockPos> 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<Set<BlockPos>> it2 = mTreeSet2.iterator();
+ Iterator<BlockPos> it3;
+ Logger.INFO("Running second iteration.");
+ while(it2.hasNext()){
+ Set<BlockPos> 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<BlockPos> 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<BlockPos> getConnectedBlocks(World W, BlockPos P, Set<BlockPos> checkedSpaces) {
+ int HARD_LIMIT = 1000;
+ int mCount = 0;
+ Logger.INFO("Finding blocks connected to "+P.getLocationString()+".");
+ Set<BlockPos> mCheckedSpaces = checkedSpaces;
+ Set<BlockPos> mStartSearch = searchSixFaces(W, P, mCheckedSpaces, false);
+ Set<BlockPos> mSecondSearch = new HashSet<BlockPos>();
+ Set<BlockPos> mThirdSearch = new HashSet<BlockPos>();
+ Iterator<BlockPos> it = mStartSearch.iterator();
+ while(it.hasNext()){
+ Logger.INFO("Running first iteration. [II]");
+ BlockPos G = it.next();
+ mCheckedSpaces.add(G);
+ Set<BlockPos> mBranchSearch = searchSixFaces(W, G, mCheckedSpaces, true);
+ Iterator<BlockPos> 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<BlockPos> itx = mSecondSearch.iterator();
+ while(itx.hasNext()){
+ BlockPos G = itx.next();
+ mCheckedSpaces.add(G);
+ Set<BlockPos> mBranchSearch = searchSixFaces(W, G, mCheckedSpaces, true);
+ Iterator<BlockPos> 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<BlockPos> searchSixFaces(World W, BlockPos P, Set<BlockPos> checkedSpaces, boolean checkLeaves) {
+ Set<BlockPos> mConnected = new HashSet<BlockPos>();
+ 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<String, BlockPos> mQueue = new ConcurrentHashMap<String, BlockPos>();
+ private AutoMap<ItemStack[]> mDrops = new AutoMap<ItemStack[]>();
+ 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<ItemStack> 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<ItemStack> mCollective = new AutoMap<ItemStack>();
+ //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<ChunkPosition> 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<ChunkPosition> blocks = Lists.newLinkedList();
+ public Set<ChunkPosition> 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));
+ }
+ }
+
+}