Made it possible to generate climates parameters individually

This commit is contained in:
Cubitect 2022-08-03 20:10:50 +02:00
parent b2c433004d
commit a81171f5ef
6 changed files with 189 additions and 96 deletions

View File

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

View File

@ -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])
}

View File

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

171
layers.c
View File

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

View File

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

39
tests.c
View File

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