Minecraft的世界生成過程(六)村莊

本篇內容是生成村莊,生成其他建築的過程也差不多就不研究了(代碼太多也研究不完)

構造村莊組件數據

它的recursiveGenerate繼承自這裏,類名net.minecraft.world.gen.structure.MapGenStructure

    // 只是生成結構數據,暫時不操作方塊
    protected final void recursiveGenerate(World worldIn, final int chunkX, final int chunkZ, int p_180701_4_, int p_180701_5_, ChunkPrimer chunkPrimerIn)
    {
        // 嘗試載入保存的結構數據
        this.func_143027_a(worldIn);

        // 載入失敗則生成
        if (!this.structureMap.containsKey(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ))))
        {
            this.rand.nextInt();

            try
            {
                // 子類實現判斷能否生成
                if (this.canSpawnStructureAtCoords(chunkX, chunkZ))
                {
                    // 子類實現的生成數據
                    StructureStart structurestart = this.getStructureStart(chunkX, chunkZ);
                    this.structureMap.put(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ)), structurestart);
                    // 保存數據
                    this.func_143026_a(chunkX, chunkZ, structurestart);
                }
            }
            catch (Throwable throwable)
            {
                // ...
            }
        }
    }

村莊構造流程是這樣的:計算村莊裏的組件(田、房子、鐵匠鋪等),構造水井,構造水井周圍的道路,沿着道路隨機選之前計算好的組件來構造或者構造新的道路

類名net.minecraft.world.gen.structure.MapGenVillage

    protected boolean canSpawnStructureAtCoords(int chunkX, int chunkZ)
    {
        int _chunkX = chunkX;
        int _chunkZ = chunkZ;

        // field_82665_g是村莊平均距離,默認=32
        // field_82666_h是村莊最小距離,默認=8
        // 所以在座標爲n * 32 + 12的區塊附近比較可能找到村莊

        // 防止在原點附近生成的村莊可能靠太近

        if (chunkX < 0)
        {
            chunkX -= this.field_82665_g - 1;
        }

        if (chunkZ < 0)
        {
            chunkZ -= this.field_82665_g - 1;
        }

        // 注意這是整數除法
        int keyChunkX = chunkX / this.field_82665_g;
        int keyChunkZ = chunkZ / this.field_82665_g;
        // 設置世界隨機種子並返回Random對象
        Random random = this.worldObj.setRandomSeed(keyChunkX, keyChunkZ, 10387312);
        // 附近可以生成村莊的區塊座標
        // keyChunkXZ * field_82665_g後變成了field_82665_g的倍數
        keyChunkX = keyChunkX * this.field_82665_g + random.nextInt(this.field_82665_g - this.field_82666_h);
        keyChunkZ = keyChunkZ * this.field_82665_g + random.nextInt(this.field_82665_g - this.field_82666_h);

        if (_chunkX == keyChunkX && _chunkZ == keyChunkZ)
        {
            // 判斷生物羣系是否可以生成村莊
            return this.worldObj.getWorldChunkManager().areBiomesViable(_chunkX * 16 + 8, _chunkZ * 16 + 8, 0, villageSpawnBiomes);
        }

        return false;
    }

    protected StructureStart getStructureStart(int chunkX, int chunkZ)
    {
        // terrainType默認爲0,超平坦爲1,影響村莊各組件數量
        // 讀取用的鍵名爲size,所以後面就叫size了
        return new MapGenVillage.Start(this.worldObj, this.rand, chunkX, chunkZ, this.terrainType);
    }

    public static class Start extends StructureStart
        {
            /** well ... thats what it does */
            private boolean hasMoreThanTwoComponents;

            public Start()
            {
            }

            public Start(World worldIn, Random rand, int x, int z, int size)
            {
                super(x, z);
                // 計算這個村莊的組件
                List<StructureVillagePieces.PieceWeight> pieces = StructureVillagePieces.getStructureVillageWeightedPieceList(rand, size);
                // 構造水井
                StructureVillagePieces.Start startComponent = new StructureVillagePieces.Start(worldIn.getWorldChunkManager(), 0, rand, x * 16 + 2, z * 16 + 2, pieces, size);
                this.components.add(startComponent);
                // 這裏構造了水井周圍的道路並加入components和field_74930_j
                startComponent.buildComponent(startComponent, this.components, rand);

                // 構造子組件(一開始只有道路)

                List<StructureComponent> list1 = startComponent.field_74930_j;
                List<StructureComponent> list2 = startComponent.field_74932_i;

                // 優先構造list1的組件(道路),然後構造list2的
                while (!list1.isEmpty() || !list2.isEmpty())
                {
                    if (list1.isEmpty())
                    {
                        // 隨機順序
                        int i = rand.nextInt(list2.size());
                        StructureComponent structurecomponent = (StructureComponent)list2.remove(i);
                        structurecomponent.buildComponent(startComponent, this.components, rand);
                    }
                    else
                    {
                        int j = rand.nextInt(list1.size());
                        StructureComponent structurecomponent2 = (StructureComponent)list1.remove(j);
                        structurecomponent2.buildComponent(startComponent, this.components, rand);
                    }
                }

                // 計算包圍盒,使所有組件在包圍盒內
                this.updateBoundingBox();

                // 計算除了道路的組件數量

                int componentCount = 0;

                for (StructureComponent component : this.components)
                {
                    if (!(component instanceof StructureVillagePieces.Road))
                    {
                        ++componentCount;
                    }
                }

                this.hasMoreThanTwoComponents = componentCount > 2;
            }

            // ...
        }

類名net.minecraft.world.gen.structure.StructureVillagePieces

    // 計算這個村莊的組件
    public static List<StructureVillagePieces.PieceWeight> getStructureVillageWeightedPieceList(Random random, int size)
    {
        List<StructureVillagePieces.PieceWeight> list = Lists.<StructureVillagePieces.PieceWeight>newArrayList();
        // 後兩個參數是權重和數量(villagePiecesLimit)
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.House4Garden.class, 4, MathHelper.getRandomIntegerInRange(random, 2 + size, 4 + size * 2)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.Church.class, 20, MathHelper.getRandomIntegerInRange(random, 0 + size, 1 + size)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.House1.class, 20, MathHelper.getRandomIntegerInRange(random, 0 + size, 2 + size)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.WoodHut.class, 3, MathHelper.getRandomIntegerInRange(random, 2 + size, 5 + size * 3)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.Hall.class, 15, MathHelper.getRandomIntegerInRange(random, 0 + size, 2 + size)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.Field1.class, 3, MathHelper.getRandomIntegerInRange(random, 1 + size, 4 + size)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.Field2.class, 3, MathHelper.getRandomIntegerInRange(random, 2 + size, 4 + size * 2)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.House2.class, 15, MathHelper.getRandomIntegerInRange(random, 0, 1 + size)));
        list.add(new StructureVillagePieces.PieceWeight(StructureVillagePieces.House3.class, 8, MathHelper.getRandomIntegerInRange(random, 0 + size, 3 + size * 2)));
        net.minecraftforge.fml.common.registry.VillagerRegistry.addExtraVillageComponents(list, random, size);
        Iterator<StructureVillagePieces.PieceWeight> iterator = list.iterator();

        while (iterator.hasNext())
        {
            // villagePiecesLimit = 0代表不生成,這裏直接去掉
            if (((StructureVillagePieces.PieceWeight)iterator.next()).villagePiecesLimit == 0)
            {
                iterator.remove();
            }
        }

        return list;
    }

    // 繼承自Well,說明水井是村莊的起點,每個村莊一定有水井
    public static class Start extends StructureVillagePieces.Well
        {
            public WorldChunkManager worldChunkMngr;
            /** Boolean that determines if the village is in a desert or not. */
            public boolean inDesert;
            /** World terrain type, 0 for normal, 1 for flap map */
            public int terrainType;
            public StructureVillagePieces.PieceWeight structVillagePieceWeight;
            public List<StructureVillagePieces.PieceWeight> structureVillageWeightedPieceList;
            public List<StructureComponent> field_74932_i = Lists.<StructureComponent>newArrayList();
            public List<StructureComponent> field_74930_j = Lists.<StructureComponent>newArrayList();
            public BiomeGenBase biome;

            public Start()
            {
            }

            public Start(WorldChunkManager chunkManagerIn, int componentType, Random rand, int x, int z, List<StructureVillagePieces.PieceWeight> pieces, int size)
            {
                super((StructureVillagePieces.Start)null, 0, rand, x, z);
                this.worldChunkMngr = chunkManagerIn;
                this.structureVillageWeightedPieceList = pieces;
                this.terrainType = size;
                BiomeGenBase biomegenbase = chunkManagerIn.getBiomeGenerator(new BlockPos(x, 0, z), BiomeGenBase.field_180279_ad);
                this.inDesert = biomegenbase == BiomeGenBase.desert || biomegenbase == BiomeGenBase.desertHills;
                this.biome = biomegenbase;
                // 設置是否在沙漠
                this.func_175846_a(this.inDesert);
            }

            // ...
        }

    public static class Well extends StructureVillagePieces.Village
        {
            // ...

            /**
             * Initiates construction of the Structure Component picked, at the current Location of StructGen
             */
            public void buildComponent(StructureComponent start, List<StructureComponent> components, Random rand)
            {
                // 對水井周圍四個方向構造道路並加入組件
                StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX - 1, this.boundingBox.maxY - 4, this.boundingBox.minZ + 1, EnumFacing.WEST, this.getComponentType());
                StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.maxX + 1, this.boundingBox.maxY - 4, this.boundingBox.minZ + 1, EnumFacing.EAST, this.getComponentType());
                StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX + 1, this.boundingBox.maxY - 4, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType());
                StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX + 1, this.boundingBox.maxY - 4, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType());
            }

            // ...
        }

    // 構造道路
    private static StructureComponent func_176069_e(StructureVillagePieces.Start start, List<StructureComponent> components, Random rand, int x, int y, int z, EnumFacing facing, int componentType)
    {
        if (componentType > 3 + start.terrainType)
        {
            return null;
        }
        else if (   Math.abs(x - start.getBoundingBox().minX) <= 112
                 && Math.abs(z - start.getBoundingBox().minZ) <= 112) // 不能離起點太遠
        {
            // 構造道路的包圍盒,保證不與其他組件重疊
            StructureBoundingBox structureboundingbox = StructureVillagePieces.Path.func_175848_a(start, components, rand, x, y, z, facing);

            if (structureboundingbox != null && structureboundingbox.minY > 10)
            {
                StructureComponent path = new StructureVillagePieces.Path(start, componentType, rand, structureboundingbox, facing);
                int xCenter = (path.boundingBox.minX + path.boundingBox.maxX) / 2;
                int zCenter = (path.boundingBox.minZ + path.boundingBox.maxZ) / 2;
                int xSize = path.boundingBox.maxX - path.boundingBox.minX;
                int zSize = path.boundingBox.maxZ - path.boundingBox.minZ;
                int length = xSize > zSize ? xSize : zSize;

                // 判斷中心生物羣系
                if (start.getWorldChunkManager().areBiomesViable(xCenter, zCenter, length / 2 + 4, MapGenVillage.villageSpawnBiomes))
                {
                    components.add(path);
                    // 加入優先構造的組件
                    start.field_74930_j.add(path);
                    return path;
                }
            }

            return null;
        }
        else
        {
            return null;
        }
    }

    public static class Path extends StructureVillagePieces.Road
        {
            // ...

            // 構造道路包圍盒
            public static StructureBoundingBox func_175848_a(StructureVillagePieces.Start start, List<StructureComponent> components, Random rand, int x, int y, int z, EnumFacing facing)
            {
                for (int length = 7 * MathHelper.getRandomIntegerInRange(rand, 3, 5); length >= 7; length -= 7)
                {
                    // 向指定方向構造這個組件的包圍盒
                    StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(x, y, z, 0, 0, 0, 3, 3, length, facing);

                    // 沒有與已有組件重疊
                    if (StructureComponent.findIntersecting(components, structureboundingbox) == null)
                    {
                        return structureboundingbox;
                    }
                }

                return null;
            }

            public void buildComponent(StructureComponent start, List<StructureComponent> components, Random rand)
            {
                boolean hasNewComponent = false;

                // 構造組件

                for (int lengthOffset = rand.nextInt(5); lengthOffset < this.length - 8; lengthOffset += 2 + rand.nextInt(5))
                {
                    StructureComponent component = this.getNextComponentNN((StructureVillagePieces.Start)start, components, rand, 0, lengthOffset);

                    if (component != null)
                    {
                        lengthOffset += Math.max(component.boundingBox.getXSize(), component.boundingBox.getZSize());
                        hasNewComponent = true;
                    }
                }

                for (int lengthOffset = rand.nextInt(5); lengthOffset < this.length - 8; lengthOffset += 2 + rand.nextInt(5))
                {
                    StructureComponent component = this.getNextComponentPP((StructureVillagePieces.Start)start, components, rand, 0, lengthOffset);

                    if (component != null)
                    {
                        lengthOffset += Math.max(component.boundingBox.getXSize(), component.boundingBox.getZSize());
                        hasNewComponent = true;
                    }
                }

                // 構造左右兩邊新的道路

                if (hasNewComponent && rand.nextInt(3) > 0 && this.coordBaseMode != null)
                {
                    switch (this.coordBaseMode)
                    {
                        case NORTH:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX - 1, this.boundingBox.minY, this.boundingBox.minZ, EnumFacing.WEST, this.getComponentType());
                            break;
                        case SOUTH:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX - 1, this.boundingBox.minY, this.boundingBox.maxZ - 2, EnumFacing.WEST, this.getComponentType());
                            break;
                        case WEST:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX, this.boundingBox.minY, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType());
                            break;
                        case EAST:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.maxX - 2, this.boundingBox.minY, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType());
                    }
                }

                if (hasNewComponent && rand.nextInt(3) > 0 && this.coordBaseMode != null)
                {
                    switch (this.coordBaseMode)
                    {
                        case NORTH:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.maxX + 1, this.boundingBox.minY, this.boundingBox.minZ, EnumFacing.EAST, this.getComponentType());
                            break;
                        case SOUTH:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.maxX + 1, this.boundingBox.minY, this.boundingBox.maxZ - 2, EnumFacing.EAST, this.getComponentType());
                            break;
                        case WEST:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.minX, this.boundingBox.minY, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType());
                            break;
                        case EAST:
                            StructureVillagePieces.func_176069_e((StructureVillagePieces.Start)start, components, rand, this.boundingBox.maxX - 2, this.boundingBox.minY, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType());
                    }
                }
            }

            // ...
        }

    public abstract static class Village extends StructureComponent
        {
            // ...

            /**
             * Gets the next village component, with the bounding box shifted -1 in the X and Z direction.
             */
            protected StructureComponent getNextComponentNN(StructureVillagePieces.Start start, List<StructureComponent> components, Random rand, int yOffset, int lengthOffset)
            {
                if (this.coordBaseMode != null)
                {
                    switch (this.coordBaseMode)
                    {
                        case NORTH:
                            return StructureVillagePieces.func_176066_d(start, components, rand, this.boundingBox.minX - 1, this.boundingBox.minY + yOffset, this.boundingBox.minZ + lengthOffset, EnumFacing.WEST, this.getComponentType());
                        case SOUTH:
                            return StructureVillagePieces.func_176066_d(start, components, rand, this.boundingBox.minX - 1, this.boundingBox.minY + yOffset, this.boundingBox.minZ + lengthOffset, EnumFacing.WEST, this.getComponentType());
                        case WEST:
                            return StructureVillagePieces.func_176066_d(start, components, rand, this.boundingBox.minX + lengthOffset, this.boundingBox.minY + yOffset, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType());
                        case EAST:
                            return StructureVillagePieces.func_176066_d(start, components, rand, this.boundingBox.minX + lengthOffset, this.boundingBox.minY + yOffset, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType());
                    }
                }

                return null;
            }

            // ...
        }

    // 構造組件,和構造道路差不多
    private static StructureComponent func_176066_d(StructureVillagePieces.Start start, List<StructureComponent> components, Random rand, int x, int y, int z, EnumFacing facing, int componentType)
    {
        if (componentType > 50)
        {
            return null;
        }
        else if (   Math.abs(x - start.getBoundingBox().minX) <= 112
                 && Math.abs(z - start.getBoundingBox().minZ) <= 112) // 不能離起點太遠
        {
            // 構造組件,保證不與其他組件重疊
            StructureComponent component = func_176067_c(start, components, rand, x, y, z, facing, componentType + 1);

            if (component != null)
            {
                int xCenter = (component.boundingBox.minX + component.boundingBox.maxX) / 2;
                int zCenter = (component.boundingBox.minZ + component.boundingBox.maxZ) / 2;
                int xSize = component.boundingBox.maxX - component.boundingBox.minX;
                int zSize = component.boundingBox.maxZ - component.boundingBox.minZ;
                int length = xSize > zSize ? xSize : zSize;

                // 判斷中心生物羣系
                if (start.getWorldChunkManager().areBiomesViable(xCenter, zCenter, length / 2 + 4, MapGenVillage.villageSpawnBiomes))
                {
                    components.add(component);
                    // 加入後構造的組件
                    start.field_74932_i.add(component);
                    return component;
                }
            }

            return null;
        }
        else
        {
            return null;
        }
    }

    // 隨機選剩下的組件來構造
    private static StructureVillagePieces.Village func_176067_c(StructureVillagePieces.Start start, List<StructureComponent> components, Random rand, int x, int y, int z, EnumFacing facing, int componentType)
    {
        // 剩下組件的總權重
        int totalWeight = func_75079_a(start.structureVillageWeightedPieceList);

        if (totalWeight <= 0)
        {
            return null;
        }
        else
        {
            // 嘗試構造structureVillageWeightedPieceList裏的組件5次
            for (i = 0; i < 5; ++i)
            {
                // 加權隨機選一個組件
                int weight = rand.nextInt(totalWeight);

                for (StructureVillagePieces.PieceWeight piece : start.structureVillageWeightedPieceList)
                {
                    weight -= piece.villagePieceWeight;

                    // 應該生成這個組件
                    if (weight < 0)
                    {
                        if (   !piece.canSpawnMoreVillagePiecesOfType(componentType) // 已達到數量限制
                            || piece == start.structVillagePieceWeight // 上次已經生成這個了?
                            && start.structureVillageWeightedPieceList.size() > 1)
                        {
                            break;
                        }

                        // 構造組件,根據不同的class調用不同的函數
                        StructureVillagePieces.Village component = func_176065_a(start, piece, components, rand, x, y, z, facing, componentType);

                        if (component != null)
                        {
                            // 已生成數量+1
                            ++piece.villagePiecesSpawned;
                            start.structVillagePieceWeight = piece;

                            // 已達到數量限制則去掉這個組件
                            if (!piece.canSpawnMoreVillagePieces())
                            {
                                start.structureVillageWeightedPieceList.remove(piece);
                            }

                            return component;
                        }
                    }
                }
            }

            // 構造路燈包圍盒,保證不與其他組件重疊
            StructureBoundingBox structureboundingbox = StructureVillagePieces.Torch.func_175856_a(start, components, rand, x, y, z, facing);

            if (structureboundingbox != null)
            {
                // 構造路燈
                return new StructureVillagePieces.Torch(start, componentType, rand, structureboundingbox, facing);
            }
            else
            {
                return null;
            }
        }
    }

    // 計算剩下組件的總權重
    private static int func_75079_a(List<StructureVillagePieces.PieceWeight> pieces)
    {
        boolean hasPiece = false;
        int totalWeight = 0;

        for (StructureVillagePieces.PieceWeight piece : pieces)
        {
            if (   piece.villagePiecesLimit > 0
                && piece.villagePiecesSpawned < piece.villagePiecesLimit)
            {
                hasPiece = true;
            }

            totalWeight += piece.villagePieceWeight;
        }

        return hasPiece ? totalWeight : -1;
    }

這樣這個村莊的所有組件和它們的位置就決定好了,接下來該操作方塊生成整個村莊

生成村莊

在provideChunk之後還會調用populate函數,它的作用是給區塊加上礦石、樹、雪層之類的點綴,還會真正生成村莊等建築

調用populate函數的參數滿足以下條件:1)周圍4個區塊有且只有一個區塊不存在,2)參數爲這4個區塊中XZ座標最小的

它會調用這個函數,類名net.minecraft.world.gen.structure.MapGenStructure

    public boolean generateStructure(World worldIn, Random randomIn, ChunkCoordIntPair chunkCoord)
    {
        // 嘗試載入保存的結構數據,recursiveGenerate也調用過
        this.func_143027_a(worldIn);
        // 用來構造4個區塊中心16*16的包圍盒
        int xMin = (chunkCoord.chunkXPos << 4) + 8;
        int zMin = (chunkCoord.chunkZPos << 4) + 8;
        boolean generated = false;

        for (StructureStart start : this.structureMap.values())
        {
            if (   start.isSizeableStructure() // 只有村莊實現了,非道路組件>2則返回true
                && start.func_175788_a(chunkCoord) // 只有神廟實現了
                && start.getBoundingBox().intersectsWith(xMin, zMin, xMin + 15, zMin + 15)) // 這個結構和包圍盒有重疊
            {
                // 生成結構和包圍盒重疊的部分
                start.generateStructure(worldIn, randomIn, new StructureBoundingBox(xMin, zMin, xMin + 15, zMin + 15));
                // 只有神廟實現了
                start.func_175787_b(chunkCoord);
                generated = true;
                // 保存數據,recursiveGenerate也調用過
                this.func_143026_a(start.getChunkPosX(), start.getChunkPosZ(), start);
            }
        }

        return generated;
    }

