cubiomes/finders.h
Cubitect 89df24c3be Update spawn algorithm for 1.21.2 + cmake + more
* added basic support for cmake (#127)
* renamed Winter Drop version from MC_1_21_3 to MC_1_21_WD
* updated world spawn location for 1.21.2 (cubiomes-viewer #340)
* tweaked mc version to text conversion (#128)
* removed properties field in structure config and added dimension field instead
* moved biome tree selection back to biomenoise.c as it's slightly faster and avoids globals
2024-11-09 21:08:05 +01:00

843 lines
29 KiB
C

#ifndef FINDERS_H_
#define FINDERS_H_
#include "generator.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define MASK48 (((int64_t)1 << 48) - 1)
enum StructureType
{
Feature, // for locations of temple generation attempts pre 1.13
Desert_Pyramid,
Jungle_Temple, Jungle_Pyramid = Jungle_Temple,
Swamp_Hut,
Igloo,
Village,
Ocean_Ruin,
Shipwreck,
Monument,
Mansion,
Outpost,
Ruined_Portal,
Ruined_Portal_N,
Ancient_City,
Treasure,
Mineshaft,
Desert_Well,
Geode,
Fortress,
Bastion,
End_City,
End_Gateway,
End_Island,
Trail_Ruins,
Trial_Chambers,
FEATURE_NUM
};
// use getStructureConfig() for the version specific structure configuration
STRUCT(StructureConfig)
{
int32_t salt;
int8_t regionSize;
int8_t chunkRange;
uint8_t structType;
int8_t dim;
float rarity;
};
STRUCT(Pos) { int x, z; };
STRUCT(Pos3) { int x, y, z; };
STRUCT(StrongholdIter)
{
Pos pos; // accurate location of current stronghold
Pos nextapprox; // approxmimate location (+/-112 blocks) of next stronghold
int index; // stronghold index counter
int ringnum; // ring number for index
int ringmax; // max index within ring
int ringidx; // index within ring
double angle; // next angle within ring
double dist; // next distance from origin (in chunks)
uint64_t rnds; // random number seed (48 bit)
int mc; // minecraft version
};
STRUCT(StructureVariant)
{
uint8_t abandoned :1; // is zombie village
uint8_t giant :1; // giant portal variant
uint8_t underground :1; // underground portal
uint8_t airpocket :1; // portal with air pocket
uint8_t basement :1; // igloo with basement
uint8_t cracked :1; // geode with crack
uint8_t size; // geode size | igloo middel pieces
uint8_t start; // starting piece index
short biome; // biome variant
uint8_t rotation; // 0:0, 1:cw90, 2:cw180, 3:cw270=ccw90
uint8_t mirror;
int16_t x, y, z;
int16_t sx, sy, sz;
};
STRUCT(Piece)
{
const char *name; // structure piece name
Pos3 pos, bb0, bb1; // position and bounding box limits
uint8_t rot; // rotation
int8_t depth;
int8_t type;
Piece *next;
};
STRUCT(EndIsland)
{
int x, y, z;
int r;
};
enum
{
BF_APPROX = 0x01, // enabled aggresive filtering, trading accuracy
BF_FORCED_OCEAN = FORCE_OCEAN_VARIANTS,
};
STRUCT(BiomeFilter)
{
// bitfields for biomes required at their respecive layers
uint64_t tempsToFind; // Special (1:1024)
uint64_t otempToFind; // OceanTemp (1:256)
uint64_t majorToFind; // Biome (1:256)
uint64_t edgesToFind; // Edge (1:64) [mod64: as special case for bamboo]
// bitfields for biomes to find at RareBiome(1:64), Shore(1:16) and Mix(1:4)
// layers for (biomeID < 64) and modified (biomeID >= 128 && biomeID < 192)
uint64_t raresToFind, raresToFindM;
uint64_t shoreToFind, shoreToFindM;
uint64_t riverToFind, riverToFindM;
uint64_t oceanToFind; // all required ocean types
int specialCnt; // number of special temperature categories required
uint32_t flags;
// the biome exclusion aborts generation when the area contains no biomes
// that can generate the excluded biomes
uint64_t tempsToExcl;
uint64_t majorToExcl;
uint64_t edgesToExcl;
uint64_t raresToExcl, raresToExclM;
uint64_t shoreToExcl, shoreToExclM;
uint64_t riverToExcl, riverToExclM;
uint64_t biomeToExcl, biomeToExclM;
uint64_t biomeToFind, biomeToFindM;
uint64_t biomeToPick, biomeToPickM;
};
/***************************** Structure Positions *****************************
*
* 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).
*
* 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.
*/
//==============================================================================
// Moving Structures
//==============================================================================
/* Transposes a base seed such that structures are moved by the specified region
* vector, (regX, regZ).
*/
static inline uint64_t moveStructure(uint64_t baseSeed, int regX, int regZ)
{
return (baseSeed - regX*341873128712 - regZ*132897987541) & 0xffffffffffff;
}
//==============================================================================
// Finding Structure Positions
//==============================================================================
/* Selects the structure configuration for a given version. Returns zero upon
* failure (e.g. version does not support structure type).
*/
int getStructureConfig(int structureType, int mc, StructureConfig *sconf);
/* The library can be compiled to use a custom internal getter for structure
* configurations. For this, the macro STRUCT_CONFIG_OVERRIDE should be defined
* as true and the function getStructureConfig_override() should be defined
* with a custom function body. However, note this is experimental and not all
* structure configs may work. (Ideally only change structure salts.)
*/
#if STRUCT_CONFIG_OVERRIDE
int getStructureConfig_override(int stype, int mc, StructureConfig *sconf);
#endif
/* Finds the block position of the structure generation attempt in a given
* region. You can use isViableStructurePos() to test if the necessary biome
* requirements are met for the structure to actually generate at that position.
* Some structure types may fail to produce a valid position in the given
* region regardless of biomes, in which case the function returns zero.
*
* @structureType : structure type
* @mc : minecraft version
* @seed : world seed (only the lower 48-bits are relevant)
* @regX,regZ : region coordinates (the region size depends on type)
* @pos : output block position
*
* Returns zero if the position is invalid, or non-zero otherwise.
*/
int getStructurePos(int structureType, int mc, uint64_t seed, int regX, int regZ, Pos *pos);
/* The inline functions below get the generation attempt position given a
* structure configuration. Most small structures use the getFeature..
* variants, which have a uniform distribution, while large structures
* (monuments and mansions) have a triangular distribution.
*/
static inline ATTR(const)
Pos getFeaturePos(StructureConfig config, uint64_t seed, int regX, int regZ);
static inline ATTR(const)
Pos getFeatureChunkInRegion(StructureConfig config, uint64_t seed, int regX, int regZ);
static inline ATTR(const)
Pos getLargeStructurePos(StructureConfig config, uint64_t seed, int regX, int regZ);
static inline ATTR(const)
Pos getLargeStructureChunkInRegion(StructureConfig config, uint64_t seed, int regX, int regZ);
/* Checks a chunk area, starting at (chunkX, chunkZ) with size (chunkW, chunkH)
* for Mineshaft positions. If not NULL, positions are written to the buffer
* 'out' up to a maximum number of 'nout'. The return value is the number of
* chunks with Mineshafts in the area.
*/
int getMineshafts(int mc, uint64_t seed, int chunkX, int chunkZ,
int chunkW, int chunkH, Pos *out, int nout);
// not exacly a structure
static inline ATTR(const)
int isSlimeChunk(uint64_t seed, int chunkX, int chunkZ)
{
uint64_t rnd = seed;
rnd += (int)(chunkX * 0x5ac0db);
rnd += (int)(chunkX * chunkX * 0x4c1906);
rnd += (int)(chunkZ * 0x5f24f);
rnd += (int)(chunkZ * chunkZ) * 0x4307a7ULL;
rnd ^= 0x3ad8025fULL;
setSeed(&rnd, rnd);
return nextInt(&rnd, 10) == 0;
}
/* Finds the position and size of the small end islands in a given chunk.
* Returns the number of end islands found.
*/
int getEndIslands(EndIsland islands[2], int mc, uint64_t seed, int chunkX, int chunkZ);
/* Finds the small end islands in the given area and updates the existing
* height map, y, accordingly. Note that values in the y-map can only increase
* using this.
*/
int mapEndIslandHeight(float *y, const EndNoise *en, uint64_t seed,
int x, int z, int w, int h, int scale);
/* Checks if the given chunk contains no blocks. This included a check for
* small end islands.
*/
int isEndChunkEmpty(const EndNoise *en, const SurfaceNoise *sn, uint64_t seed,
int chunkX, int chunkZ);
//==============================================================================
// Finding Strongholds and Spawn
//==============================================================================
/* Finds the approximate location of the first stronghold (+/-112 blocks),
* which can be determined from the lower 48 bits of the world seed without
* biome checks. If 'sh' is not NULL, it will be initialized for iteration
* using nextStronghold() to get the accurate stronghold locations, as well as
* the subsequent approximate stronghold positions.
*
* @sh : stronghold iterator to be initialized (nullable)
* @mc : minecraft version
* @s48 : world seed (only 48-bit are relevant)
*
* Returns the approximate block position of the first stronghold.
*/
Pos initFirstStronghold(StrongholdIter *sh, int mc, uint64_t s48);
/* Performs the biome checks for the stronghold iterator and finds its accurate
* location, as well as the approximate location of the next stronghold.
*
* @sh : stronghold iteration state, holding position info
* @g : generator, should be initialized for Overworld generation,
* for version 1.19.3+ the generator may be left NULL to iterate
* over the approximate locations without biome check
*
* Returns the number of further strongholds after this one.
*/
int nextStronghold(StrongholdIter *sh, const Generator *g);
/* Finds the approximate spawn point in the world.
* The random state 'rng' output can be NULL to ignore.
*/
Pos estimateSpawn(const Generator *g, uint64_t *rng);
/* Finds the spawn point in the world.
* Warning: Slow, and may be inaccurate because the world spawn depends on
* grass blocks!
*/
Pos getSpawn(const Generator *g);
/* Finds a suitable pseudo-random location in the specified area.
* This function is used to determine the positions of spawn and strongholds.
* Warning: accurate, but slow!
*
* @g : generator for Overworld biomes
* @x,y,z : origin for the search
* @radius : square 'radius' of the search
* validB : valid biomes, as a bitset for biomes with 0 <= id < 64
* validM : valid biomes, as a bitset for biomes with 192 <= id < 256
* @rnd : random obj, initialise using setSeed(rnd, world_seed)
* @passes : (output) number of valid biomes passed, NULL to ignore
*/
Pos locateBiome(
const Generator *g, int x, int y, int z, int radius,
uint64_t validB, uint64_t validM, uint64_t *rng, int *passes);
/* Get the shadow seed.
*/
static inline uint64_t getShadow(uint64_t seed)
{
return -7379792620528906219LL - seed;
}
//==============================================================================
// Validating Structure Positions
//==============================================================================
/* Performs a biome check near the specified block coordinates to determine
* whether a structure of the given type could spawn there. You can get the
* block positions using getStructurePos().
* The generator, 'g', should be initialized for the correct MC version,
* dimension and seed. The generator may be temporarily modified during the
* function call, but will be restored upon return.
* The 'flags' argument is optional structure specific information, such as the
* biome variant for villages.
*/
int isViableStructurePos(int structType, Generator *g, int blockX, int blockZ, uint32_t flags);
/* Checks if the specified structure type could generate in the given biome.
*/
int isViableFeatureBiome(int mc, int structureType, int biomeID);
/* Some structures in 1.18 now only spawn if the surface is sufficiently high
* at all four bounding box corners. This affects primarily Desert_Pyramids,
* Jungle_Temples and Mansions.
* Currently cubiomes does not provide overworld surface height and cannot
* check it, but we can rule out some unlikely positions based biomes.
*
* This function is meant only for the 1.18 Overworld and is subject to change.
*/
int isViableStructureTerrain(int structType, Generator *g, int blockX, int blockZ);
/* End Cities require a sufficiently high surface in addition to a biome check.
* The world seed should be applied to the EndNoise and SurfaceNoise before
* calling this function. (Use initSurfaceNoiseEnd() for initialization.)
*/
int isViableEndCityTerrain(const Generator *g, const SurfaceNoise *sn,
int blockX, int blockZ);
//==============================================================================
// Finding Properties of Structures
//==============================================================================
/* Initialises and returns a random seed used in the (16x16) chunk generation.
* This random object is used for recursiveGenerate() which is responsible for
* generating caves, ravines, mineshafts, and virtually all other structures.
*/
inline static
uint64_t chunkGenerateRnd(uint64_t worldSeed, int chunkX, int chunkZ)
{
uint64_t rnd;
setSeed(&rnd, worldSeed);
rnd = (nextLong(&rnd) * chunkX) ^ (nextLong(&rnd) * chunkZ) ^ worldSeed;
setSeed(&rnd, rnd);
return rnd;
}
/* Get data, such as rotation and bounding box of a structure instance.
* (Supports only some structure types.)
*/
int getVariant(StructureVariant *sv, int structType, int mc, uint64_t seed,
int blockX, int blockZ, int biomeID);
/* Generate the structure pieces of an End City. This pieces buffer should be
* large enough to hold END_CITY_PIECES_MAX elements.
* @pieces : output buffer
* @seed : world seed
* @chunkX, chunkZ : 16x16 chunk position
*
* Returns the number of structure pieces generated.
*/
int getEndCityPieces(Piece *pieces, uint64_t seed, int chunkX, int chunkZ);
enum
{ // End City piece types
BASE_FLOOR,
BASE_ROOF,
BRIDGE_END,
BRIDGE_GENTLE_STAIRS,
BRIDGE_PIECE,
BRIDGE_STEEP_STAIRS,
FAT_TOWER_BASE,
FAT_TOWER_MIDDLE,
FAT_TOWER_TOP,
SECOND_FLOOR_1,
SECOND_FLOOR_2,
SECOND_ROOF,
END_SHIP,
THIRD_FLOOR_1,
THIRD_FLOOR_2,
THIRD_ROOF,
TOWER_BASE,
TOWER_FLOOR, // unused
TOWER_PIECE,
TOWER_TOP,
END_CITY_PIECES_MAX = 421
};
/* Generate the structure pieces of a Nether Fortress. The maximum number of
* pieces that are generated is limited to 'n'. A buffer length of around 400
* should be sufficient in practice, but a fortress can in theory contain many
* more than that. The number of generated pieces is given by the return value.
*/
int getFortressPieces(Piece *list, int n, int mc, uint64_t seed, int chunkX, int chunkZ);
enum
{ // Fortress piece types
FORTRESS_START,
BRIDGE_STRAIGHT,
BRIDGE_CROSSING,
BRIDGE_FORTIFIED_CROSSING,
BRIDGE_STAIRS,
BRIDGE_SPAWNER,
BRIDGE_CORRIDOR_ENTRANCE,
CORRIDOR_STRAIGHT,
CORRIDOR_CROSSING,
CORRIDOR_TURN_RIGHT,
CORRIDOR_TURN_LEFT,
CORRIDOR_STAIRS,
CORRIDOR_T_CROSSING,
CORRIDOR_NETHER_WART,
FORTRESS_END,
PIECE_COUNT,
};
/* Find the 20 fixed inner positions where End Gateways generate upon defeating
* the Dragon. The positions are written to 'src' in generation order.
*/
void getFixedEndGateways(int mc, uint64_t seed, Pos src[20]);
/* Get the outer linked Gateway destination for an inner source Gateway.
* (mc > MC_1_12)
*/
Pos getLinkedGatewayChunk(const EndNoise *en, const SurfaceNoise *sn,
uint64_t seed, Pos src, Pos *dst);
Pos getLinkedGatewayPos(const EndNoise *en, const SurfaceNoise *sn,
uint64_t seed, Pos src);
/* Find the number of each type of house that generate in a village
* (mc < MC_1_14)
* @housesOut : output number of houses for each entry in the house type
* enum (i.e this should be an array of length HOUSE_NUM)
* @seed : world seed
* @chunkX, chunkZ : 16x16 chunk position of the village origin
*
* Returns the random object seed after finding these numbers.
*/
enum
{
HouseSmall, Church, Library, WoodHut, Butcher, FarmLarge, FarmSmall,
Blacksmith, HouseLarge, HOUSE_NUM
};
uint64_t getHouseList(int *houses, uint64_t seed, int chunkX, int chunkZ);
//==============================================================================
// Seed Filters (generic)
//==============================================================================
/* Add the given biome 'id' to a biome set which is represented by the
* bitfields mL and mM for ids 0-63 and 128-191, respectively.
*/
static inline void idSetAdd(uint64_t *mL, uint64_t *mM, int id)
{
switch (id & ~0x3f) {
case 0: *mL |= 1ULL << id; break; // [0, 64)
case 128: *mM |= 1ULL << (id-128); break; // [128, 192)
}
}
static inline int idSetTest(uint64_t mL, uint64_t mM, int id)
{
switch (id & ~0x3f) {
case 0: return !!(mL & (1ULL << id)); // [0, 64)
case 128: return !!(mM & (1ULL << (id-128))); // [128, 192)
}
return 0;
}
/* Samples biomes within the specified range and checks that at least a given
* proportion of the biomes in that area evaluate as successes.
*
* @g : biome generator
* @r : range to be checked
* @rng : random number seed for the sampling positions
* @coverage : minimum coverage of successful evaluations, [0,1]
* @confidence : confidence level, (0,1), e.g. 0.95 for a 95% confidence
* @eval : evaluation function - 0:fail, 1:success, -1:skip, else:abort
* @data : data argument for eval()
*
* Returns non-zero if a sufficient proportion of the sampled positions
* evaluted as successes.
*/
int monteCarloBiomes(
Generator * g,
Range r,
uint64_t * rng,
double coverage,
double confidence,
int (*eval)(Generator *g, int scale, int x, int y, int z, void *data),
void * data
);
//==============================================================================
// Seed Filters (for versions up to 1.17)
//==============================================================================
/* Creates a biome filter configuration from a given list of required and
* excluded biomes. Biomes should not appear in both lists. Lists of length
* zero may be passed as null.
*/
void setupBiomeFilter(
BiomeFilter *bf,
int mc, uint32_t flags,
const int *required, int requiredLen,
const int *excluded, int excludedLen,
const int *matchany, int matchanyLen);
/* Starts to generate the specified range and checks if the biomes meet the
* requirements of the biome filter, returning either:
* 0 (failed),
* 1 (okay, area is fully generated), or
* 2 (okay, incomplete generation).
*
* The area will be generated inside the cache (if != NULL) but is only
* defined if the generation was fully completed (check return value).
* More aggressive filtering can be enabled with the flags which may yield
* some false negatives in exchange for speed.
*
* The generator should be set up for the correct version, however the
* dimension and seed will be applied internally. This will modify the
* generator into a partially initialized state that is not valid to use
* outside this function without re-applying a seed.
*
* @g : biome generator
* @cache : working buffer and output (nullable)
* @r : range to be checked
* @dim : dimension (0:Overworld, -1:Nether, +1:End)
* @seed : world seed
* @filter : biome requirements to be met
* @flags : enables features (see below)
* @stop : occasional check for abort (nullable)
*/
int checkForBiomes(
Generator * g,
int * cache,
Range r,
int dim,
uint64_t seed,
const BiomeFilter * filter,
volatile char * stop // should be atomic, but is fine as stop flag
);
/* Specialization of checkForBiomes() for a LayerStack, i.e. the Overworld up
* to 1.17.
*
* @ls : layered generator (will be modified!)
* @entry : generation entry point (setLayerSeed() may be applied here)
* @cache : working buffer, and output (if != NULL)
* @seed : world seed
* @x,z,w,h : requested area
* @filter : biomes to be checked for
*/
int checkForBiomesAtLayer(
LayerStack * ls,
Layer * entry,
int * cache,
uint64_t seed,
int x,
int z,
unsigned int w,
unsigned int h,
const BiomeFilter * filter
);
/* Checks that the area (x,z,w,h) at layer Special, scale 1:1024 contains the
* temperature category requirements defined by 'tc' as:
* if (tc[TEMP_CAT] >= 0) require at least this many entries of this category
* if (tc[TEMP_CAT] < 0) avoid, there shall be no entries of this category
* TEMP_CAT is any of:
* Oceanic, Warm, Lush, Cold, Freeing, Special+Warm, Special+Lush, Special+Cold
* For 1.7-1.17 only.
*/
int checkForTemps(LayerStack *g, uint64_t seed, int x, int z, int w, int h, const int tc[9]);
/* Find the center positions for a given biome id.
* @pos : output biome center positions
* @siz : output size of biomes (nullable)
* @nmax : maximum number of output entries
* @g : generator, should be initialized for overworld generation
* @r : area to examine, requires: scale = 4, sy = 1
* @match : biome id to find
* @minsiz : minimum size of output biomes
* @tol : border tolerance
* @stop : stopping flag (nullable)
* Returns the number of entries written to pos and siz.
*/
int getBiomeCenters(
Pos * pos,
int * siz,
int nmax,
Generator * g,
Range r,
int match,
int minsiz,
int tol,
volatile char * stop
);
/* Checks if a biome may generate given a version and layer ID as entry point.
* The supported layers are:
* L_BIOME_256, L_BAMBOO_256, L_BIOME_EDGE_64, L_HILLS_64, L_SUNFLOWER_64,
* L_SHORE_16, L_RIVER_MIX_4, L_OCEAN_MIX_4, L_VORONOI_1
* (provided the version matches)
*/
int canBiomeGenerate(int layerId, int mc, uint32_t flags, int biomeID);
/* Given a 'biomeID' at a generation 'layerId', this functions finds which
* biomes may generate from it. The result is stored in the bitfields:
* mL : for ids 0-63
* mM : for ids 128-191
*/
void genPotential(uint64_t *mL, uint64_t *mM, int layerId, int mc, uint32_t flags, int biomeID);
/* Gets the biomes that can generate in the given version and layer ID.
* In contrast to canBiomeGenerate() and genPotential() it also supports
* L_OCEAN_TEMP_256 and 1.18+, where the layerId is ignored.
* mL : for ids 0-63
* mM : for ids 128-191
*/
void getAvailableBiomes(uint64_t *mL, uint64_t *mM, int layerId, int mc, uint32_t flags);
//==============================================================================
// Biome Noise Finders (for 1.18+)
//==============================================================================
/**
* Runs a gradient descent towards the minimum of the noise parameter times a
* given factor. The algorithm is restricted to the area (x,z,w,h) and starts
* at (i0,j0) relative to (x,z). The iteration is terminated when either
* 1) a fix point has been reached,
* 2) maxiter iterations have been completed,
* 3) or the sampling position has moved more than maxrad away from (i0,j0).
*
* Alpha is an optimization argument that is used to determine the length of
* large steps based on the current gradient.
*
* Optionally, the iteration can also call the custom function:
* func(data, x, z, factor*para_noise(x,z));
*
* The return value is the minimum value reached.
*/
double getParaDescent(const DoublePerlinNoise *para, double factor,
int x, int z, int w, int h, int i0, int j0, int maxrad,
int maxiter, double alpha, void *data, int (*func)(void*,int,int,double));
/**
* Determines the value range of a climate noise parameter over the given area.
* The sampling has scale 1:4 and sampling shift is not considered, so biomes
* could potentially *leak* in at the boarders.
* An optional function:
* func(data, x, z, climate_noise(x,z))
* is called in each gradient descent iteration. If this function returns
* non-zero the search is aborted, the results are undefined and a non-zero
* error is returned.
*
* The results are written to pmin and pmax (which would be cast to an integer
* during boime mapping). Nullable, to look for minima and maxima separately.
*/
int getParaRange(const DoublePerlinNoise *para, double *pmin, double *pmax,
int x, int z, int w, int h, void *data, int (*func)(void*,int,int,double));
/**
* Gets the min/max parameter values within which a biome change can occur.
*/
const int *getBiomeParaExtremes(int mc);
/**
* Gets the min/max possible noise parameter values at which the given biome
* can generate. The values are in min/max pairs in order of:
* temperature, humidity, continentalness, erosion, depth, weirdness.
*/
const int *getBiomeParaLimits(int mc, int id);
/**
* Determines which biomes are able to generate given a set of climate
* parameter limits. Possible biomes are marked non-zero in the 'ids'.
*/
void getPossibleBiomesForLimits(char ids[256], int mc, int limits[6][2]);
/**
* Find the largest rectangle in ids[sx][sz] which consists only of 'match'.
* The limit corners are written to p0 and p1. Returned is the rectangle's area.
*/
int getLargestRec(int match, const int *ids, int sx, int sz, Pos *p0, Pos *p1);
//==============================================================================
// Implementaions for Functions that Ideally Should be Inlined
//==============================================================================
static inline ATTR(const)
Pos getFeatureChunkInRegion(StructureConfig config, uint64_t seed, int regX, int regZ)
{
/*
// Vanilla like implementation.
setSeed(&seed, regX*341873128712 + regZ*132897987541 + seed + config.salt);
Pos pos;
pos.x = nextInt(&seed, 24);
pos.z = nextInt(&seed, 24);
*/
Pos pos;
const uint64_t K = 0x5deece66dULL;
const uint64_t M = (1ULL << 48) - 1;
const uint64_t b = 0xb;
// set seed
seed = seed + regX*341873128712ULL + regZ*132897987541ULL + config.salt;
seed = (seed ^ K);
seed = (seed * K + b) & M;
uint64_t r = config.chunkRange;
if (r & (r-1))
{
pos.x = (int)(seed >> 17) % r;
seed = (seed * K + b) & M;
pos.z = (int)(seed >> 17) % r;
}
else
{
// Java RNG treats powers of 2 as a special case.
pos.x = (int)((r * (seed >> 17)) >> 31);
seed = (seed * K + b) & M;
pos.z = (int)((r * (seed >> 17)) >> 31);
}
return pos;
}
static inline ATTR(const)
Pos getFeaturePos(StructureConfig config, uint64_t seed, int regX, int regZ)
{
Pos pos = getFeatureChunkInRegion(config, seed, regX, regZ);
pos.x = (int)(((uint64_t)regX*config.regionSize + pos.x) << 4);
pos.z = (int)(((uint64_t)regZ*config.regionSize + pos.z) << 4);
return pos;
}
static inline ATTR(const)
Pos getLargeStructureChunkInRegion(StructureConfig config, uint64_t seed, int regX, int regZ)
{
Pos pos;
const uint64_t K = 0x5deece66dULL;
const uint64_t M = (1ULL << 48) - 1;
const uint64_t b = 0xb;
//TODO: power of two chunk ranges...
// set seed
seed = seed + regX*341873128712ULL + regZ*132897987541ULL + 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 ATTR(const)
Pos getLargeStructurePos(StructureConfig config, uint64_t seed, int regX, int regZ)
{
Pos pos = getLargeStructureChunkInRegion(config, seed, regX, regZ);
pos.x = (int)(((uint64_t)regX*config.regionSize + pos.x) << 4);
pos.z = (int)(((uint64_t)regZ*config.regionSize + pos.z) << 4);
return pos;
}
#ifdef __cplusplus
}
#endif
#endif // FINDERS_H_