mirror of
https://github.com/Cubitect/cubiomes.git
synced 2025-09-22 11:04:57 -04:00
Added flags for 1.18 biome finder: match any of a set
This commit is contained in:
parent
81040b1f9e
commit
95723f90bb
180
finders.c
180
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(
|
||||
Generator * g,
|
||||
int * cache,
|
||||
@ -2683,7 +2730,7 @@ int checkForBiomes(
|
||||
int dim,
|
||||
uint64_t seed,
|
||||
BiomeFilter filter,
|
||||
int approx,
|
||||
uint32_t flags,
|
||||
volatile char * stop
|
||||
)
|
||||
{
|
||||
@ -2695,7 +2742,7 @@ int checkForBiomes(
|
||||
{
|
||||
Layer *entry = (Layer*) getLayerForScale(g, r.scale);
|
||||
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)
|
||||
{
|
||||
for (i = 0; i < r.sy; i++)
|
||||
@ -2707,12 +2754,6 @@ int checkForBiomes(
|
||||
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;
|
||||
if (cache)
|
||||
ids = cache;
|
||||
@ -2724,23 +2765,60 @@ int checkForBiomes(
|
||||
applySeed(g, dim, seed);
|
||||
}
|
||||
|
||||
// Biome checks are very expensive now, so we should sample the area one
|
||||
// voxel at a time in a 'random' order and constantly check the conditions.
|
||||
// This is not very efficient for scale 1:1 biome filters, but those
|
||||
// should be avoided here anyway.
|
||||
uint64_t b = 0, m = 0;
|
||||
uint64_t breq = filter.riverToFind;
|
||||
uint64_t mreq = filter.riverToFindM;
|
||||
uint64_t bexc = filter.biomeToExcl;
|
||||
uint64_t mexc = filter.biomeToExclM;
|
||||
breq &= ~((1ULL << ocean) | (1ULL << deep_ocean));
|
||||
breq |= filter.oceanToFind;
|
||||
gdt_info_t info;
|
||||
info.g = g;
|
||||
info.ids = ids;
|
||||
info.r = r;
|
||||
info.flags = flags;
|
||||
info.b = info.m = 0;
|
||||
info.breq = filter.riverToFind;
|
||||
info.mreq = filter.riverToFindM;
|
||||
info.bexc = filter.biomeToExcl;
|
||||
info.mexc = filter.biomeToExclM;
|
||||
info.breq &= ~((1ULL << ocean) | (1ULL << deep_ocean));
|
||||
info.breq |= filter.oceanToFind;
|
||||
info.stop = stop;
|
||||
|
||||
ret = 0;
|
||||
memset(ids, -1, r.sx * r.sz * sizeof(int));
|
||||
|
||||
// shuffle indeces
|
||||
struct touple { int i, x, y, z; } *buf;
|
||||
buf = (struct touple*) malloc(r.sx * r.sy * r.sz * sizeof(*buf));
|
||||
int n = r.sx*r.sy*r.sz;
|
||||
int trials = n;
|
||||
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;
|
||||
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
|
||||
// the biomes that are present, assuming a completely random and
|
||||
// independent biome distribution. (This is actually not at all the case.)
|
||||
int trials = n;
|
||||
if (approx)
|
||||
if (flags & CFB_APPROX)
|
||||
{
|
||||
int t = 400 + (int) sqrt(n);
|
||||
if (trials > t)
|
||||
@ -2784,41 +2860,48 @@ int checkForBiomes(
|
||||
|
||||
if (stop && *stop)
|
||||
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);
|
||||
ids[t.i] = id;
|
||||
if (id < 128) b |= (1ULL << id);
|
||||
else m |= (1ULL << (id-128));
|
||||
info.ids[t.i] = id;
|
||||
if (id < 128) info.b |= (1ULL << id);
|
||||
else info.m |= (1ULL << (id-128));
|
||||
|
||||
if (bexc || mexc)
|
||||
if (info.bexc || info.mexc)
|
||||
{
|
||||
if ((b & bexc) || (m & mexc))
|
||||
{ // found an excluded biome
|
||||
break;
|
||||
}
|
||||
if ((info.b & info.bexc) || (info.m & info.mexc))
|
||||
break; // found an excluded biome
|
||||
}
|
||||
else if (flags & CFB_MATCH_ANY)
|
||||
{
|
||||
if ((info.b & info.breq) || (info.m & info.mreq))
|
||||
break; // one of the required biomes is present
|
||||
}
|
||||
else
|
||||
{ // 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
L_end:
|
||||
if (stop && *stop)
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ((b & breq) ^ breq) == 0 &&
|
||||
((m & mreq) ^ mreq) == 0 &&
|
||||
(b & bexc) == 0 &&
|
||||
(m & mexc) == 0;
|
||||
ret = (info.b & info.bexc) == 0 && (info.m & info.mexc) == 0;
|
||||
if (flags & CFB_MATCH_ANY)
|
||||
ret &= (info.b & info.breq) || (info.m & info.mreq);
|
||||
else
|
||||
ret &= (((info.b & info.breq) ^ info.breq) == 0 &&
|
||||
((info.m & info.mreq) ^ info.mreq) == 0);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (ids != cache)
|
||||
free(ids);
|
||||
return ret;
|
||||
@ -3704,7 +3787,7 @@ double getParaDescent(const DoublePerlinNoise *para, double factor,
|
||||
/// We can remember and try the direction from the previous cycle first to
|
||||
/// 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 step size of 1 first, and then jump if the gradient appears large
|
||||
/// 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
|
||||
double v, lmin, lmax, dr, vdif, small_regime;
|
||||
char *skip = NULL;
|
||||
int i, j, step, ii, jj, ww, hh;
|
||||
int i, j, step, ii, jj, ww, hh, skipsiz;
|
||||
int maxrad, maxiter;
|
||||
int err = 1;
|
||||
|
||||
@ -3925,10 +4008,11 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax,
|
||||
maxiter = step*2;
|
||||
ww = (w+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
|
||||
memset(skip, 0, ww * hh * sizeof(*skip));
|
||||
memset(skip, 0, skipsiz);
|
||||
|
||||
for (jj = 0; jj <= hh; jj++)
|
||||
{
|
||||
@ -3974,7 +4058,7 @@ int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax,
|
||||
}
|
||||
|
||||
// look for maxima
|
||||
memset(skip, 0, ww * hh * sizeof(*skip));
|
||||
memset(skip, 0, skipsiz);
|
||||
|
||||
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
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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)
|
||||
* @seed : world seed
|
||||
* @filter : biome requirements to be met
|
||||
* @approx : enables approximations with more aggressive filtering
|
||||
* @flags : enables features (see below)
|
||||
* @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(
|
||||
Generator * g,
|
||||
int * cache,
|
||||
@ -676,7 +680,7 @@ int checkForBiomes(
|
||||
int dim,
|
||||
uint64_t seed,
|
||||
BiomeFilter filter,
|
||||
int approx,
|
||||
uint32_t flags,
|
||||
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;
|
||||
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;
|
||||
d.buf[(x-d.x)*d.w + (z-d.z)] = d.v;
|
||||
k_tot++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void testNoiseRangeFinder()
|
||||
@ -291,7 +292,7 @@ void testNoiseRangeFinder()
|
||||
|
||||
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];
|
||||
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][1]) bbounds[id][i][1] = np[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void findBiomeParaBounds()
|
||||
@ -320,7 +322,7 @@ void findBiomeParaBounds()
|
||||
setupGenerator(&g, MC_1_18, 0);
|
||||
int64_t s;
|
||||
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());
|
||||
applySeed(&g, 0, seed);
|
||||
@ -351,7 +353,7 @@ void findBiomeParaBounds()
|
||||
|
||||
int main()
|
||||
{
|
||||
findBiomeParaBounds();
|
||||
//findBiomeParaBounds();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user