diff --git a/README.md b/README.md index 9fe855d..43835c3 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ Strongholds as well as the world spawn point actually search until they find a s int main() { - int mc = MC_1_17; + int mc = MC_1_18; uint64_t seed = 3055141959546LL; // Only the first stronghold has a position which can be estimated diff --git a/finders.c b/finders.c index 95dcb2c..b46c28e 100644 --- a/finders.c +++ b/finders.c @@ -944,12 +944,17 @@ Pos locateBiome( x >>= 2; z >>= 2; radius >>= 2; + uint64_t dat = 0; - for (i = -radius; i <= radius; i++) + for (j = -radius; j <= radius; j++) { - for (j = -radius; j <= radius; j++) + for (i = -radius; i <= radius; i++) { - int id = getBiomeAt(g, 4, x+i, y, z+j); + int id, xi = x+i, zj = z+j; + // emulate dependent biome generation MC-241546 + //id = getBiomeAt(g, 4, xi, y, zj); + id = sampleBiomeNoise(&g->bn, NULL, xi, y, zj, &dat, 0); + if (!validBiomes[id]) continue; if (found == 0 || nextInt(rng, found+1) == 0) { @@ -1114,28 +1119,29 @@ const char* getValidStrongholdBiomes(int mc) modified_gravelly_mountains, shattered_savanna, shattered_savanna_plateau, eroded_badlands, modified_wooded_badlands_plateau, modified_badlands_plateau, - bamboo_jungle, bamboo_jungle_hills, + bamboo_jungle, bamboo_jungle_hills, dripstone_caves, lush_caves, meadow, + grove, snowy_slopes, stony_peaks, jagged_peaks, frozen_peaks, }; - - static char isValid115[256], isValid[256]; unsigned int i; + static char v15[256], v17[256], v18[256]; + char *valid = (mc <= MC_1_15 ? v15 : mc <= MC_1_17 ? v17 : v18); - if (mc <= MC_1_15) + if (!valid[strongholdBiomes[0]]) { - if (!isValid115[strongholdBiomes[0]]) - for (i = 0; i < sizeof(strongholdBiomes) / sizeof(int); i++) - isValid115[ strongholdBiomes[i] ] = 1; - return isValid115; - } - else - { // simulate MC-199298 - if (!isValid[strongholdBiomes[0]]) - for (i = 0; i < sizeof(strongholdBiomes) / sizeof(int); i++) - isValid[ strongholdBiomes[i] ] = 1; - isValid[bamboo_jungle] = 0; - isValid[bamboo_jungle_hills] = 0; - return isValid; + for (i = 0; i < sizeof(strongholdBiomes)/sizeof(int); i++) + valid[ strongholdBiomes[i] ] = 1; + + if (mc >= MC_1_18) + { + valid[stone_shore] = 0; + } + else if (mc >= MC_1_16) + { // simulate MC-199298 + valid[bamboo_jungle] = 0; + valid[bamboo_jungle_hills] = 0; + } } + return valid; } Pos initFirstStronghold(StrongholdIter *sh, int mc, uint64_t s48) @@ -1343,6 +1349,79 @@ static int findServerSpawn(const Generator *g, int chunkX, int chunkZ, } } +static +uint64_t getSpawnDist(const Generator *g, int x, int z) +{ + int64_t np[6]; + uint32_t flags = SAMPLE_NO_DEPTH | SAMPLE_NO_BIOME; + sampleBiomeNoise(&g->bn, np, x>>2, 0, z>>2, NULL, flags); + const int64_t spawn_np[][2] = { + {-10000,10000},{-10000,10000},{-1100,10000},{-10000,10000},{0,0}, + {-10000,-1600},{1600,10000} // [6]: weirdness for the second noise point + }; + uint64_t ds = 0, ds1 = 0, ds2 = 0; + uint64_t a, b, q, i; + for (i = 0; i < 5; i++) + { + a = +np[i] - (uint64_t)spawn_np[i][1]; + b = -np[i] + (uint64_t)spawn_np[i][0]; + q = (int64_t)a > 0 ? a : (int64_t)b > 0 ? b : 0; + ds += q * q; + } + a = +np[5] - (uint64_t)spawn_np[5][1]; + b = -np[5] + (uint64_t)spawn_np[5][0]; + q = (int64_t)a > 0 ? a : (int64_t)b > 0 ? b : 0; + ds1 = ds + q*q; + a = +np[5] - (uint64_t)spawn_np[6][1]; + b = -np[5] + (uint64_t)spawn_np[6][0]; + q = (int64_t)a > 0 ? a : (int64_t)b > 0 ? b : 0; + ds2 = ds + q*q; + return ds1 <= ds2 ? ds1 : ds2; +} + +static +void findFittest(const Generator *g, Pos *pos, uint64_t *fitness, double maxrad, double step) +{ + double rad = step, ang = 0; + Pos p = *pos; + while (rad <= maxrad) + { + int x = p.x + (int)(sin(ang) * rad); + int z = p.z + (int)(cos(ang) * rad); + // calc fitness + double d = ((double)x*x + (double)z*z) / (2500*2500); + uint64_t fit = (uint64_t)(d*d * 1e8); + // calculate the distance to the noise points for spawn + fit += getSpawnDist(g, x, z); + if (fit < *fitness) + { + pos->x = x; + pos->z = z; + *fitness = fit; + } + + ang += step / rad; + if (ang <= M_PI*2) + continue; + ang = 0; + rad += step; + } +} + +static +Pos findFittestPos(const Generator *g) +{ + Pos spawn = {0, 0}; + uint64_t fitness = getSpawnDist(g, 0, 0); + findFittest(g, &spawn, &fitness, 2048.0, 512.0); + findFittest(g, &spawn, &fitness, 512.0, 32.0); + // center of chunk + spawn.x = ((spawn.x >> 4) << 4) + 8; + spawn.z = ((spawn.z >> 4) << 4) + 8; + return spawn; +} + + Pos getSpawn(const Generator *g) { const char *isSpawnBiome = getValidSpawnBiomes(); @@ -1351,13 +1430,18 @@ Pos getSpawn(const Generator *g) int i; uint64_t rnd; - setSeed(&rnd, g->seed); - spawn = locateBiome(g, 0, 63, 0, 256, isSpawnBiome, &rnd, &found); - - if (!found) + if (g->mc <= MC_1_17) { - //printf("Unable to find spawn biome.\n"); - spawn.x = spawn.z = 8; + setSeed(&rnd, g->seed); + spawn = locateBiome(g, 0, 63, 0, 256, isSpawnBiome, &rnd, &found); + if (!found) + { + spawn.x = spawn.z = 8; + } + } + else + { + spawn = findFittestPos(g); } double accum = 1; @@ -1374,7 +1458,7 @@ Pos getSpawn(const Generator *g) { if (j > -16 && j <= 16 && k > -16 && k <= 16) { - if (findServerSpawn(g, (spawn.x>>4)+j, (spawn.x>>4)+k, + if (findServerSpawn(g, (spawn.x>>4)+j, (spawn.z>>4)+k, &bx, &bz, &bn, &accum)) { spawn.x = (int) round(bx / bn); @@ -1420,25 +1504,30 @@ Pos getSpawn(const Generator *g) return spawn; } - Pos estimateSpawn(const Generator *g) { const char *isSpawnBiome = getValidSpawnBiomes(); Pos spawn; - int found; - uint64_t rnd; - setSeed(&rnd, g->seed); - spawn = locateBiome(g, 0, 63, 0, 256, isSpawnBiome, &rnd, &found); - if (!found) + if (g->mc <= MC_1_17) { - spawn.x = spawn.z = 8; + int found; + uint64_t rnd; + setSeed(&rnd, g->seed); + spawn = locateBiome(g, 0, 63, 0, 256, isSpawnBiome, &rnd, &found); + if (!found) + { + spawn.x = spawn.z = 8; + } + if (g->mc >= MC_1_13) + { + spawn.x &= ~0xf; + spawn.z &= ~0xf; + } } - - if (g->mc >= MC_1_13) + else { - spawn.x &= ~0xf; - spawn.z &= ~0xf; + spawn = findFittestPos(g); } return spawn; diff --git a/layers.c b/layers.c index 4d98fd3..137dabe 100644 --- a/layers.c +++ b/layers.c @@ -1354,11 +1354,12 @@ int p2overworld(const uint64_t np[6], uint64_t *dat); #endif /// Biome sampler for MC 1.18 -int sampleBiomeNoise(const BiomeNoise *bn, int x, int y, int z, uint64_t *dat, int approx) +int sampleBiomeNoise(const BiomeNoise *bn, int64_t *np, int x, int y, int z, + uint64_t *dat, uint32_t flags) { float t = 0, h = 0, c = 0, e = 0, d = 0, w = 0; double px = x, pz = z; - if (approx == 0) + if (!(flags & SAMPLE_NO_SHIFT)) { px += sampleDoublePerlin(&bn->shift, x, 0, z) * 4.0; pz += sampleDoublePerlin(&bn->shift, z, x, 0) * 4.0; @@ -1368,27 +1369,32 @@ int sampleBiomeNoise(const BiomeNoise *bn, int x, int y, int z, uint64_t *dat, i e = sampleDoublePerlin(&bn->erosion, px, 0, pz); w = sampleDoublePerlin(&bn->weirdness, px, 0, pz); - float np_param[] = { - c, e, -3.0F * ( fabsf( fabsf(w) - 0.6666667F ) - 0.33333334F ), w, - }; - double off = getSpline(bn->sp, np_param) + 0.015F; + if (!(flags & SAMPLE_NO_DEPTH)) + { + float np_param[] = { + c, e, -3.0F * ( fabsf( fabsf(w) - 0.6666667F ) - 0.33333334F ), w, + }; + double off = getSpline(bn->sp, np_param) + 0.015F; - //double py = y + sampleDoublePerlin(&bn->shift, y, z, x) * 4.0; - d = 1.0 - (y << 2) / 128.0 - 83.0/160.0 + off; + //double py = y + sampleDoublePerlin(&bn->shift, y, z, x) * 4.0; + 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); - int64_t np[] = { - (int64_t)(10000.0F*t), - (int64_t)(10000.0F*h), - (int64_t)(10000.0F*c), - (int64_t)(10000.0F*e), - (int64_t)(10000.0F*d), - (int64_t)(10000.0F*w), - }; + int64_t l_np[6]; + int64_t *p_np = np ? np : l_np; + p_np[0] = (int64_t)(10000.0F*t); + p_np[1] = (int64_t)(10000.0F*h); + p_np[2] = (int64_t)(10000.0F*c); + p_np[3] = (int64_t)(10000.0F*e); + p_np[4] = (int64_t)(10000.0F*d); + p_np[5] = (int64_t)(10000.0F*w); - int id = p2overworld((const uint64_t*)np, dat); + int id = none; + if (!(flags & SAMPLE_NO_BIOME)) + id = p2overworld((const uint64_t*)p_np, dat); return id; } @@ -1396,6 +1402,8 @@ int sampleBiomeNoise(const BiomeNoise *bn, int x, int y, int z, uint64_t *dat, i static void genBiomeNoise3D(const BiomeNoise *bn, int *out, Range r, int opt) { uint64_t dat = 0; + uint64_t *p_dat = opt ? &dat : NULL; + uint32_t flags = opt ? SAMPLE_NO_SHIFT : 0; int i, j, k; int *p = out; int scale = r.scale > 4 ? r.scale / 4 : 1; @@ -1409,7 +1417,7 @@ static void genBiomeNoise3D(const BiomeNoise *bn, int *out, Range r, int opt) for (i = 0; i < r.sx; i++) { int xi = (r.x+i)*scale + mid; - *p = sampleBiomeNoise(bn, xi, yk, zj, opt ? &dat : NULL, opt); + *p = sampleBiomeNoise(bn, NULL, xi, yk, zj, p_dat, flags); p++; } } @@ -1457,7 +1465,7 @@ int genBiomeNoiseScaled(const BiomeNoise *bn, int *out, Range r, int mc, uint64_ } else { - *p = sampleBiomeNoise(bn, x4, y4, z4, 0, 0); + *p = sampleBiomeNoise(bn, 0, x4, y4, z4, 0, 0); } p++; } diff --git a/layers.h b/layers.h index fc7b079..33adf69 100644 --- a/layers.h +++ b/layers.h @@ -436,9 +436,15 @@ int genEndScaled(const EndNoise *en, int *out, Range r, int mc, uint64_t sha); * The 1.18 End generation remains similar to 1.17 and does NOT use the * biome noise. */ +enum { + SAMPLE_NO_SHIFT = 0x1, + SAMPLE_NO_DEPTH = 0x2, + SAMPLE_NO_BIOME = 0x4, +}; void initBiomeNoise(BiomeNoise *bn, int mc); void setBiomeSeed(BiomeNoise *bn, uint64_t seed, int large); -int sampleBiomeNoise(const BiomeNoise *bn, int x, int y, int z, uint64_t *dat, int approx); +int sampleBiomeNoise(const BiomeNoise *bn, int64_t *np, int x, int y, int z, + uint64_t *dat, uint32_t flags); /** * The scaled biome noise generation applies for the Overworld version 1.18. * The 'sha' hash of the seed is only required for voronoi at scale 1:1. diff --git a/tests.c b/tests.c index bccf3bc..b1d8af8 100644 --- a/tests.c +++ b/tests.c @@ -112,7 +112,7 @@ int testBiomeGen1x1(const int *mc, const uint32_t *expect, int dim, int bits, in fflush(stdout); double t = -now(); - h = getRef(mc[test], dim, bits, spread, "t16"); + h = getRef(mc[test], dim, bits, spread, NULL); t += now(); printf("got %08x %s\e[0m (%ld msec)\n", h, h == expect[test] ? "\e[1;92mOK" : "\e[1;91mFAILED", @@ -158,6 +158,8 @@ uint32_t testAreas(int mc, int dim, int scale) } + + int testGeneration() { const int mc_vers[] = { @@ -172,9 +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, 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); + + 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);