avoid recursion floodfill exceeding stack limit (crashes on windows)

This commit is contained in:
Cubitect 2022-10-01 19:39:40 +02:00
parent 6989510924
commit d3112ca416
2 changed files with 55 additions and 38 deletions

View File

@ -3697,46 +3697,64 @@ struct locate_info_t
Generator *g; Generator *g;
int *ids; int *ids;
Range r; Range r;
int match; int match, tol;
int64_t sumx, sumz;
int n, dmax;
volatile char *stop; volatile char *stop;
}; };
static static
void floodFillGen(struct locate_info_t *info, int i, int j, int d) int floodFillGen(struct locate_info_t *info, int i, int j, Pos *p)
{
typedef struct { int i, j, d; } entry_t;
entry_t *queue = (entry_t*) malloc(info->r.sx*info->r.sz * sizeof(*queue));
int qn = 1, d = 0;
queue->i = i;
queue->j = j;
int64_t sumx = 0;
int64_t sumz = 0;
int n = 0;
while (--qn >= 0)
{ {
if (i < 0 || j < 0 || i >= info->r.sx || j >= info->r.sz)
return;
if (info->stop && *info->stop) if (info->stop && *info->stop)
return; return 0;
int idx = j * info->r.sx + i; i = queue[qn].i;
j = queue[qn].j;
d = queue[qn].d;
if (i < 0 || j < 0 || i >= info->r.sx || j >= info->r.sz)
continue;
int k, idx = j * info->r.sx + i;
int id = info->ids[idx]; int id = info->ids[idx];
if (id == INT_MAX) if (id == INT_MAX)
return; continue;
info->ids[idx] = INT_MAX; info->ids[idx] = INT_MAX;
int x = info->r.x + i; int x = info->r.x + i;
int z = info->r.z + j; int z = info->r.z + j;
if (info->g->mc >= MC_1_18) if (info->g->mc >= MC_1_18)
id = getBiomeAt(info->g, 4, x, info->r.y, z); id = getBiomeAt(info->g, 4, x, info->r.y, z);
if (id == info->match) if (id == info->match)
{ {
info->sumx += x; sumx += x;
info->sumz += z; sumz += z;
info->n += 1; n++;
d = 0; d = 0;
} }
else else
{ {
if (++d >= info->dmax) if (++d >= info->tol)
return; continue;
} }
floodFillGen(info, i, j-1, d); entry_t next[] = { {i,j-1,d}, {i,j+1,d}, {i-1,j,d}, {i+1,j,d} };
floodFillGen(info, i, j+1, d); for (k = 0; k < 4; k++)
floodFillGen(info, i-1, j, d); queue[qn++] = next[k];
floodFillGen(info, i+1, j, d);
} }
free(queue);
if (n)
{
p->x = (int) round(2.0 + 4.0*sumx / n);
p->z = (int) round(2.0 + 4.0*sumz / n);
}
return n;
}
int getBiomeCenters(Pos *pos, int *siz, int nmax, Generator *g, Range r, int getBiomeCenters(Pos *pos, int *siz, int nmax, Generator *g, Range r,
int match, int minsiz, int tol, volatile char *stop) int match, int minsiz, int tol, volatile char *stop)
@ -3760,7 +3778,7 @@ int getBiomeCenters(Pos *pos, int *siz, int nmax, Generator *g, Range r,
info.r = r; info.r = r;
info.stop = stop; info.stop = stop;
info.match = match; info.match = match;
info.dmax = tol; info.tol = tol;
if (g->mc >= MC_1_18) if (g->mc >= MC_1_18)
{ {
@ -3855,13 +3873,12 @@ int getBiomeCenters(Pos *pos, int *siz, int nmax, Generator *g, Range r,
break; break;
if (ids[j*r.sx + i] != match) if (ids[j*r.sx + i] != match)
continue; continue;
info.sumx = info.sumz = info.n = 0; Pos center;
floodFillGen(&info, i, j, 0); int area = floodFillGen(&info, i, j, &center);
if (info.n >= minsiz) if (area >= minsiz)
{ {
pos[n].x = (int) round(2.0 + 4.0*info.sumx / info.n); pos[n] = center;
pos[n].z = (int) round(2.0 + 4.0*info.sumz / info.n); if (siz) siz[n] = area;
if (siz) siz[n] = info.n;
if (++n >= nmax) if (++n >= nmax)
goto L_end; goto L_end;
} }

View File

@ -549,7 +549,7 @@ int checkForTemps(LayerStack *g, uint64_t seed, int x, int z, int w, int h, cons
* @r : area to examine, requires: scale = 4, sy = 1 * @r : area to examine, requires: scale = 4, sy = 1
* @match : biome id to find * @match : biome id to find
* @minsiz : minimum size of output biomes * @minsiz : minimum size of output biomes
* @tol : border tollerance * @tol : border tolerance
* @stop : stopping flag (nullable) * @stop : stopping flag (nullable)
* Returns the number of entries written to pos and siz. * Returns the number of entries written to pos and siz.
*/ */