Minecraft的世界生成過程(七)礦物和樹

目前的世界是不是還少了點什麼——沒有樹、礦石怎麼致富!

本篇應該是最後一篇了,研究下樹和礦石之類的點綴的生成

populate函數

上一篇提到的,在provideChunk之後調用

    /**
     * Populates chunk with ores etc etc
     */
    public void populate(IChunkProvider chunkProvider, int chunkX, int chunkZ)
    {
        // 如果生成了可掉落方塊則立即掉落
        BlockFalling.fallInstantly = true;
        int minBlockX = chunkX * 16;
        int minBlockZ = chunkZ * 16;
        BlockPos minBlockPos = new BlockPos(minBlockX, 0, minBlockZ);
        // 4個區塊中心點生物羣系
        BiomeGenBase biome = this.worldObj.getBiomeGenForCoords(minBlockPos.add(16, 0, 16));
        this.rand.setSeed(this.worldObj.getSeed());
        long k = this.rand.nextLong() / 2L * 2L + 1L;
        long l = this.rand.nextLong() / 2L * 2L + 1L;
        this.rand.setSeed((long)chunkX * k + (long)chunkZ * l ^ this.worldObj.getSeed());
        boolean hasVillage = false;
        ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(chunkX, chunkZ);

        net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.terraingen.PopulateChunkEvent.Pre(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage));

        // 生成建築

        if (this.settings.useMineShafts && this.mapFeaturesEnabled)
        {
            this.mineshaftGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
        }

        if (this.settings.useVillages && this.mapFeaturesEnabled)
        {
            hasVillage = this.villageGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
        }

        if (this.settings.useStrongholds && this.mapFeaturesEnabled)
        {
            this.strongholdGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
        }

        if (this.settings.useTemples && this.mapFeaturesEnabled)
        {
            this.scatteredFeatureGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
        }

        if (this.settings.useMonuments && this.mapFeaturesEnabled)
        {
            this.oceanMonumentGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
        }

        // 生成湖
        if (   biome != BiomeGenBase.desert
            && biome != BiomeGenBase.desertHills
            && this.settings.useWaterLakes
            && !hasVillage
            && this.rand.nextInt(this.settings.waterLakeChance) == 0
            && net.minecraftforge.event.terraingen.TerrainGen.populate(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.LAKE))
        {
            int i1 = this.rand.nextInt(16) + 8;
            int j1 = this.rand.nextInt(256);
            int k1 = this.rand.nextInt(16) + 8;
            (new WorldGenLakes(Blocks.water)).generate(this.worldObj, this.rand, minBlockPos.add(i1, j1, k1));
        }

        // 生成岩漿湖
        if (   !hasVillage
            && this.rand.nextInt(this.settings.lavaLakeChance / 10) == 0
            && this.settings.useLavaLakes
            && net.minecraftforge.event.terraingen.TerrainGen.populate(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.LAVA))
        {
            int i2 = this.rand.nextInt(16) + 8;
            int l2 = this.rand.nextInt(this.rand.nextInt(248) + 8);
            int k3 = this.rand.nextInt(16) + 8;

            if (l2 < this.worldObj.getSeaLevel() || this.rand.nextInt(this.settings.lavaLakeChance / 8) == 0)
            {
                (new WorldGenLakes(Blocks.lava)).generate(this.worldObj, this.rand, minBlockPos.add(i2, l2, k3));
            }
        }

        // 生成地牢(刷怪籠)
        if (this.settings.useDungeons)
        {
            boolean doGen = net.minecraftforge.event.terraingen.TerrainGen.populate(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.DUNGEON);
            for (int j2 = 0; doGen && j2 < this.settings.dungeonChance; ++j2)
            {
                int i3 = this.rand.nextInt(16) + 8;
                int l3 = this.rand.nextInt(256);
                int l1 = this.rand.nextInt(16) + 8;
                (new WorldGenDungeons()).generate(this.worldObj, this.rand, minBlockPos.add(i3, l3, l1));
            }
        }

        // 生成樹和礦石等
        biome.decorate(this.worldObj, this.rand, new BlockPos(minBlockX, 0, minBlockZ));

        // 生成動物
        if (net.minecraftforge.event.terraingen.TerrainGen.populate(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.ANIMALS))
        {
            SpawnerAnimals.performWorldGenSpawning(this.worldObj, biome, minBlockX + 8, minBlockZ + 8, 16, 16, this.rand);
        }

        minBlockPos = minBlockPos.add(8, 0, 8);

        // 生成冰和雪
        boolean doGen = net.minecraftforge.event.terraingen.TerrainGen.populate(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.ICE);
        for (int x = 0; doGen && x < 16; ++x)
        {
            for (int z = 0; z < 16; ++z)
            {
                BlockPos topBlock = this.worldObj.getPrecipitationHeight(minBlockPos.add(x, 0, z));
                BlockPos downBlock = topBlock.down();

                if (this.worldObj.canBlockFreezeWater(downBlock))
                {
                    this.worldObj.setBlockState(downBlock, Blocks.ice.getDefaultState(), 2);
                }

                if (this.worldObj.canSnowAt(topBlock, true))
                {
                    this.worldObj.setBlockState(topBlock, Blocks.snow_layer.getDefaultState(), 2);
                }
            }
        }

        net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.terraingen.PopulateChunkEvent.Post(chunkProvider, worldObj, rand, chunkX, chunkZ, hasVillage));

        BlockFalling.fallInstantly = false;
    }

