diff --git a/biome_tree.c b/biome_tree.c index 98b9755..a139ec1 100644 --- a/biome_tree.c +++ b/biome_tree.c @@ -4362,13 +4362,13 @@ int get_resulting_node(const struct _args *arg, int idx, int alt, uint64_t ds, i uint32_t step; do { + if (depth >= 4) { + __builtin_unreachable(); + //fprintf(stderr, "get_resulting_node(): fatal error\n"); + //exit(1); + } step = steps[depth]; depth++; - if (depth > 4) - { - fprintf(stderr, "get_resulting_node(): fatal error\n"); - exit(1); - } } while (idx+step >= arg->len); diff --git a/finders.c b/finders.c index 58061e2..4b0fe19 100644 --- a/finders.c +++ b/finders.c @@ -3028,19 +3028,19 @@ int checkForBiomes( int err = 0; do { - err = getParaRange(&g->bn.temperature, &tmin, &tmax, + err = getParaRange(&g->bn.climate[NP_TEMPERATURE], &tmin, &tmax, r.x, r.z, r.sx, r.sz, info, f_graddesc_test); if (err) break; - err = getParaRange(&g->bn.humidity, &tmin, &tmax, + err = getParaRange(&g->bn.climate[NP_HUMIDITY], &tmin, &tmax, r.x, r.z, r.sx, r.sz, info, f_graddesc_test); if (err) break; - err = getParaRange(&g->bn.erosion, &tmin, &tmax, + err = getParaRange(&g->bn.climate[NP_EROSION], &tmin, &tmax, r.x, r.z, r.sx, r.sz, info, f_graddesc_test); if (err) break; - //err = getParaRange(&g->bn.continentalness, &tmin, &tmax, + //err = getParaRange(&g->bn.climate[NP_CONTINENTALNESS], &tmin, &tmax, // r.x, r.z, r.sx, r.sz, info, f_graddesc_test); //if (err) break; - //err = getParaRange(&g->bn.weirdness, &tmin, &tmax, + //err = getParaRange(&g->bn.climate[NP_WEIRDNESS], &tmin, &tmax, // r.x, r.z, r.sx, r.sz, info, f_graddesc_test); //if (err) break; } @@ -4471,6 +4471,25 @@ static const int g_biome_para_range_19_diff[][13] = { {mangrove_swamp , 2000, IMAX, IMIN, IMAX, -1100, IMAX, 5500, IMAX, IMIN, IMAX, IMIN, IMAX}, }; + +/** + * Gets the min/max parameter values within which a biome change can occur. + */ +const int *getBiomeParaExtremes(int mc) +{ + if (mc < MC_1_18) + return NULL; + static const int extremes[] = { + -4501, 5500, + -3500, 6999, + -10500, 300, + -7799, 5500, + 1000, 10500, // depth has more dependencies + -9333, 9333, + }; + return extremes; +} + /** * Gets the min/max possible noise parameter values at which the given biome * can generate. The values are in min/max pairs in order: @@ -4528,5 +4547,3 @@ void getPossibleBiomesForLimits(char ids[256], int mc, int limits[6][2]) } - - diff --git a/finders.h b/finders.h index 3796ade..04c9593 100644 --- a/finders.h +++ b/finders.h @@ -799,6 +799,11 @@ double getParaDescent(const DoublePerlinNoise *para, double factor, int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax, int x, int z, int w, int h, void *data, int (*func)(void*,int,int,double)); +/** + * Gets the min/max parameter values within which a biome change can occur. + */ +const int *getBiomeParaExtremes(int mc); + /** * Gets the min/max possible noise parameter values at which the given biome * can generate. The values are in min/max pairs in order of: diff --git a/layers.c b/layers.c index 773f60f..2c82435 100644 --- a/layers.c +++ b/layers.c @@ -1090,63 +1090,109 @@ int genEndScaled(const EndNoise *en, int *out, Range r, int mc, uint64_t sha) // Overworld and Nether Biome Generation 1.18 //============================================================================== -void setBiomeSeed(BiomeNoise *bn, uint64_t seed, int large) +static int init_climate_seed( + DoublePerlinNoise *dpn, PerlinNoise *oct, + uint64_t xlo, uint64_t xhi, int large, int nptype + ) { Xoroshiro pxr; int n = 0; + switch (nptype) + { + case NP_SHIFT: { + double amp_s[] = {1, 1, 1, 0}; + int len = sizeof(amp_s)/sizeof(double); + // md5 "minecraft:offset" + pxr.lo = xlo ^ 0x080518cf6af25384; + pxr.hi = xhi ^ 0x3f3dfb40a54febd5; + n += xDoublePerlinInit(dpn, &pxr, oct, amp_s, -3, len); + } break; + + case NP_TEMPERATURE: { + double amp_t[] = {1.5, 0, 1, 0, 0, 0}; + int len = sizeof(amp_t)/sizeof(double); + // md5 "minecraft:temperature" or "minecraft:temperature_large" + pxr.lo = xlo ^ (large ? 0x944b0073edf549db : 0x5c7e6b29735f0d7f); + pxr.hi = xhi ^ (large ? 0x4ff44347e9d22b96 : 0xf7d86f1bbc734988); + n += xDoublePerlinInit(dpn, &pxr, oct, amp_t, large ? -12 : -10, len); + } break; + + case NP_HUMIDITY: { + double amp_h[] = {1, 1, 0, 0, 0, 0}; + int len = sizeof(amp_h)/sizeof(double); + // md5 "minecraft:vegetation" or "minecraft:vegetation_large" + pxr.lo = xlo ^ (large ? 0x71b8ab943dbd5301 : 0x81bb4d22e8dc168e); + pxr.hi = xhi ^ (large ? 0xbb63ddcf39ff7a2b : 0xf1c8b4bea16303cd); + n += xDoublePerlinInit(dpn, &pxr, oct, amp_h, large ? -10 : -8, len); + } break; + + case NP_CONTINENTALNESS: { + double amp_c[] = {1, 1, 2, 2, 2, 1, 1, 1, 1}; + int len = sizeof(amp_c)/sizeof(double); + // md5 "minecraft:continentalness" or "minecraft:continentalness_large" + pxr.lo = xlo ^ (large ? 0x9a3f51a113fce8dc : 0x83886c9d0ae3a662); + pxr.hi = xhi ^ (large ? 0xee2dbd157e5dcdad : 0xafa638a61b42e8ad); + n += xDoublePerlinInit(dpn, &pxr, oct, amp_c, large ? -11 : -9, len); + } break; + + case NP_EROSION: { + double amp_e[] = {1, 1, 0, 1, 1}; + int len = sizeof(amp_e)/sizeof(double); + // md5 "minecraft:erosion" or "minecraft:erosion_large" + pxr.lo = xlo ^ (large ? 0x8c984b1f8702a951 : 0xd02491e6058f6fd8); + pxr.hi = xhi ^ (large ? 0xead7b1f92bae535f : 0x4792512c94c17a80); + n += xDoublePerlinInit(dpn, &pxr, oct, amp_e, large ? -11 : -9, len); + } break; + + case NP_WEIRDNESS: { + double amp_w[] = {1, 2, 1, 0, 0, 0}; + int len = sizeof(amp_w)/sizeof(double); + // md5 "minecraft:ridge" + pxr.lo = xlo ^ 0xefc8ef4d36102b34; + pxr.hi = xhi ^ 0x1beeeb324a0f24ea; + n += xDoublePerlinInit(dpn, &pxr, oct, amp_w, -7, len); + } break; + + default: + printf("unsupported climate parameter %d\n", nptype); + exit(1); + } + return n; +} + +void setClimateParaSeed(BiomeNoise *bn, uint64_t seed, int large, int nptype) +{ + Xoroshiro pxr; + xSetSeed(&pxr, seed); + uint64_t xlo = xNextLong(&pxr); + uint64_t xhi = xNextLong(&pxr); + init_climate_seed(&bn->climate[nptype], bn->oct, xlo, xhi, large, nptype); + bn->nptype = nptype; +} + +double sampleClimatePara(const BiomeNoise *bn, double x, double z) +{ + return sampleDoublePerlin(&bn->climate[bn->nptype], x, 0, z); +} + +void setBiomeSeed(BiomeNoise *bn, uint64_t seed, int large) +{ + Xoroshiro pxr; xSetSeed(&pxr, seed); uint64_t xlo = xNextLong(&pxr); uint64_t xhi = xNextLong(&pxr); - double amp_s[] = {1, 1, 1, 0}; - // md5 "minecraft:offset" - pxr.lo = xlo ^ 0x080518cf6af25384; - pxr.hi = xhi ^ 0x3f3dfb40a54febd5; - n += xDoublePerlinInit(&bn->shift, &pxr, bn->oct+n, - amp_s, -3, sizeof(amp_s)/sizeof(double)); - - double amp_t[] = {1.5, 0, 1, 0, 0, 0}; - // md5 "minecraft:temperature" or "minecraft:temperature_large" - pxr.lo = xlo ^ (large ? 0x944b0073edf549db : 0x5c7e6b29735f0d7f); - pxr.hi = xhi ^ (large ? 0x4ff44347e9d22b96 : 0xf7d86f1bbc734988); - n += xDoublePerlinInit(&bn->temperature, &pxr, bn->oct+n, - amp_t, large ? -12 : -10, sizeof(amp_t)/sizeof(double)); - - double amp_h[] = {1, 1, 0, 0, 0, 0}; - // md5 "minecraft:vegetation" or "minecraft:vegetation_large" - pxr.lo = xlo ^ (large ? 0x71b8ab943dbd5301 : 0x81bb4d22e8dc168e); - pxr.hi = xhi ^ (large ? 0xbb63ddcf39ff7a2b : 0xf1c8b4bea16303cd); - n += xDoublePerlinInit(&bn->humidity, &pxr, bn->oct+n, - amp_h, large ? -10 : -8, sizeof(amp_h)/sizeof(double)); - - double amp_c[] = {1, 1, 2, 2, 2, 1, 1, 1, 1}; - // md5 "minecraft:continentalness" or "minecraft:continentalness_large" - pxr.lo = xlo ^ (large ? 0x9a3f51a113fce8dc : 0x83886c9d0ae3a662); - pxr.hi = xhi ^ (large ? 0xee2dbd157e5dcdad : 0xafa638a61b42e8ad); - n += xDoublePerlinInit(&bn->continentalness, &pxr, bn->oct+n, - amp_c, large ? -11 : -9, sizeof(amp_c)/sizeof(double)); - - double amp_e[] = {1, 1, 0, 1, 1}; - // md5 "minecraft:erosion" or "minecraft:erosion_large" - pxr.lo = xlo ^ (large ? 0x8c984b1f8702a951 : 0xd02491e6058f6fd8); - pxr.hi = xhi ^ (large ? 0xead7b1f92bae535f : 0x4792512c94c17a80); - n += xDoublePerlinInit(&bn->erosion, &pxr, bn->oct+n, - amp_e, large ? -11 : -9, sizeof(amp_e)/sizeof(double)); - - double amp_w[] = {1, 2, 1, 0, 0, 0}; - // md5 "minecraft:ridge" - pxr.lo = xlo ^ 0xefc8ef4d36102b34; - pxr.hi = xhi ^ 0x1beeeb324a0f24ea; - n += xDoublePerlinInit(&bn->weirdness, &pxr, bn->oct+n, - amp_w, -7, sizeof(amp_w)/sizeof(double)); + int n = 0, i = 0; + for (; i < NP_MAX; i++) + n += init_climate_seed(&bn->climate[i], bn->oct+n, xlo, xhi, large, i); if ((size_t)n > sizeof(bn->oct) / sizeof(*bn->oct)) { printf("setBiomeSeed(): BiomeNoise is malformed, buffer too small\n"); exit(1); } - bn->previdx = 0; + bn->nptype = -1; } @@ -1358,21 +1404,32 @@ int p2overworld(int mc, const uint64_t np[6], uint64_t *dat); /// Biome sampler for MC 1.18 int sampleBiomeNoise(const BiomeNoise *bn, int64_t *np, int x, int y, int z, - uint64_t *dat, uint32_t flags) + uint64_t *dat, uint32_t sample_flags) { - float t = 0, h = 0, c = 0, e = 0, d = 0, w = 0; - double px = x, pz = z; - if (!(flags & SAMPLE_NO_SHIFT)) - { - px += sampleDoublePerlin(&bn->shift, x, 0, z) * 4.0; - pz += sampleDoublePerlin(&bn->shift, z, x, 0) * 4.0; + if (bn->nptype >= 0) + { // initialized for a specific climate parameter + int64_t id = (int64_t) (10000.0 * sampleClimatePara(bn, x, z)); + if (np) + { + memset(np, 0, NP_MAX*sizeof(*np)); + np[bn->nptype] = id; + } + return (int) id; } - c = sampleDoublePerlin(&bn->continentalness, px, 0, pz); - e = sampleDoublePerlin(&bn->erosion, px, 0, pz); - w = sampleDoublePerlin(&bn->weirdness, px, 0, pz); + float t = 0, h = 0, c = 0, e = 0, d = 0, w = 0; + double px = x, pz = z; + if (!(sample_flags & SAMPLE_NO_SHIFT)) + { + px += sampleDoublePerlin(&bn->climate[NP_SHIFT], x, 0, z) * 4.0; + pz += sampleDoublePerlin(&bn->climate[NP_SHIFT], z, x, 0) * 4.0; + } - if (!(flags & SAMPLE_NO_DEPTH)) + c = sampleDoublePerlin(&bn->climate[NP_CONTINENTALNESS], px, 0, pz); + e = sampleDoublePerlin(&bn->climate[NP_EROSION], px, 0, pz); + w = sampleDoublePerlin(&bn->climate[NP_WEIRDNESS], px, 0, pz); + + if (!(sample_flags & SAMPLE_NO_DEPTH)) { float np_param[] = { c, e, -3.0F * ( fabsf( fabsf(w) - 0.6666667F ) - 0.33333334F ), w, @@ -1383,8 +1440,8 @@ int sampleBiomeNoise(const BiomeNoise *bn, int64_t *np, int x, int y, int z, d = 1.0 - (y << 2) / 128.0 - 83.0/160.0 + off; } - t = sampleDoublePerlin(&bn->temperature, px, 0, pz); - h = sampleDoublePerlin(&bn->humidity, px, 0, pz); + t = sampleDoublePerlin(&bn->climate[NP_TEMPERATURE], px, 0, pz); + h = sampleDoublePerlin(&bn->climate[NP_HUMIDITY], px, 0, pz); int64_t l_np[6]; int64_t *p_np = np ? np : l_np; @@ -1396,7 +1453,7 @@ int sampleBiomeNoise(const BiomeNoise *bn, int64_t *np, int x, int y, int z, p_np[5] = (int64_t)(10000.0F*w); int id = none; - if (!(flags & SAMPLE_NO_BIOME)) + if (!(sample_flags & SAMPLE_NO_BIOME)) id = p2overworld(bn->mc, (const uint64_t*)p_np, dat); return id; } diff --git a/layers.h b/layers.h index 2182b0a..a0e37f3 100644 --- a/layers.h +++ b/layers.h @@ -335,19 +335,25 @@ STRUCT(SplineStack) int len, flen; }; + +enum +{ + NP_TEMPERATURE = 0, + NP_HUMIDITY = 1, + NP_CONTINENTALNESS = 2, + NP_EROSION = 3, + NP_SHIFT = 4, NP_DEPTH = NP_SHIFT, // not a real climate + NP_WEIRDNESS = 5, + NP_MAX +}; /// Overworld and Nether biome generator for 1.18 STRUCT(BiomeNoise) { - DoublePerlinNoise shift; - DoublePerlinNoise temperature; - DoublePerlinNoise humidity; - DoublePerlinNoise continentalness; - DoublePerlinNoise erosion; - DoublePerlinNoise weirdness; + DoublePerlinNoise climate[NP_MAX]; PerlinNoise oct[2*23]; // buffer for octaves in double perlin noise Spline *sp; SplineStack ss; - int previdx; + int nptype; int mc; }; @@ -448,7 +454,14 @@ enum { void initBiomeNoise(BiomeNoise *bn, int mc); void setBiomeSeed(BiomeNoise *bn, uint64_t seed, int large); int sampleBiomeNoise(const BiomeNoise *bn, int64_t *np, int x, int y, int z, - uint64_t *dat, uint32_t flags); + uint64_t *dat, uint32_t sample_flags); +/** + * Initialize BiomeNoise for only a single climate parameter. + * (Faster than setBiomeSeed(), does not support nptype == NP_DEPTH.) + */ +void setClimateParaSeed(BiomeNoise *bn, uint64_t seed, int large, int nptype); +double sampleClimatePara(const BiomeNoise *bn, double x, double z); + /** * Currently, in 1.18, we have to generate biomes a chunk at a time to get an * accurate mapping of the biomes in the level storage, as there is no longer a diff --git a/tests.c b/tests.c index 2266b8e..6776aa4 100644 --- a/tests.c +++ b/tests.c @@ -174,20 +174,20 @@ int testGeneration() }; const int testcnt = sizeof(mc_vers) / sizeof(int); - //printf("Testing 1x1 biome generation (quick):\n"); - //if (!testBiomeGen1x1(mc_vers, b6_hashes, 0, 6, 1, testcnt)) - // return -1; + printf("Testing 1x1 biome generation (quick):\n"); + if (!testBiomeGen1x1(mc_vers, b6_hashes, 0, 6, 1, testcnt)) + return -1; - Generator g; - setupGenerator(&g, MC_1_18, 0); - applySeed(&g, 0, 1234); - Pos p = getSpawn(&g); - printf("%d %d\n", p.x, p.z); + //Generator g; + //setupGenerator(&g, MC_1_18, 0); + //applySeed(&g, 0, 1234); + //Pos p = getSpawn(&g); + //printf("%d %d\n", p.x, p.z); - StrongholdIter sh; - initFirstStronghold(&sh, g.mc, g.seed); - while (nextStronghold(&sh, &g) > 0) - printf("Stronghold #: (%6d, %6d)\n", sh.pos.x, sh.pos.z); + //StrongholdIter sh; + //initFirstStronghold(&sh, g.mc, g.seed); + //while (nextStronghold(&sh, &g) > 0) + // printf("Stronghold #: (%6d, %6d)\n", sh.pos.x, sh.pos.z); printf("Area generation tests:\n"); testAreas(MC_1_18, 0, 1); @@ -240,7 +240,7 @@ void testNoiseRangeFinder() { for (j = 0; j < n; j++) { - double t = sampleDoublePerlin(&g.bn.humidity, x+i, 0, z+j); + double t = sampleDoublePerlin(&g.bn.climate[NP_HUMIDITY], x+i, 0, z+j); if (t < bmin) bmin = t; if (t > bmax) bmax = t; buf[i*n+j] = t; @@ -250,7 +250,7 @@ void testNoiseRangeFinder() struct _f_para f_p = {-1e9, buf, x, z, n, n }; double tmin, tmax; int k = k_tot; - getParaRange(&g.bn.humidity, &tmin, &tmax, x, z, n, n, &f_p, _f1); + getParaRange(&g.bn.climate[NP_HUMIDITY], &tmin, &tmax, x, z, n, n, &f_p, _f1); if (abs(tmin-bmin*1e4)>.01||abs(tmax-bmax*1e4)>.01) { printf("=========================== BAD ============================\n"); @@ -329,11 +329,11 @@ void findBiomeParaBounds() double tmin, tmax; int x = rand() % 10000 - 5000; int z = rand() % 10000 - 5000; - getParaRange(&g.bn.temperature, &tmin, &tmax, x-r, z-r, r, r, &g, _f2); - getParaRange(&g.bn.humidity, &tmin, &tmax, x-r, z-r, r, r, &g, _f2); - getParaRange(&g.bn.erosion, &tmin, &tmax, x-r, z-r, r, r, &g, _f2); - getParaRange(&g.bn.continentalness, &tmin, &tmax, x-r, z-r, r, r, &g, _f2); - getParaRange(&g.bn.weirdness, &tmin, &tmax, x-r, z-r, r, r, &g, _f2); + getParaRange(&g.bn.climate[NP_TEMPERATURE], &tmin, &tmax, x-r, z-r, r, r, &g, _f2); + getParaRange(&g.bn.climate[NP_HUMIDITY], &tmin, &tmax, x-r, z-r, r, r, &g, _f2); + getParaRange(&g.bn.climate[NP_EROSION], &tmin, &tmax, x-r, z-r, r, r, &g, _f2); + getParaRange(&g.bn.climate[NP_CONTINENTALNESS], &tmin, &tmax, x-r, z-r, r, r, &g, _f2); + getParaRange(&g.bn.climate[NP_WEIRDNESS], &tmin, &tmax, x-r, z-r, r, r, &g, _f2); } for (i = 0; i < 256; i++) @@ -353,6 +353,7 @@ void findBiomeParaBounds() int main() { + testGeneration(); //findBiomeParaBounds(); return 0; }