Резкие перепады между биомами

Версия Minecraft
1.6.4
Сап форум.
Пытаюсь переписать генерацию мира таким образом, чтобы биомы были распределены по разным широтам, проще говоря - пытаюсь воссоздать климатические пояса наподобие Climatic Control и Climatic Biomes. Юзаю супердревнюю версию, но принцип генерации остался тем же, поэтому надеюсь что это не будет иметь большой роли.
За основу взял исходники BOP под свою версию, каждому биому назначил тип климата (в 1.6.4 климатических енумов не было), далее в самом первом слое генерации чуть-чуть изменил getInts, таким образом, чтобы вместо простых 0 и 1 он заполнялся либо нулем, либо, в зависимости от Z, числом от 1 до 4, где 4 - это пустыня, 3 - тропический климат, 2 - умеренный климат, 1 - холодный климат.
Почему за основу был взят BOP? Потому что на версии 1.6.4 он слоями практически целиком копирует ваниль, плюс хотелось сразу поиграться с разными вариациями уже готовых биомов.

Последовательность слоев BOP (ее не трогал):
BiomeLayer#initializeAllBiomeGenerators():
    public static GenLayer[] initializeAllBiomeGenerators(long seed, WorldType worldtype, int dim)
    {
        if(dim == 0)
        {
            BiomeLayer obj = new BiomeLayerCreate(1L, true);
            obj = new BiomeLayerFuzzyZoom(2000L, (obj));
            obj = new BiomeLayerIsland(1L, (obj));
            obj = new BiomeLayerZoom(2001L, (obj));
            obj = new BiomeLayerIsland(2L, (obj));
            obj = new BiomeLayerZoom(2002L, (obj));
            obj = new BiomeLayerIsland(3L, (obj));
            obj = new BiomeLayerZoom(2003L, (obj));
            obj = new BiomeLayerIsland(4L, (obj));

            byte size = 4;
            size = getModdedBiomeSize(worldtype, size);

            BiomeLayer obj1 = obj;
            obj1 = BiomeLayerZoom.func_75915_a(1000L, ((obj1)), 0);
            obj1 = new BiomeLayerRiverInit(100L, ((obj1)));
            obj1 = BiomeLayerZoom.func_75915_a(1000L, ((obj1)), size + 2);
            obj1 = new BiomeLayerRiver(1L, ((obj1)));
            obj1 = new BiomeLayerSmooth(1000L, ((obj1)));

            BiomeLayer obj2 = obj;
            obj2 = BiomeLayerZoom.func_75915_a(1000L, ((obj2)), 0);
            obj2 = new BiomeLayerBiomes(200L, ((obj2)), worldtype, 0);
            obj2 = BiomeLayerZoom.func_75915_a(1000L, ((obj2)), 2);
            obj2 = new BiomeLayerSub(1000L, ((BiomeLayer)(obj2)));
            obj2 = new BiomeLayerZoom(1000, ((obj2)));
            obj2 = new BiomeLayerShore(1000L, ((BiomeLayer)(obj2)));

            for (int i = 0 + 1; i < size; i++)
            {
                obj2 = new BiomeLayerZoom(1000 + i, ((obj2)));
            }

            obj2 = new BiomeLayerSmooth(1000L, ((obj2)));
            obj2 = new BiomeLayerRiverMix(100L, ((obj2)), ((obj1)));
            BiomeLayerRiverMix bwg4layerrivermix = ((BiomeLayerRiverMix)(obj2));
            BiomeLayerVoronoiZoom genlayervoronoizoom = new BiomeLayerVoronoiZoom(10L, ((obj2)));
            (obj2).initWorldGenSeed(seed);
            genlayervoronoizoom.initWorldGenSeed(seed);

            return (new GenLayer[]
                    {
                    obj2, genlayervoronoizoom, bwg4layerrivermix
                    });
        }
        else
        {
            int biomesize = 3;
            if(dim == 1)
            {
                biomesize = 2;
            }

            //Hell and promised biome gen
            BiomeLayer obj = new BiomeLayerCreate(1L, false);
            obj = new BiomeLayerFuzzyZoom(2000L, (obj));
            for(int i = 1; i < 3; i++) { obj = new BiomeLayerZoom(2000L + i, (obj)); }
            obj = BiomeLayerZoom.func_75915_a(1000L, ((obj)), 0);
            obj = new BiomeLayerBiomes(200L, ((obj)), worldtype, dim);
            obj = BiomeLayerZoom.func_75915_a(1000L, ((obj)), 2);
            for(int j = 0; j < biomesize; j++) { obj = new BiomeLayerZoom(1000L + j, (obj)); }
            BiomeLayerVoronoiZoom genlayervoronoizoom = new BiomeLayerVoronoiZoom(10L, ((obj)));
            (obj).initWorldGenSeed(seed);
            genlayervoronoizoom.initWorldGenSeed(seed);
            return (new GenLayer[] { obj, genlayervoronoizoom });
        }
    }

