Reworking structure finding.

1) Turned getStructurePos into a wrapper that deals with all structure types.
2) Major changes to accomodate for more sophisticated quad-base finders.
3) Classifying quad-bases according to certain properties which they fulfill.
4) Removed precompiled quad-base files, as they can be generated quickly now.
5) Removed tri-base finders (until there's a more accurate finder in future).
This commit is contained in:
Cubitect 2020-08-21 00:34:07 +02:00
parent 7dea686d31
commit 1236b91e63
13 changed files with 919 additions and 971374 deletions

View File

@ -44,8 +44,8 @@ static DWORD WINAPI searchCompactBiomesThread(LPVOID data)
for (x = -r; x < r; x++)
{
Pos p;
p = getStructurePos(SWAMP_HUT_CONFIG, s, x, z);
if (isViableStructurePos(SWAMP_HUT_CONFIG, mcversion, &g, s, p.x, p.z))
p = getStructurePos(SWAMP_HUT_CONFIG, s, x, z, NULL);
if (isViableStructurePos(Swamp_Hut, mcversion, &g, s, p.x, p.z))
goto L_hut_found;
}
}
@ -60,8 +60,8 @@ static DWORD WINAPI searchCompactBiomesThread(LPVOID data)
for (x = -r; x < r; x++)
{
Pos p;
p = getLargeStructurePos(MONUMENT_CONFIG, s, x, z);
if (isViableStructurePos(MONUMENT_CONFIG, mcversion, &g, s, p.x, p.z))
p = getStructurePos(MONUMENT_CONFIG, s, x, z, NULL);
if (isViableStructurePos(Monument, mcversion, &g, s, p.x, p.z))
goto L_monument_found;
}
}
@ -69,7 +69,7 @@ static DWORD WINAPI searchCompactBiomesThread(LPVOID data)
L_monument_found:;
}
printf("%ld\n", s);
printf("%" PRId64 "\n", s);
fflush(stdout);
}
}

View File

