Fix 1.18 spawn and stronghold finders (please fix MC-241546, Mojang)

This commit is contained in:
Cubitect 2021-11-24 23:14:19 +01:00
parent 65414ac3be
commit 8fea920b49
5 changed files with 179 additions and 63 deletions

View File

@ -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

165
finders.c
View File

@ -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;

View File

@ -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++;
}

View File

@ -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.

21
tests.c
View File

@ -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);