mirror of
https://github.com/Cubitect/cubiomes.git
synced 2025-01-07 03:06:38 +08:00
89df24c3be
* 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
843 lines
29 KiB
C
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_
|
|
|