Привожу метод из слоя BiomeLayerCreate

BiomeLayerCreate#getInts():
@Override
    public int[] getInts(int par1, int par2, int par3, int par4)
    {
        int[] var5 = IntCache.getIntCache(par3 * par4);

        boolean ocean = BOPConfigurationBiomeGen.oceanGen;
        boolean abyss = Biomes.oceanAbyss.isPresent();
        boolean coral = Biomes.oceanCoral.isPresent();
        boolean kelp = Biomes.oceanKelp.isPresent();

        for (int var6 = 0; var6 < par4; ++var6)
        {
            for (int var7 = 0; var7 < par3; ++var7)
            {
                this.initChunkSeed(par1 + var7, par2 + var6);
                if(ocean)
                {
                    if(abyss) { var5[var7 + var6 * par3] = this.nextInt(50) == 0 ? 1 : Biomes.oceanAbyss.get().biomeID; }
                    else if(coral) { var5[var7 + var6 * par3] = this.nextInt(20) == 0 ? 1 : Biomes.oceanCoral.get().biomeID; }
                    else if(kelp) { var5[var7 + var6 * par3] = this.nextInt(20) == 0 ? 1 : Biomes.oceanKelp.get().biomeID; }
                    else { var5[var7 + var6 * par3] = this.nextInt(10) == 0 ? 1 : 0;}
                }
                else
                {
                    int a = 1;
                    if (par2<-2) a=1;
                    if (par2>=-2 && par2<-1) a=2;
                    if (par2>=-1 && par2<0) a=3;
                    if (par2>=0) a=4;
                    var5[var7 + var6 * par3] = a;
                }
            }
        }

        if(ocean)
        {
            if (par1 > -par3 && par1 <= 0 && par2 > -par4 && par2 <= 0)
            {
                var5[-par1 + -par2 * par3] = 1;
            }
        }

        return var5;
    }

По поводу кода выше - я прекрасно понимаю, что назначать таким образом пояса не совсем правильно, но по факту я просто хочу создать хотя бы работающий прототип, поэтому это не так важно.

Далее, назначение биомов в BiomeLayerBiome:
BiomeLayerBiome#getInts():
  @Override
    public int[] getInts(int x, int z, int width, int height)
    {
        Climat climat = null;
        int[] var5 = this.parent.getInts(x, z, width, height);
        int[] var6 = IntCache.getIntCache(width * height);
      
        boolean abyss = Biomes.oceanCoral.isPresent();
        boolean coral = Biomes.oceanCoral.isPresent();
        boolean kelp = Biomes.oceanKelp.isPresent();
      
        for (int iz = 0; iz < height; ++iz)
        {
            for (int ix = 0; ix < width; ++ix)
            {
                this.initChunkSeed((long)(ix + x), (long)(iz + z));
                int var9 = var5[ix + iz * width];
                if(dimension == 0) //SURFACE BIOMES
                {
                    if (var9 == 0)
                    {
                        var6[ix + iz * width] = 0;
                    }
                    else
                    {
                        if (var9==1) climat = Climat.NORTH;
                        if (var9==2) climat = Climat.MID;
                        if (var9==3) climat = Climat.TROPIC;
                        if (var9==4) climat = Climat.DESERT;
                        var6[ix + iz * width] = getRandomBiomeOfType(climat);
                    }
                  
                    if (abyss)
                    {
                        if(var9 == Biomes.oceanAbyss.get().biomeID)
                        {
                            var6[ix + iz * width] = oceanBiomes.get(this.nextInt(oceanBiomes.size())).biomeID;
                        }
                    }
                  
                    if (coral)
                    {
                        if(var9 == Biomes.oceanCoral.get().biomeID)
                        {
                            var6[ix + iz * width] = oceanBiomes.get(this.nextInt(oceanBiomes.size())).biomeID;
                        }
                    }
                  
                    if (kelp)
                    {
                        if(var9 == Biomes.oceanKelp.get().biomeID)
                        {
                            var6[ix + iz * width] = oceanBiomes.get(this.nextInt(oceanBiomes.size())).biomeID;
                        }
                    }

                }
                else if(dimension == 1) //HELL BIOMES
                {
                    var6[ix + iz * width] = netherBiomes.get(this.nextInt(netherBiomes.size())).biomeID;
                }
                else if(dimension == 2) //PROMISED BIOMES
                {
                    var6[ix + iz * width] = promisedBiomes.get(this.nextInt(promisedBiomes.size())).biomeID;
                }
                else
                {
                    var6[ix + iz * width] = surfaceBiomes[this.nextInt(surfaceBiomes.length)].biomeID;
                }
            }
        }
        return var6;
    }

