    001    package net.minecraft.world.gen.feature;
    002
    003    import java.util.Random;
    004    import net.minecraft.block.Block;
    005    import net.minecraft.util.MathHelper;
    006    import net.minecraft.world.World;
    007
    008    public class WorldGenBigTree extends WorldGenerator
    009    {
    010        /**
    011         * Contains three sets of two values that provide complimentary indices for a given 'major' index - 1 and 2 for 0, 0
    012         * and 2 for 1, and 0 and 1 for 2.
    013         */
    014        static final byte[] otherCoordPairs = new byte[] {(byte)2, (byte)0, (byte)0, (byte)1, (byte)2, (byte)1};
    015
    016        /** random seed for GenBigTree */
    017        Random rand = new Random();
    018
    019        /** Reference to the World object. */
    020        World worldObj;
    021        int[] basePos = new int[] {0, 0, 0};
    022        int heightLimit = 0;
    023        int height;
    024        double heightAttenuation = 0.618D;
    025        double branchDensity = 1.0D;
    026        double branchSlope = 0.381D;
    027        double scaleWidth = 1.0D;
    028        double leafDensity = 1.0D;
    029
    030        /**
    031         * Currently always 1, can be set to 2 in the class constructor to generate a double-sized tree trunk for big trees.
    032         */
    033        int trunkSize = 1;
    034
    035        /**
    036         * Sets the limit of the random value used to initialize the height limit.
    037         */
    038        int heightLimitLimit = 12;
    039
    040        /**
    041         * Sets the distance limit for how far away the generator will populate leaves from the base leaf node.
    042         */
    043        int leafDistanceLimit = 4;
    044
    045        /** Contains a list of a points at which to generate groups of leaves. */
    046        int[][] leafNodes;
    047
    048        public WorldGenBigTree(boolean par1)
    049        {
    050            super(par1);
    051        }
    052
    053        /**
    054         * Generates a list of leaf nodes for the tree, to be populated by generateLeaves.
    055         */
    056        void generateLeafNodeList()
    057        {
    058            this.height = (int)((double)this.heightLimit * this.heightAttenuation);
    059
    060            if (this.height >= this.heightLimit)
    061            {
    062                this.height = this.heightLimit - 1;
    063            }
    064
    065            int var1 = (int)(1.382D + Math.pow(this.leafDensity * (double)this.heightLimit / 13.0D, 2.0D));
    066
    067            if (var1 < 1)
    068            {
    069                var1 = 1;
    070            }
    071
    072            int[][] var2 = new int[var1 * this.heightLimit][4];
    073            int var3 = this.basePos[1] + this.heightLimit - this.leafDistanceLimit;
    074            int var4 = 1;
    075            int var5 = this.basePos[1] + this.height;
    076            int var6 = var3 - this.basePos[1];
    077            var2[0][0] = this.basePos[0];
    078            var2[0][1] = var3;
    079            var2[0][2] = this.basePos[2];
    080            var2[0][3] = var5;
    081            --var3;
    082
    083            while (var6 >= 0)
    084            {
    085                int var7 = 0;
    086                float var8 = this.layerSize(var6);
    087
    088                if (var8 < 0.0F)
    089                {
    090                    --var3;
    091                    --var6;
    092                }
    093                else
    094                {
    095                    for (double var9 = 0.5D; var7 < var1; ++var7)
    096                    {
    097                        double var11 = this.scaleWidth * (double)var8 * ((double)this.rand.nextFloat() + 0.328D);
    098                        double var13 = (double)this.rand.nextFloat() * 2.0D * Math.PI;
    099                        int var15 = MathHelper.floor_double(var11 * Math.sin(var13) + (double)this.basePos[0] + var9);
    100                        int var16 = MathHelper.floor_double(var11 * Math.cos(var13) + (double)this.basePos[2] + var9);
    101                        int[] var17 = new int[] {var15, var3, var16};
    102                        int[] var18 = new int[] {var15, var3 + this.leafDistanceLimit, var16};
    103
    104                        if (this.checkBlockLine(var17, var18) == -1)
    105                        {
    106                            int[] var19 = new int[] {this.basePos[0], this.basePos[1], this.basePos[2]};
    107                            double var20 = Math.sqrt(Math.pow((double)Math.abs(this.basePos[0] - var17[0]), 2.0D) + Math.pow((double)Math.abs(this.basePos[2] - var17[2]), 2.0D));
    108                            double var22 = var20 * this.branchSlope;
    109
    110                            if ((double)var17[1] - var22 > (double)var5)
    111                            {
    112                                var19[1] = var5;
    113                            }
    114                            else
    115                            {
    116                                var19[1] = (int)((double)var17[1] - var22);
    117                            }
    118
    119                            if (this.checkBlockLine(var19, var17) == -1)
    120                            {
    121                                var2[var4][0] = var15;
    122                                var2[var4][1] = var3;
    123                                var2[var4][2] = var16;
    124                                var2[var4][3] = var19[1];
    125                                ++var4;
    126                            }
    127                        }
    128                    }
    129
    130                    --var3;
    131                    --var6;
    132                }
    133            }
    134
    135            this.leafNodes = new int[var4][4];
    136            System.arraycopy(var2, 0, this.leafNodes, 0, var4);
    137        }
    138
    139        void genTreeLayer(int par1, int par2, int par3, float par4, byte par5, int par6)
    140        {
    141            int var7 = (int)((double)par4 + 0.618D);
    142            byte var8 = otherCoordPairs[par5];
    143            byte var9 = otherCoordPairs[par5 + 3];
    144            int[] var10 = new int[] {par1, par2, par3};
    145            int[] var11 = new int[] {0, 0, 0};
    146            int var12 = -var7;
    147            int var13 = -var7;
    148
    149            for (var11[par5] = var10[par5]; var12 <= var7; ++var12)
    150            {
    151                var11[var8] = var10[var8] + var12;
    152                var13 = -var7;
    153
    154                while (var13 <= var7)
    155                {
    156                    double var15 = Math.pow((double)Math.abs(var12) + 0.5D, 2.0D) + Math.pow((double)Math.abs(var13) + 0.5D, 2.0D);
    157
    158                    if (var15 > (double)(par4 * par4))
    159                    {
    160                        ++var13;
    161                    }
    162                    else
    163                    {
    164                        var11[var9] = var10[var9] + var13;
    165                        int var14 = this.worldObj.getBlockId(var11[0], var11[1], var11[2]);
    166
    167                        if (var14 != 0 && var14 != Block.leaves.blockID)
    168                        {
    169                            ++var13;
    170                        }
    171                        else
    172                        {
    173                            this.setBlockAndMetadata(this.worldObj, var11[0], var11[1], var11[2], par6, 0);
    174                            ++var13;
    175                        }
    176                    }
    177                }
    178            }
    179        }
    180
    181        /**
    182         * Gets the rough size of a layer of the tree.
    183         */
    184        float layerSize(int par1)
    185        {
    186            if ((double)par1 < (double)((float)this.heightLimit) * 0.3D)
    187            {
    188                return -1.618F;
    189            }
    190            else
    191            {
    192                float var2 = (float)this.heightLimit / 2.0F;
    193                float var3 = (float)this.heightLimit / 2.0F - (float)par1;
    194                float var4;
    195
    196                if (var3 == 0.0F)
    197                {
    198                    var4 = var2;
    199                }
    200                else if (Math.abs(var3) >= var2)
    201                {
    202                    var4 = 0.0F;
    203                }
    204                else
    205                {
    206                    var4 = (float)Math.sqrt(Math.pow((double)Math.abs(var2), 2.0D) - Math.pow((double)Math.abs(var3), 2.0D));
    207                }
    208
    209                var4 *= 0.5F;
    210                return var4;
    211            }
    212        }
    213
    214        float leafSize(int par1)
    215        {
    216            return par1 >= 0 && par1 < this.leafDistanceLimit ? (par1 != 0 && par1 != this.leafDistanceLimit - 1 ? 3.0F : 2.0F) : -1.0F;
    217        }
    218
    219        /**
    220         * Generates the leaves surrounding an individual entry in the leafNodes list.
    221         */
    222        void generateLeafNode(int par1, int par2, int par3)
    223        {
    224            int var4 = par2;
    225
    226            for (int var5 = par2 + this.leafDistanceLimit; var4 < var5; ++var4)
    227            {
    228                float var6 = this.leafSize(var4 - par2);
    229                this.genTreeLayer(par1, var4, par3, var6, (byte)1, Block.leaves.blockID);
    230            }
    231        }
    232
    233        /**
    234         * Places a line of the specified block ID into the world from the first coordinate triplet to the second.
    235         */
    236        void placeBlockLine(int[] par1ArrayOfInteger, int[] par2ArrayOfInteger, int par3)
    237        {
    238            int[] var4 = new int[] {0, 0, 0};
    239            byte var5 = 0;
    240            byte var6;
    241
    242            for (var6 = 0; var5 < 3; ++var5)
    243            {
    244                var4[var5] = par2ArrayOfInteger[var5] - par1ArrayOfInteger[var5];
    245
    246                if (Math.abs(var4[var5]) > Math.abs(var4[var6]))
    247                {
    248                    var6 = var5;
    249                }
    250            }
    251
    252            if (var4[var6] != 0)
    253            {
    254                byte var7 = otherCoordPairs[var6];
    255                byte var8 = otherCoordPairs[var6 + 3];
    256                byte var9;
    257
    258                if (var4[var6] > 0)
    259                {
    260                    var9 = 1;
    261                }
    262                else
    263                {
    264                    var9 = -1;
    265                }
    266
    267                double var10 = (double)var4[var7] / (double)var4[var6];
    268                double var12 = (double)var4[var8] / (double)var4[var6];
    269                int[] var14 = new int[] {0, 0, 0};
    270                int var15 = 0;
    271
    272                for (int var16 = var4[var6] + var9; var15 != var16; var15 += var9)
    273                {
    274                    var14[var6] = MathHelper.floor_double((double)(par1ArrayOfInteger[var6] + var15) + 0.5D);
    275                    var14[var7] = MathHelper.floor_double((double)par1ArrayOfInteger[var7] + (double)var15 * var10 + 0.5D);
    276                    var14[var8] = MathHelper.floor_double((double)par1ArrayOfInteger[var8] + (double)var15 * var12 + 0.5D);
    277                    byte var17 = 0;
    278                    int var18 = Math.abs(var14[0] - par1ArrayOfInteger[0]);
    279                    int var19 = Math.abs(var14[2] - par1ArrayOfInteger[2]);
    280                    int var20 = Math.max(var18, var19);
    281
    282                    if (var20 > 0)
    283                    {
    284                        if (var18 == var20)
    285                        {
    286                            var17 = 4;
    287                        }
    288                        else if (var19 == var20)
    289                        {
    290                            var17 = 8;
    291                        }
    292                    }
    293
    294                    this.setBlockAndMetadata(this.worldObj, var14[0], var14[1], var14[2], par3, var17);
    295                }
    296            }
    297        }
    298
    299        /**
    300         * Generates the leaf portion of the tree as specified by the leafNodes list.
    301         */
    302        void generateLeaves()
    303        {
    304            int var1 = 0;
    305
    306            for (int var2 = this.leafNodes.length; var1 < var2; ++var1)
    307            {
    308                int var3 = this.leafNodes[var1][0];
    309                int var4 = this.leafNodes[var1][1];
    310                int var5 = this.leafNodes[var1][2];
    311                this.generateLeafNode(var3, var4, var5);
    312            }
    313        }
    314
    315        /**
    316         * Indicates whether or not a leaf node requires additional wood to be added to preserve integrity.
    317         */
    318        boolean leafNodeNeedsBase(int par1)
    319        {
    320            return (double)par1 >= (double)this.heightLimit * 0.2D;
    321        }
    322
    323        /**
    324         * Places the trunk for the big tree that is being generated. Able to generate double-sized trunks by changing a
    325         * field that is always 1 to 2.
    326         */
    327        void generateTrunk()
    328        {
    329            int var1 = this.basePos[0];
    330            int var2 = this.basePos[1];
    331            int var3 = this.basePos[1] + this.height;
    332            int var4 = this.basePos[2];
    333            int[] var5 = new int[] {var1, var2, var4};
    334            int[] var6 = new int[] {var1, var3, var4};
    335            this.placeBlockLine(var5, var6, Block.wood.blockID);
    336
    337            if (this.trunkSize == 2)
    338            {
    339                ++var5[0];
    340                ++var6[0];
    341                this.placeBlockLine(var5, var6, Block.wood.blockID);
    342                ++var5[2];
    343                ++var6[2];
    344                this.placeBlockLine(var5, var6, Block.wood.blockID);
    345                var5[0] += -1;
    346                var6[0] += -1;
    347                this.placeBlockLine(var5, var6, Block.wood.blockID);
    348            }
    349        }
    350
    351        /**
    352         * Generates additional wood blocks to fill out the bases of different leaf nodes that would otherwise degrade.
    353         */
    354        void generateLeafNodeBases()
    355        {
    356            int var1 = 0;
    357            int var2 = this.leafNodes.length;
    358
    359            for (int[] var3 = new int[] {this.basePos[0], this.basePos[1], this.basePos[2]}; var1 < var2; ++var1)
    360            {
    361                int[] var4 = this.leafNodes[var1];
    362                int[] var5 = new int[] {var4[0], var4[1], var4[2]};
    363                var3[1] = var4[3];
    364                int var6 = var3[1] - this.basePos[1];
    365
    366                if (this.leafNodeNeedsBase(var6))
    367                {
    368                    this.placeBlockLine(var3, var5, (byte)Block.wood.blockID);
    369                }
    370            }
    371        }
    372
    373        /**
    374         * Checks a line of blocks in the world from the first coordinate to triplet to the second, returning the distance
    375         * (in blocks) before a non-air, non-leaf block is encountered and/or the end is encountered.
    376         */
    377        int checkBlockLine(int[] par1ArrayOfInteger, int[] par2ArrayOfInteger)
    378        {
    379            int[] var3 = new int[] {0, 0, 0};
    380            byte var4 = 0;
    381            byte var5;
    382
    383            for (var5 = 0; var4 < 3; ++var4)
    384            {
    385                var3[var4] = par2ArrayOfInteger[var4] - par1ArrayOfInteger[var4];
    386
    387                if (Math.abs(var3[var4]) > Math.abs(var3[var5]))
    388                {
    389                    var5 = var4;
    390                }
    391            }
    392
    393            if (var3[var5] == 0)
    394            {
    395                return -1;
    396            }
    397            else
    398            {
    399                byte var6 = otherCoordPairs[var5];
    400                byte var7 = otherCoordPairs[var5 + 3];
    401                byte var8;
    402
    403                if (var3[var5] > 0)
    404                {
    405                    var8 = 1;
    406                }
    407                else
    408                {
    409                    var8 = -1;
    410                }
    411
    412                double var9 = (double)var3[var6] / (double)var3[var5];
    413                double var11 = (double)var3[var7] / (double)var3[var5];
    414                int[] var13 = new int[] {0, 0, 0};
    415                int var14 = 0;
    416                int var15;
    417
    418                for (var15 = var3[var5] + var8; var14 != var15; var14 += var8)
    419                {
    420                    var13[var5] = par1ArrayOfInteger[var5] + var14;
    421                    var13[var6] = MathHelper.floor_double((double)par1ArrayOfInteger[var6] + (double)var14 * var9);
    422                    var13[var7] = MathHelper.floor_double((double)par1ArrayOfInteger[var7] + (double)var14 * var11);
    423                    int var16 = this.worldObj.getBlockId(var13[0], var13[1], var13[2]);
    424
    425                    if (var16 != 0 && var16 != Block.leaves.blockID)
    426                    {
    427                        break;
    428                    }
    429                }
    430
    431                return var14 == var15 ? -1 : Math.abs(var14);
    432            }
    433        }
    434
    435        /**
    436         * Returns a boolean indicating whether or not the current location for the tree, spanning basePos to to the height
    437         * limit, is valid.
    438         */
    439        boolean validTreeLocation()
    440        {
    441            int[] var1 = new int[] {this.basePos[0], this.basePos[1], this.basePos[2]};
    442            int[] var2 = new int[] {this.basePos[0], this.basePos[1] + this.heightLimit - 1, this.basePos[2]};
    443            int var3 = this.worldObj.getBlockId(this.basePos[0], this.basePos[1] - 1, this.basePos[2]);
    444
    445            if (var3 != 2 && var3 != 3)
    446            {
    447                return false;
    448            }
    449            else
    450            {
    451                int var4 = this.checkBlockLine(var1, var2);
    452
    453                if (var4 == -1)
    454                {
    455                    return true;
    456                }
    457                else if (var4 < 6)
    458                {
    459                    return false;
    460                }
    461                else
    462                {
    463                    this.heightLimit = var4;
    464                    return true;
    465                }
    466            }
    467        }
    468
    469        /**
    470         * Rescales the generator settings, only used in WorldGenBigTree
    471         */
    472        public void setScale(double par1, double par3, double par5)
    473        {
    474            this.heightLimitLimit = (int)(par1 * 12.0D);
    475
    476            if (par1 > 0.5D)
    477            {
    478                this.leafDistanceLimit = 5;
    479            }
    480
    481            this.scaleWidth = par3;
    482            this.leafDensity = par5;
    483        }
    484
    485        public boolean generate(World par1World, Random par2Random, int par3, int par4, int par5)
    486        {
    487            this.worldObj = par1World;
    488            long var6 = par2Random.nextLong();
    489            this.rand.setSeed(var6);
    490            this.basePos[0] = par3;
    491            this.basePos[1] = par4;
    492            this.basePos[2] = par5;
    493
    494            if (this.heightLimit == 0)
    495            {
    496                this.heightLimit = 5 + this.rand.nextInt(this.heightLimitLimit);
    497            }
    498
    499            if (!this.validTreeLocation())
    500            {
    501                return false;
    502            }
    503            else
    504            {
    505                this.generateLeafNodeList();
    506                this.generateLeaves();
    507                this.generateTrunk();
    508                this.generateLeafNodeBases();
    509                return true;
    510            }
    511        }
    512    }