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