類名net.minecraft.world.gen.structure.StructureStart

    /**
     * Keeps iterating Structure Pieces and spawning them until the checks tell it to stop
     */
    public void generateStructure(World worldIn, Random rand, StructureBoundingBox structurebb)
    {
        Iterator<StructureComponent> iterator = this.components.iterator();

        // 遍歷結構所有組件
        while (iterator.hasNext())
        {
            StructureComponent structurecomponent = (StructureComponent)iterator.next();

            if (   structurecomponent.getBoundingBox().intersectsWith(structurebb) // 和包圍盒有重疊
                && !structurecomponent.addComponentParts(worldIn, rand, structurebb)) // 生成組件,如果生成失敗返回false
            {
                // 組件生成失敗
                iterator.remove();
            }
        }
    }

addComponentParts由子類實現,這裏只研究水井的實現吧

類名net.minecraft.world.gen.structure.StructureVillagePieces.Well

            /**
             * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes
             * Mineshafts at the end, it adds Fences...
             */
            public boolean addComponentParts(World worldIn, Random randomIn, StructureBoundingBox structureBoundingBoxIn)
            {
                // 地面高度,默認-1
                if (this.field_143015_k < 0)
                {
                    this.field_143015_k = this.getAverageGroundLevel(worldIn, structureBoundingBoxIn);

                    if (this.field_143015_k < 0)
                    {
                        return true;
                    }

                    // 把包圍盒移動到地面
                    this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 3, 0);
                }

                // 填充水,兩個方塊參數是邊界方塊和填充方塊
                this.fillWithBlocks(worldIn, structureBoundingBoxIn, 1, 0, 1, 4, 12, 4, Blocks.cobblestone.getDefaultState(), Blocks.flowing_water.getDefaultState(), false);
                // 開口
                this.setBlockState(worldIn, Blocks.air.getDefaultState(), 2, 12, 2, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.air.getDefaultState(), 3, 12, 2, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.air.getDefaultState(), 2, 12, 3, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.air.getDefaultState(), 3, 12, 3, structureBoundingBoxIn);
                // 柵欄
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 1, 13, 1, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 1, 14, 1, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 4, 13, 1, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 4, 14, 1, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 1, 13, 4, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 1, 14, 4, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 4, 13, 4, structureBoundingBoxIn);
                this.setBlockState(worldIn, Blocks.oak_fence.getDefaultState(), 4, 14, 4, structureBoundingBoxIn);
                // 房頂
                this.fillWithBlocks(worldIn, structureBoundingBoxIn, 1, 15, 1, 4, 15, 4, Blocks.cobblestone.getDefaultState(), Blocks.cobblestone.getDefaultState(), false);

                // 底座的砂礫
                for (int x = 0; x <= 5; ++x)
                {
                    for (int z = 0; z <= 5; ++z)
                    {
                        if (z == 0 || z == 5 || x == 0 || x == 5)
                        {
                            this.setBlockState(worldIn, Blocks.gravel.getDefaultState(), z, 11, x, structureBoundingBoxIn);
                            this.clearCurrentPositionBlocksUpwards(worldIn, z, 12, x, structureBoundingBoxIn);
                        }
                    }
                }

                return true;
            }
        }

MC中沒有模型,建築全是硬編碼生成的…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章