Метод, выбирающий случайный биом определенного климата:
BiomeLayerBiome#getRandomBiomeOfType():
    public int getRandomBiomeOfType(Climat climat){
        while (true) {
            int b = this.nextInt(BiomeGenBase.biomeList.length);
            if (BiomeDictionary.isBiomeRegistered(b)) {
                {
                    if (BiomeGenBase.biomeList[b] instanceof IClimaticBIome){
                        IClimaticBIome bb = (IClimaticBIome) BiomeGenBase.biomeList[b];
                        if (bb.getClimat()==climat){
                            return BiomeGenBase.biomeList[b].biomeID;
                        }
                    }

                }
            }
        }
    }

Собственно, на этом все мои действия заканчиваются. Климатические пояса есть, в определенных мною широтах генерируются случайные биомы из заданной категории, однако границы между климатическими поясами слишком резкие в плане высоты. Вот пример:
Screenshot_89 (1).png
Screenshot_88.png
Это касается только тех биомов, у которых minHeight и maxHeight различаются. Если всем биомам задать их одинаковыми, перепадов не будет.
Что странно, при обычной генерации этих перепадов нет даже между очень разными по высотам биомами.
Собственно вопрос - как подобное исправить?
 
Последнее редактирование:
Решение
Вот пример распределения типов биомов по октантам.
1) За основу взял ванильный алгоритм.
2) Выкинул GenLayerAddSnow.
3) Убрал GenLayerEdge.COOL_WARM, GenLayerEdge.HEAT_ICE и вместо них вставил свой слой GenLayerClimate. Но GenLayerEdge.SPECIAL оставил.
4) Убрал GenLayerAddMushroomIsland.

Java:
package ddooss.world.gen.layer.climate;

import minecraft.world.gen.layer.GenLayer;
import minecraft.world.gen.layer.IntCache;

public class GenLayerClimate extends GenLayer {

    public GenLayerClimate(long seed, GenLayer parent) {
        super(seed);
        this.parent = parent;
    }

    public int[] getInts(int areaX, int areaY, int areaWidth, int...
102
3
77
Вот пример распределения типов биомов по октантам.
1) За основу взял ванильный алгоритм.
2) Выкинул GenLayerAddSnow.
3) Убрал GenLayerEdge.COOL_WARM, GenLayerEdge.HEAT_ICE и вместо них вставил свой слой GenLayerClimate. Но GenLayerEdge.SPECIAL оставил.
4) Убрал GenLayerAddMushroomIsland.

Java:
package ddooss.world.gen.layer.climate;

import minecraft.world.gen.layer.GenLayer;
import minecraft.world.gen.layer.IntCache;

public class GenLayerClimate extends GenLayer {

    public GenLayerClimate(long seed, GenLayer parent) {
        super(seed);
        this.parent = parent;
    }

    public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight) {
        int i = areaX - 1;
        int j = areaY - 1;
        int k = 1 + areaWidth + 1;
        int l = 1 + areaHeight + 1;
        int[] aint = this.parent.getInts(i, j, k, l);
        int[] aint1 = IntCache.getIntCache(areaWidth * areaHeight);

        for (int i1 = 0; i1 < areaHeight; ++i1) {
            for (int j1 = 0; j1 < areaWidth; ++j1) {
                this.initChunkSeed((long) (j1 + areaX), (long) (i1 + areaY));
                int k1 = aint[j1 + 1 + (i1 + 1) * k];
                int i2 = i1 + areaY;
                int j2 = j1 + areaX;

                if (k1 == 1) {
                    if (j2 >= 0 && i2 >= 0) {
                        k1 = 1;
                    } else if (j2 <= 0 && i2 <= 0) {
                        k1 = 3;
                    } else if (j2 > 0 && i2 < 0) {
                        k1 = 2;
                    } else {
                        k1 = 4;
                    }
                }

                aint1[j1 + i1 * areaWidth] = k1;
            }
        }

        return aint1;
    }
}