@ -12,6 +12,12 @@
#include <unistd.h>
#if defined(_WIN32)
#include <direct.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
int main(int argc, char *argv[])
{
@ -25,9 +31,12 @@ int main(int argc, char *argv[])
int regPosZ = 0;
int mcversion = MC_1_16;
const char *seedFileName;
StructureConfig featureConfig;
char seedFileName[256] = {};
enum LowBitSet lbitset = LBIT_ALL;
int radius = 128;
if (argc > 2)
{
if (sscanf(argv[1], "%d", &regPosX) != 1) regPosX = 0;
@ -69,25 +78,44 @@ int main(int argc, char *argv[])
if (mcversion >= MC_1_13)
{
featureConfig = SWAMP_HUT_CONFIG;
seedFileName = "./seeds/quadhutbases_1_13_Q1.txt";
}
else
{
featureConfig = FEATURE_CONFIG;
seedFileName = "./seeds/quadhutbases_1_7_Q1.txt";
}
setupGenerator(&g, mcversion);
#if defined(_WIN32)
_mkdir("./seeds");
#else
mkdir("./seeds", 0773);
#endif
//seedFileName = "./seeds/quadbases_Q1b.txt";
#if 0
sprintf(seedFileName, "./seeds/quadbase_ideal_%d.txt", featureConfig.salt);
lbitset = LBIT_IDEAL;
radius = 128;
#elif 0
sprintf(seedFileName, "./seeds/quadbase_classic_%d.txt", featureConfig.salt);
lbitset = LBIT_CLASSIC;
radius = 128;
#elif 1
sprintf(seedFileName, "./seeds/quadbase_normal_%d.txt", featureConfig.salt);
lbitset = LBIT_HUT_NORMAL;
radius = 128;
#else
sprintf(seedFileName, "./seeds/quadbase_barely_%d.txt", featureConfig.salt);
lbitset = LBIT_HUT_BARELY;
radius = 128;
#endif
if (access(seedFileName, F_OK))
{
printf("Seed base file does not exist: Creating new one.\n"
"This may take a few minutes...\n");
"This can take a while...\n");
int threads = 6;
int quality = 1;
search4QuadBases(seedFileName, threads, featureConfig, quality);
search4QuadBases(seedFileName, threads, featureConfig, radius, lbitset);
}
int64_t i, j, qhcnt;
@ -101,7 +129,7 @@ int main(int argc, char *argv[])
// Load the positions of the four structures that make up the quad-structure
// so we can test the biome at these positions.
Pos qhpos[4];
Pos qpos[4];
// layerSeed for Layer 19: Biome, to make preliminary seed tests.
int64_t lsBiome = g.layers[L_BIOME_256].layerSeed;
@ -110,49 +138,52 @@ int main(int argc, char *argv[])
int areaX = (regPosX << 1) + 1;
int areaZ = (regPosZ << 1) + 1;
int check_swamp_hut_specifics = 1;
int64_t ss, cs;
// Search for a swamp at the structure positions
for (i = 0; i < qhcnt; i++)
{
base = moveStructure(qhcandidates[i], regPosX, regPosZ);
qhpos[0] = getStructurePos(featureConfig, base, 0+regPosX, 0+regPosZ);
qhpos[1] = getStructurePos(featureConfig, base, 0+regPosX, 1+regPosZ);
qhpos[2] = getStructurePos(featureConfig, base, 1+regPosX, 0+regPosZ);
qhpos[3] = getStructurePos(featureConfig, base, 1+regPosX, 1+regPosZ);
qpos[0] = getStructurePos(featureConfig, base, 0+regPosX, 0+regPosZ, NULL);
qpos[1] = getStructurePos(featureConfig, base, 0+regPosX, 1+regPosZ, NULL);
qpos[2] = getStructurePos(featureConfig, base, 1+regPosX, 0+regPosZ, NULL);
qpos[3] = getStructurePos(featureConfig, base, 1+regPosX, 1+regPosZ, NULL);
/*
for (j = 0; j < 4; j++)
{
printf("(%d,%d) ", qhpos[j].x, qhpos[j].z);
printf("(%d,%d) ", qpos[j].x, qpos[j].z);
}
printf("\n");
*/
// This little magic code checks if there is a meaningful chance for
// this seed base to generate swamps in the area.
// The idea is, that the conversion from Lush temperature to swamp is
// independent of surroundings, so we can test for this conversion
// beforehand. Furthermore, biomes tend to leak into the negative
// coordinates because of the Zoom layers, so the majority of hits will
// occur when SouthEast corner (at a 1:256 scale) of the quad-hut has a
// swamp. (This assumption misses about 1 in 500 quad-hut seeds.)
// Finally, here we also exploit that the minecraft random number
// generator is quite bad, the "mcNextRand() mod 6" check has a period
// pattern of ~3 on the high seed-bits, which means we can avoid
// checking all 16 high-bit combinations.
int64_t ss, cs;
for (j = 0; j < 5; j++)
if (check_swamp_hut_specifics)
{
seed = base + ((j+0x53) << 48);
ss = getStartSeed(seed, lsBiome);
cs = getChunkSeed(ss, areaX+1, areaZ+1);
if (mcFirstInt(cs, 6) == 5)
break;
// This little magic code checks if there is a meaningful chance for
// this seed base to generate swamps in the area.
// The idea is, that the conversion from Lush temperature to swamp
// is independent of surroundings, so we can test for this
// conversion beforehand. Furthermore, biomes tend to leak into the
// negative coordinates because of the Zoom layers, so the majority
// of hits will occur when SouthEast corner (at a 1:256 scale) of
// the quad-hut has a swamp. (This assumption misses about 1 in 500
// quad-hut seeds.) Finally, here we also exploit that the minecraft
// random number generator is quite bad, the "mcNextRand() mod 6"
// check has a period pattern of ~3 on the high seed-bits, which
// means we can avoid checking all 16 high-bit combinations.
for (j = 0; j < 5; j++)
{
seed = base + ((j+0x53) << 48);
ss = getStartSeed(seed, lsBiome);
cs = getChunkSeed(ss, areaX+1, areaZ+1);
if (mcFirstInt(cs, 6) == 5)
break;
}
if (j >= 5)
continue;
}
if (j >= 5)
continue;
int64_t hits = 0, swpc;
@ -160,42 +191,48 @@ int main(int argc, char *argv[])
{
seed = base + (j << 48);
/** Pre-Generation Checks **/
// We can check that at least one swamp could generate in this area
// before doing the biome generator checks.
ss = getStartSeed(seed, lsBiome);
cs = getChunkSeed(ss, areaX+1, areaZ+1);
if (mcFirstInt(cs, 6) != 5)
continue;
// This seed base does not seem to contain many quad huts, so make
// a more detailed analysis of the surroundings and see if there is
// enough potential for more swamps to justify searching further.
if (hits == 0 && (j & 0xfff) == 0xfff)
if (check_swamp_hut_specifics)
{
swpc = 0;
cs = getChunkSeed(ss, areaX, areaZ+1);
swpc += mcFirstInt(cs, 6) == 5;
cs = getChunkSeed(ss, areaX+1, areaZ);
swpc += mcFirstInt(cs, 6) == 5;
cs = getChunkSeed(ss, areaX, areaZ);
swpc += mcFirstInt(cs, 6) == 5;
/** Pre-Generation Checks **/
// We can check that at least one swamp could generate in this
// area before doing the biome generator checks.
ss = getStartSeed(seed, lsBiome);
cs = getChunkSeed(ss, areaX+1, areaZ+1);
if (mcFirstInt(cs, 6) != 5)
continue;
if (swpc < (j > 0x1000 ? 2 : 1))
break;
// This seed base does not seem to contain many quad huts, so
// make a more detailed analysis of the surroundings and see if
// there is enough potential for more swamps to justify
// searching further.
if (hits == 0 && (j & 0xfff) == 0xfff)
{
swpc = 0;
cs = getChunkSeed(ss, areaX, areaZ+1);
swpc += mcFirstInt(cs, 6) == 5;
cs = getChunkSeed(ss, areaX+1, areaZ);
swpc += mcFirstInt(cs, 6) == 5;
cs = getChunkSeed(ss, areaX, areaZ);
swpc += mcFirstInt(cs, 6) == 5;
if (swpc < (j > 0x1000 ? 2 : 1))
break;
}
// Dismiss seeds that don't have a swamp near the quad temple.
setWorldSeed(lFilterBiome, seed);
genArea(lFilterBiome, biomeCache, (regPosX<<1)+2, (regPosZ<<1)+2, 1, 1);
if (biomeCache[0] != swamp)
continue;
}
// Dismiss seeds that don't have a swamp near the quad temple.
setWorldSeed(lFilterBiome, seed);
genArea(lFilterBiome, biomeCache, (regPosX<<1)+2, (regPosZ<<1)+2, 1, 1);
if (biomeCache[0] != swamp)
continue;
if (!isViableStructurePos(SWAMP_HUT_CONFIG, mcversion, &g, seed, qhpos[0].x, qhpos[0].z)) continue;
if (!isViableStructurePos(SWAMP_HUT_CONFIG, mcversion, &g, seed, qhpos[1].x, qhpos[1].z)) continue;
if (!isViableStructurePos(SWAMP_HUT_CONFIG, mcversion, &g, seed, qhpos[2].x, qhpos[2].z)) continue;
if (!isViableStructurePos(SWAMP_HUT_CONFIG, mcversion, &g, seed, qhpos[3].x, qhpos[3].z)) continue;
// we need to use config here for pre 1.13 as that would not
// specify that we are only interested in swamp huts
if (!isViableStructurePos(Swamp_Hut, mcversion, &g, seed, qpos[0].x, qpos[0].z)) continue;
if (!isViableStructurePos(Swamp_Hut, mcversion, &g, seed, qpos[1].x, qpos[1].z)) continue;
if (!isViableStructurePos(Swamp_Hut, mcversion, &g, seed, qpos[2].x, qpos[2].z)) continue;
if (!isViableStructurePos(Swamp_Hut, mcversion, &g, seed, qpos[3].x, qpos[3].z)) continue;
printf("%" PRId64 "\n", seed);
hits++;

856
finders.c

File diff suppressed because it is too large Load Diff

666
finders.h
View File

@ -5,6 +5,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifdef _WIN32
#include <Windows.h>
@ -19,6 +20,10 @@ typedef pthread_t thread_id_t;
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#define SEED_BASE_MAX (1LL << 48)
#define PI 3.141592653589793
@ -28,12 +33,19 @@ typedef pthread_t thread_id_t;
enum StructureType
{
// scattered features
Desert_Pyramid, Igloo, Jungle_Pyramid, Swamp_Hut,
//
Village, Ocean_Ruin, Shipwreck, Monument, Mansion, Outpost,
Feature, // for locations of temple generation attempts pre 1.13
Desert_Pyramid,
Jungle_Pyramid,
Swamp_Hut,
Igloo,
Village,
Ocean_Ruin,
Shipwreck,
Monument,
Mansion,
Outpost,
Ruined_Portal,
Treasure
Treasure,
};
enum // village house types prior to 1.14
@ -51,8 +63,8 @@ STRUCT(StructureConfig)
unsigned char properties;
};
/* for desert temples, igloos, jungle temples and witch huts prior to 1.13 */
static const StructureConfig FEATURE_CONFIG = { 14357617, 32, 24, Desert_Pyramid, 0};
/* for desert pyramids, jungle temples, witch huts and igloos prior to 1.13 */
static const StructureConfig FEATURE_CONFIG = { 14357617, 32, 24, Feature, 0};
/* ocean features before 1.16 */
static const StructureConfig OCEAN_RUIN_CONFIG_113 = { 14357621, 16, 8, Ocean_Ruin, 0};
@ -112,10 +124,6 @@ STRUCT(BiomeFilter)
int specialCnt; // number of special temperature categories required
};
#ifdef __cplusplus
extern "C"
{
#endif
/******************************** SEED FINDING *********************************
*
@ -129,39 +137,42 @@ extern "C"
*/
/*************************** Quad-Structure Checks *****************************
/***************************** Structure Positions *****************************
*
* Several tricks can be applied to determine candidate seeds for quad
* temples (inc. witch huts).
*
* Minecraft uses a 48-bit pseudo random number generator (PRNG) to determine
* the position of it's structures. The remaining top 16 bits do not influence
* the structure positioning. Additionally the position of most structures in a
* world can be translated by applying the following transformation to the
* seed:
* For most structure positions, Minecraft divides the world into a grid of
* regions (usually 32x32 chunks) and performs one generation attempt
* somewhere in each region. The position of this attempt is governed by the
* structure type, the region coordiates and the lower 48-bits of the world
* seed. The remaining top 16 bits do not influence structure positions.
* The dependency on the region coordinates is linear for both the X and Z
* directions, which means that the positions of most structures in a world
* can be translated by applying the following transformation to a seed:
*
* seed2 = seed1 - dregX * 341873128712 - dregZ * 132897987541;
*
* Here seed1 and seed2 have the same structure positioning, but moved by a
* region offset of (dregX,dregZ). [a region is 32x32 chunks].
* region offset of (dregX,dregZ).
*
* Another property of note is that seed1 at region (0,0) is simply the world
* seed plus a constant that is specific to the stucture type (its salt). This
* means that some structure types share quad-bases which are just offset by
* their respective salt differences.
*
*
** Quad-Witch-Huts
*
* For a quad-structure, we mainly care about relative positioning, so we can
* get away with just checking the regions near the origin: (0,0),(0,1),(1,0)
* and (1,1) and then move the structures to the desired position.
*
* Lastly we can recognise a that the transformation of relative region-
* coordinates imposes some restrictions in the PRNG, such that
* perfect-position quad-structure-seeds can only have certain values for the
* lower 16-bits in their seeds.
*
*
** The Set of all Quad-Witch-Huts
*
* These conditions only leave 32 free bits which can comfortably be brute-
* forced to get the entire set of quad-structure candidates. Each of the seeds
* found this way describes an entire set of possible quad-witch-huts (with
* degrees of freedom for region-transposition, and the top 16-bit bits).
*
* Futhermore, the PRNG that determines the chunk positions inside each region,
* performs some modular arithmatic on the 48-bit numbers which causes some
* restrictions on the lower bits when looking for near perfect structure
* positions. This is difficult to prove, but can be used to reduce the number
* of free bits to 28 which can be comfortably brute-forced to get the entire
* set of quad-structure candidates. Each of the seeds found this way
* describes entire set of possible quad-witch-huts (with degrees of freedom
* for region-transposition, as well as the top 16-bit bits).
*/
@ -186,77 +197,141 @@ static inline int64_t moveStructure(const int64_t baseSeed,
//==============================================================================
/* Loads a list of seeds from a file. The seeds should be written as decimal
* UFT-8 numbers separated by newlines.
* ASCII numbers separated by newlines.
* @fnam: file path
* @scnt: number of valid seeds found in the file, which is also the number of
* elements in the returned buffer
*
* Return a pointer to dynamically allocated seed list.
* Return a pointer to a dynamically allocated seed list.
*/
int64_t *loadSavedSeeds(const char *fnam, int64_t *scnt);
//==============================================================================
// Finding Structure Positions
//==============================================================================
/* Finds the block position at which the structure generation attempt will
* occur within the specified region. This function is a wrapper for the more
* specific inlinable functions, which can be found below. You can use
* isViableStructurePos() to test if the necessary biome requirements are met
* for the structure to actually generate at the returned position (much much
* slower than checking attempts).
*
* @config : the structure configuration
* @seed : world seed (only the lower 48-bits are relevant)
* @regX,regZ : region coordinates
* @valid : some structures, like outposts, can have invalid positions,
* use NULL to ignore this options
*/
Pos getStructurePos(StructureConfig config, int64_t seed, int regX, int regZ, int *valid);
static inline __attribute__((const))
Pos getFeaturePos(StructureConfig config, int64_t seed, int regX, int regZ);
static inline __attribute__((const))
Pos getFeatureChunkInRegion(StructureConfig config, int64_t seed, int regX, int regZ);
static inline __attribute__((const))
Pos getLargeStructurePos(StructureConfig config, int64_t seed, int regX, int regZ);
static inline __attribute__((const))
Pos getLargeStructureChunkInRegion(StructureConfig config, int64_t seed, int regX, int regZ);
/* Some structures check each chunk individually for viability.
* The placement and biome check within a valid chunk is at block position (9,9)
* or at (2,2) with layer scale=4 from 1.16 onwards.
*/
int isMineshaftChunk(int64_t seed, int chunkX, int chunkZ);
int isTreasureChunk(int64_t seed, int chunkX, int chunkZ);
//==============================================================================
// Multi-Structure-Base Checks
//==============================================================================
/* Calls the correct quad-base finder for the structure config, if available.
* (Exits program otherwise.)
*/
int isQuadBase(const StructureConfig sconf, const int64_t seed, const int64_t qual);
/* Calls the correct tri-base finder for the structure config, if available.
* (Exits program otherwise.)
/* This function determines if the lower 48-bits of a seed qualify as a
* quad-base. This implies that the four structures in the adjacent regions
* (0,0)-(1,1) will attempt to generate close enough together to be within the
* specified block radius of a single block position. The quad-structure can be
* moved to a different location by applying moveStructure() to the quad-base.
* The upper 16 bits of the seed can be chosen freely, as they do not affect
* structure positions.
*
* This function is a wrapper for more specific filtering functions which can
* be found below. Using the correct quad-base finder directly can be faster as
* it is more likely to avoid code branching and offers more control over the
* quality of the structure positions.
*
* The return value is zero if the seed is not a quad-base, and equal to the
* radius of the enclosing sphere if it is, and can be used as a measure of
* quality for the quad-base (smaller is better).
*/
int isTriBase(const StructureConfig sconf, const int64_t seed, const int64_t qual);
static inline float isQuadBase(const StructureConfig sconf, int64_t seed, int radius);
/* Starts a multi-threaded search for structure base seeds of the specified
* quality (chunk tolerance). The result is saved in a file of path 'fnam'.
/* Determines if the specified seed qualifies as a quad-base, given a required
* structure size. The structure size should include the actual dimensions of
* the structure and any additional size requirements where despawning shall
* not occur (such as fall damage drop chutes). A smaller size requirement can
* yield more seeds and relax constraints for other structure positions.
* (Since most structures use the same positioning algorithm with an offset,
* this also affects restrictions on the placement of other structure types.)
*
* The function variants are:
* isQuadBaseFeature24Classic() - finds only the classic constellations
* isQuadBaseFeature24() - optimisation for region=32,range=24,radius=128
* isQuadBaseFeature() - for small features (chunkRange not a power of 2)
* isQuadBaseLarge() - for large structures (chunkRange not a power of 2)
*
* The function returns the actual block radius to the furthest block inside
* any of the four structures or zero if the seed does not satisfy the
* quad-base requirements.
*
* @sconf : structure configuration
* @seed : world seed (only the lower 48-bits are relevant)
* @ax,ay,az : required structure size
* @radius : maximum radius for a sphere that encloses all four structures
*
* Implementation sidenote:
* Inline actually matters here, as these functions are not small and compilers
* generally don't want to inline them. However, these functions usually return
* so quickly that the function call is a major contributor to the overall time.
*/
static inline __attribute__((always_inline, const))
float isQuadBaseFeature24Classic (const StructureConfig sconf, int64_t seed);
static inline __attribute__((always_inline, const))
float isQuadBaseFeature24 (const StructureConfig sconf, int64_t seed,
int ax, int ay, int az);
static inline __attribute__((always_inline, const))
float isQuadBaseFeature (const StructureConfig sconf, int64_t seed,
int ax, int ay, int az, int radius);
static inline __attribute__((always_inline, const))
float isQuadBaseLarge (const StructureConfig sconf, int64_t seed,
int ax, int ay, int az, int radius);
// Defines how the search should limit the lower bits of the seed bases.
// Conveniently this also provides a way of specifying a quality category.
enum LowBitSet
{
LBIT_ALL, // all bit configurations
LBIT_IDEAL, // only the very best constellations that exist
LBIT_CLASSIC, // only classic constellations
LBIT_HUT_NORMAL, // sufficiently close for standard farm designs
LBIT_HUT_BARELY, // any constellation for huts within 128 blocks
};
/* Starts a multi-threaded search for quad-bases, given a maximum block radius
* for the enclosing sphere. The result is saved in a file of path 'fnam'.
*/
void search4QuadBases(const char *fnam, int threads,
const StructureConfig structureConfig, int quality);
const StructureConfig structureConfig, int radius, int lbitset);
void checkVec4QuadBases(const StructureConfig sconf, int64_t seeds[256]);
//==============================================================================
// Finding Structure Positions
//==============================================================================
/* Fast implementation for finding the block position at which the structure
* generation attempt will occur within the specified region.
* This function applies for scattered-feature structureSeeds and villages.
*/
Pos getStructurePos(const StructureConfig config, int64_t seed,
const int regionX, const int regionZ);
/* Finds the chunk position within the specified region (a square region of
* chunks depending on structure type) where the structure generation attempt
* will occur.
* This function applies for scattered-feature structureSeeds and villages.
*/
Pos getStructureChunkInRegion(const StructureConfig config, int64_t seed,
const int regionX, const int regionZ);
/* Fast implementation for finding the block position at which the ocean
* monument or woodland mansion generation attempt will occur within the
* specified region.
*/
Pos getLargeStructurePos(const StructureConfig config, int64_t seed,
const int regionX, const int regionZ);
/* Fast implementation for finding the chunk position at which the ocean
* monument or woodland mansion generation attempt will occur within the
* specified region.
*/
Pos getLargeStructureChunkInRegion(const StructureConfig config, int64_t seed,
const int regionX, const int regionZ);
/* Some structures check each chunk individually for viability.
* The placement and biome check within a valid chunk is at block position (9,9).
*/
int isMineshaftChunk(int64_t seed, const int chunkX, const int chunkZ);
int isTreasureChunk(int64_t seed, const int chunkX, const int chunkZ);
//==============================================================================
@ -280,7 +355,7 @@ int getBiomeAtPos(const LayerStack *g, const Pos pos);
* @isValid : boolean array of valid biome ids (size = 256)
* @seed : seed used for the RNG
* (initialise RNG using setSeed(&seed))
* @passes : number of valid biomes passed, set to NULL to ignore this
* @passes : (output) number of valid biomes passed, NULL to ignore
*/
Pos findBiomePosition(
const int mcversion,
@ -396,7 +471,7 @@ Pos estimateSpawn(const int mcversion, const LayerStack *g, int *cache, int64_t
* determine whether the corresponding structure would spawn there. You can get
* the block positions using the appropriate getXXXPos() function.
*
* @sconf : structure config for the type to be checked
* @structureType : structure type to be checked
* @mcversion : minecraft version
* @g : generator layer stack, seed will be applied to layers
* @seed : world seed, will be applied to generator
@ -404,8 +479,8 @@ Pos estimateSpawn(const int mcversion, const LayerStack *g, int *cache, int64_t
*
* The return value is non-zero if the position is valid.
*/
int isViableStructurePos(const StructureConfig sconf, int mcversion,
LayerStack *g, int64_t seed, int blockX, int blockZ);
int isViableStructurePos(int structureType, int mcversion, LayerStack *g,
int64_t seed, int blockX, int blockZ);
/* Checks if the specified structure type could generate in the given biome.
*/
@ -420,7 +495,8 @@ int isViableFeatureBiome(int structureType, int biomeID);
* This random object is used for recursiveGenerate() which is responsible for
* generating caves, ravines, mineshafts, and virtually all other structures.
*/
inline static int64_t chunkGenerateRnd(const int64_t worldSeed, const int chunkX, const int chunkZ)
inline static int64_t chunkGenerateRnd(const int64_t worldSeed,
const int chunkX, const int chunkZ)
{
int64_t rnd = worldSeed;
setSeed(&rnd);
@ -487,6 +563,414 @@ int checkForBiomes(
int hasAllTemps(LayerStack *g, int64_t seed, int x1024, int z1024);
//==============================================================================
// Implementaions for Functions that Ideally Should be Inlined
//==============================================================================
static inline __attribute__((const))
Pos getFeatureChunkInRegion(StructureConfig config, int64_t seed, int regX, int regZ)
{
/*
// Vanilla like implementation.
seed = regionX*341873128712 + regionZ*132897987541 + seed + structureSeed;
setSeed(&(seed));
Pos pos;
pos.x = nextInt(&seed, 24);
pos.z = nextInt(&seed, 24);
*/
Pos pos;
const int64_t K = 0x5deece66dLL;
const int64_t M = (1ULL << 48) - 1;
const int64_t b = 0xb;
// set seed
seed = seed + regX*341873128712 + regZ*132897987541 + config.salt;
seed = (seed ^ K);
seed = (seed * K + b) & M;
if (config.chunkRange & (config.chunkRange-1))
{
pos.x = (int)(seed >> 17) % config.chunkRange;
seed = (seed * K + b) & M;
pos.z = (int)(seed >> 17) % config.chunkRange;
}
else
{
// Java RNG treats powers of 2 as a special case.
pos.x = (config.chunkRange * (seed >> 17)) >> 31;
seed = (seed * K + b) & M;
pos.z = (config.chunkRange * (seed >> 17)) >> 31;
}
return pos;
}
static inline __attribute__((const))
Pos getFeaturePos(StructureConfig config, int64_t seed, int regX, int regZ)
{
Pos pos = getFeatureChunkInRegion(config, seed, regX, regZ);
// The structure is positioned at the chunk origin, but the biome check is
// performed near the middle of the chunk [(9,9) in 1.13, TODO: check 1.7]
// In 1.16 the biome check is always performed at (2,2) with layer scale=4.
pos.x = ((regX*config.regionSize + pos.x) << 4) + 9;
pos.z = ((regZ*config.regionSize + pos.z) << 4) + 9;
return pos;
}
static inline __attribute__((const))
Pos getLargeStructureChunkInRegion(StructureConfig config, int64_t seed, int regX, int regZ)
{
Pos pos;
const int64_t K = 0x5deece66dLL;
const int64_t M = (1ULL << 48) - 1;
const int64_t b = 0xb;
//TODO: power of two chunk ranges...
// set seed
seed = seed + regX*341873128712 + regZ*132897987541 + config.salt;
seed = (seed ^ K);
seed = (seed * K + b) & M;
pos.x = (int)(seed >> 17) % config.chunkRange;
seed = (seed * K + b) & M;
pos.x += (int)(seed >> 17) % config.chunkRange;
seed = (seed * K + b) & M;
pos.z = (int)(seed >> 17) % config.chunkRange;
seed = (seed * K + b) & M;
pos.z += (int)(seed >> 17) % config.chunkRange;
pos.x >>= 1;
pos.z >>= 1;
return pos;
}
static inline __attribute__((const))
Pos getLargeStructurePos(StructureConfig config, int64_t seed, int regX, int regZ)
{
Pos pos = getLargeStructureChunkInRegion(config, seed, regX, regZ);
pos.x = regX*config.regionSize + pos.x;
pos.z = regZ*config.regionSize + pos.z;
pos.x = pos.x*16 + 9;
pos.z = pos.z*16 + 9;
return pos;
}
static __attribute__((const))
float getEnclosingRadius(
int x0, int z0, int x1, int z1, int x2, int z2, int x3, int z3,
int ax, int ay, int az, int reg, int gap)
{
// convert chunks to blocks
x0 = (x0 << 4);
z0 = (z0 << 4);
x1 = ((reg+x1) << 4) + ax;
z1 = ((reg+z1) << 4) + az;
x2 = ((reg+x2) << 4) + ax;
z2 = (z2 << 4);
x3 = (x3 << 4);
z3 = ((reg+z3) << 4) + az;
int sqrad = 0x7fffffff;
// build the inner rectangle containing the center point
int cbx0 = (x1 > x2 ? x1 : x2) - gap;
int cbz0 = (z1 > z3 ? z1 : z3) - gap;
int cbx1 = (x0 < x3 ? x0 : x3) + gap;
int cbz1 = (z0 < z2 ? z0 : z2) + gap;
int x, z;
// brute force the ideal center position
for (z = cbz0; z <= cbz1; z++)
{
for (x = cbx0; x <= cbx1; x++)
{
int sq = 0;
int s;
s = (x-x0)*(x-x0) + (z-z0)*(z-z0); if (s > sq) sq = s;
s = (x-x1)*(x-x1) + (z-z1)*(z-z1); if (s > sq) sq = s;
s = (x-x2)*(x-x2) + (z-z2)*(z-z2); if (s > sq) sq = s;
s = (x-x3)*(x-x3) + (z-z3)*(z-z3); if (s > sq) sq = s;
if (sq < sqrad)
sqrad = sq;
}
}
return sqrad < 0x7fffffff ? sqrtf(sqrad + ay*ay/4.0f) : 0xffff;
}
static inline float isQuadBase(const StructureConfig sconf, int64_t seed, int radius)
{
switch(sconf.structType)
{
case Swamp_Hut:
if (radius == 128)
return isQuadBaseFeature24(sconf, seed, 7+1, 7+43+1, 9+1);
else
return isQuadBaseFeature(sconf, seed, 7+1, 7+43+1, 9+1, radius);
case Desert_Pyramid:
case Jungle_Pyramid:
case Igloo:
case Village:
// nothing special spawns here, why would you want these?
if (radius == 128)
return isQuadBaseFeature24(sconf, seed, 0, 0, 0);
else
return isQuadBaseFeature(sconf, seed, 0, 0, 0, radius);
case Outpost:
// Outposts are tricky. They require an additional 1 in 5 PRNG pass to
// generate and no village nearby. Also perfect quad-outposts don't
// exist as they are too large, given that the generation point will
// always be 8 chunks apart. However, the watchtower can be offset to
// the generation attempt by a chunk or two (TODO: investivgate this!).
return isQuadBaseFeature(sconf, seed, 72, 54, 72, radius);
case Monument:
return isQuadBaseLarge(sconf, seed, 58, 23, 58, radius);
//case Mansion:
//case Ocean_Ruin:
//case Shipwreck:
//case Ruined_Portal:
default:
fprintf(stderr, "ERR isQuadBase: not implemented for structure type"
" %d\n", sconf.structType);
exit(-1);
}
return 0;
}
// optimised version for regionSize=32,chunkRange=24,radius=128
static inline __attribute__((always_inline, const))
float isQuadBaseFeature24(const StructureConfig sconf, int64_t seed,
int ax, int ay, int az)
{
seed += sconf.salt;
int64_t s00 = seed;
int64_t s11 = 341873128712 + 132897987541 + seed;
const int64_t K = 0x5deece66dLL;
int x0, z0, x1, z1, x2, z2, x3, z3;
int x, z;
// check that the two structures in the opposing diagonal quadrants are
// close enough together
s00 ^= K;
JAVA_NEXT_INT24(s00, x0); if L(x0 < 20) return 0;
JAVA_NEXT_INT24(s00, z0); if L(z0 < 20) return 0;
s11 ^= K;
JAVA_NEXT_INT24(s11, x1); if L(x1 > x0-20) return 0;
JAVA_NEXT_INT24(s11, z1); if L(z1 > z0-20) return 0;
x = x1 + 32 - x0;
z = z1 + 32 - z0;
if (x*x + z*z > 255)
return 0;
int64_t s01 = 341873128712 + seed;
int64_t s10 = 132897987541 + seed;
s01 ^= K;
JAVA_NEXT_INT24(s01, x2); if L(x2 >= 4) return 0;
JAVA_NEXT_INT24(s01, z2); if L(z2 < 20) return 0;
s10 ^= K;
JAVA_NEXT_INT24(s10, x3); if L(x3 < 20) return 0;
JAVA_NEXT_INT24(s10, z3); if L(z3 >= 4) return 0;
x = x2 + 32 - x3;
z = z3 + 32 - z2;
if (x*x + z*z > 255)
return 0;
// only approx. 1 in 100M seeds makes it here, now we have to determine if
// there is a sphere, centered on a block, which is in range of all four
// structures
float sqrad = getEnclosingRadius(x0,z0,x1,z1,x2,z2,x3,z3,ax,ay,az,32,128);
return sqrad < 128 ? sqrad : 0;
}
// variant of isQuadBaseFeature24 which finds only the classic constellations
static inline __attribute__((always_inline, const))
float isQuadBaseFeature24Classic(const StructureConfig sconf, int64_t seed)
{
seed += sconf.salt;
int64_t s00 = seed;
int64_t s11 = 341873128712 + 132897987541 + seed;
const int64_t K = 0x5deece66dLL;
int p;
// check that the two structures in the opposing diagonal quadrants are
// close enough together
s00 ^= K;
JAVA_NEXT_INT24(s00, p); if L(p < 22) return 0;
JAVA_NEXT_INT24(s00, p); if L(p < 22) return 0;
s11 ^= K;
JAVA_NEXT_INT24(s11, p); if L(p > 1) return 0;
JAVA_NEXT_INT24(s11, p); if L(p > 1) return 0;
int64_t s01 = 341873128712 + seed;
int64_t s10 = 132897987541 + seed;
s01 ^= K;
JAVA_NEXT_INT24(s01, p); if L(p > 1) return 0;
JAVA_NEXT_INT24(s01, p); if L(p < 22) return 0;
s10 ^= K;
JAVA_NEXT_INT24(s10, p); if L(p < 22) return 0;
JAVA_NEXT_INT24(s10, p); if L(p > 1) return 0;
return 1; // should actually return one of 122.781311 or 127.887650
}
static inline __attribute__((always_inline, const))
float isQuadBaseFeature(const StructureConfig sconf, int64_t seed,
int ax, int ay, int az, int radius)
{
seed += sconf.salt;
int64_t s00 = seed;
int64_t s11 = 341873128712 + 132897987541 + seed;
const int64_t M = (1ULL << 48) - 1;
const int64_t K = 0x5deece66dLL;
const int64_t b = 0xbLL;
int x0, z0, x1, z1, x2, z2, x3, z3;
int x, z;
const int R = sconf.regionSize;
const int C = sconf.chunkRange;
int cd = radius/8;
int rm = R - (int)sqrtf(cd*cd - (R-C+1)*(R-C+1));
int64_t s;
s = s00 ^ K;
s = (s * K + b) & M; x0 = (int)(s >> 17) % C; if L(x0 <= rm) return 0;
s = (s * K + b) & M; z0 = (int)(s >> 17) % C; if L(z0 <= rm) return 0;
s = s11 ^ K;
s = (s * K + b) & M; x1 = (int)(s >> 17) % C; if L(x1 >= x0-rm) return 0;
s = (s * K + b) & M; z1 = (int)(s >> 17) % C; if L(z1 >= z0-rm) return 0;
// check that the two structures in the opposing diagonal quadrants are
// close enough together
x = x1 + R - x0;
z = z1 + R - z0;
if L(x*x + z*z > cd*cd)
return 0;
int64_t s01 = 341873128712 + seed;
int64_t s10 = 132897987541 + seed;
s = s01 ^ K;
s = (s * K + b) & M; x2 = (int)(s >> 17) % C; if L(x2 >= C-rm) return 0;
s = (s * K + b) & M; z2 = (int)(s >> 17) % C; if L(z2 <= rm) return 0;
s = s10 ^ K;
s = (s * K + b) & M; x3 = (int)(s >> 17) % C; if L(x3 <= rm) return 0;
s = (s * K + b) & M; z3 = (int)(s >> 17) % C; if L(z3 >= C-rm) return 0;
x = x2 + R - x3;
z = z3 + R - z2;
if L(x*x + z*z > cd*cd)
return 0;
float sqrad = getEnclosingRadius(
x0,z0,x1,z1,x2,z2,x3,z3,ax,ay,az,sconf.regionSize,radius);
return sqrad < radius ? sqrad : 0;
}
static inline __attribute__((always_inline, const))
float isQuadBaseLarge(const StructureConfig sconf, int64_t seed,
int ax, int ay, int az, int radius)
{
// Good quad-monument bases are very rare indeed. There are only two seeds
// for a radius below 148 blocks, between seed-bases 0 and 1e13:
// 775379617447 : radius=143.30 (400,384);(384,528);(528,384);(528,528)
// 3752024106001 : radius=145.07 (400,384);(400,560);(544,416);(528,512)
const int64_t M = (1ULL << 48) - 1;
const int64_t K = 0x5deece66dLL;
const int64_t b = 0xbLL;
seed += sconf.salt;
int64_t s00 = seed;
int64_t s01 = 341873128712 + seed;
int64_t s10 = 132897987541 + seed;
int64_t s11 = 341873128712 + 132897987541 + seed;
// p1 = nextInt(range); p2 = nextInt(range); pos = (p1+p2)>>1
const int R = sconf.regionSize;
const int C = sconf.chunkRange;
int rm = (int)(2 * R + ((ax<az?ax:az) - 2*radius + 7) / 8);
int64_t s;
int p;
int x0,z0,x1,z1,x2,z2,x3,z3;
s = s00 ^ K;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p <= rm) return 0;
x0 = p;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p <= rm) return 0;
z0 = p;
s = s11 ^ K;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p > x0-rm) return 0;
x1 = p;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p > z0-rm) return 0;
z1 = p;
s = ((x1-x0)>>1)*((x1-x0)>>1) + ((z1-z0)>>1)*((z1-z0)>>1);
if (s > 4*radius*radius)
return 0;
s = s01 ^ K;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p > x0-rm) return 0;
x2 = p;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p <= rm) return 0;
z2 = p;
s = s10 ^ K;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p <= rm) return 0;
x3 = p;
s = (s * K + b) & M; p = (int)(s >> 17) % C;
s = (s * K + b) & M; p += (int)(s >> 17) % C; if L(p > z0-rm) return 0;
z3 = p;
float sqrad = getEnclosingRadius(
x0>>1,z0>>1, x1>>1,z1>>1, x2>>1,z2>>1, x3>>1,z3>>1,
ax,ay,az, sconf.regionSize, radius);
return sqrad < radius ? sqrad : 0;
}
#ifdef __cplusplus
}
#endif

