-
Notifications
You must be signed in to change notification settings - Fork 104
/
finders.h
842 lines (728 loc) · 29 KB
/
finders.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
#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_