Check MC in structure validation + scanning for quad-huts.

This commit is contained in:
Cubitect 2020-12-27 15:36:41 +01:00
parent 13c9e34f89
commit 496c6a2f6a
3 changed files with 132 additions and 37 deletions

107
finders.c
View File

@ -4,6 +4,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -150,8 +151,8 @@ int isTreasureChunk(int64_t seed, int chunkX, int chunkZ)
*/
int countBlocksInSpawnRange(Pos p[4], int ax, int ay, int az, Pos *afk)
{
int minX = 3e7, minZ = 3e7, maxX = -3e7, maxZ = -3e7;
int bestr, bestn, i, x, z, px, pz;
int64_t minX = INT_MAX, minZ = INT_MAX, maxX = INT_MIN, maxZ = INT_MIN;
int64_t bestr, bestn, i, x, z, px, pz;
// Find corners
@ -169,6 +170,7 @@ int countBlocksInSpawnRange(Pos p[4], int ax, int ay, int az, Pos *afk)
maxZ += az;
bestr = 0;
bestn = 0;
double afkx = 0, afkz = 0;
double thsq = 128.0*128.0 - ay*ay/4.0;
@ -198,8 +200,8 @@ int countBlocksInSpawnRange(Pos p[4], int ax, int ay, int az, Pos *afk)
{
if (afk)
{
afk->x = x;
afk->z = z;
afkx = x;
afkz = z;
bestn = 1;
}
bestr = inrange;
@ -208,8 +210,8 @@ int countBlocksInSpawnRange(Pos p[4], int ax, int ay, int az, Pos *afk)
{
if (afk)
{
afk->x += x;
afk->z += z;
afkx += x;
afkz += z;
bestn++;
}
}
@ -218,8 +220,8 @@ int countBlocksInSpawnRange(Pos p[4], int ax, int ay, int az, Pos *afk)
if (afk && bestn)
{
afk->x /= bestn;
afk->z /= bestn;
afk->x = (int)round(afkx / bestn);
afk->z = (int)round(afkz / bestn);
}
return bestr;
@ -593,6 +595,40 @@ L_ERR:
}
int scanForQuads(const StructureConfig sconf, int64_t s48, int64_t low20,
int x, int z, int w, int h, Pos *qplist, int n)
{
const int m = (1LL << 20);
const int64_t A = 341873128712LL;
const int64_t invB = 132477LL; // = mulInv(132897987541LL, m);
if (n < 1)
return 0;
int i, j, cnt = 0;
for (i = x; i <= x+w; i++)
{
int64_t sx = s48 + A * i;
j = (z & ~(m-1)) | ((low20 - sx) * invB & (m-1));
if (j < z)
j += m;
for (; j <= z+h; j += m)
{
int64_t sp = moveStructure(s48, -i, -j);
if (isQuadBase(sconf, sp - sconf.salt, 128))
{
qplist[cnt].x = i;
qplist[cnt].z = j;
cnt++;
if (cnt >= n)
return cnt;
}
}
}
return cnt;
}
//==============================================================================
// Checking Biomes & Biome Helper Functions
@ -1193,7 +1229,9 @@ int isViableFeatureBiome(int structureType, int biomeID)
case Mansion:
return biomeID == dark_forest || biomeID == dark_forest_hills;
default:
fprintf(stderr, "ERR isViableFeatureBiome: not implemented for structure type.\n");
fprintf(stderr,
"isViableFeatureBiome: not implemented for structure type %d.\n",
structureType);
exit(1);
}
return 0;
@ -1359,13 +1397,18 @@ int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
switch (structureType)
{
case Desert_Pyramid:
case Jungle_Pyramid:
case Swamp_Hut:
case Igloo:
case Ocean_Ruin:
case Shipwreck:
case Treasure:
if (mcversion < MC_1_13) goto L_NOT_VIABLE;
goto L_FEATURE;
case Igloo:
if (mcversion < MC_1_9) goto L_NOT_VIABLE;
goto L_FEATURE;
case Desert_Pyramid:
case Jungle_Pyramid:
case Swamp_Hut:
L_FEATURE:
if (mcversion < MC_1_16)
{
l = &g->layers[L_VORONOI_ZOOM_1];
@ -1414,7 +1457,7 @@ int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
case Outpost:
{
if (!testOutpostPos(seed, chunkX, chunkZ))
if (mcversion < MC_1_14 || !testOutpostPos(seed, chunkX, chunkZ))
goto L_NOT_VIABLE;
if (mcversion < MC_1_16)
{
@ -1458,7 +1501,18 @@ int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
}
case Monument:
if (mcversion >= MC_1_9)
if (mcversion < MC_1_8)
goto L_NOT_VIABLE;
else if (mcversion == MC_1_8)
{
// In 1.8 monuments require only a single deep ocean block.
l = g->entry_1;
setWorldSeed(l, seed);
map = allocCache(l, 1, 1);
if (genArea(l, map, blockX, blockZ, 1, 1))
goto L_NOT_VIABLE;
}
else
{
// Monuments require two viability checks with the ocean layer
// branch => worth checking for potential deep ocean beforehand.
@ -1468,15 +1522,6 @@ int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
if (genArea(l, map, chunkX, chunkZ, 1, 1))
goto L_NOT_VIABLE;
}
else
{
// In 1.8 monuments require only a single deep ocean block.
l = g->entry_1;
setWorldSeed(l, seed);
map = allocCache(l, 1, 1);
if (genArea(l, map, blockX, blockZ, 1, 1))
goto L_NOT_VIABLE;
}
if (!isDeepOcean(map[0]))
goto L_NOT_VIABLE;
if (mcversion >= MC_1_13)
@ -1490,6 +1535,8 @@ int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
goto L_NOT_VIABLE;
case Mansion:
if (mcversion < MC_1_11)
goto L_NOT_VIABLE;
l = &g->layers[L_RIVER_MIX_4];
setWorldSeed(l, seed);
if (areBiomesViable(l, NULL, blockX, blockZ, 32, getValidMansionBiomes()))
@ -1497,10 +1544,14 @@ int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
goto L_NOT_VIABLE;
case Ruined_Portal:
goto L_VIABLE;
if (mcversion >= MC_1_16)
goto L_VIABLE;
goto L_NOT_VIABLE;
default:
fprintf(stderr, "ERR isViableStructurePos: validation for structure type not implemented");
fprintf(stderr,
"isViableStructurePos: validation for structure type %d not implemented",
structureType);
goto L_NOT_VIABLE;
}
@ -1594,7 +1645,7 @@ BiomeFilter setupBiomeFilter(const int *biomeList, int listLen)
id = biomeList[i];
if (id & ~0xbf) // i.e. not in ranges [0,64),[128,192)
{
fprintf(stderr, "ERR: biomeID=%d not supported by filter.\n", id);
fprintf(stderr, "setupBiomeFilter: biomeID=%d not supported.\n", id);
exit(-1);
}
@ -1642,6 +1693,8 @@ BiomeFilter setupBiomeFilter(const int *biomeList, int listLen)
if (id == bamboo_jungle || id == bamboo_jungle_hills) {
// bamboo%64 are End biomes, so we can reuse the edgesToFind
bf.edgesToFind |= (1ULL << (bamboo_jungle & 0x3f));
bf.raresToFindM |= (1ULL << (id-128));
bf.riverToFindM |= (1ULL << (id-128));
} else if (id == jungle_edge) {
// un-modified jungle_edge can be created at shore layer
bf.riverToFind |= (1ULL << jungle_edge);

View File

@ -25,7 +25,7 @@ extern "C"
{
#endif
#define MASK48 ((1LL << 48) - 1)
#define MASK48 (((int64_t)1 << 48) - 1)
#define PI 3.141592653589793
#define LARGE_STRUCT 1
@ -66,14 +66,14 @@ STRUCT(StructureConfig)
/* for desert pyramids, jungle temples, witch huts and igloos prior to 1.13 */
static const StructureConfig FEATURE_CONFIG = { 14357617, 32, 24, Feature, 0};
static const StructureConfig DESERT_CONFIG_17 = { 14357617, 32, 24, Desert_Pyramid, 0};
static const StructureConfig IGLOO_CONFIG_17 = { 14357617, 32, 24, Igloo, 0};
static const StructureConfig JUNGLE_CONFIG_17 = { 14357617, 32, 24, Jungle_Pyramid, 0};
static const StructureConfig SWAMP_HUT_CONFIG_17 = { 14357617, 32, 24, Swamp_Hut, 0};
static const StructureConfig IGLOO_CONFIG_112 = { 14357617, 32, 24, Igloo, 0};
static const StructureConfig SWAMP_HUT_CONFIG_112 = { 14357617, 32, 24, Swamp_Hut, 0};
static const StructureConfig DESERT_PYRAMID_CONFIG_112 = { 14357617, 32, 24, Desert_Pyramid, 0};
static const StructureConfig JUNGLE_PYRAMID_CONFIG_112 = { 14357617, 32, 24, Jungle_Pyramid, 0};
/* ocean features before 1.16 */
static const StructureConfig OCEAN_RUIN_CONFIG_113 = { 14357621, 16, 8, Ocean_Ruin, 0};
static const StructureConfig SHIPWRECK_CONFIG_113 = {165745295, 15, 7, Shipwreck, 0};
static const StructureConfig OCEAN_RUIN_CONFIG_115 = { 14357621, 16, 8, Ocean_Ruin, 0};
static const StructureConfig SHIPWRECK_CONFIG_115 = {165745295, 15, 7, Shipwreck, 0};
/* 1.13 separated feature seeds by type */
static const StructureConfig DESERT_PYRAMID_CONFIG = { 14357617, 32, 24, Desert_Pyramid, 0};
@ -399,6 +399,23 @@ int searchAll48(
int countBlocksInSpawnRange(Pos p[4], int ax, int ay, int az, Pos *afk);
/* Scans the seed 's48' for quad-structures in the given area of region
* coordiantes. The search is performed for only a specific lower 20-bits of
* the transformed bases (i.e. each call looks for only one constellation of
* quad-structure).
*
* @sconf : structure config (SWAMP_HUT_CONFIG or FEATURE_CONFIG)
* @s48 : 48-bit seed to scan
* @low20 : only consider transformations that yield these lower bits
* @x,z,w,h : area to scan in region coordinates (inclusive)
* @qplist : output region coordinates for the descovered quad-structures
* @n : maximum number of quad-structures to look for
*
* Returns the number of quad-structures found (up to 'n').
*/
int scanForQuads(const StructureConfig sconf, int64_t s48, int64_t low20,
int x, int z, int w, int h, Pos *qplist, int n);
//==============================================================================
// Checking Biomes & Biome Helper Functions
//==============================================================================
@ -835,8 +852,8 @@ static inline float isQuadBase(const StructureConfig sconf, int64_t seed, int ra
//case Ruined_Portal:
default:
fprintf(stderr, "ERR isQuadBase: not implemented for structure type"
" %d\n", sconf.structType);
fprintf(stderr, "isQuadBase: not implemented for structure type %d\n",
sconf.structType);
exit(-1);
}

View File

@ -81,7 +81,8 @@ static inline void skipNextN(int64_t *seed, const int n)
* Returns the previous 48-bit seed which will generate 'nseed'.
* The upper 16 bits are ignored, both here and in the generator.
*/
static inline int64_t invSeed48(int64_t nseed)
static inline __attribute__((const))
int64_t invSeed48(int64_t nseed)
{
const int64_t x = 0x5deece66d;
const int64_t xinv = 0xdfe05bcb1365LL;
@ -111,4 +112,28 @@ static inline int64_t invSeed48(int64_t nseed)
}
/* Find the modular inverse: (1/x) | mod m.
* Assumes x and m are positive and co-prime.
*/
static inline __attribute__((const))
int64_t mulInv(int64_t x, int64_t m)
{
int64_t t, q, a, b;
if (m == 1)
return 0; // no solution
a = 0; b = 1;
while (x > 1)
{
if (m == 0)
return 0; // x and m are co-prime
q = x / m;
t = m; m = x % m; x = t;
t = a; a = b - q * a; b = t;
}
return b;
}
#endif /* JAVARND_H_ */