Вот результат (На самом деле нет. Тут 3200 чанков и настоящая картинка на сайт не загрузится):
Вверху справа– теплые биомы; Вверху слева– умеренные биомы; Внизу слева– холодные биомы; Снизу справа – снежные биомы.

25 GenLayerShore 1604x1604.png

Чтоб ты понимал, что тут все действительно по октантам, вот один из зумов (после разделения на типы биомов):

15 GenLayerDeepOcean 105x105.png


Далее - если хочешь по каким-то "широтам разбивать", то алгоритм похожий. И да, я уже писал, что проблема чанкволлов не в генераторе биомов. Какие бы биомы рядом не находились, ванильный маинкрафт всегда генерит перепады плавно. У тебя проблема в другом месте, а не в генераторе биомов.

UPD. Вот алгоритм

Java:
public static GenLayer climate2(long seed) {
        GenLayer genlayer = new GenLayerIsland(1L);
        genlayer = new GenLayerFuzzyZoom(2000L, genlayer);
        GenLayer genlayeraddisland = new GenLayerAddIsland(1L, genlayer);
        GenLayer genlayerzoom = new GenLayerZoom(2001L, genlayeraddisland);
        GenLayer genlayeraddisland1 = new GenLayerAddIsland(2L, genlayerzoom);
        genlayeraddisland1 = new GenLayerAddIsland(50L, genlayeraddisland1);
        genlayeraddisland1 = new GenLayerAddIsland(70L, genlayeraddisland1);
        GenLayer genlayerremovetoomuchocean = new GenLayerRemoveTooMuchOcean(2L, genlayeraddisland1);
        GenLayer genlayeraddisland2 = new GenLayerAddIsland(3L, genlayerremovetoomuchocean);
        GenLayer genlayerclimate = new GenLayerClimate(3L, genlayeraddisland2);
        GenLayer genlayeredge = new GenLayerEdge(3L, genlayerclimate, GenLayerEdge.Mode.SPECIAL);
        GenLayer genlayerzoom1 = new GenLayerZoom(2002L, genlayeredge);
        genlayerzoom1 = new GenLayerZoom(2003L, genlayerzoom1);
        GenLayer genlayeraddisland3 = new GenLayerAddIsland(4L, genlayerzoom1);
        GenLayer genlayerdeepocean = new GenLayerDeepOcean(4L, genlayeraddisland3);
        GenLayer genlayer4 = GenLayerZoom.magnify(1000L, genlayerdeepocean, 0);
        int biomeSize = 4;
        int riverSize = biomeSize;
        GenLayer lvt_7_1_ = GenLayerZoom.magnify(1000L, genlayer4, 0);
        GenLayer genlayerriverinit = new GenLayerRiverInit(100L, lvt_7_1_);
        GenLayer genlayerbiome = new GenLayerBiome(200L, genlayer4);
        genlayerbiome = GenLayerZoom.magnify(1000L, genlayerbiome, 2);
        GenLayer genlayerbiomeedge = new GenLayerBiomeEdge(1000L, genlayerbiome);
        GenLayer lvt_9_1_ = GenLayerZoom.magnify(1000L, genlayerriverinit, 2);
        GenLayer genlayerhills = new GenLayerHills(1000L, genlayerbiomeedge, lvt_9_1_);
        GenLayer genlayer5 = GenLayerZoom.magnify(1000L, genlayerriverinit, 2);
        genlayer5 = GenLayerZoom.magnify(1000L, genlayer5, riverSize);
        GenLayer genlayerriver = new GenLayerRiver(1L, genlayer5);
        GenLayer genlayersmooth = new GenLayerSmooth(1000L, genlayerriver);
        genlayerhills = new GenLayerRareBiome(1001L, genlayerhills);

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

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

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

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

Вложения

  • 13 GenLayerZoom 109x109.png
    13 GenLayerZoom 109x109.png
    2.1 KB · Просмотры: 0
Последнее редактирование:
Java:
  /**
     * the first array item is a linked list of the bioms, the second is the zoom function, the third is the same as the
     * first.
     */
    public static GenLayer[] initializeAllBiomeGenerators(long par0, WorldType par2WorldType)
    {
        GenLayerIsland genlayerisland = new GenLayerIsland(1L);
        GenLayerFuzzyZoom genlayerfuzzyzoom = new GenLayerFuzzyZoom(2000L, genlayerisland);
        GenLayerAddIsland genlayeraddisland = new GenLayerAddIsland(1L, genlayerfuzzyzoom);
        GenLayerZoom genlayerzoom = new GenLayerZoom(2001L, genlayeraddisland);
        genlayeraddisland = new GenLayerAddIsland(2L, genlayerzoom);
        GenLayerAddSnow genlayeraddsnow = new GenLayerAddSnow(2L, genlayeraddisland);
        genlayerzoom = new GenLayerZoom(2002L, genlayeraddsnow);
        genlayeraddisland = new GenLayerAddIsland(3L, genlayerzoom);
        genlayerzoom = new GenLayerZoom(2003L, genlayeraddisland);
        genlayeraddisland = new GenLayerAddIsland(4L, genlayerzoom);
        GenLayerAddMushroomIsland genlayeraddmushroomisland = new GenLayerAddMushroomIsland(5L, genlayeraddisland);
        byte b0 = 4;

        if (par2WorldType == WorldType.LARGE_BIOMES)
        {
            b0 = 6;
        }
        b0 = getModdedBiomeSize(par2WorldType, b0);

        GenLayer genlayer = GenLayerZoom.magnify(1000L, genlayeraddmushroomisland, 0);
        GenLayerRiverInit genlayerriverinit = new GenLayerRiverInit(100L, genlayer);
        genlayer = GenLayerZoom.magnify(1000L, genlayerriverinit, b0 + 2);
        GenLayerRiver genlayerriver = new GenLayerRiver(1L, genlayer);
        GenLayerSmooth genlayersmooth = new GenLayerSmooth(1000L, genlayerriver);
        GenLayer genlayer1 = GenLayerZoom.magnify(1000L, genlayeraddmushroomisland, 0);
        GenLayerBiome genlayerbiome = new GenLayerBiome(200L, genlayer1, par2WorldType);
        genlayer1 = GenLayerZoom.magnify(1000L, genlayerbiome, 2);
        Object object = new GenLayerHills(1000L, genlayer1);

        for (int j = 0; j < b0; ++j)
        {
            object = new GenLayerZoom((long)(1000 + j), (GenLayer)object);

            if (j == 0)
            {
                object = new GenLayerAddIsland(3L, (GenLayer)object);
            }

            if (j == 1)
            {
                object = new GenLayerShore(1000L, (GenLayer)object);
            }

            if (j == 1)
            {
                object = new GenLayerSwampRivers(1000L, (GenLayer)object);
            }
        }

        GenLayerSmooth genlayersmooth1 = new GenLayerSmooth(1000L, (GenLayer)object);
        GenLayerRiverMix genlayerrivermix = new GenLayerRiverMix(100L, genlayersmooth1, genlayersmooth);
        GenLayerVoronoiZoom genlayervoronoizoom = new GenLayerVoronoiZoom(10L, genlayerrivermix);
        genlayerrivermix.initWorldGenSeed(par0);
        genlayervoronoizoom.initWorldGenSeed(par0);
        return new GenLayer[] {genlayerrivermix, genlayervoronoizoom, genlayerrivermix};
    }
 
102
3
77
Значит в другом слое на типы биомов разделяется, либо с самого начала уже типы биомов есть. В любом случае тебе это разделение на типы биомов нужно заменить на свое. Посмотри GenLayerIsland, GenLayerAddSnow, GenLayerAddIsland
 
Да, и правда. Я не в том месте и не от тех аргументов плясал с выбором климатических зон. Твой климатический слой делает это верно и не оставляет резких перепадов на границах, благодарю.
А если по широтам делать, по оси Y?
Не совсем понимаю за что зацепиться по аналогии с твоим способом
Java:
    if (j2 >= 0 && i2 >= 0) {
                        k1 = 1;
                    } else if (j2 <= 0 && i2 <= 0) {
                        k1 = 3;
                    } else if (j2 > 0 && i2 < 0) {
                        k1 = 2;
                    } else {
                        k1 = 4;
                    }
ты просто по знакам аргументы проверяешь на двух осях, а мне надо только по оси Y четыре разных зоны разбить. С какими числами мне i2 сравнивать?
 
102
3
77
Сверху