類名net.minecraft.world.biome.BiomeDecorator

    public void decorate(World worldIn, Random random, BiomeGenBase biome, BlockPos minBlockPos)
    {
        if (this.currentWorld != null)
        {
            throw new RuntimeException("Already decorating");
        }
        else
        {
            // 讀取世界設置

            this.currentWorld = worldIn;
            String s = worldIn.getWorldInfo().getGeneratorOptions();

            if (s != null)
            {
                this.chunkProviderSettings = ChunkProviderSettings.Factory.jsonToFactory(s).func_177864_b();
            }
            else
            {
                this.chunkProviderSettings = ChunkProviderSettings.Factory.jsonToFactory("").func_177864_b();
            }

            this.randomGenerator = random;
            this.field_180294_c = minBlockPos;
            // 構造礦物、泥土、砂礫等數據
            this.dirtGen = new WorldGenMinable(Blocks.dirt.getDefaultState(), this.chunkProviderSettings.dirtSize);
            this.gravelGen = new WorldGenMinable(Blocks.gravel.getDefaultState(), this.chunkProviderSettings.gravelSize);
            this.graniteGen = new WorldGenMinable(Blocks.stone.getDefaultState().withProperty(BlockStone.VARIANT, BlockStone.EnumType.GRANITE), this.chunkProviderSettings.graniteSize);
            this.dioriteGen = new WorldGenMinable(Blocks.stone.getDefaultState().withProperty(BlockStone.VARIANT, BlockStone.EnumType.DIORITE), this.chunkProviderSettings.dioriteSize);
            this.andesiteGen = new WorldGenMinable(Blocks.stone.getDefaultState().withProperty(BlockStone.VARIANT, BlockStone.EnumType.ANDESITE), this.chunkProviderSettings.andesiteSize);
            this.coalGen = new WorldGenMinable(Blocks.coal_ore.getDefaultState(), this.chunkProviderSettings.coalSize);
            this.ironGen = new WorldGenMinable(Blocks.iron_ore.getDefaultState(), this.chunkProviderSettings.ironSize);
            this.goldGen = new WorldGenMinable(Blocks.gold_ore.getDefaultState(), this.chunkProviderSettings.goldSize);
            this.redstoneGen = new WorldGenMinable(Blocks.redstone_ore.getDefaultState(), this.chunkProviderSettings.redstoneSize);
            this.diamondGen = new WorldGenMinable(Blocks.diamond_ore.getDefaultState(), this.chunkProviderSettings.diamondSize);
            this.lapisGen = new WorldGenMinable(Blocks.lapis_ore.getDefaultState(), this.chunkProviderSettings.lapisSize);
            // 生成
            this.genDecorations(biome);
            this.currentWorld = null;
            this.randomGenerator = null;
        }
    }

    protected void genDecorations(BiomeGenBase biomeGenBaseIn)
    {
        net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.terraingen.DecorateBiomeEvent.Pre(currentWorld, randomGenerator, field_180294_c));
        // 生成礦物
        this.generateOres();

        // ...

        int treeCount = this.treesPerChunk;

        if (this.randomGenerator.nextInt(10) == 0)
        {
            ++treeCount;
        }

        if(net.minecraftforge.event.terraingen.TerrainGen.decorate(currentWorld, randomGenerator, field_180294_c, net.minecraftforge.event.terraingen.DecorateBiomeEvent.Decorate.EventType.TREE))
        for (int i = 0; i < treeCount; ++i)
        {
            int x = this.randomGenerator.nextInt(16) + 8;
            int z = this.randomGenerator.nextInt(16) + 8;
            // 1/10概率生成大樹
            WorldGenAbstractTree genTree = biomeGenBaseIn.genBigTreeChance(this.randomGenerator);
            // 只有大樹實現了,設置葉子最遠距離
            genTree.func_175904_e();
            BlockPos blockpos = this.currentWorld.getHeight(this.field_180294_c.add(x, 0, z));

            // 生成樹
            if (genTree.generate(this.currentWorld, this.randomGenerator, blockpos))
            {
                // 只有巨型菠蘿樹實現了
                genTree.func_180711_a(this.currentWorld, this.randomGenerator, blockpos);
            }
        }

        // ...

        net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.terraingen.DecorateBiomeEvent.Post(currentWorld, randomGenerator, field_180294_c));
    }

    /**
     * Generates ores in the current chunk
     */
    protected void generateOres()
    {
        net.minecraftforge.common.MinecraftForge.ORE_GEN_BUS.post(new net.minecraftforge.event.terraingen.OreGenEvent.Pre(currentWorld, randomGenerator, field_180294_c));
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, dirtGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.DIRT))
        this.genStandardOre1(this.chunkProviderSettings.dirtCount, this.dirtGen, this.chunkProviderSettings.dirtMinHeight, this.chunkProviderSettings.dirtMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, gravelGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.GRAVEL))
        this.genStandardOre1(this.chunkProviderSettings.gravelCount, this.gravelGen, this.chunkProviderSettings.gravelMinHeight, this.chunkProviderSettings.gravelMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, dioriteGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.DIORITE))
        this.genStandardOre1(this.chunkProviderSettings.dioriteCount, this.dioriteGen, this.chunkProviderSettings.dioriteMinHeight, this.chunkProviderSettings.dioriteMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, graniteGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.GRANITE))
        this.genStandardOre1(this.chunkProviderSettings.graniteCount, this.graniteGen, this.chunkProviderSettings.graniteMinHeight, this.chunkProviderSettings.graniteMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, andesiteGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.ANDESITE))
        this.genStandardOre1(this.chunkProviderSettings.andesiteCount, this.andesiteGen, this.chunkProviderSettings.andesiteMinHeight, this.chunkProviderSettings.andesiteMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, coalGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.COAL))
        this.genStandardOre1(this.chunkProviderSettings.coalCount, this.coalGen, this.chunkProviderSettings.coalMinHeight, this.chunkProviderSettings.coalMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, ironGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.IRON))
        this.genStandardOre1(this.chunkProviderSettings.ironCount, this.ironGen, this.chunkProviderSettings.ironMinHeight, this.chunkProviderSettings.ironMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, goldGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.GOLD))
        this.genStandardOre1(this.chunkProviderSettings.goldCount, this.goldGen, this.chunkProviderSettings.goldMinHeight, this.chunkProviderSettings.goldMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, redstoneGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.REDSTONE))
        this.genStandardOre1(this.chunkProviderSettings.redstoneCount, this.redstoneGen, this.chunkProviderSettings.redstoneMinHeight, this.chunkProviderSettings.redstoneMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, diamondGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.DIAMOND))
        this.genStandardOre1(this.chunkProviderSettings.diamondCount, this.diamondGen, this.chunkProviderSettings.diamondMinHeight, this.chunkProviderSettings.diamondMaxHeight);
        if (net.minecraftforge.event.terraingen.TerrainGen.generateOre(currentWorld, randomGenerator, lapisGen, field_180294_c, net.minecraftforge.event.terraingen.OreGenEvent.GenerateMinable.EventType.LAPIS))
        this.genStandardOre2(this.chunkProviderSettings.lapisCount, this.lapisGen, this.chunkProviderSettings.lapisCenterHeight, this.chunkProviderSettings.lapisSpread);
        net.minecraftforge.common.MinecraftForge.ORE_GEN_BUS.post(new net.minecraftforge.event.terraingen.OreGenEvent.Post(currentWorld, randomGenerator, field_180294_c));
    }

    /**
     * Standard ore generation helper. Generates most ores.
     */
    protected void genStandardOre1(int blockCount, WorldGenerator generator, int minHeight, int maxHeight)
    {
        if (maxHeight < minHeight)
        {
            int t = minHeight;
            minHeight = maxHeight;
            maxHeight = t;
        }
        else if (maxHeight == minHeight)
        {
            if (minHeight < 255)
            {
                ++maxHeight;
            }
            else
            {
                --minHeight;
            }
        }

        // 生成blockCount堆礦石
        for (int i = 0; i < blockCount; ++i)
        {
            BlockPos blockpos = this.field_180294_c.add(this.randomGenerator.nextInt(16), this.randomGenerator.nextInt(maxHeight - minHeight) + minHeight, this.randomGenerator.nextInt(16));
            generator.generate(this.currentWorld, this.randomGenerator, blockpos);
        }
    }

生成礦物

劃一條線,然後沿着線上生成numberOfBlocks個橢球,把橢球內的方塊替換爲礦石

類名net.minecraft.world.gen.feature.WorldGenMinable

    public boolean generate(World worldIn, Random rand, BlockPos position)
    {
        // 在xz平面上的方向
        float angle = rand.nextFloat() * (float)Math.PI;
        // 起始點和結束點
        double startX = (double)((float)(position.getX() + 8) + MathHelper.sin(angle) * (float)this.numberOfBlocks / 8.0F);
        double endX   = (double)((float)(position.getX() + 8) - MathHelper.sin(angle) * (float)this.numberOfBlocks / 8.0F);
        double startZ = (double)((float)(position.getZ() + 8) + MathHelper.cos(angle) * (float)this.numberOfBlocks / 8.0F);
        double endZ   = (double)((float)(position.getZ() + 8) - MathHelper.cos(angle) * (float)this.numberOfBlocks / 8.0F);
        double startY = (double)(position.getY() + rand.nextInt(3) - 2);
        double endY   = (double)(position.getY() + rand.nextInt(3) - 2);

        // numberOfBlocks是反混淆錯誤,應該是幾個橢球的意思
        for (int i = 0; i < this.numberOfBlocks; ++i)
        {
            // 插值參數
            float t = (float)i / (float)this.numberOfBlocks;
            // 橢球中心
            double centerX = startX + (endX - startX) * (double)t;
            double centerY = startY + (endY - startY) * (double)t;
            double centerZ = startZ + (endZ - startZ) * (double)t;
            // 橢球尺寸(可以看出XZ和Y尺寸一樣,應該是球)
            double scale = rand.nextDouble() * (double)this.numberOfBlocks / 16.0D;
            double diameterXZ = (double)(MathHelper.sin((float)Math.PI * t) + 1.0F) * scale + 1.0D;
            double diameterY  = (double)(MathHelper.sin((float)Math.PI * t) + 1.0F) * scale + 1.0D;
            // 橢球包圍盒
            int minX = MathHelper.floor_double(centerX - diameterXZ / 2.0D);
            int minY = MathHelper.floor_double(centerY - diameterY / 2.0D);
            int minZ = MathHelper.floor_double(centerZ - diameterXZ / 2.0D);
            int maxX = MathHelper.floor_double(centerX + diameterXZ / 2.0D);
            int maxY = MathHelper.floor_double(centerY + diameterY / 2.0D);
            int maxZ = MathHelper.floor_double(centerZ + diameterXZ / 2.0D);

            // 把這個橢球裏的方塊替換爲礦石
            for (int x = minX; x <= maxX; ++x)
            {
                double xDist = ((double)x + 0.5D - centerX) / (diameterXZ / 2.0D);

                if (xDist * xDist < 1.0D) // 參考橢球方程
                {
                    for (int y = minY; y <= maxY; ++y)
                    {
                        double yDist = ((double)y + 0.5D - centerY) / (diameterY / 2.0D);

                        if (xDist * xDist + yDist * yDist < 1.0D) // 參考橢球方程
                        {
                            for (int z = minZ; z <= maxZ; ++z)
                            {
                                double zDist = ((double)z + 0.5D - centerZ) / (diameterXZ / 2.0D);

                                if (xDist * xDist + yDist * yDist + zDist * zDist < 1.0D) // 參考橢球方程
                                {
                                    BlockPos blockpos = new BlockPos(x, y, z);

                                    // 可以替換這個方塊
                                    if (worldIn.getBlockState(blockpos).getBlock().isReplaceableOreGen(worldIn, blockpos, this.predicate))
                                    {
                                        // 替換爲礦石
                                        worldIn.setBlockState(blockpos, this.oreBlock, 2);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        return true;
    }

生成樹

隨便找了一個可可豆樹的類,類名net.minecraft.world.gen.feature.WorldGenTrees

    public boolean generate(World worldIn, Random rand, BlockPos position)
    {
        int height = rand.nextInt(3) + this.minTreeHeight;
        boolean isReplaceable = true;

        if (position.getY() >= 1 && position.getY() + height + 1 <= 256)
        {
            // 檢查所有方塊可替換
            for (int y = position.getY(); y <= position.getY() + 1 + height; ++y)
            {
                int xzSize = 1;

                // 底端
                if (y == position.getY())
                {
                    xzSize = 0;
                }

                // 頂端
                if (y >= position.getY() + height - 1)
                {
                    xzSize = 2;
                }

                // 檢查這個平面所有方塊可替換
                BlockPos.MutableBlockPos tmpPos = new BlockPos.MutableBlockPos();
                for (int x = position.getX() - xzSize; x <= position.getX() + xzSize && isReplaceable; ++x)
                {
                    for (int z = position.getZ() - xzSize; z <= position.getZ() + xzSize && isReplaceable; ++z)
                    {
                        if (y >= 0 && y < 256)
                        {
                            if (!this.isReplaceable(worldIn, tmpPos.set(x, y, z)))
                            {
                                isReplaceable = false;
                            }
                        }
                        else
                        {
                            isReplaceable = false;
                        }
                    }
                }
            }

            if (!isReplaceable)
            {
                return false;
            }
            else
            {
                BlockPos downPos = position.downPos();
                Block downBlock = worldIn.getBlockState(downPos).getBlock();
                // 是可生成樹的土壤
                boolean isSoil = downBlock.canSustainPlant(worldIn, downPos, net.minecraft.util.EnumFacing.UP, (net.minecraft.block.BlockSapling)Blocks.sapling);

                if (isSoil && position.getY() < 256 - height - 1)
                {
                    downBlock.onPlantGrow(worldIn, downPos, position);

                    // 生成葉子
                    for (int y = position.getY() + height - 3; y <= position.getY() + height; ++y)
                    {
                        int restHeight = y - (position.getY() + height);
                        int xzSize = 1 - restHeight / 2;

                        for (int x = position.getX() - xzSize; x <= position.getX() + xzSize; ++x)
                        {
                            int xOffset = x - position.getX();

                            for (int z = position.getZ() - xzSize; z <= position.getZ() + xzSize; ++z)
                            {
                                int zOffset = z - position.getZ();

                                if (   Math.abs(xOffset) != xzSize
                                    || Math.abs(zOffset) != xzSize // 不在邊緣4個點
                                    || rand.nextInt(2) != 0
                                    && restHeight != 0)
                                {
                                    BlockPos blockpos = new BlockPos(x, y, z);
                                    Block block = worldIn.getBlockState(blockpos).getBlock();

                                    if (   block.isAir(worldIn, blockpos)
                                        || block.isLeaves(worldIn, blockpos)
                                        || block.getMaterial() == Material.vine)
                                    {
                                        this.setBlockAndNotifyAdequately(worldIn, blockpos, this.metaLeaves);
                                    }
                                }
                            }
                        }
                    }

                    // 生成木頭
                    for (int y = 0; y < height; ++y)
                    {
                        BlockPos upPos = position.up(y);
                        Block upBlock = worldIn.getBlockState(upPos).getBlock();

                        if (   upBlock.isAir(worldIn, upPos)
                            || upBlock.isLeaves(worldIn, upPos)
                            || upBlock.getMaterial() == Material.vine)
                        {
                            this.setBlockAndNotifyAdequately(worldIn, position.up(y), this.metaWood);

                            // 生成藤蔓
                            if (this.vinesGrow && y > 0)
                            {
                                if (rand.nextInt(3) > 0 && worldIn.isAirBlock(position.add(-1, y, 0)))
                                {
                                    this.func_181651_a(worldIn, position.add(-1, y, 0), BlockVine.EAST);
                                }

                                if (rand.nextInt(3) > 0 && worldIn.isAirBlock(position.add(1, y, 0)))
                                {
                                    this.func_181651_a(worldIn, position.add(1, y, 0), BlockVine.WEST);
                                }

                                if (rand.nextInt(3) > 0 && worldIn.isAirBlock(position.add(0, y, -1)))
                                {
                                    this.func_181651_a(worldIn, position.add(0, y, -1), BlockVine.SOUTH);
                                }

                                if (rand.nextInt(3) > 0 && worldIn.isAirBlock(position.add(0, y, 1)))
                                {
                                    this.func_181651_a(worldIn, position.add(0, y, 1), BlockVine.NORTH);
                                }
                            }
                        }
                    }

                    // 生成藤蔓
                    if (this.vinesGrow)
                    {
                        for (int y = position.getY() + height - 3; y <= position.getY() + height; ++y)
                        {
                            int restHeight = y - (position.getY() + height);
                            int xzSize = 2 - restHeight / 2;
                            BlockPos.MutableBlockPos tmpPos = new BlockPos.MutableBlockPos();

                            for (int x = position.getX() - xzSize; x <= position.getX() + xzSize; ++x)
                            {
                                for (int z = position.getZ() - xzSize; z <= position.getZ() + xzSize; ++z)
                                {
                                    tmpPos.set(x, y, z);

                                    if (worldIn.getBlockState(tmpPos).getBlock().isLeaves(worldIn,tmpPos))
                                    {
                                        BlockPos blockpos2 = tmpPos.west();
                                        BlockPos blockpos3 = tmpPos.east();
                                        BlockPos blockpos4 = tmpPos.north();
                                        BlockPos blockpos1 = tmpPos.south();

                                        if (rand.nextInt(4) == 0 && worldIn.getBlockState(blockpos2).getBlock().isAir(worldIn,blockpos2))
                                        {
                                            this.func_181650_b(worldIn, blockpos2, BlockVine.EAST);
                                        }

                                        if (rand.nextInt(4) == 0 && worldIn.getBlockState(blockpos3).getBlock().isAir(worldIn,blockpos3))
                                        {
                                            this.func_181650_b(worldIn, blockpos3, BlockVine.WEST);
                                        }

                                        if (rand.nextInt(4) == 0 && worldIn.getBlockState(blockpos4).getBlock().isAir(worldIn,blockpos4))
                                        {
                                            this.func_181650_b(worldIn, blockpos4, BlockVine.SOUTH);
                                        }

                                        if (rand.nextInt(4) == 0 && worldIn.getBlockState(blockpos1).getBlock().isAir(worldIn,blockpos1))
                                        {
                                            this.func_181650_b(worldIn, blockpos1, BlockVine.NORTH);
                                        }
                                    }
                                }
                            }
                        }

                        // 生成可可豆
                        if (rand.nextInt(5) == 0 && height > 5)
                        {
                            for (int yOffset = 0; yOffset < 2; ++yOffset)
                            {
                                for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL)
                                {
                                    if (rand.nextInt(4 - yOffset) == 0)
                                    {
                                        EnumFacing enumfacing1 = enumfacing.getOpposite();
                                        this.func_181652_a(worldIn, rand.nextInt(3), position.add(enumfacing1.getFrontOffsetX(), height - 5 + yOffset, enumfacing1.getFrontOffsetZ()), enumfacing);
                                    }
                                }
                            }
                        }
                    }

                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        else
        {
            return false;
        }
    }

生成動物

雖然生成方塊研究完了,姑且研究下動物

類名net.minecraft.world.SpawnerAnimals

    /**
     * Called during chunk generation to spawn initial creatures.
     *  
     * @param biomeIn The biome to use for the weighted entity creatureList
     * @param randomIn The random to use for mob spawning
     */
    public static void performWorldGenSpawning(World worldIn, BiomeGenBase biomeIn, int x, int z, int xSize, int zSize, Random randomIn)
    {
        // 這個生物羣系可生成的生物
        List<BiomeGenBase.SpawnListEntry> creatureList = biomeIn.getSpawnableList(EnumCreatureType.CREATURE);

        if (!creatureList.isEmpty())
        {
            while (randomIn.nextFloat() < biomeIn.getSpawningChance())
            {
                BiomeGenBase.SpawnListEntry spawn = (BiomeGenBase.SpawnListEntry)WeightedRandom.getRandomItem(worldIn.rand, creatureList);
                int entityCount = spawn.minGroupCount + randomIn.nextInt(1 + spawn.maxGroupCount - spawn.minGroupCount);
                IEntityLivingData data = null;
                int spawnX = x + randomIn.nextInt(xSize);
                int spawnZ = z + randomIn.nextInt(zSize);
                int centerX = spawnX;
                int centerZ = spawnZ;

                for (int i = 0; i < entityCount; ++i)
                {
                    boolean hasSpawned = false;

                    // 嘗試生成4次
                    for (int j = 0; !hasSpawned && j < 4; ++j)
                    {
                        BlockPos topPos = worldIn.getTopSolidOrLiquidBlock(new BlockPos(spawnX, 0, spawnZ));

                        // 能生成在這個方塊上
                        if (canCreatureTypeSpawnAtLocation(EntityLiving.SpawnPlacementType.ON_GROUND, worldIn, topPos))
                        {
                            EntityLiving entity;

                            try
                            {
                                entity = (EntityLiving)spawn.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {worldIn});
                            }
                            catch (Exception exception)
                            {
                                exception.printStackTrace();
                                continue;
                            }

                            // 設置位置和方向
                            entity.setLocationAndAngles((double)((float)spawnX + 0.5F), (double)topPos.getY(), (double)((float)spawnZ + 0.5F), randomIn.nextFloat() * 360.0F, 0.0F);
                            // 生成
                            worldIn.spawnEntityInWorld(entity);
                            data = entity.onInitialSpawn(worldIn.getDifficultyForLocation(new BlockPos(entity)), data);
                            hasSpawned = true;
                        }

                        spawnX += randomIn.nextInt(5) - randomIn.nextInt(5);

                        for (spawnZ += randomIn.nextInt(5) - randomIn.nextInt(5); spawnX < x || spawnX >= x + xSize || spawnZ < z || spawnZ >= z + xSize; spawnZ = centerZ + randomIn.nextInt(5) - randomIn.nextInt(5))
                        {
                            spawnX = centerX + randomIn.nextInt(5) - randomIn.nextInt(5);
                        }
                    }
                }
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章