View File

@ -48,27 +48,23 @@ static inline double nextDouble(int64_t *seed)
return (((int64_t) next(seed, 26) << 27) + next(seed, 27)) / (double) (1LL << 53);
}
/* A macro to generate the ideal assembly for X = nextInt(S, 24)
* This is a macro and not an inline function, as many compilers can make use
* of the additional optimisation passes for the surrounding code.
*/
#define JAVA_NEXT_INT24(S,X) \
do { \
int64_t a = (1ULL << 48) - 1; \
int64_t c = 0x5deece66dLL * (S); \
c += 11; a &= c; \
(S) = a; \
a >>= 17; \
c = 0xaaaaaaab * a; \
c >>= 36; \
(X) = (int)a - (int)(c << 3) * 3; \
} while (0)
// Custom, faster alternative for the first and second call to nextInt(24)
static inline int firstInt24(int64_t seed)
{
seed ^= 0x5deece66d;
seed = (seed * 0x5deece66d) & 0xffffffffffff;
seed >>= 17;
return seed % 24;
}
static inline int secondInt24(int64_t seed)
{
seed ^= 0x5deece66d;
seed = (seed * 0x5deece66d + 0xb) & 0xffffffffffff;
seed = (seed * 0x5deece66d) & 0xffffffffffff;
seed >>= 17;
return seed % 24;
}
/* skipNextN
* ---------
* Jumps forwards in the random number sequence by simulating 'n' calls to next.

View File

@ -182,7 +182,7 @@ int mapZoomIsland(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int newW = (pW) << 1;
@ -264,7 +264,7 @@ int mapZoom(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int newW = (pW) << 1;
@ -361,7 +361,7 @@ int mapAddIsland(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t st = l->startSalt;
@ -474,7 +474,7 @@ int mapRemoveTooMuchOcean(const Layer * l, int * out, int x, int z, int w, int h
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -516,7 +516,7 @@ int mapAddSnow(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -560,7 +560,7 @@ int mapCoolWarm(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
for (j = 0; j < h; j++)
@ -599,7 +599,7 @@ int mapHeatIce(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
for (j = 0; j < h; j++)
@ -632,7 +632,7 @@ int mapHeatIce(const Layer * l, int * out, int x, int z, int w, int h)
int mapSpecial(const Layer * l, int * out, int x, int z, int w, int h)
{
int err = l->p->getMap(l->p, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t st = l->startSalt;
@ -672,7 +672,7 @@ int mapAddMushroomIsland(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -711,7 +711,7 @@ int mapDeepOcean(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
for (j = 0; j < h; j++)
@ -770,7 +770,7 @@ const int snowBiomes[] = {snowy_tundra, snowy_tundra, snowy_tundra, snowy_taiga}
int mapBiome(const Layer * l, int * out, int x, int z, int w, int h)
{
int err = l->p->getMap(l->p, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -826,7 +826,7 @@ const int lushBiomesBE[] = {forest, dark_forest, mountains, plains, plains, plai
int mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h)
{
int err = l->p->getMap(l->p, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -880,7 +880,7 @@ int mapBiomeBE(const Layer * l, int * out, int x, int z, int w, int h)
int mapRiverInit(const Layer * l, int * out, int x, int z, int w, int h)
{
int err = l->p->getMap(l->p, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -910,7 +910,7 @@ int mapRiverInit(const Layer * l, int * out, int x, int z, int w, int h)
int mapAddBamboo(const Layer * l, int * out, int x, int z, int w, int h)
{
int err = l->p->getMap(l->p, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -959,7 +959,7 @@ int mapBiomeEdge(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
for (j = 0; j < h; j++)
@ -1037,14 +1037,14 @@ int mapHills(const Layer * l, int * out, int x, int z, int w, int h)
}
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
buf = (int *) malloc(pW*pH*sizeof(int));
memcpy(buf, out, pW*pH*sizeof(int));
err = l->p2->getMap(l->p2, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
{
free(buf);
return err;
@ -1172,14 +1172,14 @@ int mapHills113(const Layer * l, int * out, int x, int z, int w, int h)
}
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
buf = (int *) malloc(pW*pH*sizeof(int));
memcpy(buf, out, pW*pH*sizeof(int));
err = l->p2->getMap(l->p2, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
{
free(buf);
return err;
@ -1318,7 +1318,7 @@ int mapRiver(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
for (j = 0; j < h; j++)
@ -1359,7 +1359,7 @@ int mapSmooth(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -1409,7 +1409,7 @@ int mapRareBiome(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int64_t ss = l->startSeed;
@ -1463,7 +1463,7 @@ int mapShore(const Layer * l, int * out, int x, int z, int w, int h)
int i, j;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
for (j = 0; j < h; j++)
@ -1563,7 +1563,7 @@ int mapRiverMix(const Layer * l, int * out, int x, int z, int w, int h)
int err = l->p->getMap(l->p, out, x, z, w, h); // biome chain
if (EXPECT(err, 0))
if U(err != 0)
return err;
len = w*h;
@ -1571,7 +1571,7 @@ int mapRiverMix(const Layer * l, int * out, int x, int z, int w, int h)
memcpy(buf, out, len*sizeof(int));
err = l->p2->getMap(l->p2, out, x, z, w, h); // rivers
if (EXPECT(err, 0))
if U(err != 0)
{
free(buf);
return err;
@ -1737,7 +1737,7 @@ int mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h)
}
int err = l->p2->getMap(l->p2, out, x, z, w, h);
if (EXPECT(err, 0))
if U(err != 0)
return err;
otyp = (int *) malloc(w*h*sizeof(int));
@ -1768,7 +1768,7 @@ int mapOceanMix(const Layer * l, int * out, int x, int z, int w, int h)
lw = lx1 - lx0;
lh = lz1 - lz0;
err = l->p->getMap(l->p, out, x+lx0, z+lz0, lw, lh);
if (EXPECT(err, 0))
if U(err != 0)
{
free(otyp);
return err;
@ -1855,7 +1855,7 @@ int mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h)
int pH = ((z + h) >> 2) - pZ + 2;
int err = l->p->getMap(l->p, out, pX, pZ, pW, pH);
if (EXPECT(err, 0))
if U(err != 0)
return err;
int newW = pW << 2;
@ -1933,11 +1933,11 @@ int mapVoronoiZoom(const Layer * l, int * out, int x, int z, int w, int h)
int64_t dd = (mi-dd1) * (mi-dd1) + sjd;
int v;
if (EXPECT( (da < db) && (da < dc) && (da < dd), 0 ))
if U((da < db) && (da < dc) && (da < dd))
v = v00;
else if (EXPECT( (db < da) && (db < dc) && (db < dd), 0 ))
else if U((db < da) && (db < dc) && (db < dd))
v = v10;
else if (EXPECT( (dc < da) && (dc < db) && (dc < dd), 0 ))
else if U((dc < da) && (dc < db) && (dc < dd))
v = v01;
else
v = v11;

View File

@ -17,10 +17,12 @@
#if __GNUC__
#define PREFETCH(PTR,RW,LOC) __builtin_prefetch(PTR,RW,LOC)
#define EXPECT(COND,VAL) __builtin_expect(COND,VAL)
#define L(COND) (__builtin_expect(!!(COND),1)) // [[likely]]
#define U(COND) (__builtin_expect((COND),0)) // [[unlikely]]
#else
#define PREFETCH(PTR)
#define EXPECT(COND,VAL) (COND)
#define L(COND) (COND)
#define U(COND) (COND)
#endif

View File

@ -17,7 +17,7 @@ endif
all: release
debug: CFLAGS += -DDEBUG -O0 -ggdb3
debug: libcubiomes
debug: libcubiomes find_quadhuts find_compactbiomes
release: CFLAGS += -O3 -march=native
release: libcubiomes find_quadhuts find_compactbiomes

File diff suppressed because it is too large Load Diff

View File

@ -1,223 +0,0 @@
10697299265738628
137642513762244484
240943830215055236
249106604539664260
323415998391277444
359444795410241412
386466393174464388
529455681343477636
635290272586684292
665408095094724484
733806514435413892
903254450415228804
977000894313420676
1067917311790962564
1089590884997683076
1241305897444726660
1308015466925152132
1372473236591892356
1391050585054795652
1485344702252865412
1516306949691037572
1591742243449493380
1610882541865817988
1615104666516477828
1648318713768335236
1662110987627157380
1751901505197856644
1790182102030505860
1798907826308536196
1841129072815134596
1905305367505164164
2014799133445609348
2091078852134197124
2108811775666968452
2243638289511372676
2443766997952649092
2698220376899082116
2783225819865700228
2956332930542753668
2960555055193413508
3020790700209493892
3311272876174890884
3312117301105022852
3410070593000331140
3424144341835863940
3465802638389041028
3495638985920370564
3542082357077628804
3555593155959740292
3632154349625038724
3674375596131637124
3758818089144833924
3910814576568588164
3962324497306638212
4038885690971936644
4199607902673721220
4289116945267709828
4438580157901068164
4530622475285452676
4569747497048233860
4642086566062872452
4742573132748576644
4861355572920473476
5066269355965831044
5089350304056104836
5206725369344448388
5281597713149482884
5295671461985015684
5349433182536750980
5549843365954738052
5738150125374166916
5804296744901171076
5851021591035139972
5860591740243302276
6083801396774852484
6161769965323704196
6249871633034139524
6317988577398118276
6432267417942644612
6818451085989664644
6844065308870334340
6857294632775735172
6895012279654963076
6972136423273682820
6988743446899611524
7028994368569235332
7080785764283996036
7199005254502471556
7262900074215790468
7353253541739911044
7392941513456113540
7417992786383361924
7464154682563909508
7501309379489716100
7633884093520435076
7691023513792698244
7831479527171315588
7971935540549932932
8049622634122073988
8092406830582093700
8196552571965036420
8214848445451229060
8266358366189279108
8430458277611591556
8456072500492261252
8634809110703527812
8643253360004847492
8724036678320805764
8762317275153454980
8763443175060297604
8764006125013718916
8841693218585859972
8949498134666041220
8961601558664599428
9050829126281877380
9082635798650181508
9170174516407195524
9214084612774057860
-9204511963264428156
-8996783430451964028
-8971169207571294332
-8961880533339842684
-8915155687205873788
-8893200639022442620
-8810165520892799100
-8754996425457510524
-8584141114594142332
-8530942343995828348
-8500261571534366844
-8360649983085881468
-8182194847851325564
-7939844892903450748
-7924363769184364668
-7685954463910439036
-7519321277697730684
-7281474922377226364
-7279786072516962428
-7267682648518404220
-7242912850567866492
-7015481069385656444
-7010695994781575292
-6798745337318451324
-6649282124685092988
-6456753240615004284
-6422694768433014908
-6391451046018132092
-6366962723044305020
-6263661406591494268
-6111383444191029372
-6094494945588390012
-6082391521589831804
-6077606446985750652
-6027785376107964540
-5909002935936067708
-5711970452238608508
-5642727607967787132
-5565603464349067388
-5512686168727464060
-5509308469006936188
-5380392929673455740
-5302705836101314684
-5278498988104198268
-5266395564105640060
-5223892842622331004
-5193775020114290812
-5113554651751753852
-4630543591716268156
-4398045260953266300
-4379749387467073660
-4350475989889165436
-4290240344873085052
-4271381521433471100
-4217338325905025148
-4087015411687991420
-4074067562759301244
-4002572918674794620
-3996661944163870844
-3960633147144906876
-3854235605948278908
-3841006282042878076
-3560657205239064700
-3558123930448668796
-3455667038925990012
-3421890041720711292
-3361935871681341564
-3238086881928652924
-3160962738309933180
-3073142545576208508
-3029795399162767484
-2909324109130606716
-2706099175945513084
-2616308658374813820
-2417868799793801340
-2297960459715061884
-2197473893029357692
-2067150978812323964
-2042099705885075580
-1950338863477401724
-1841689522467088508
-1739232630944409724
-1710522183319922812
-1664641762116085884
-1660138162488715388
-1659856687512004732
-1644375563792918652
-1602717267239741564
-1490127276555479164
-1487875476741793916
-1445935705211906172
-1268043519930771580
-1173186452779280508
-1056937287397779580
-883267226767304828
-813742907519772796
-558445103643207804
-532267930809116796
-454299362260265084
-332139222367840380
-324820872973363324
-281192251583211644
-211386457358968956
-188024034291984508

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff