mirror of
https://github.com/Cubitect/cubiomes.git
synced 2025-09-24 04:03:39 -04:00
Added flags for 1.18 biome finder: match any of a set
This commit is contained in:
parent
81040b1f9e
commit
95723f90bb
174
finders.c
174
finders.c
@ -2676,6 +2676,53 @@ BiomeFilter setupBiomeFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Generator *g;
|
||||||
|
int *ids;
|
||||||
|
Range r;
|
||||||
|
uint32_t flags;
|
||||||
|
uint64_t b, m;
|
||||||
|
uint64_t breq, mreq;
|
||||||
|
uint64_t bexc, mexc;
|
||||||
|
volatile char *stop;
|
||||||
|
} gdt_info_t;
|
||||||
|
|
||||||
|
static int f_graddesc_test(void *data, int x, int z, double p)
|
||||||
|
{
|
||||||
|
(void) p;
|
||||||
|
gdt_info_t *info = (gdt_info_t *) data;
|
||||||
|
if (info->stop && *info->stop)
|
||||||
|
return 1;
|
||||||
|
int idx = (z - info->r.z) * info->r.sx + (x - info->r.x);
|
||||||
|
if (info->ids[idx] != -1)
|
||||||
|
return 0;
|
||||||
|
int id = getBiomeAt(info->g, info->r.scale, x, info->r.y, z);
|
||||||
|
info->ids[idx] = id;
|
||||||
|
if (id < 128) info->b |= (1ULL << id);
|
||||||
|
else info->m |= (1ULL << (id-128));
|
||||||
|
|
||||||
|
if (info->bexc || info->mexc)
|
||||||
|
{
|
||||||
|
if ((info->b & info->bexc) || (info->m & info->mexc))
|
||||||
|
return 1; // found an excluded biome
|
||||||
|
}
|
||||||
|
else if (info->flags & CFB_MATCH_ANY)
|
||||||
|
{
|
||||||
|
if ((info->b & info->breq) || (info->m & info->mreq))
|
||||||
|
return 1; // one of the required biomes is present
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // no excluded: do the current biomes satisfy the condition?
|
||||||
|
if (((info->b & info->breq) ^ info->breq) == 0 &&
|
||||||
|
((info->m & info->mreq) ^ info->mreq) == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int checkForBiomes(
|
int checkForBiomes(
|
||||||
Generator * g,
|
Generator * g,
|
||||||
int * cache,
|
int * cache,
|
||||||
@ -2683,7 +2730,7 @@ int checkForBiomes(
|
|||||||
int dim,
|
int dim,
|
||||||
uint64_t seed,
|
uint64_t seed,
|
||||||
BiomeFilter filter,
|
BiomeFilter filter,
|
||||||
int approx,
|
uint32_t flags,
|
||||||
volatile char * stop
|
volatile char * stop
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -2695,7 +2742,7 @@ int checkForBiomes(
|
|||||||
{
|
{
|
||||||
Layer *entry = (Layer*) getLayerForScale(g, r.scale);
|
Layer *entry = (Layer*) getLayerForScale(g, r.scale);
|
||||||
ret = checkForBiomesAtLayer(&g->ls, entry, cache, seed,
|
ret = checkForBiomesAtLayer(&g->ls, entry, cache, seed,
|
||||||
r.x, r.z, r.sx, r.sz, filter, approx);
|
r.x, r.z, r.sx, r.sz, filter, flags);
|
||||||
if (ret == 0 && r.sy > 1 && cache)
|
if (ret == 0 && r.sy > 1 && cache)
|
||||||
{
|
{
|
||||||
for (i = 0; i < r.sy; i++)
|
for (i = 0; i < r.sy; i++)
|
||||||
@ -2707,12 +2754,6 @@ int checkForBiomes(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check optimization ideas...
|
|
||||||
// 1) excluded biomes can terminate noise generation early
|
|
||||||
// 2) set of biomes in the End might be determined by min,max heights
|
|
||||||
// 3) each biome in the 1.18 noise generator might have min.max biome
|
|
||||||
// parameter ranged
|
|
||||||
|
|
||||||
int *ids, id;
|
int *ids, id;
|
||||||
if (cache)
|
if (cache)
|
||||||
ids = cache;
|
ids = cache;
|
||||||
@ -2724,23 +2765,60 @@ int checkForBiomes(
|
|||||||
applySeed(g, dim, seed);
|
applySeed(g, dim, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Biome checks are very expensive now, so we should sample the area one
|
gdt_info_t info;
|
||||||
// voxel at a time in a 'random' order and constantly check the conditions.
|
info.g = g;
|
||||||
// This is not very efficient for scale 1:1 biome filters, but those
|
info.ids = ids;
|
||||||
// should be avoided here anyway.
|
info.r = r;
|
||||||
uint64_t b = 0, m = 0;
|
info.flags = flags;
|
||||||
uint64_t breq = filter.riverToFind;
|
info.b = info.m = 0;
|
||||||
uint64_t mreq = filter.riverToFindM;
|
info.breq = filter.riverToFind;
|
||||||
uint64_t bexc = filter.biomeToExcl;
|
info.mreq = filter.riverToFindM;
|
||||||
uint64_t mexc = filter.biomeToExclM;
|
info.bexc = filter.biomeToExcl;
|
||||||
breq &= ~((1ULL << ocean) | (1ULL << deep_ocean));
|
info.mexc = filter.biomeToExclM;
|
||||||
breq |= filter.oceanToFind;
|
info.breq &= ~((1ULL << ocean) | (1ULL << deep_ocean));
|
||||||
|
info.breq |= filter.oceanToFind;
|
||||||
|
info.stop = stop;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
memset(ids, -1, r.sx * r.sz * sizeof(int));
|
||||||
|
|
||||||
// shuffle indeces
|
int n = r.sx*r.sy*r.sz;
|
||||||
struct touple { int i, x, y, z; } *buf;
|
int trials = n;
|
||||||
buf = (struct touple*) malloc(r.sx * r.sy * r.sz * sizeof(*buf));
|
struct touple { int i, x, y, z; } *buf = NULL;
|
||||||
|
|
||||||
|
if (r.scale == 4 && r.sx * r.sz > 64)
|
||||||
|
{
|
||||||
|
// Do a gradient descent to find the min/max of some climate parameters
|
||||||
|
// and check the biomes along the way. This gives a much better chance
|
||||||
|
// of fining the biomes that require the more exteme conditions early.
|
||||||
|
double tmin, tmax;
|
||||||
|
int err = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
err = getParaRange(&g->bn.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,
|
||||||
|
r.x, r.z, r.sx, r.sz, &info, f_graddesc_test);
|
||||||
|
if (err) break;
|
||||||
|
err = getParaRange(&g->bn.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,
|
||||||
|
// r.x, r.z, r.sx, r.sz, &info, f_graddesc_test);
|
||||||
|
//if (err) break;
|
||||||
|
//err = getParaRange(&g->bn.weirdness, &tmin, &tmax,
|
||||||
|
// r.x, r.z, r.sx, r.sz, &info, f_graddesc_test);
|
||||||
|
//if (err) break;
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
if (err || (stop && *stop) || (flags & CFB_APPROX))
|
||||||
|
goto L_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll shuffle the coordinates so we'll generate the biomes in a
|
||||||
|
// stochasitc mannor.
|
||||||
|
buf = (struct touple*) malloc(n * sizeof(*buf));
|
||||||
|
|
||||||
id = 0;
|
id = 0;
|
||||||
for (k = 0; k < r.sy; k++)
|
for (k = 0; k < r.sy; k++)
|
||||||
@ -2758,12 +2836,10 @@ int checkForBiomes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = r.sx*r.sy*r.sz;
|
|
||||||
// Determine a number of trials that gives a decent chance to sample all
|
// Determine a number of trials that gives a decent chance to sample all
|
||||||
// the biomes that are present, assuming a completely random and
|
// the biomes that are present, assuming a completely random and
|
||||||
// independent biome distribution. (This is actually not at all the case.)
|
// independent biome distribution. (This is actually not at all the case.)
|
||||||
int trials = n;
|
if (flags & CFB_APPROX)
|
||||||
if (approx)
|
|
||||||
{
|
{
|
||||||
int t = 400 + (int) sqrt(n);
|
int t = 400 + (int) sqrt(n);
|
||||||
if (trials > t)
|
if (trials > t)
|
||||||
@ -2784,40 +2860,47 @@ int checkForBiomes(
|
|||||||
|
|
||||||
if (stop && *stop)
|
if (stop && *stop)
|
||||||
break;
|
break;
|
||||||
|
if (t.y == 0 && info.ids[t.i] != -1)
|
||||||
|
continue;
|
||||||
id = getBiomeAt(g, r.scale, r.x+t.x, r.y+t.y, r.z+t.z);
|
id = getBiomeAt(g, r.scale, r.x+t.x, r.y+t.y, r.z+t.z);
|
||||||
ids[t.i] = id;
|
info.ids[t.i] = id;
|
||||||
if (id < 128) b |= (1ULL << id);
|
if (id < 128) info.b |= (1ULL << id);
|
||||||
else m |= (1ULL << (id-128));
|
else info.m |= (1ULL << (id-128));
|
||||||
|
|
||||||
if (bexc || mexc)
|
if (info.bexc || info.mexc)
|
||||||
{
|
{
|
||||||
if ((b & bexc) || (m & mexc))
|
if ((info.b & info.bexc) || (info.m & info.mexc))
|
||||||
{ // found an excluded biome
|
break; // found an excluded biome
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (flags & CFB_MATCH_ANY)
|
||||||
|
{
|
||||||
|
if ((info.b & info.breq) || (info.m & info.mreq))
|
||||||
|
break; // one of the required biomes is present
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // no excluded: do the current biomes satisfy the condition?
|
{ // no excluded: do the current biomes satisfy the condition?
|
||||||
if (((b & breq) ^ breq) == 0 && ((m & mreq) ^ mreq) == 0)
|
if (((info.b & info.breq) ^ info.breq) == 0 &&
|
||||||
{
|
((info.m & info.mreq) ^ info.mreq) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
L_end:
|
||||||
if (stop && *stop)
|
if (stop && *stop)
|
||||||
{
|
{
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = ((b & breq) ^ breq) == 0 &&
|
ret = (info.b & info.bexc) == 0 && (info.m & info.mexc) == 0;
|
||||||
((m & mreq) ^ mreq) == 0 &&
|
if (flags & CFB_MATCH_ANY)
|
||||||
(b & bexc) == 0 &&
|
ret &= (info.b & info.breq) || (info.m & info.mreq);
|
||||||
(m & mexc) == 0;
|
else
|
||||||
|
ret &= (((info.b & info.breq) ^ info.breq) == 0 &&
|
||||||
|
((info.m & info.mreq) ^ info.mreq) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buf)
|
||||||
free(buf);
|
free(buf);
|
||||||
if (ids != cache)
|
if (ids != cache)
|
||||||
free(ids);
|
free(ids);
|
||||||
@ -3704,7 +3787,7 @@ double getParaDescent(const DoublePerlinNoise *para, double factor,
|
|||||||
/// We can remember and try the direction from the previous cycle first to
|
/// We can remember and try the direction from the previous cycle first to
|
||||||
/// reduce the number of wrong guesses.
|
/// reduce the number of wrong guesses.
|
||||||
///
|
///
|
||||||
/// We can also use a larger step size than 1, as long as we are believe
|
/// We can also use a larger step size than 1, as long as we believe that
|
||||||
/// the minimum is not in between. To determine if this is viable, we check
|
/// the minimum is not in between. To determine if this is viable, we check
|
||||||
/// the step size of 1 first, and then jump if the gradient appears large
|
/// the step size of 1 first, and then jump if the gradient appears large
|
||||||
/// enough in that direction.
|
/// enough in that direction.
|
||||||
@ -3835,7 +3918,7 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax,
|
|||||||
const double perlin_grad = 2.0 * 1.875; // max perlin noise gradient
|
const double perlin_grad = 2.0 * 1.875; // max perlin noise gradient
|
||||||
double v, lmin, lmax, dr, vdif, small_regime;
|
double v, lmin, lmax, dr, vdif, small_regime;
|
||||||
char *skip = NULL;
|
char *skip = NULL;
|
||||||
int i, j, step, ii, jj, ww, hh;
|
int i, j, step, ii, jj, ww, hh, skipsiz;
|
||||||
int maxrad, maxiter;
|
int maxrad, maxiter;
|
||||||
int err = 1;
|
int err = 1;
|
||||||
|
|
||||||
@ -3925,10 +4008,11 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax,
|
|||||||
maxiter = step*2;
|
maxiter = step*2;
|
||||||
ww = (w+step-1) / step;
|
ww = (w+step-1) / step;
|
||||||
hh = (h+step-1) / step;
|
hh = (h+step-1) / step;
|
||||||
skip = (char*) malloc(ww * hh * sizeof(*skip));
|
skipsiz = (ww+1) * (hh+1) * sizeof(*skip);
|
||||||
|
skip = (char*) malloc(skipsiz);
|
||||||
|
|
||||||
// look for minima
|
// look for minima
|
||||||
memset(skip, 0, ww * hh * sizeof(*skip));
|
memset(skip, 0, skipsiz);
|
||||||
|
|
||||||
for (jj = 0; jj <= hh; jj++)
|
for (jj = 0; jj <= hh; jj++)
|
||||||
{
|
{
|
||||||
@ -3974,7 +4058,7 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// look for maxima
|
// look for maxima
|
||||||
memset(skip, 0, ww * hh * sizeof(*skip));
|
memset(skip, 0, skipsiz);
|
||||||
|
|
||||||
for (jj = 0; jj <= hh; jj++)
|
for (jj = 0; jj <= hh; jj++)
|
||||||
{
|
{
|
||||||
|
10
finders.h
10
finders.h
@ -652,7 +652,7 @@ BiomeFilter setupBiomeFilter(
|
|||||||
* requirements of the biome filter. If so, the area will be fully generated
|
* requirements of the biome filter. If so, the area will be fully generated
|
||||||
* inside the cache (if != NULL), and the return value will be > 0.
|
* inside the cache (if != NULL), and the return value will be > 0.
|
||||||
* Otherwise, the contents of 'cache' is undefined and a value <= 0 is returned.
|
* Otherwise, the contents of 'cache' is undefined and a value <= 0 is returned.
|
||||||
* More aggressive filtering can be enabled with 'approx' which may yield some
|
* More aggressive filtering can be enabled with the flags which may yield some
|
||||||
* some false negatives in exchange for speed.
|
* some false negatives in exchange for speed.
|
||||||
*
|
*
|
||||||
* The generator should be set up for the correct version, but the dimension
|
* The generator should be set up for the correct version, but the dimension
|
||||||
@ -666,9 +666,13 @@ BiomeFilter setupBiomeFilter(
|
|||||||
* @dim : dimension (0:Overworld, -1:Nether, +1:End)
|
* @dim : dimension (0:Overworld, -1:Nether, +1:End)
|
||||||
* @seed : world seed
|
* @seed : world seed
|
||||||
* @filter : biome requirements to be met
|
* @filter : biome requirements to be met
|
||||||
* @approx : enables approximations with more aggressive filtering
|
* @flags : enables features (see below)
|
||||||
* @stop : occasional check for abort (nullable)
|
* @stop : occasional check for abort (nullable)
|
||||||
*/
|
*/
|
||||||
|
enum {
|
||||||
|
CFB_APPROX = 0x01, // enabled aggresive filtering, trading accuracy
|
||||||
|
CFB_MATCH_ANY = 0x10, // we need only one of the required biomes (1.18+)
|
||||||
|
};
|
||||||
int checkForBiomes(
|
int checkForBiomes(
|
||||||
Generator * g,
|
Generator * g,
|
||||||
int * cache,
|
int * cache,
|
||||||
@ -676,7 +680,7 @@ int checkForBiomes(
|
|||||||
int dim,
|
int dim,
|
||||||
uint64_t seed,
|
uint64_t seed,
|
||||||
BiomeFilter filter,
|
BiomeFilter filter,
|
||||||
int approx,
|
uint32_t flags,
|
||||||
volatile char * stop // should be atomic, but is fine as stop flag
|
volatile char * stop // should be atomic, but is fine as stop flag
|
||||||
);
|
);
|
||||||
|
|
||||||
|
10
tests.c
10
tests.c
@ -209,11 +209,12 @@ int testGeneration()
|
|||||||
|
|
||||||
int k_tot;
|
int k_tot;
|
||||||
struct _f_para { double v; double *buf; int x, z, w, h; };
|
struct _f_para { double v; double *buf; int x, z, w, h; };
|
||||||
void _f1(void *data, int x, int z, double v)
|
int _f1(void *data, int x, int z, double v)
|
||||||
{
|
{
|
||||||
struct _f_para d = *(struct _f_para*) data;
|
struct _f_para d = *(struct _f_para*) data;
|
||||||
d.buf[(x-d.x)*d.w + (z-d.z)] = d.v;
|
d.buf[(x-d.x)*d.w + (z-d.z)] = d.v;
|
||||||
k_tot++;
|
k_tot++;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testNoiseRangeFinder()
|
void testNoiseRangeFinder()
|
||||||
@ -291,7 +292,7 @@ void testNoiseRangeFinder()
|
|||||||
|
|
||||||
int64_t bbounds[256][6][2]; // [biome][np][min/max]
|
int64_t bbounds[256][6][2]; // [biome][np][min/max]
|
||||||
|
|
||||||
void _f2(void *data, int x, int z, double v)
|
int _f2(void *data, int x, int z, double v)
|
||||||
{
|
{
|
||||||
int64_t np[6];
|
int64_t np[6];
|
||||||
Generator *g = (Generator*) data;
|
Generator *g = (Generator*) data;
|
||||||
@ -302,6 +303,7 @@ void _f2(void *data, int x, int z, double v)
|
|||||||
if (np[i] < bbounds[id][i][0]) bbounds[id][i][0] = np[i];
|
if (np[i] < bbounds[id][i][0]) bbounds[id][i][0] = np[i];
|
||||||
if (np[i] > bbounds[id][i][1]) bbounds[id][i][1] = np[i];
|
if (np[i] > bbounds[id][i][1]) bbounds[id][i][1] = np[i];
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void findBiomeParaBounds()
|
void findBiomeParaBounds()
|
||||||
@ -320,7 +322,7 @@ void findBiomeParaBounds()
|
|||||||
setupGenerator(&g, MC_1_18, 0);
|
setupGenerator(&g, MC_1_18, 0);
|
||||||
int64_t s;
|
int64_t s;
|
||||||
int r = 1000;
|
int r = 1000;
|
||||||
for (s = 1000; s < 20000; s++)
|
for (s = 0; s < 20000; s++)
|
||||||
{
|
{
|
||||||
int64_t seed = ((int64_t)hash32(s) << 32) ^ hash32(rand());
|
int64_t seed = ((int64_t)hash32(s) << 32) ^ hash32(rand());
|
||||||
applySeed(&g, 0, seed);
|
applySeed(&g, 0, seed);
|
||||||
@ -351,7 +353,7 @@ void findBiomeParaBounds()
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
findBiomeParaBounds();
|
//findBiomeParaBounds();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user