Minecraft的世界生成过程(二)生物群系

本文深入探讨Minecraft的生物群系生成过程,详细介绍了GenLayer的各个层级,如GenLayerIsland、GenLayerZoom、GenLayerRemoveTooMuchOcean等,以及它们在生成区块中的作用,包括创建岛屿、减少海洋、添加特殊生物群系等,揭示了生物群系与地形之间的复杂关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

终于看到生成区块的代码了,接下来比较复杂,分成几篇文章吧

本篇内容是生物群系的算法

生成生物群系总流程

接着上篇文章我们看到这个函数

类名net.minecraft.world.gen.ChunkProviderGenerate

    /**
     * Will return back a chunk, if it doesn't exist and its not a MP client it will generates all the blocks for the
     * specified chunk from the map seed and chunk seed
     */
    public Chunk provideChunk(int x, int z)
    {
        // 根据区块坐标设置随机种子
        this.rand.setSeed((long)x * 341873128712L + (long)z * 132897987541L);
        // 这个是生成区块时临时储存方块数据的对象,后面会转为Chunk对象
        ChunkPrimer chunkprimer = new ChunkPrimer();
        // 生成基本地形(没有洞穴等建筑)
        this.setBlocksInChunk(x, z, chunkprimer);
        // ...
    }

    public void setBlocksInChunk(int x, int z, ChunkPrimer chunkprimer)
    {
        // 决定生物群系,这里把区块坐标*4-2了,而且结果是10*10的
        this.biomesForGeneration = this.worldObj.getWorldChunkManager().getBiomesForGeneration(this.biomesForGeneration, x * 4 - 2, z * 4 - 2, 10, 10);
        // ...
    }

类名net.minecraft.world.biome.WorldChunkManager

    /**
     * Returns an array of biomes for the location input.
     */
    public BiomeGenBase[] getBiomesForGeneration(BiomeGenBase[] result, int x, int z, int width, int height)
    {
        IntCache.resetIntCache();

        if (result == null || result.length < width * height)
        {
            result = new BiomeGenBase[width * height];
        }

        // 生成生物群系ID
        int[] biomeId = this.genBiomes.getInts(x, z, width, height);

        try
        {
            for (int i = 0; i < width * height; ++i)
            {
                // 把生物群系ID转成BiomeGenBase对象
                result[i] = BiomeGenBase.getBiomeFromBiomeList(biomeId[i], BiomeGenBase.field_180279_ad);
            }

            return result;
        }
        catch (Throwable throwable)
        {
            // ...
        }
    }

    public WorldChunkManager(long seed, WorldType p_i45744_3_, String p_i45744_4_)
    {
        this();
        this.field_180301_f = p_i45744_4_;
        GenLayer[] agenlayer = GenLayer.initializeAllBiomeGenerators(seed, p_i45744_3_, p_i45744_4_);
        agenlayer = getModdedBiomeGenerators(p_i45744_3_, seed, agenlayer);
        // 这里初始化了genBiomes
        this.genBiomes = agenlayer[0];
        this.biomeIndexLayer = agenlayer[1];
    }

接下来就非常复杂了,net.minecraft.world.gen.layer这个包里有很多GenLayer,每层都会用上一层的输出生成这一层的输出

调用堆栈
调用堆栈

它们的初始化函数如下,最后的genlayerrivermix就是用来生成生物群系的

类名net.minecraft.world.gen.layer.GenLayer

    public static GenLayer[] initializeAllBiomeGenerators(long worldSeed, WorldType worldType, String settings)
    {
        GenLayer genlayer = new GenLayerIsland(1L);
        genlayer = new GenLayerFuzzyZoom(2000L, genlayer);
        GenLayerAddIsland genlayeraddisland = new GenLayerAddIsland(1L, genlayer);
        GenLayerZoom genlayerzoom = new GenLayerZoom(2001L, genlayeraddisland);
        GenLayerAddIsland genlayeraddisland1 = new GenLayerAddIsland(2L, genlayerzoom);
        genlayeraddisland1 = new GenLayerAddIsland(50L, genlayeraddisland1);
        genlayeraddisland1 = new GenLayerAddIsland(70L, genlayeraddisland1);
        GenLayerRemoveTooMuchOcean genlayerremovetoomuchocean = new GenLayerRemoveTooMuchOcean(2L, genlayeraddisland1);
        GenLayerAddSnow genlayeraddsnow = new GenLayerAddSnow(2L, genlayerremovetoomuchocean);
        GenLayerAddIsland genlayeraddisland2 = new GenLayerAddIsland(3L, genlayeraddsnow);
        GenLayerEdge genlayeredge = new GenLayerEdge(2L, genlayeraddisland2, GenLayerEdge.Mode.COOL_WARM);
        genlayeredge = new GenLayerEdge(2L, genlayeredge, GenLayerEdge.Mode.HEAT_ICE);
        genlayeredge = new GenLayerEdge(3L, genlayeredge, GenLayerEdge.Mode.SPECIAL);
        GenLayerZoom genlayerzoom1 = new GenLayerZoom(2002L, genlayeredge);
        genlayerzoom1 = new GenLayerZoom(2003L, genlayerzoom1);
        GenLayerAddIsland genlayeraddisland3 = new GenLayerAddIsland(4L, genlayerzoom1);
        GenLayerAddMushroomIsland genlayeraddmushroomisland = new GenLayerAddMushroomIsland(5L, genlayeraddisland3);
        GenLayerDeepOcean genlayerdeepocean = new GenLayerDeepOcean(4L, genlayeraddmushroomisland);
        GenLayer genlayer4 = GenLayerZoom.magnify(1000L, genlayerdeepocean, 0);
        ChunkProviderSettings chunkprovidersettings = null;
        int biomeSize = 4;
        int riverSize = biomeSize;

        if (worldType == WorldType.CUSTOMIZED && settings.length() > 0)
        {
            chunkprovidersettings = ChunkProviderSettings.Factory.jsonToFactory(settings).func_177864_b();
            biomeSize = chunkprovidersettings.biomeSize;
            riverSize = chunkprovidersettings.riverSize;
        }

        if (worldType == WorldType.LARGE_BIOMES)
        {
            biomeSize = 6;
        }

        biomeSize = getModdedBiomeSize(worldType, biomeSize);

        GenLayer lvt_8_1_ = GenLayerZoom.magnify(1000L, genlayer4, 0);
        GenLayerRiverInit genlayerriverinit = new GenLayerRiverInit(100L, lvt_8_1_);
        GenLayer lvt_10_1_ = GenLayerZoom.magnify(1000L, genlayerriverinit, 2);
        GenLayer genlayerbiomeedge = worldType.getBiomeLayer(worldSeed, genlayer4, settings);
        GenLayer genlayerhills = new GenLayerHills(1000L, genlayerbiomeedge, lvt_10_1_);
        GenLayer genlayer5 = GenLayerZoom.magnify(1000L, genlayerriverinit, 2);
        genlayer5 = GenLayerZoom.magnify(1000L, genlayer5, riverSize);
        GenLayerRiver genlayerriver = new GenLayerRiver(1L, genlayer5);
        GenLayerSmooth genlayersmooth = new GenLayerSmooth(1000L, genlayerriver);
        genlayerhills = new GenLayerRareBiome(1001L, genlayerhills);

        for (int i = 0; i < biomeSize; ++i)
        {
            genlayerhills = new GenLayerZoom((long)(1000 + i), genlayerhills);

            if (i == 0)
            {
                genlayerhills = new GenLayerAddIsland(3L, genlayerhills);
            }

            if (i == 1 || biomeSize == 1)
            {
                genlayerhills = new GenLayerShore(1000L, genlayerhills);
            }
        }

        GenLayerSmooth genlayersmooth1 = new GenLayerSmooth(1000L, genlayerhills);
        GenLayerRiverMix genlayerrivermix = new GenLayerRiverMix(100L, genlayersmooth1, genlayersmooth);
        GenLayer genlayer3 = new GenLayerVoronoiZoom(10L, genlayerrivermix);
        genlayerrivermix.initWorldGenSeed(worldSeed);
        genlayer3.initWorldGenSeed(worldSeed);
        return new GenLayer[] {genlayerrivermix, genlayer3, genlayerrivermix};
    }

各层GenLayer

GenLayer生成的就是生物群系ID,对应的生物群系可以在net.minecraft.world.biome.BiomeGenBase查看。每个GenLayer有3个种子,baseSeed初始化时指定,worldGenSeed世界种子,chunkSeed计算时根据坐标计算。还有一个parent层,初始化时指定

GenLayerIsland

这个是最底层,很简单,随机生成1和0(平原和海洋)

    /**
     * Returns a list of integer values generated by this layer. These may be interpreted as temperatures, rainfall
     * amounts, or biomeList[] indices based on the particular GenLayer subclass.
     */
    public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
    {
        // IntCache用来避免反复分配内存,提高性能,后面还会看到很多次
        int[] result = IntCache.getIntCache(areaWidth * areaHeight);

        for (int y = 0; y < areaHeight; ++y)
        {
            for (int x = 0; x < areaWidth; ++x)
            {
                this.initChunkSeed((long)(areaX + x), (long)(areaY + y));
                // 1/10的概率为1,其他为0
                result[x + y * areaWidth] = this.nextInt(10) == 0 ? 1 : 0;
            }
        }

        if (-areaWidth < areaX && areaX <= 0 && -areaHeight < areaY && areaY <= 0)
        {
            result[-areaX - areaY * areaWidth] = 1;
        }

        return result;
    }

    // 以下两个函数是基类(GenLayer)的,以后会经常用到

    /**
     * Initialize layer's current chunkSeed based on the local worldGenSeed and the (x,z) chunk coordinates.
     */
    public void initChunkSeed(long x, long y)
    {
        this.chunkSeed = this.worldGenSeed;
        this.chunkSeed *= this.chunkSeed * 6364136223846793005L + 1442695040888963407L;
        this.chunkSeed += x;
        this.chunkSeed *= this.chunkSeed * 6364136223846793005L + 1442695040888963407L;
        this.chunkSeed += y;
        this.chunkSeed *= this.chunkSeed * 6364136223846793005L + 1442695040888963407L;
        this.chunkSeed += x;
        this.chunkSeed *= this.chunkSeed * 6364136223846793005L + 1442695040888963407L;
        this.chunkSeed += y;
    }

    /**
     * returns a LCG pseudo random number from [0, x). Args: int x
     */
    protected int nextInt(int upperLimit)
    {
        int i = (int)((this.chunkSeed >> 24) % (long)upperLimit);

        if (i < 0)
        {
            i += upperLimit;
        }

        this.chunkSeed *= this.chunkSeed * 6364136223846793005L + 1442695040888963407L;
        this.chunkSeed += this.worldGenSeed;
        return i;
    }

GenLayerZoom、GenLayerFuzzZoom

这层作用是把上一层结果放大,采样方式是在附近4个点随机采样

    public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
    {
        // parent尺度是本层的1/2
        int parentAreaX = areaX / 2;
        int parentAreaY = areaY / 2;
        // +2添加边界
        int parentWidth  = areaWidth  / 2 + 2;
        int parentHeight = areaHeight / 2 + 2;
        // parentRes是本层的1/4
        int[] parentRes = this.parent.getInts(parentAreaX, parentAreaY, parentWidth, parentHeight);
        int tmpWidth  = (parentWidth  - 1) * 2;
        int tmpHeight = (parentHeight - 1) * 2;
        // 临时结果
        int[] tmp = IntCache.getIntCache(tmpWidth * tmpHeight);

        for (int parentY = 0; parentY < parentHeight - 1; ++parentY)
        {
            // tmp中当前点索引
            int tmpIndex = (parentY * 2) * tmpWidth;
            // parent当前点的值
            int parentValue   = parentRes[ parentY      * parentWidth];
            // parent当前点y+1点的值
            int parentValueY1 = parentRes[(parentY + 1) * parentWidth];

            for (int parentX = 0; parentX < parentWidth - 1; ++parentX)
            {
                this.initChunkSeed((parentX + parentAreaX) * 2, (parentY + parentAreaY) * 2);
                // parent当前点x+1点的值
                int parentValueX1   = parentRes[parentX + 1 +  parentY      * parentWidth];
                // parent当前点x+1, y+1点的值
                int parentValueX1Y1 = parentRes[parentX + 1 + (parentY + 1) * parentWidth];

                // 当前点值 = parent点值
                tmp[tmpIndex] = parentValue;
                // 当前点y+1值 = 在 parent点、parent点y+1 中随机选
                tmp[tmpIndex + tmpWidth] = this.selectRandom(new int[] {parentValue, parentValueY1});
                // 当前点移动x+1
                ++tmpIndex;

                // 当前点值 = 在 parent点、parent点x+1 中随机选
                tmp[tmpIndex] = this.selectRandom(new int[] {parentValue, parentValueX1});
                // 当前点y+1值 = parent四个点值中的众数或随机选
                tmp[tmpIndex + tmpWidth] = this.selectModeOrRandom(parentValue, parentValueX1, parentValueY1, parentValueX1Y1);
                // 当前点移动x+1
                ++tmpIndex;

                // parent当前点移动x+1
                parentValue = parentValueX1;
                parentValueY1 = parentValueX1Y1;
            }
        }

        int[] result = IntCache.getIntCache(areaWidth * areaHeight);

        // tmp和result尺寸可能不同,这里把tmp左上角部分复制到result
        for (int resultY = 0; resultY < areaHeight; ++resultY)
        {
            System.arraycopy(tmp, (resultY + areaY % 2) * tmpWidth + areaX % 2, result, resultY * areaWidth, areaWidth);
        }

        return result;
    }

GenLayerAddIsland

从名字来看貌似是用来添加岛屿的

    public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight)
    {
        int parentAreaX = areaX - 1;
        int parentAreaY = areaY - 1;
        int parentWidth = areaWidth + 2;
        int parentHeight = areaHeight + 2;
        int[] parentRes = this.parent.getInts(parentAreaX, parentAreaY, parentWidth, parentHeight);
        int[] result = IntCache.getIntCache(areaWidth * areaHeight);

        for (int y = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值