├── .gitignore ├── ChunkData.cpp ├── ChunkData.h ├── ChunkGenerator.cpp ├── ChunkGenerator.h ├── NoiseGeneratorImproved.cpp ├── NoiseGeneratorImproved.h ├── NoiseGeneratorOctaves.cpp ├── NoiseGeneratorOctaves.h ├── NoiseGeneratorPerlin.cpp ├── NoiseGeneratorPerlin.h ├── NoiseGeneratorSimplex.cpp ├── NoiseGeneratorSimplex.h ├── README.md ├── Search.cpp ├── Search.h └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | x64 2 | Release 3 | Debug 4 | FormationFinder.sln 5 | FormationFinder.vcxproj* 6 | .vs -------------------------------------------------------------------------------- /ChunkData.cpp: -------------------------------------------------------------------------------- 1 | #include "ChunkData.h" 2 | 3 | int ChunkData::getBlock(int x, int y, int z) 4 | { 5 | return blocks_[x][y][z]; 6 | } 7 | void ChunkData::setBlock(int x, int y, int z, int block) 8 | { 9 | blocks_[x][y][z] = block; 10 | } 11 | 12 | int ChunkHeightmap::getHeightmap(int x, int z) 13 | { 14 | return heightmap_[x][z]; 15 | } 16 | void ChunkHeightmap::setHeightmap(int x, int z, int height) 17 | { 18 | heightmap_[x][z] = height; 19 | } 20 | int ChunkHeightmap::getBlock(int x, int y, int z) // 1 == terrain, 0 == air 21 | { 22 | return heightmap_[x][z] == y ? 1 : 0; 23 | } -------------------------------------------------------------------------------- /ChunkData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef CHUNKDATA_H 3 | #define CHUNKDATA_H 4 | 5 | class ChunkData 6 | { 7 | public: 8 | ChunkData() {}; 9 | ~ChunkData() {}; 10 | 11 | int getBlock(int, int, int); 12 | void setBlock(int, int, int, int); 13 | 14 | private: 15 | int blocks_[16][256][16]; 16 | }; 17 | 18 | class ChunkHeightmap 19 | { 20 | public: 21 | ChunkHeightmap() {}; 22 | ~ChunkHeightmap() {}; 23 | 24 | int getHeightmap(int, int); 25 | void setHeightmap(int, int, int); 26 | 27 | int getBlock(int, int, int); 28 | 29 | private: 30 | int heightmap_[16][16]; 31 | }; 32 | 33 | #endif -------------------------------------------------------------------------------- /ChunkGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "ChunkGenerator.h" 2 | #include "generator.h" 3 | #include 4 | 5 | ChunkGenerator::ChunkGenerator(uint64_t world_seed, MCversion version) 6 | { 7 | version_ = version; 8 | 9 | uint64_t seed = world_seed; 10 | uint64_t seedcopy = world_seed; 11 | setSeed(&seed, world_seed); 12 | 13 | minLimitPerlinNoise = std::make_unique(&seed, 16); 14 | maxLimitPerlinNoise = std::make_unique(&seed, 16); 15 | mainPerlinNoise = std::make_unique(&seed, 8); 16 | surfaceNoise = std::make_unique(&seed, 4); 17 | scaleNoise = std::make_unique(&seed, 10); 18 | depthNoise = std::make_unique(&seed, 16); 19 | forestNoise = std::make_unique(&seed, 8); 20 | 21 | for (int i = -2; i <= 2; ++i) 22 | { 23 | for (int j = -2; j <= 2; ++j) 24 | { 25 | float f = 10.0F / sqrt((float)(i * i + j * j) + 0.2F); 26 | biomeWeights[i + 2 + (j + 2) * 5] = f; 27 | } 28 | } 29 | amplified_ = false; 30 | 31 | top_block_ = GRASS; 32 | filler_block_ = DIRT; 33 | underwater_block_ = GRAVEL; 34 | 35 | setSeed(&seedcopy, world_seed); 36 | mesaPillarNoise = std::make_unique(&seedcopy, 4); 37 | mesaPillarRoofNoise = std::make_unique(&seedcopy, 1); 38 | 39 | uint64_t grassNoiseSeed = 2345LL; 40 | setSeed(&grassNoiseSeed, world_seed); 41 | grassColorNoise = std::make_unique(&grassNoiseSeed, 1); 42 | 43 | setupGenerator(&stack_, version); 44 | applySeed(&stack_, world_seed); 45 | 46 | registerBaseAndVariation(); 47 | registerTernaryBlocks(); 48 | registerTernaryIds(); 49 | registerSurfaceBuilderIds(); 50 | registerSurfaceBuilderFuncs(version); 51 | 52 | no_def_surface_building_.insert(MESA_S); 53 | no_def_surface_building_.insert(ERODED_MESA_S); 54 | no_def_surface_building_.insert(WOODED_MESA_S); 55 | no_def_surface_building_.insert(FROZEN_OCEAN_S);//still unsupported 56 | } 57 | 58 | bool ChunkGenerator::provideChunk(int x, int z, ChunkData& chunk, std::unordered_set* biomes) 59 | { 60 | int* map1 = allocCache(&stack_.layers[L_RIVER_MIX_4], 10, 10);//10x10?? 61 | genArea(&stack_.layers[L_RIVER_MIX_4], map1, x * 4 - 2, z * 4 - 2, 10, 10); 62 | for (int i = 0; i < 100; i++) 63 | biomesForGeneration1[i] = map1[i]; 64 | 65 | int* map2 = allocCache(&stack_.layers[L_VORONOI_ZOOM_1], 16, 16); 66 | genArea(&stack_.layers[L_VORONOI_ZOOM_1], map2, x*16, z*16, 16, 16); 67 | for (int i = 0; i < 256; i++) 68 | biomesForGeneration2[i] = map2[i]; 69 | 70 | free(map1); 71 | free(map2); 72 | 73 | if (biomes) 74 | { 75 | if (std::end(*biomes) == biomes->find(biomesForGeneration2[0])) //only check one block in chunk, could check every one but the biome probably still doesnt exist and thats just slower 76 | { 77 | return false; 78 | } 79 | } 80 | 81 | for (int i = 0; i < 16; i++) 82 | for (int j = 0; j < 16; j++) 83 | for (int k = 0; k < 256; k++) 84 | chunk.setBlock(i, k, j, ChunkGenerator::AIR); 85 | 86 | /*for (int i = 15; i >= 0; i--) 87 | { 88 | for (int j = 0; j < 16; j++) 89 | { 90 | std::cout << biomesForGeneration2[j*16+i] << " "; 91 | } 92 | std::cout << std::endl; 93 | }*/ 94 | 95 | uint64_t rand = 0; 96 | setSeed(&rand, (int64_t)x * 341873128712L + (int64_t)z * 132897987541L); 97 | setBlocksInChunk(x, z, chunk); 98 | replaceBiomeBlocks(&rand, x, z, chunk); 99 | 100 | return true; 101 | } 102 | 103 | static double clampedLerp(double lowerBnd, double upperBnd, double slide) 104 | { 105 | if (slide < 0.0) 106 | { 107 | return lowerBnd; 108 | } 109 | else 110 | { 111 | return slide > 1.0 ? upperBnd : lowerBnd + (upperBnd - lowerBnd) * slide; 112 | } 113 | } 114 | 115 | void ChunkGenerator::setBlocksInChunk(int x, int z, ChunkData& primer) 116 | { 117 | generateHeightmap(x * 4, 0, z * 4); 118 | 119 | for (int i = 0; i < 4; ++i) //x 120 | { 121 | int j = i * 5; 122 | int k = (i + 1) * 5; 123 | 124 | for (int l = 0; l < 4; ++l) //z 125 | { 126 | int i1 = (j + l) * 33; 127 | int j1 = (j + l + 1) * 33; 128 | int k1 = (k + l) * 33; 129 | int l1 = (k + l + 1) * 33; 130 | 131 | for (int i2 = 0; i2 < 32; ++i2) //y 132 | { 133 | double d0 = 0.125; 134 | double d1 = heightMap[i1 + i2]; 135 | double d2 = heightMap[j1 + i2]; 136 | double d3 = heightMap[k1 + i2]; 137 | double d4 = heightMap[l1 + i2]; 138 | double d5 = (heightMap[i1 + i2 + 1] - d1) * 0.125; 139 | double d6 = (heightMap[j1 + i2 + 1] - d2) * 0.125; 140 | double d7 = (heightMap[k1 + i2 + 1] - d3) * 0.125; 141 | double d8 = (heightMap[l1 + i2 + 1] - d4) * 0.125; 142 | 143 | for (int j2 = 0; j2 < 8; ++j2) 144 | { 145 | double d9 = 0.25; 146 | double d10 = d1; 147 | double d11 = d2; 148 | double d12 = (d3 - d1) * 0.25; 149 | double d13 = (d4 - d2) * 0.25; 150 | 151 | for (int k2 = 0; k2 < 4; ++k2) 152 | { 153 | double d16 = (d11 - d10) * 0.25; 154 | double lvt_45_1_ = d10 - d16; 155 | 156 | for (int l2 = 0; l2 < 4; ++l2) 157 | { 158 | //if (i * 4 + k2 == 2 && l * 4 + l2 == 0 && i2 * 8 + j2 == 67) 159 | // i = i; 160 | if ((lvt_45_1_ += d16) > 0.0) 161 | { 162 | primer.setBlock(i * 4 + k2, i2 * 8 + j2, l * 4 + l2, STONE); 163 | } 164 | else if (i2 * 8 + j2 < 63)//sealevel 165 | { 166 | primer.setBlock(i * 4 + k2, i2 * 8 + j2, l * 4 + l2, WATER); 167 | } 168 | } 169 | 170 | d10 += d12; 171 | d11 += d13; 172 | } 173 | 174 | d1 += d5; 175 | d2 += d6; 176 | d3 += d7; 177 | d4 += d8; 178 | } 179 | } 180 | } 181 | } 182 | } 183 | 184 | bool ChunkGenerator::terrainAtHeight(int x, int z, int y) //POSSIBLY INACCURATE DUE TO FLOATING POINT PRECISION OF MULTIPLIES VS ADDS 185 | { 186 | if (y < 63) 187 | return true; 188 | 189 | int i = x / 4; 190 | int k2 = x % 4; 191 | int l = z / 4; 192 | int l2 = z % 4; 193 | int i2 = y / 8; 194 | int j2 = y % 8; 195 | 196 | int j = i * 5; 197 | int k = (i + 1) * 5; 198 | 199 | int i1 = (j + l) * 33; 200 | int j1 = (j + l + 1) * 33; 201 | int k1 = (k + l) * 33; 202 | int l1 = (k + l + 1) * 33; 203 | 204 | double d1 = heightMap[i1 + i2]; 205 | double d2 = heightMap[j1 + i2]; 206 | double d3 = heightMap[k1 + i2]; 207 | double d4 = heightMap[l1 + i2]; 208 | 209 | double d5 = (heightMap[i1 + i2 + 1] - d1) * .125; 210 | double d6 = (heightMap[j1 + i2 + 1] - d2) * .125; 211 | double d7 = (heightMap[k1 + i2 + 1] - d3) * .125; 212 | double d8 = (heightMap[l1 + i2 + 1] - d4) * .125; 213 | for (int ind = 0; ind < j2; ind++) //can't just multiply by index due to floating point imprecision 214 | { 215 | d1 += d5; 216 | d2 += d6; 217 | d3 += d7; 218 | d4 += d8; 219 | } 220 | 221 | double d12 = (d3 - d1) * .25; 222 | double d13 = (d4 - d2) * .25; 223 | 224 | double d10 = d1; 225 | double d11 = d2; 226 | for (int ind = 0; ind < k2; ind++) 227 | { 228 | d10 += d12; 229 | d11 += d13; 230 | } 231 | 232 | double d16 = (d11 - d10) * .25; 233 | 234 | double lvt = d10 - d16; 235 | for (int ind = 0; ind <= l2; ind++) 236 | { 237 | lvt += d16; 238 | } 239 | 240 | return lvt > 0.0; 241 | } 242 | 243 | int ChunkGenerator::terrainHeight(int x, int z, int seed) 244 | { 245 | bool at_seed = terrainAtHeight(x, z, seed); 246 | 247 | if (at_seed) 248 | { 249 | seed++; 250 | while (seed < 256 && terrainAtHeight(x, z, seed)) 251 | { 252 | seed++; 253 | } 254 | return --seed; 255 | } 256 | else 257 | { 258 | seed--; 259 | while (seed >= 0 && !terrainAtHeight(x, z, seed)) 260 | { 261 | seed--; 262 | } 263 | } 264 | return seed; 265 | } 266 | 267 | /*bool ChunkGenerator::terrainAtHeightOptim(int x, int z, int y) //INACCURATE DUE TO FLOATING POINT PRECISION OF MULTIPLIES VS ADDS 268 | { 269 | int i = x / 4; 270 | int k2 = x % 4; 271 | int l = z / 4; 272 | int l2 = z % 4; 273 | int i2 = y / 8; 274 | int j2 = y % 8; 275 | 276 | int j = i * 5; 277 | int k = (i + 1) * 5; 278 | 279 | int i1 = (j + l) * 33; 280 | int j1 = (j + l + 1) * 33; 281 | int k1 = (k + 1) * 33; 282 | int l1 = (k + l + 1) * 33; 283 | 284 | double d5 = (heightMap[i1 + i2 + 1] - heightMap[i1 + i2]) * .125; 285 | double d6 = (heightMap[j1 + i2 + 1] - heightMap[j1 + i2]) * .125; 286 | double d7 = (heightMap[k1 + i2 + 1] - heightMap[k1 + i2]) * .125; 287 | double d8 = (heightMap[l1 + i2 + 1] - heightMap[l1 + i2]) * .125; 288 | 289 | double d1 = heightMap[i1 + i2] + (d5 * j2); 290 | double d2 = heightMap[j1 + i2] + (d6 * j2); 291 | double d3 = heightMap[k1 + i2] + (d7 * j2); 292 | double d4 = heightMap[l1 + i2] + (d8 * j2); 293 | 294 | double d12 = (d3 - d1) * .25; 295 | double d13 = (d4 - d2) * .25; 296 | 297 | double d10 = d1 + (k2 * d12); 298 | double d11 = d2 + (k2 * d13); 299 | 300 | double d16 = (d11 - d10) * .25; 301 | 302 | double lvt = d10 - d16; 303 | 304 | return lvt + (l2 + 1) * d16 > 0.0; 305 | }*/ 306 | 307 | bool ChunkGenerator::provideChunkHeightmap(int x, int z, ChunkHeightmap& chunk, std::unordered_set* biomes) 308 | { 309 | int* map1 = allocCache(&stack_.layers[L_RIVER_MIX_4], 10, 10);//10x10?? 310 | genArea(&stack_.layers[L_RIVER_MIX_4], map1, x * 4 - 2, z * 4 - 2, 10, 10); 311 | for (int i = 0; i < 100; i++) 312 | biomesForGeneration1[i] = map1[i]; 313 | 314 | int* map2 = allocCache(&stack_.layers[L_VORONOI_ZOOM_1], 16, 16); 315 | genArea(&stack_.layers[L_VORONOI_ZOOM_1], map2, x * 16, z * 16, 16, 16); 316 | for (int i = 0; i < 256; i++) 317 | biomesForGeneration2[i] = map2[i]; 318 | 319 | free(map1); 320 | free(map2); 321 | 322 | if (biomes) 323 | { 324 | if (std::end(*biomes) == biomes->find(biomesForGeneration2[0])) //only check one block in chunk, could check every one but the biome probably still doesnt exist and thats just slower 325 | { 326 | return false; 327 | } 328 | } 329 | 330 | /*std::cout << "BIOMES\n"; 331 | 332 | for (int i = 15; i >= 0; i--) 333 | { 334 | for (int j = 0; j < 16; j++) 335 | { 336 | std::cout << biomesForGeneration2[j*16+i] << " "; 337 | } 338 | std::cout << std::endl; 339 | }*/ 340 | 341 | generateHeightmap(x * 4, 0, z * 4); 342 | 343 | //height seeded search, adjacent location will have similar or same height 344 | 345 | int seed = 67; //typical terrain height 346 | 347 | for (int xc = 0; xc < 16; xc++) 348 | { 349 | for (int zc = 0; zc < 16; zc++) 350 | { 351 | seed = terrainHeight(xc, zc, seed); 352 | chunk.setHeightmap(xc, zc, seed); 353 | } 354 | seed = chunk.getHeightmap(xc, 0); 355 | } 356 | return true; 357 | } 358 | 359 | void ChunkGenerator::generateHeightmap(int p_185978_1_, int p_185978_2_, int p_185978_3_) 360 | { 361 | double* depthRegion = depthNoise->generateNoiseOctaves(nullptr, 0, p_185978_1_, p_185978_3_, 5, 5, depthNoiseScaleX, depthNoiseScaleZ, depthNoiseScaleExponent); 362 | float f = coordinateScale; 363 | float f1 = heightScale; 364 | double* mainNoiseRegion = mainPerlinNoise->generateNoiseOctaves(nullptr, 0, p_185978_1_, p_185978_2_, p_185978_3_, 5, 33, 5, (double)(f / mainNoiseScaleX), (double)(f1 / mainNoiseScaleY), (double)(f / mainNoiseScaleZ)); 365 | double* minLimitRegion = minLimitPerlinNoise->generateNoiseOctaves(nullptr, 0, p_185978_1_, p_185978_2_, p_185978_3_, 5, 33, 5, (double)f, (double)f1, (double)f); 366 | double* maxLimitRegion = maxLimitPerlinNoise->generateNoiseOctaves(nullptr, 0, p_185978_1_, p_185978_2_, p_185978_3_, 5, 33, 5, (double)f, (double)f1, (double)f); 367 | int i = 0; 368 | int j = 0; 369 | 370 | for (int k = 0; k < 5; ++k) 371 | { 372 | for (int l = 0; l < 5; ++l) 373 | { 374 | float f2 = 0.0F; 375 | float f3 = 0.0F; 376 | float f4 = 0.0F; 377 | int i1 = 2; 378 | int biome = biomesForGeneration1[k + 2 + (l + 2) * 10]; 379 | 380 | for (int j1 = -2; j1 <= 2; ++j1) 381 | { 382 | for (int k1 = -2; k1 <= 2; ++k1) 383 | { 384 | int biome1 = biomesForGeneration1[k + j1 + 2 + (l + k1 + 2) * 10]; 385 | float f5 = biomeDepthOffset + getBaseHeight(biome1) * biomeDepthWeight; 386 | float f6 = biomeScaleOffset + getHeightVariation(biome1) * biomeScaleWeight; 387 | 388 | if (amplified_ && f5 > 0.0F) 389 | { 390 | f5 = 1.0F + f5 * 2.0F; 391 | f6 = 1.0F + f6 * 4.0F; 392 | } 393 | 394 | float f7 = biomeWeights[j1 + 2 + (k1 + 2) * 5] / (f5 + 2.0F); 395 | 396 | if (getBaseHeight(biome1) > getBaseHeight(biome)) 397 | { 398 | f7 /= 2.0F; 399 | } 400 | 401 | f2 += f6 * f7; 402 | f3 += f5 * f7; 403 | f4 += f7; 404 | } 405 | } 406 | 407 | f2 = f2 / f4; 408 | f3 = f3 / f4; 409 | f2 = f2 * 0.9F + 0.1F; 410 | f3 = (f3 * 4.0F - 1.0F) / 8.0F; 411 | double d7 = depthRegion[j] / 8000.0; 412 | 413 | if (d7 < 0.0) 414 | { 415 | d7 = -d7 * 0.3; 416 | } 417 | 418 | d7 = d7 * 3.0 - 2.0; 419 | 420 | if (d7 < 0.0) 421 | { 422 | d7 = d7 / 2.0; 423 | 424 | if (d7 < -1.0) 425 | { 426 | d7 = -1.0; 427 | } 428 | 429 | d7 = d7 / 1.4; 430 | d7 = d7 / 2.0; 431 | } 432 | else 433 | { 434 | if (d7 > 1.0) 435 | { 436 | d7 = 1.0; 437 | } 438 | 439 | d7 = d7 / 8.0; 440 | } 441 | 442 | ++j; 443 | double d8 = (double)f3; 444 | double d9 = (double)f2; 445 | d8 = d8 + d7 * 0.2; 446 | d8 = d8 * (double)baseSize / 8.0; 447 | double d0 = (double)baseSize + d8 * 4.0; 448 | 449 | for (int l1 = 0; l1 < 33; ++l1) 450 | { 451 | double d1 = ((double)l1 - d0) * (double)stretchY * 128.0 / 256.0 / d9; 452 | 453 | if (d1 < 0.0) 454 | { 455 | d1 *= 4.0; 456 | } 457 | 458 | double d2 = minLimitRegion[i] / (double)lowerLimitScale; 459 | double d3 = maxLimitRegion[i] / (double)upperLimitScale; 460 | double d4 = (mainNoiseRegion[i] / 10.0 + 1.0) / 2.0; 461 | double d5 = clampedLerp(d2, d3, d4) - d1; 462 | 463 | if (l1 > 29) 464 | { 465 | double d6 = (double)((float)(l1 - 29) / 3.0F); 466 | d5 = d5 * (1.0 - d6) + -10.0 * d6; 467 | } 468 | 469 | heightMap[i] = d5; 470 | ++i; 471 | } 472 | } 473 | } 474 | delete[] depthRegion; 475 | delete[] mainNoiseRegion; 476 | delete[] minLimitRegion; 477 | delete[] maxLimitRegion; 478 | 479 | } 480 | 481 | void ChunkGenerator::generateBiomeTerrain112(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 482 | { 483 | int i = 63;//sealevel 484 | int iblockstate = top_block_;//topblock 485 | int iblockstate1 = filler_block_;//filler 486 | int j = -1; 487 | int k = (int)(noiseVal / 3.0 + 3.0 + nextDouble(rand) * 0.25); 488 | int l = x & 15; 489 | int i1 = z & 15; 490 | std::tuple blockpos$mutableblockpos; 491 | 492 | for (int j1 = 255; j1 >= 0; --j1) 493 | { 494 | if (j1 <= nextInt(rand, 5)) 495 | { 496 | chunkPrimerIn.setBlock(i1, j1, l, BEDROCK); 497 | } 498 | else 499 | { 500 | int iblockstate2 = chunkPrimerIn.getBlock(i1, j1, l); 501 | 502 | if (iblockstate2 == AIR) 503 | { 504 | j = -1; 505 | } 506 | else if (iblockstate2 == STONE) 507 | { 508 | if (j == -1) 509 | { 510 | if (k <= 0) 511 | { 512 | iblockstate = AIR; 513 | iblockstate1 = STONE; 514 | } 515 | else if (j1 >= i - 4 && j1 <= i + 1) 516 | { 517 | iblockstate = top_block_; 518 | iblockstate1 = filler_block_; 519 | } 520 | 521 | if (j1 < i && (iblockstate == AIR)) 522 | { 523 | /*if (getFloatTemperature(blockpos$mutableblockpos.setPos(x, j1, z)) < 0.15F) 524 | { 525 | iblockstate = ICE; 526 | } 527 | else 528 | { 529 | iblockstate = WATER; 530 | }*/ 531 | iblockstate = WATER; 532 | } 533 | 534 | j = k; 535 | 536 | if (j1 >= i - 1) 537 | { 538 | chunkPrimerIn.setBlock(i1, j1, l, iblockstate); 539 | } 540 | else if (j1 < i - 7 - k) 541 | { 542 | iblockstate = AIR; 543 | iblockstate1 = STONE; 544 | chunkPrimerIn.setBlock(i1, j1, l, GRAVEL); 545 | } 546 | else 547 | { 548 | chunkPrimerIn.setBlock(i1, j1, l, iblockstate1); 549 | } 550 | } 551 | else if (j > 0) 552 | { 553 | --j; 554 | chunkPrimerIn.setBlock(i1, j1, l, iblockstate1); 555 | 556 | if (j == 0 && iblockstate1 == SAND && k > 1) 557 | { 558 | j = nextInt(rand, 4) + std::max(0, j1 - 63); 559 | iblockstate1 = iblockstate1 == RED_SAND ? RED_SANDSTONE : SANDSTONE; 560 | } 561 | } 562 | } 563 | } 564 | } 565 | } 566 | 567 | void ChunkGenerator::defaultSurfaceBuild113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 568 | { 569 | int l = 63; 570 | int lv = top_block_; 571 | int lv2 = filler_block_; 572 | int m = -1; 573 | int n = (int)(noiseVal / 3.0 + 3.0 + nextDouble(rand) * 0.25); 574 | int o = x & 15; 575 | int p = z & 15; 576 | 577 | for (int q = 255; q >= 0; --q) {//reduce iteration using ported heightmap for performance??? instead of 255 always 578 | int lv4 = chunkPrimerIn.getBlock(o, q, p); 579 | if (lv4 == AIR) { 580 | m = -1; 581 | } 582 | else if (lv4 == STONE) { 583 | if (m == -1) { 584 | if (n <= 0) { 585 | lv = AIR; 586 | lv2 = STONE; 587 | } 588 | else if (q >= l - 4 && q <= l + 1) { 589 | lv = top_block_; 590 | lv2 = filler_block_; 591 | } 592 | 593 | if (q < l && lv == AIR) { 594 | lv = WATER; 595 | } 596 | 597 | m = n; 598 | if (q >= l - 1) { 599 | chunkPrimerIn.setBlock(o, q, p, lv); 600 | } 601 | else if (q < l - 7 - n) { 602 | lv = AIR; 603 | lv2 = STONE; 604 | chunkPrimerIn.setBlock(o, q, p, underwater_block_); 605 | } 606 | else { 607 | chunkPrimerIn.setBlock(o, q, p, lv2); 608 | } 609 | } 610 | else if (m > 0) { 611 | --m; 612 | chunkPrimerIn.setBlock(o, q, p, lv2); 613 | if (m == 0 && lv2 == SAND && n > 1) { 614 | m = nextInt(rand, 4) + std::max(0, q - 63); 615 | lv2 = lv2 == RED_SAND ? RED_SANDSTONE : SANDSTONE; 616 | } 617 | } 618 | } 619 | } 620 | } 621 | 622 | void ChunkGenerator::buildBedrock113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 623 | { 624 | //in 1.13+, buildBedrock called after surface building 625 | //1.14+ and 1.13 have different bedrock gen 626 | } 627 | 628 | void ChunkGenerator::buildBedrock114(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 629 | { 630 | } 631 | 632 | void ChunkGenerator::replaceBiomeBlocks(uint64_t* rand, int x, int z, ChunkData& primer) 633 | { 634 | double d0 = 0.03125; 635 | double* depthBuffer = surfaceNoise->getRegion(nullptr, 0, (double)(x * 16), (double)(z * 16), 16, 16, 0.0625, 0.0625, 1.0); 636 | 637 | for (int i = 0; i < 16; ++i) 638 | { 639 | for (int j = 0; j < 16; ++j) 640 | { 641 | int biome = biomesForGeneration2[j + i * 16]; 642 | int ternary; 643 | if (std::end(biome_to_ternary_) != biome_to_ternary_.find(biome)) 644 | ternary = biome_to_ternary_[biome]; 645 | else 646 | throw std::runtime_error("biome_to_ternary__, invalid mapping for " + std::to_string(biome)); 647 | 648 | if (std::end(ternary_to_blocktypes_) != ternary_to_blocktypes_.find(ternary)) 649 | { 650 | auto& ternary_blocks = ternary_to_blocktypes_[ternary]; 651 | top_block_ = std::get<0>(ternary_blocks); 652 | filler_block_ = std::get<1>(ternary_blocks); 653 | underwater_block_ = std::get<2>(ternary_blocks); 654 | } 655 | else 656 | throw std::runtime_error("ternary_to_blocktypes_, invalid mapping for " + std::to_string(ternary)); 657 | 658 | if (biome_to_surface_builder_.end() != biome_to_surface_builder_.find(biome)) 659 | surface_builder_to_additions_func_[biome_to_surface_builder_[biome]](rand, primer, x * 16 + i, z * 16 + j, depthBuffer[j + i * 16]); 660 | 661 | if (biome_to_surface_builder_.end() == biome_to_surface_builder_.find(biome) || std::end(no_def_surface_building_) == no_def_surface_building_.find(biome_to_surface_builder_[biome])) 662 | { 663 | if (version_ == MC_1_12) 664 | { 665 | generateBiomeTerrain112(rand, primer, x * 16 + i, z * 16 + j, depthBuffer[j + i * 16]); 666 | } 667 | else 668 | { 669 | defaultSurfaceBuild113(rand, primer, x * 16 + i, z * 16 + j, depthBuffer[j + i * 16]); 670 | if(version_ == MC_1_13) 671 | buildBedrock113(rand, primer, x * 16 + i, z * 16 + j, depthBuffer[j + i * 16]); 672 | else 673 | buildBedrock114(rand, primer, x * 16 + i, z * 16 + j, depthBuffer[j + i * 16]); 674 | } 675 | } 676 | } 677 | } 678 | 679 | delete[] depthBuffer; 680 | } 681 | 682 | void ChunkGenerator::registerBaseAndVariation() 683 | { 684 | biome_to_base_and_variation_[0] = std::make_pair(-1.0F, 0.1F); 685 | biome_to_base_and_variation_[1] = std::make_pair(0.125F, 0.05F); 686 | biome_to_base_and_variation_[2] = std::make_pair(0.125F, 0.05F); 687 | biome_to_base_and_variation_[3] = std::make_pair(1.0F, 0.5F); 688 | biome_to_base_and_variation_[4] = std::make_pair(0.1F, 0.2F); 689 | biome_to_base_and_variation_[5] = std::make_pair(0.2F, 0.2F); 690 | biome_to_base_and_variation_[6] = std::make_pair(-0.2F, 0.1F); 691 | biome_to_base_and_variation_[7] = std::make_pair(-0.5F, 0.0F); 692 | biome_to_base_and_variation_[8] = std::make_pair(0.1F, 0.2F); 693 | biome_to_base_and_variation_[9] = std::make_pair(0.1F, 0.2F); 694 | biome_to_base_and_variation_[10] = std::make_pair(-1.0F, 0.1F); 695 | biome_to_base_and_variation_[11] = std::make_pair(-0.5F, 0.0F); 696 | biome_to_base_and_variation_[12] = std::make_pair(0.125F, 0.05F); 697 | biome_to_base_and_variation_[13] = std::make_pair(0.45F, 0.3F); 698 | biome_to_base_and_variation_[14] = std::make_pair(0.2F, 0.3F); 699 | biome_to_base_and_variation_[15] = std::make_pair(0.0F, 0.025F); 700 | biome_to_base_and_variation_[16] = std::make_pair(0.0F, 0.025F); 701 | biome_to_base_and_variation_[17] = std::make_pair(0.45F, 0.3F); 702 | biome_to_base_and_variation_[18] = std::make_pair(0.45F, 0.3F); 703 | biome_to_base_and_variation_[19] = std::make_pair(0.45F, 0.3F); 704 | biome_to_base_and_variation_[20] = std::make_pair(0.8F, 0.3F); 705 | biome_to_base_and_variation_[21] = std::make_pair(0.1F, 0.2F); 706 | biome_to_base_and_variation_[22] = std::make_pair(0.45F, 0.3F); 707 | biome_to_base_and_variation_[23] = std::make_pair(0.1F, 0.2F); 708 | biome_to_base_and_variation_[24] = std::make_pair(-1.8F, 0.1F); 709 | biome_to_base_and_variation_[25] = std::make_pair(0.1F, 0.8F); 710 | biome_to_base_and_variation_[26] = std::make_pair(0.0F, 0.025F); 711 | biome_to_base_and_variation_[27] = std::make_pair(0.1F, 0.2F); 712 | biome_to_base_and_variation_[28] = std::make_pair(0.45F, 0.3F); 713 | biome_to_base_and_variation_[29] = std::make_pair(0.1F, 0.2F); 714 | biome_to_base_and_variation_[30] = std::make_pair(0.2F, 0.2F); 715 | biome_to_base_and_variation_[31] = std::make_pair(0.45F, 0.3F); 716 | biome_to_base_and_variation_[32] = std::make_pair(0.2F, 0.2F); 717 | biome_to_base_and_variation_[33] = std::make_pair(0.45F, 0.3F); 718 | biome_to_base_and_variation_[34] = std::make_pair(1.0F, 0.5F); 719 | biome_to_base_and_variation_[35] = std::make_pair(0.125F, 0.05F); 720 | biome_to_base_and_variation_[36] = std::make_pair(1.5F, 0.025F); 721 | biome_to_base_and_variation_[37] = std::make_pair(0.1F, 0.2F); 722 | biome_to_base_and_variation_[38] = std::make_pair(1.5F, 0.025F); 723 | biome_to_base_and_variation_[39] = std::make_pair(1.5F, 0.025F); 724 | 725 | //post 1.12: 726 | biome_to_base_and_variation_[40] = std::make_pair(0.1F, 0.2F); 727 | biome_to_base_and_variation_[41] = std::make_pair(0.1F, 0.2F); 728 | biome_to_base_and_variation_[42] = std::make_pair(0.1F, 0.2F); 729 | biome_to_base_and_variation_[43] = std::make_pair(0.1F, 0.2F); 730 | biome_to_base_and_variation_[44] = std::make_pair(-1.0F, 0.1F); 731 | biome_to_base_and_variation_[45] = std::make_pair(-1.0F, 0.1F); 732 | biome_to_base_and_variation_[46] = std::make_pair(-1.0F, 0.1F); 733 | biome_to_base_and_variation_[47] = std::make_pair(-1.8F, 0.1F); 734 | biome_to_base_and_variation_[48] = std::make_pair(-1.8F, 0.1F); 735 | biome_to_base_and_variation_[49] = std::make_pair(-1.8F, 0.1F); 736 | biome_to_base_and_variation_[50] = std::make_pair(-1.8F, 0.1F); 737 | 738 | 739 | biome_to_base_and_variation_[127] = std::make_pair(0.1F, 0.2F); 740 | biome_to_base_and_variation_[129] = std::make_pair(0.125F, 0.05F); 741 | biome_to_base_and_variation_[130] = std::make_pair(0.225F, 0.25F); 742 | biome_to_base_and_variation_[131] = std::make_pair(1.0F, 0.5F); 743 | biome_to_base_and_variation_[132] = std::make_pair(0.1F, 0.4F); 744 | biome_to_base_and_variation_[133] = std::make_pair(0.3F, 0.4F); 745 | biome_to_base_and_variation_[134] = std::make_pair(-0.1F, 0.3F); 746 | biome_to_base_and_variation_[140] = std::make_pair(0.425F, 0.45000002F); 747 | biome_to_base_and_variation_[149] = std::make_pair(0.2F, 0.4F); 748 | biome_to_base_and_variation_[151] = std::make_pair(0.2F, 0.4F); 749 | biome_to_base_and_variation_[155] = std::make_pair(0.2F, 0.4F); 750 | biome_to_base_and_variation_[156] = std::make_pair(0.55F, 0.5F); 751 | biome_to_base_and_variation_[157] = std::make_pair(0.2F, 0.4F); 752 | biome_to_base_and_variation_[158] = std::make_pair(0.3F, 0.4F); 753 | biome_to_base_and_variation_[160] = std::make_pair(0.2F, 0.2F); 754 | biome_to_base_and_variation_[161] = std::make_pair(0.2F, 0.2F); 755 | biome_to_base_and_variation_[162] = std::make_pair(1.0F, 0.5F); 756 | biome_to_base_and_variation_[163] = std::make_pair(0.3625F, 1.225F); 757 | biome_to_base_and_variation_[164] = std::make_pair(1.05F, 1.2125001F); 758 | biome_to_base_and_variation_[165] = std::make_pair(0.1F, 0.2F); 759 | biome_to_base_and_variation_[166] = std::make_pair(0.45F, 0.3F); 760 | biome_to_base_and_variation_[167] = std::make_pair(0.45F, 0.3F); 761 | 762 | //post 1.12 763 | biome_to_base_and_variation_[168] = std::make_pair(0.1F, 0.2F); 764 | biome_to_base_and_variation_[169] = std::make_pair(0.45F, 0.3F); 765 | biome_to_base_and_variation_[170] = std::make_pair(0.1F, 0.2F); 766 | biome_to_base_and_variation_[171] = std::make_pair(0.1F, 0.2F); 767 | biome_to_base_and_variation_[172] = std::make_pair(0.1F, 0.2F); 768 | biome_to_base_and_variation_[173] = std::make_pair(0.1F, 0.2F); 769 | 770 | } 771 | 772 | float ChunkGenerator::getBaseHeight(int biome) 773 | { 774 | if (std::end(biome_to_base_and_variation_) == biome_to_base_and_variation_.find(biome)) 775 | throw std::runtime_error("biome_to_base_and_variation_, no mapping for biome id " + std::to_string(biome)); 776 | return biome_to_base_and_variation_[biome].first; 777 | } 778 | float ChunkGenerator::getHeightVariation(int biome) 779 | { 780 | if (std::end(biome_to_base_and_variation_) == biome_to_base_and_variation_.find(biome)) 781 | throw std::runtime_error("biome_to_base_and_variation_, no mapping for biome id " + std::to_string(biome)); 782 | return biome_to_base_and_variation_[biome].second; 783 | } 784 | 785 | void ChunkGenerator::registerTernaryIds() 786 | { 787 | biome_to_ternary_[0] = GRASS_T; 788 | biome_to_ternary_[1] = GRASS_T; 789 | biome_to_ternary_[2] = SAND_T; 790 | biome_to_ternary_[3] = GRASS_T; 791 | biome_to_ternary_[4] = GRASS_T; 792 | biome_to_ternary_[5] = GRASS_T; 793 | biome_to_ternary_[6] = GRASS_T; 794 | biome_to_ternary_[7] = GRASS_T; 795 | biome_to_ternary_[8] = NETHER_T; 796 | biome_to_ternary_[9] = END_T; 797 | biome_to_ternary_[10] = GRASS_T; 798 | biome_to_ternary_[11] = GRASS_T; 799 | biome_to_ternary_[12] = GRASS_T; 800 | biome_to_ternary_[13] = GRASS_T; 801 | biome_to_ternary_[14] = MYCELIUM_T; 802 | biome_to_ternary_[15] = MYCELIUM_T; 803 | biome_to_ternary_[16] = SAND_T; 804 | biome_to_ternary_[17] = SAND_T; 805 | biome_to_ternary_[18] = GRASS_T; 806 | biome_to_ternary_[19] = GRASS_T; 807 | biome_to_ternary_[20] = GRASS_T; 808 | biome_to_ternary_[21] = GRASS_T; 809 | biome_to_ternary_[22] = GRASS_T; 810 | biome_to_ternary_[23] = GRASS_T; 811 | biome_to_ternary_[24] = GRASS_T; 812 | biome_to_ternary_[25] = STONE_T; 813 | biome_to_ternary_[26] = SAND_T; 814 | biome_to_ternary_[27] = GRASS_T; 815 | biome_to_ternary_[28] = GRASS_T; 816 | biome_to_ternary_[29] = GRASS_T; 817 | biome_to_ternary_[30] = GRASS_T; 818 | biome_to_ternary_[31] = GRASS_T; 819 | biome_to_ternary_[32] = GRASS_T; 820 | biome_to_ternary_[33] = GRASS_T; 821 | biome_to_ternary_[34] = GRASS_T; 822 | biome_to_ternary_[35] = GRASS_T; 823 | biome_to_ternary_[36] = GRASS_T; 824 | biome_to_ternary_[37] = MESA_T; 825 | biome_to_ternary_[38] = MESA_T; 826 | biome_to_ternary_[39] = MESA_T; 827 | 828 | //post 1.12: 829 | biome_to_ternary_[40] = END_T; 830 | biome_to_ternary_[41] = END_T; 831 | biome_to_ternary_[42] = END_T; 832 | biome_to_ternary_[43] = END_T; 833 | biome_to_ternary_[44] = SAND_SAND_UNDERWATER_T; 834 | biome_to_ternary_[45] = GRASS_SAND_UNDERWATER_T; 835 | biome_to_ternary_[46] = GRASS_T; 836 | biome_to_ternary_[47] = SAND_SAND_UNDERWATER_T; 837 | biome_to_ternary_[48] = GRASS_SAND_UNDERWATER_T; 838 | biome_to_ternary_[49] = GRASS_T; 839 | biome_to_ternary_[50] = GRASS_T; 840 | 841 | 842 | biome_to_ternary_[127] = STONE_T; 843 | biome_to_ternary_[129] = GRASS_T; 844 | biome_to_ternary_[130] = SAND_T; 845 | biome_to_ternary_[131] = GRASS_T; 846 | biome_to_ternary_[132] = GRASS_T; 847 | biome_to_ternary_[133] = GRASS_T; 848 | biome_to_ternary_[134] = GRASS_T; 849 | biome_to_ternary_[140] = ICE_SPIKES_T; 850 | biome_to_ternary_[149] = GRASS_T; 851 | biome_to_ternary_[151] = GRASS_T; 852 | biome_to_ternary_[155] = GRASS_T; 853 | biome_to_ternary_[156] = GRASS_T; 854 | biome_to_ternary_[157] = GRASS_T; 855 | biome_to_ternary_[158] = GRASS_T; 856 | biome_to_ternary_[160] = GRASS_T; 857 | biome_to_ternary_[161] = GRASS_T; 858 | biome_to_ternary_[162] = GRASS_T; 859 | biome_to_ternary_[163] = GRASS_T; 860 | biome_to_ternary_[164] = GRASS_T; 861 | biome_to_ternary_[165] = MESA_T; 862 | biome_to_ternary_[166] = MESA_T; 863 | biome_to_ternary_[167] = MESA_T; 864 | 865 | //post 1.12 866 | biome_to_ternary_[168] = GRASS_T; 867 | biome_to_ternary_[169] = GRASS_T; 868 | biome_to_ternary_[170] = SOUL_SAND_T; 869 | biome_to_ternary_[171] = CRIMSON_NYLIUM_T; 870 | biome_to_ternary_[172] = WARPED_NYLIUM_T; 871 | //biome_to_ternary_[173], this is basalt deltas 872 | } 873 | 874 | void ChunkGenerator::registerTernaryBlocks() 875 | { 876 | ternary_to_blocktypes_[AIR_T] = std::make_tuple(AIR, AIR, AIR); 877 | ternary_to_blocktypes_[PODZOL_T] = std::make_tuple(PODZOL, DIRT, GRAVEL); 878 | ternary_to_blocktypes_[GRAVEL_T] = std::make_tuple(GRAVEL, GRAVEL, GRAVEL); 879 | ternary_to_blocktypes_[GRASS_T] = std::make_tuple(GRASS, DIRT, GRAVEL); 880 | ternary_to_blocktypes_[DIRT_T] = std::make_tuple(DIRT, DIRT, GRAVEL); 881 | ternary_to_blocktypes_[STONE_T] = std::make_tuple(STONE, STONE, GRAVEL); 882 | ternary_to_blocktypes_[COARSE_DIRT_T] = std::make_tuple(COARSE_DIRT, DIRT, GRAVEL); 883 | ternary_to_blocktypes_[SAND_T] = std::make_tuple(SAND, SAND, GRAVEL); 884 | ternary_to_blocktypes_[GRASS_SAND_UNDERWATER_T] = std::make_tuple(GRASS, DIRT, SAND); 885 | ternary_to_blocktypes_[SAND_SAND_UNDERWATER_T] = std::make_tuple(SAND, SAND, SAND); 886 | ternary_to_blocktypes_[MESA_T] = std::make_tuple(RED_SAND, HARDCLAY, GRAVEL); 887 | ternary_to_blocktypes_[MYCELIUM_T] = std::make_tuple(MYCELIUM, DIRT, GRAVEL); 888 | //ternary_to_blocktypes_[NETHER_T] = std::make_tuple(NETHERRACK, NETHERRACK, NETHERRACK); //dimension support later 889 | //ternary_to_blocktypes_[SOUL_SAND_T] = std::make_tuple(SOUL_SAND, SOUL_SAND, SOUL_SAND); 890 | //ternary_to_blocktypes_[END_T] = std::make_tuple(END_STONE, END_STONE, END_STONE); 891 | //ternary_to_blocktypes_[CRIMSON_NYLIUM_T] = std::make_tuple(AIR, AIR, AIR); 892 | //ternary_to_blocktypes_[WARPED_NYLIUM_T] = std::make_tuple(AIR, AIR, AIR); 893 | ternary_to_blocktypes_[ICE_SPIKES_T] = std::make_tuple(SNOW_BLOCK, DIRT, GRAVEL); 894 | } 895 | 896 | void ChunkGenerator::registerSurfaceBuilderIds()//don't register default 897 | { 898 | biome_to_surface_builder_[3] = MOUNTAIN_S; 899 | biome_to_surface_builder_[163] = SHATTERED_SAVANNA_S; 900 | biome_to_surface_builder_[164] = SHATTERED_SAVANNA_S; 901 | biome_to_surface_builder_[131] = GRAVELLY_MOUNTAIN_S; 902 | biome_to_surface_builder_[162] = GRAVELLY_MOUNTAIN_S; 903 | biome_to_surface_builder_[160] = GIANT_TREE_TAIGA_S; 904 | biome_to_surface_builder_[161] = GIANT_TREE_TAIGA_S; 905 | biome_to_surface_builder_[32] = GIANT_TREE_TAIGA_S; 906 | biome_to_surface_builder_[33] = GIANT_TREE_TAIGA_S; 907 | biome_to_surface_builder_[6] = SWAMP_S; 908 | biome_to_surface_builder_[134] = SWAMP_S; 909 | biome_to_surface_builder_[37] = MESA_S; 910 | biome_to_surface_builder_[39] = MESA_S; 911 | biome_to_surface_builder_[167] = MESA_S; 912 | biome_to_surface_builder_[38] = WOODED_MESA_S; 913 | biome_to_surface_builder_[166] = WOODED_MESA_S; 914 | biome_to_surface_builder_[165] = ERODED_MESA_S; 915 | biome_to_surface_builder_[10] = FROZEN_OCEAN_S; 916 | biome_to_surface_builder_[50] = FROZEN_OCEAN_S; 917 | //type 20/34 are mountain/hills, but uses default 918 | //type 3/19/30/31 are taiga but use default 919 | } 920 | 921 | void ChunkGenerator::registerSurfaceBuilderFuncs(MCversion version) 922 | { 923 | surface_builder_to_additions_func_[MOUNTAIN_S] = [this](uint64_t* a, ChunkData& b, int c, int d, double e) {this->HillsMountainsSB(a, b, c, d, e, false); }; 924 | surface_builder_to_additions_func_[SHATTERED_SAVANNA_S] = [this](uint64_t* a, ChunkData& b, int c, int d, double e) {this->SavannaMutatedSB(a, b, c, d, e); }; 925 | surface_builder_to_additions_func_[GRAVELLY_MOUNTAIN_S] = [this](uint64_t* a, ChunkData& b, int c, int d, double e) {this->HillsMountainsSB(a, b, c, d, e, true); }; 926 | surface_builder_to_additions_func_[GIANT_TREE_TAIGA_S] = [this](uint64_t* a, ChunkData& b, int c, int d, double e) {this->TaigaSB(a, b, c, d, e); }; 927 | surface_builder_to_additions_func_[SWAMP_S] = [this](uint64_t* a, ChunkData& b, int c, int d, double e) {this->SwampSB(a, b, c, d, e); }; 928 | 929 | //no running default surface building after mesa/badlands, still need bedrock gen though 930 | if (version == MC_1_12) 931 | { 932 | surface_builder_to_additions_func_[MESA_S] = [this, version](uint64_t* a, ChunkData& b, int c, int d, double e) {this->MesaSB112(a, b, c, d, e, false, false); }; 933 | surface_builder_to_additions_func_[WOODED_MESA_S] = [this, version](uint64_t* a, ChunkData& b, int c, int d, double e) {this->MesaSB112(a, b, c, d, e, false, true); }; 934 | surface_builder_to_additions_func_[ERODED_MESA_S] = [this, version](uint64_t* a, ChunkData& b, int c, int d, double e) {this->MesaSB112(a, b, c, d, e, true, false); }; 935 | } 936 | else 937 | { 938 | surface_builder_to_additions_func_[MESA_S] = [this, version](uint64_t* a, ChunkData& b, int c, int d, double e) {this->MesaDefSB113(a, b, c, d, e); }; 939 | surface_builder_to_additions_func_[WOODED_MESA_S] = [this, version](uint64_t* a, ChunkData& b, int c, int d, double e) {this->MesaWoodedSB113(a, b, c, d, e); }; 940 | surface_builder_to_additions_func_[ERODED_MESA_S] = [this, version](uint64_t* a, ChunkData& b, int c, int d, double e) {this->MesaErodedSB113(a, b, c, d, e); }; 941 | } 942 | 943 | surface_builder_to_additions_func_[FROZEN_OCEAN_S] = [this](uint64_t* , ChunkData& , int , int , double ) { };//frozen ocean has temp dependencies, don't support right now 944 | } 945 | 946 | void ChunkGenerator::HillsMountainsSB(uint64_t*, ChunkData&, int, int, double noiseVal, bool mutated) //hills were changed to mountains in 1.13. biome ids 3, 20, 34, 131, 162 947 | { 948 | top_block_ = GRASS; 949 | filler_block_ = DIRT; 950 | if ((noiseVal < -1.0 || noiseVal > 2.0) && mutated) { 951 | top_block_ = GRAVEL; 952 | filler_block_ = GRAVEL; 953 | } 954 | else if (noiseVal > 1.0) { 955 | top_block_ = STONE; 956 | filler_block_ = STONE; 957 | } 958 | } 959 | 960 | void ChunkGenerator::MesaSB112(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal, bool bryce/*'eroded 1.13+*/, bool forest/*'wooded' 1.13+*/) 961 | { 962 | double d4 = 0.0; 963 | int k1; 964 | int l1; 965 | if (bryce) { 966 | k1 = (x & -16) + (z & 15); 967 | l1 = (z & -16) + (x & 15); 968 | double d0 = std::min(std::abs(noiseVal), mesaPillarNoise->getValue((double)k1 * 0.25, (double)l1 * 0.25)); 969 | if (d0 > 0.0) { 970 | double d1 = 0.001953125; 971 | double d2 = std::abs(mesaPillarRoofNoise->getValue((double)k1 * 0.001953125, (double)l1 * 0.001953125)); 972 | d4 = d0 * d0 * 2.5; 973 | double d3 = std::ceil(d2 * 50.0) + 14.0; 974 | if (d4 > d3) { 975 | d4 = d3; 976 | } 977 | 978 | d4 += 64.0; 979 | } 980 | } 981 | 982 | k1 = x & 15; 983 | l1 = z & 15; 984 | int i2 = 63; 985 | int iblockstate = HARDCLAY; 986 | int iblockstate3 = filler_block_; 987 | int k = (int)(noiseVal / 3.0 + 3.0 + nextDouble(rand) * 0.25); 988 | bool flag = cos(noiseVal / 3.0 * 3.141592653589793) > 0.0; 989 | int l = -1; 990 | bool flag1 = false; 991 | int i1 = 0; 992 | 993 | for (int j1 = 255; j1 >= 0; --j1) { 994 | if (chunkPrimerIn.getBlock(l1, j1, k1) == AIR && j1 < (int)d4) { 995 | chunkPrimerIn.setBlock(l1, j1, k1, STONE); 996 | } 997 | 998 | if (j1 <= nextInt(rand, 5)) { 999 | chunkPrimerIn.setBlock(l1, j1, k1, BEDROCK); 1000 | } 1001 | else if (i1 < 15 || bryce) { 1002 | int iblockstate1 = chunkPrimerIn.getBlock(l1, j1, k1); 1003 | if (iblockstate1 == AIR) { 1004 | l = -1; 1005 | } 1006 | else if (iblockstate1 == STONE) { 1007 | if (l == -1) { 1008 | flag1 = false; 1009 | if (k <= 0) { 1010 | iblockstate = AIR; 1011 | iblockstate3 = STONE; 1012 | } 1013 | else if (j1 >= i2 - 4 && j1 <= i2 + 1) { 1014 | iblockstate = HARDCLAY; 1015 | iblockstate3 = filler_block_; 1016 | } 1017 | 1018 | if (j1 < i2 && (iblockstate == AIR)) { 1019 | iblockstate = WATER; 1020 | } 1021 | 1022 | l = k + std::max(0, j1 - i2); 1023 | if (j1 >= i2 - 1) { 1024 | if (forest && j1 > 86 + k * 2) { 1025 | if (flag) { 1026 | chunkPrimerIn.setBlock(l1, j1, k1, COARSE_DIRT); 1027 | } 1028 | else { 1029 | chunkPrimerIn.setBlock(l1, j1, k1, GRASS); 1030 | } 1031 | } 1032 | else if (j1 > i2 + 3 + k) { 1033 | int iblockstate2; 1034 | if (j1 >= 64 && j1 <= 127) { 1035 | if (flag) { 1036 | iblockstate2 = HARDCLAY; 1037 | } 1038 | else { 1039 | iblockstate2 = HARDCLAY; 1040 | } 1041 | } 1042 | else { 1043 | iblockstate2 = HARDCLAY; 1044 | } 1045 | 1046 | chunkPrimerIn.setBlock(l1, j1, k1, iblockstate2); 1047 | } 1048 | else { 1049 | chunkPrimerIn.setBlock(l1, j1, k1, top_block_); 1050 | flag1 = true; 1051 | } 1052 | } 1053 | else { 1054 | chunkPrimerIn.setBlock(l1, j1, k1, iblockstate3); 1055 | if (iblockstate3 == HARDCLAY) { 1056 | chunkPrimerIn.setBlock(l1, j1, k1, HARDCLAY); 1057 | } 1058 | } 1059 | } 1060 | else if (l > 0) { 1061 | --l; 1062 | if (flag1) { 1063 | chunkPrimerIn.setBlock(l1, j1, k1, HARDCLAY); 1064 | } 1065 | else { 1066 | chunkPrimerIn.setBlock(l1, j1, k1, HARDCLAY); 1067 | } 1068 | } 1069 | 1070 | ++i1; 1071 | } 1072 | } 1073 | } 1074 | } 1075 | 1076 | void ChunkGenerator::MesaDefSB113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 1077 | { 1078 | int n = x & 15; 1079 | int o = z & 15; 1080 | int l = 63; 1081 | int lv = HARDCLAY; 1082 | int lv2 = filler_block_; 1083 | int p = (int)(noiseVal / 3.0 + 3.0 + nextDouble(rand) * 0.25); 1084 | bool bl = cos(noiseVal / 3.0 * 3.141592653589793) > 0.0; 1085 | int q = -1; 1086 | bool bl2 = false; 1087 | int r = 0; 1088 | 1089 | for (int s = 255; s >= 0; --s) { 1090 | if (r < 15) { 1091 | //lv3 is n, s, o coord 1092 | int lv4 = chunkPrimerIn.getBlock(n, s, o); 1093 | if (lv4 == AIR) { 1094 | q = -1; 1095 | } 1096 | else if (lv4 == STONE) { 1097 | if (q == -1) { 1098 | bl2 = false; 1099 | if (p <= 0) { 1100 | lv = AIR; 1101 | lv2 = STONE; 1102 | } 1103 | else if (s >= l - 4 && s <= l + 1) { 1104 | lv = HARDCLAY; 1105 | lv2 = filler_block_; 1106 | } 1107 | 1108 | if (s < l && (lv == AIR)) { 1109 | lv = WATER; 1110 | } 1111 | 1112 | q = p + std::max(0, s - l); 1113 | if (s >= l - 1) { 1114 | if (s > l + 3 + p) { 1115 | int lv7; 1116 | if (s >= 64 && s <= 127) { 1117 | if (bl) { 1118 | lv7 = HARDCLAY; 1119 | } 1120 | else { 1121 | lv7 = HARDCLAY; 1122 | } 1123 | } 1124 | else { 1125 | lv7 = HARDCLAY; 1126 | } 1127 | 1128 | chunkPrimerIn.setBlock(n, s, o, lv7); 1129 | } 1130 | else { 1131 | chunkPrimerIn.setBlock(n, s, o, top_block_); 1132 | bl2 = true; 1133 | } 1134 | } 1135 | else { 1136 | chunkPrimerIn.setBlock(n, s, o, lv2); 1137 | int lv8 = lv2; 1138 | if (lv8 == HARDCLAY) { 1139 | chunkPrimerIn.setBlock(n, s, o, HARDCLAY); 1140 | } 1141 | } 1142 | } 1143 | else if (q > 0) { 1144 | --q; 1145 | if (bl2) { 1146 | chunkPrimerIn.setBlock(n, s, o, HARDCLAY); 1147 | } 1148 | else { 1149 | chunkPrimerIn.setBlock(n, s, o, HARDCLAY); 1150 | } 1151 | } 1152 | 1153 | ++r; 1154 | } 1155 | } 1156 | } 1157 | } 1158 | void ChunkGenerator::MesaWoodedSB113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 1159 | { 1160 | int n = x & 15; 1161 | int o = z & 15; 1162 | int l = 63; 1163 | int lv = HARDCLAY; 1164 | int lv2 = filler_block_; 1165 | int p = (int)(noiseVal / 3.0 + 3.0 + nextDouble(rand) * 0.25); 1166 | bool bl = cos(noiseVal / 3.0 * 3.141592653589793) > 0.0; 1167 | int q = -1; 1168 | bool bl2 = false; 1169 | int r = 0; 1170 | 1171 | for (int s = 255; s >= 0; --s) { 1172 | if (r < 15) { 1173 | int lv4 = chunkPrimerIn.getBlock(n, s, o); 1174 | if (lv4 == AIR) { 1175 | q = -1; 1176 | } 1177 | else if (lv4 == STONE) { 1178 | if (q == -1) { 1179 | bl2 = false; 1180 | if (p <= 0) { 1181 | lv = AIR; 1182 | lv2 = STONE; 1183 | } 1184 | else if (s >= l - 4 && s <= l + 1) { 1185 | lv = HARDCLAY; 1186 | lv2 = filler_block_; 1187 | } 1188 | 1189 | if (s < l && lv == AIR) { 1190 | lv = WATER; 1191 | } 1192 | 1193 | q = p + std::max(0, s - l); 1194 | if (s >= l - 1) { 1195 | if (s > 86 + p * 2) { 1196 | if (bl) { 1197 | chunkPrimerIn.setBlock(n, s, o, COARSE_DIRT); 1198 | } 1199 | else { 1200 | chunkPrimerIn.setBlock(n, s, o, GRASS); 1201 | } 1202 | } 1203 | else if (s > l + 3 + p) { 1204 | int lv7; 1205 | if (s >= 64 && s <= 127) { 1206 | if (bl) { 1207 | lv7 = HARDCLAY; 1208 | } 1209 | else { 1210 | lv7 = HARDCLAY; 1211 | } 1212 | } 1213 | else { 1214 | lv7 = HARDCLAY; 1215 | } 1216 | 1217 | chunkPrimerIn.setBlock(n, s, o, lv7); 1218 | } 1219 | else { 1220 | chunkPrimerIn.setBlock(n, s, o, top_block_); 1221 | bl2 = true; 1222 | } 1223 | } 1224 | else { 1225 | chunkPrimerIn.setBlock(n, s, o, lv2); 1226 | if (lv2 == HARDCLAY) { 1227 | chunkPrimerIn.setBlock(n, s, o, HARDCLAY); 1228 | } 1229 | } 1230 | } 1231 | else if (q > 0) { 1232 | --q; 1233 | if (bl2) { 1234 | chunkPrimerIn.setBlock(n, s, o, HARDCLAY); 1235 | } 1236 | else { 1237 | chunkPrimerIn.setBlock(n, s, o, HARDCLAY); 1238 | } 1239 | } 1240 | 1241 | ++r; 1242 | } 1243 | } 1244 | } 1245 | } 1246 | void ChunkGenerator::MesaErodedSB113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal) 1247 | { 1248 | double e = 0.0; 1249 | double f = std::min(std::abs(noiseVal), mesaPillarNoise->getValue((double)x * 0.25, (double)z * 0.25) * 15.0); 1250 | if (f > 0.0) { 1251 | double g = 0.001953125; 1252 | double h = std::abs(mesaPillarRoofNoise->getValue((double)x * 0.001953125, (double)z * 0.001953125)); 1253 | e = f * f * 2.5; 1254 | double n = std::ceil(h * 50.0) + 14.0; 1255 | if (e > n) { 1256 | e = n; 1257 | } 1258 | 1259 | e += 64.0; 1260 | } 1261 | 1262 | int o = x & 15; 1263 | int p = z & 15; 1264 | int l = 63; 1265 | int lv = HARDCLAY; 1266 | int lv2 = filler_block_; 1267 | int q = (int)(noiseVal / 3.0 + 3.0 + nextDouble(rand) * 0.25); 1268 | bool bl = cos(noiseVal / 3.0 * 3.141592653589793) > 0.0; 1269 | int r = -1; 1270 | bool bl2 = false; 1271 | 1272 | for (int s = 255; s >= 0; --s) { 1273 | if (chunkPrimerIn.getBlock(o, s, p) == AIR && s < (int)e) { 1274 | chunkPrimerIn.setBlock(o, s, p, STONE); 1275 | } 1276 | 1277 | int lv4 = chunkPrimerIn.getBlock(o, s, p); 1278 | if (lv4 == AIR) { 1279 | r = -1; 1280 | } 1281 | else if (lv4 == STONE) { 1282 | if (r == -1) { 1283 | bl2 = false; 1284 | if (q <= 0) { 1285 | lv = AIR; 1286 | lv2 = STONE; 1287 | } 1288 | else if (s >= l - 4 && s <= l + 1) { 1289 | lv = HARDCLAY; 1290 | lv2 = filler_block_; 1291 | } 1292 | 1293 | if (s < l && lv == AIR) { 1294 | lv = WATER; 1295 | } 1296 | 1297 | r = q + std::max(0, s - l); 1298 | if (s >= l - 1) { 1299 | if (s <= l + 3 + q) { 1300 | chunkPrimerIn.setBlock(o, s, p, top_block_); 1301 | bl2 = true; 1302 | } 1303 | else { 1304 | int lv7; 1305 | if (s >= 64 && s <= 127) { 1306 | if (bl) { 1307 | lv7 = HARDCLAY; 1308 | } 1309 | else { 1310 | lv7 = HARDCLAY; 1311 | } 1312 | } 1313 | else { 1314 | lv7 = HARDCLAY; 1315 | } 1316 | 1317 | chunkPrimerIn.setBlock(o, s, p, lv7); 1318 | } 1319 | } 1320 | else { 1321 | chunkPrimerIn.setBlock(o, s, p, lv2); 1322 | int lv8 = lv2; 1323 | if (lv8 == HARDCLAY) { 1324 | chunkPrimerIn.setBlock(o, s, p, HARDCLAY); 1325 | } 1326 | } 1327 | } 1328 | else if (r > 0) { 1329 | --r; 1330 | if (bl2) { 1331 | chunkPrimerIn.setBlock(o, s, p, HARDCLAY); 1332 | } 1333 | else { 1334 | chunkPrimerIn.setBlock(o, s, p, HARDCLAY); 1335 | } 1336 | } 1337 | } 1338 | } 1339 | } 1340 | 1341 | void ChunkGenerator::SwampSB(uint64_t*, ChunkData& chunkPrimerIn, int x, int z, double) 1342 | { 1343 | double d0 = grassColorNoise->getValue((double)x * 0.25, (double)z * 0.25); 1344 | if (d0 > 0.0) { 1345 | int i = x & 15; 1346 | int j = z & 15; 1347 | 1348 | for (int k = 255; k >= 0; --k) { 1349 | if (chunkPrimerIn.getBlock(j, k, i) != AIR) { 1350 | if (k == 62 && chunkPrimerIn.getBlock(j, k, i) != WATER) { 1351 | chunkPrimerIn.setBlock(j, k, i, WATER); 1352 | if (d0 < 0.12) { 1353 | chunkPrimerIn.setBlock(j, k + 1, i, WATER_LILY); 1354 | } 1355 | } 1356 | break; 1357 | } 1358 | } 1359 | } 1360 | } 1361 | void ChunkGenerator::TaigaSB(uint64_t*, ChunkData&, int, int, double noiseVal) 1362 | { 1363 | top_block_ = GRASS; 1364 | filler_block_ = DIRT; 1365 | if (noiseVal > 1.75) { 1366 | top_block_ = COARSE_DIRT; 1367 | } 1368 | else if (noiseVal > -0.95) { 1369 | top_block_ = PODZOL; 1370 | } 1371 | } 1372 | void ChunkGenerator::SavannaMutatedSB(uint64_t*, ChunkData&, int, int, double noiseVal) 1373 | { 1374 | top_block_ = GRASS; 1375 | filler_block_ = DIRT; 1376 | if (noiseVal > 1.75) { 1377 | top_block_ = STONE; 1378 | filler_block_ = STONE; 1379 | } 1380 | else if (noiseVal > -0.5) { 1381 | top_block_ = COARSE_DIRT; 1382 | } 1383 | } -------------------------------------------------------------------------------- /ChunkGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NoiseGeneratorOctaves.h" 4 | #include "NoiseGeneratorPerlin.h" 5 | #include "ChunkData.h" 6 | #include "javarnd.h" 7 | #include "generator.h" 8 | #include "layers.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | class ChunkGenerator 18 | { 19 | public: 20 | static const constexpr int AIR = 0; 21 | static const constexpr int STONE = 1; 22 | static const constexpr int SAND = 2; 23 | static const constexpr int GRASS = 3; 24 | static const constexpr int DIRT = 4; 25 | static const constexpr int BEDROCK = 5; 26 | static const constexpr int WATER = 6; 27 | static const constexpr int GRAVEL = 7; 28 | static const constexpr int HARDCLAY = 8; 29 | static const constexpr int MYCELIUM = 9; 30 | static const constexpr int SNOW_BLOCK = 10; 31 | static const constexpr int WATER_LILY = 11; 32 | static const constexpr int SANDSTONE = 12; 33 | static const constexpr int PODZOL = 13; 34 | static const constexpr int COARSE_DIRT = 14; 35 | static const constexpr int RED_SAND = 15; 36 | static const constexpr int NETHERRACK = 16; 37 | static const constexpr int SOUL_SAND = 17; 38 | static const constexpr int END_STONE = 18; 39 | static const constexpr int RED_SANDSTONE = 19; 40 | 41 | //"ternary surface" ids 42 | static const constexpr int AIR_T = 0; 43 | static const constexpr int PODZOL_T = 1; 44 | static const constexpr int GRAVEL_T = 2; 45 | static const constexpr int GRASS_T = 3; 46 | static const constexpr int DIRT_T = 4; 47 | static const constexpr int STONE_T = 5; 48 | static const constexpr int COARSE_DIRT_T = 6; 49 | static const constexpr int SAND_T = 7; 50 | static const constexpr int GRASS_SAND_UNDERWATER_T = 8; 51 | static const constexpr int SAND_SAND_UNDERWATER_T = 9; 52 | static const constexpr int MESA_T = 10; 53 | static const constexpr int MYCELIUM_T = 11; 54 | static const constexpr int NETHER_T = 12; 55 | static const constexpr int SOUL_SAND_T = 13; 56 | static const constexpr int END_T = 14; 57 | static const constexpr int CRIMSON_NYLIUM_T = 15; 58 | static const constexpr int WARPED_NYLIUM_T = 16; 59 | static const constexpr int ICE_SPIKES_T = 17; 60 | 61 | //"surface builder" ids 62 | static const constexpr int MOUNTAIN_S = 0; //mountains used to be hills in 1.12 63 | static const constexpr int SHATTERED_SAVANNA_S = 1; 64 | static const constexpr int GRAVELLY_MOUNTAIN_S = 2; 65 | static const constexpr int GIANT_TREE_TAIGA_S = 3; 66 | static const constexpr int SWAMP_S = 4; 67 | static const constexpr int MESA_S = 5; 68 | static const constexpr int WOODED_MESA_S = 6; 69 | static const constexpr int ERODED_MESA_S = 7; 70 | static const constexpr int FROZEN_OCEAN_S = 8; 71 | static const constexpr int NETHER_S = 9; 72 | static const constexpr int NETHER_FOREST_S = 10; 73 | static const constexpr int SOUL_SAND_VALLEY_S = 11; 74 | static const constexpr int BASALT_DELTAS_S = 12; 75 | 76 | private: 77 | static const constexpr float depthNoiseScaleX = 200.0; 78 | static const constexpr float depthNoiseScaleZ = 200.0; 79 | static const constexpr float depthNoiseScaleExponent = 0.5; 80 | static const constexpr float mainNoiseScaleX = 80.0; 81 | static const constexpr float mainNoiseScaleY = 160.0; 82 | static const constexpr float mainNoiseScaleZ = 80.0; 83 | static const constexpr float coordinateScale = 684.412F; 84 | static const constexpr float heightScale = 684.412F; 85 | static const constexpr float biomeDepthOffset = 0.0; 86 | static const constexpr float biomeDepthWeight = 1.0; 87 | static const constexpr float biomeScaleOffset = 0.0; 88 | static const constexpr float biomeScaleWeight = 1.0; 89 | static const constexpr float baseSize = 8.5F; 90 | static const constexpr float stretchY = 12.0F; 91 | static const constexpr float upperLimitScale = 512.0F; 92 | static const constexpr float lowerLimitScale = 512.0F; 93 | 94 | int top_block_, filler_block_, underwater_block_; 95 | bool amplified_; 96 | std::unique_ptr minLimitPerlinNoise; 97 | std::unique_ptr maxLimitPerlinNoise; 98 | std::unique_ptr mainPerlinNoise; 99 | std::unique_ptr surfaceNoise; 100 | std::unique_ptr mesaPillarNoise; 101 | std::unique_ptr mesaPillarRoofNoise; 102 | std::unique_ptr grassColorNoise; 103 | std::unique_ptr scaleNoise; 104 | std::unique_ptr depthNoise; 105 | std::unique_ptr forestNoise; 106 | double heightMap[825]; 107 | float biomeWeights[25]; 108 | int biomesForGeneration1[100]; 109 | int biomesForGeneration2[256]; 110 | 111 | LayerStack stack_; 112 | std::unordered_map> biome_to_base_and_variation_; 113 | 114 | std::unordered_map biome_to_ternary_; 115 | std::unordered_map> ternary_to_blocktypes_; //top, filler, and underwater blocks 116 | 117 | void registerBaseAndVariation(); 118 | 119 | void registerTernaryBlocks(); 120 | void registerTernaryIds(); 121 | 122 | using SurfaceBuilderAdditionsFunc = std::function; 123 | std::unordered_map biome_to_surface_builder_; 124 | std::unordered_map surface_builder_to_additions_func_; 125 | //1.12 had a 'genTerrainBlocks' function for additional biome generation, but 1.16- has 'surface builders', of which most use the 'default' which generateBiomeTerrain implements 126 | //mesa still overrides this generateBiomeTerrain completely, frozen ocean too but dont support now 127 | 128 | void registerSurfaceBuilderIds(); 129 | void registerSurfaceBuilderFuncs(MCversion version); 130 | 131 | std::unordered_set no_def_surface_building_;//only for mesa 132 | 133 | MCversion version_; 134 | 135 | 136 | public: 137 | ChunkGenerator(uint64_t world_seed, MCversion version); 138 | bool provideChunk(int x, int z, ChunkData& chunk, std::unordered_set* biomes = nullptr); //NONE OF THESE ARE THREAD SAFE 139 | bool provideChunkHeightmap(int x, int z, ChunkHeightmap& chunk, std::unordered_set* biomes = nullptr); 140 | 141 | float getBaseHeight(int biome); 142 | float getHeightVariation(int biome); 143 | 144 | private: 145 | void setBlocksInChunk(int x, int z, ChunkData& primer); 146 | inline bool terrainAtHeight(int x, int z, int y); 147 | inline int terrainHeight(int x, int z, int seed); 148 | void generateHeightmap(int p_185978_1_, int p_185978_2_, int p_185978_3_); 149 | void generateHeightmap(int p_185978_1_, int p_185978_2_, int p_185978_3_, std::pair base_and_variation); 150 | void generateBiomeTerrain112(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal); 151 | void defaultSurfaceBuild113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal); 152 | void buildBedrock113(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal); 153 | void buildBedrock114(uint64_t* rand, ChunkData& chunkPrimerIn, int x, int z, double noiseVal); 154 | void replaceBiomeBlocks(uint64_t* rand, int x, int z, ChunkData& primer); 155 | 156 | private: 157 | 158 | void HillsMountainsSB(uint64_t*, ChunkData&, int, int, double, bool);//1.12 called hills, mountains 1.13+ 159 | void MesaSB112(uint64_t*, ChunkData&, int, int, double, bool, bool);//there is slight variation in mesa generation between 1.12/1.13+ 160 | void MesaDefSB113(uint64_t*, ChunkData&, int, int, double); 161 | void MesaWoodedSB113(uint64_t*, ChunkData&, int, int, double); 162 | void MesaErodedSB113(uint64_t*, ChunkData&, int, int, double); 163 | void SwampSB(uint64_t*, ChunkData&, int, int, double); 164 | void TaigaSB(uint64_t*, ChunkData&, int, int, double); 165 | void SavannaMutatedSB(uint64_t*, ChunkData&, int, int, double); 166 | 167 | }; 168 | -------------------------------------------------------------------------------- /NoiseGeneratorImproved.cpp: -------------------------------------------------------------------------------- 1 | #include "NoiseGeneratorImproved.h" 2 | #include "javarnd.h" 3 | 4 | const double NoiseGeneratorImproved::GRAD_X[] = { 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.0, 0.0 }; 5 | 6 | const double NoiseGeneratorImproved::GRAD_Y[] = { 1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0 }; 7 | 8 | const double NoiseGeneratorImproved::GRAD_Z[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 0.0, 1.0, 0.0, -1.0 }; 9 | 10 | const double NoiseGeneratorImproved::GRAD_2X[] = { 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.0, 0.0 }; 11 | 12 | const double NoiseGeneratorImproved::GRAD_2Z[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 0.0, 1.0, 0.0, -1.0 }; 13 | 14 | 15 | NoiseGeneratorImproved::NoiseGeneratorImproved(uint64_t* p_i45469_1_) 16 | { 17 | xCoord = nextDouble(p_i45469_1_) * 256.0; 18 | yCoord = nextDouble(p_i45469_1_) * 256.0; 19 | zCoord = nextDouble(p_i45469_1_) * 256.0; 20 | 21 | for (int i = 0; i < 256; i++) 22 | { 23 | permutations[i]=i; 24 | } 25 | for (int i = 256; i < 512; i++) 26 | { 27 | permutations[i] = 0; 28 | } 29 | 30 | for (int l = 0; l < 256; ++l) 31 | { 32 | int j = nextInt(p_i45469_1_, 256 - l) + l; 33 | int k = permutations[l]; 34 | permutations[l] = permutations[j]; 35 | permutations[j] = k; 36 | permutations[l + 256] = permutations[l]; 37 | } 38 | } 39 | 40 | double NoiseGeneratorImproved::lerp(double p_76311_1_, double p_76311_3_, double p_76311_5_) 41 | { 42 | return p_76311_3_ + p_76311_1_ * (p_76311_5_ - p_76311_3_); 43 | } 44 | 45 | double NoiseGeneratorImproved::grad2(int p_76309_1_, double p_76309_2_, double p_76309_4_) 46 | { 47 | int i = p_76309_1_ & 15; 48 | return GRAD_2X[i] * p_76309_2_ + GRAD_2Z[i] * p_76309_4_; 49 | } 50 | 51 | double NoiseGeneratorImproved::grad(int p_76310_1_, double p_76310_2_, double p_76310_4_, double p_76310_6_) 52 | { 53 | int i = p_76310_1_ & 15; 54 | //std::cout << i << sizeof(long); 55 | return GRAD_X[i] * p_76310_2_ + GRAD_Y[i] * p_76310_4_ + GRAD_Z[i] * p_76310_6_; 56 | } 57 | 58 | void NoiseGeneratorImproved::populateNoiseArray(double* noiseArray, double xOffset, double yOffset, double zOffset, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale, double noiseScale) 59 | { 60 | if (ySize == 1) 61 | { 62 | int i5 = 0; 63 | int j5 = 0; 64 | int j = 0; 65 | int k5 = 0; 66 | double d14 = 0.0; 67 | double d15 = 0.0; 68 | int l5 = 0; 69 | double d16 = 1.0 / noiseScale; 70 | 71 | for (int j2 = 0; j2 < xSize; ++j2) 72 | { 73 | double d17 = xOffset + (double)j2 * xScale + xCoord; 74 | int i6 = (int)d17; 75 | 76 | if (d17 < (double)i6) 77 | { 78 | --i6; 79 | } 80 | 81 | int k2 = i6 & 255; 82 | d17 = d17 - (double)i6; 83 | double d18 = d17 * d17 * d17 * (d17 * (d17 * 6.0 - 15.0) + 10.0); 84 | 85 | for (int j6 = 0; j6 < zSize; ++j6) 86 | { 87 | double d19 = zOffset + (double)j6 * zScale + zCoord; 88 | int k6 = (int)d19; 89 | 90 | if (d19 < (double)k6) 91 | { 92 | --k6; 93 | } 94 | 95 | int l6 = k6 & 255; 96 | d19 = d19 - (double)k6; 97 | double d20 = d19 * d19 * d19 * (d19 * (d19 * 6.0 - 15.0) + 10.0); 98 | i5 = permutations[k2] + 0; 99 | j5 = permutations[i5] + l6; 100 | j = permutations[k2 + 1] + 0; 101 | k5 = permutations[j] + l6; 102 | d14 = lerp(d18, grad2(permutations[j5], d17, d19), grad(permutations[k5], d17 - 1.0, 0.0, d19)); 103 | d15 = lerp(d18, grad(permutations[j5 + 1], d17, 0.0, d19 - 1.0), grad(permutations[k5 + 1], d17 - 1.0, 0.0, d19 - 1.0)); 104 | double d21 = lerp(d20, d14, d15); 105 | int i7 = l5++; 106 | noiseArray[i7] += d21 * d16; 107 | } 108 | } 109 | } 110 | else 111 | { 112 | int i = 0; 113 | double d0 = 1.0 / noiseScale; 114 | int k = -1; 115 | int l = 0; 116 | int i1 = 0; 117 | int j1 = 0; 118 | int k1 = 0; 119 | int l1 = 0; 120 | int i2 = 0; 121 | double d1 = 0.0; 122 | double d2 = 0.0; 123 | double d3 = 0.0; 124 | double d4 = 0.0; 125 | 126 | for (int l2 = 0; l2 < xSize; ++l2) 127 | { 128 | double d5 = xOffset + (double)l2 * xScale + xCoord; 129 | int i3 = (int)d5; 130 | 131 | if (d5 < (double)i3) 132 | { 133 | --i3; 134 | } 135 | 136 | int j3 = i3 & 255; 137 | d5 = d5 - (double)i3; 138 | double d6 = d5 * d5 * d5 * (d5 * (d5 * 6.0 - 15.0) + 10.0); 139 | 140 | for (int k3 = 0; k3 < zSize; ++k3) 141 | { 142 | double d7 = zOffset + (double)k3 * zScale + zCoord; 143 | int l3 = (int)d7; 144 | 145 | if (d7 < (double)l3) 146 | { 147 | --l3; 148 | } 149 | 150 | int i4 = l3 & 255; 151 | d7 = d7 - (double)l3; 152 | double d8 = d7 * d7 * d7 * (d7 * (d7 * 6.0 - 15.0) + 10.0); 153 | 154 | for (int j4 = 0; j4 < ySize; ++j4) 155 | { 156 | double d9 = yOffset + (double)j4 * yScale + yCoord; 157 | int k4 = (int)d9; 158 | 159 | if (d9 < (double)k4) 160 | { 161 | --k4; 162 | } 163 | 164 | int l4 = k4 & 255; 165 | d9 = d9 - (double)k4; 166 | double d10 = d9 * d9 * d9 * (d9 * (d9 * 6.0 - 15.0) + 10.0); 167 | 168 | if (j4 == 0 || l4 != k) 169 | { 170 | k = l4; 171 | l = permutations[j3] + l4; 172 | i1 = permutations[l] + i4; 173 | j1 = permutations[l + 1] + i4; 174 | k1 = permutations[j3 + 1] + l4; 175 | l1 = permutations[k1] + i4; 176 | i2 = permutations[k1 + 1] + i4; 177 | d1 = lerp(d6, grad(permutations[i1], d5, d9, d7), grad(permutations[l1], d5 - 1.0, d9, d7)); 178 | d2 = lerp(d6, grad(permutations[j1], d5, d9 - 1.0, d7), grad(permutations[i2], d5 - 1.0, d9 - 1.0, d7)); 179 | d3 = lerp(d6, grad(permutations[i1 + 1], d5, d9, d7 - 1.0), grad(permutations[l1 + 1], d5 - 1.0, d9, d7 - 1.0)); 180 | d4 = lerp(d6, grad(permutations[j1 + 1], d5, d9 - 1.0, d7 - 1.0), grad(permutations[i2 + 1], d5 - 1.0, d9 - 1.0, d7 - 1.0)); 181 | } 182 | 183 | double d11 = lerp(d10, d1, d2); 184 | double d12 = lerp(d10, d3, d4); 185 | double d13 = lerp(d8, d11, d12); 186 | int j7 = i++; 187 | noiseArray[j7] += d13 * d0; 188 | } 189 | } 190 | } 191 | } 192 | } -------------------------------------------------------------------------------- /NoiseGeneratorImproved.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class NoiseGeneratorImproved { 6 | public: 7 | NoiseGeneratorImproved(uint64_t*); 8 | double lerp(double p_76311_1_, double p_76311_3_, double p_76311_5_); 9 | double grad2(int p_76309_1_, double p_76309_2_, double p_76309_4_); 10 | double grad(int p_76310_1_, double p_76310_2_, double p_76310_4_, double p_76310_6_); 11 | void populateNoiseArray(double* noiseArray, double xOffset, double yOffset, double zOffset, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale, double noiseScale); 12 | 13 | double xCoord; 14 | double yCoord; 15 | double zCoord; 16 | 17 | private: 18 | 19 | int permutations[512]; 20 | 21 | const static double GRAD_X[]; 22 | const static double GRAD_Y[]; 23 | const static double GRAD_Z[]; 24 | const static double GRAD_2X[]; 25 | const static double GRAD_2Z[]; 26 | }; -------------------------------------------------------------------------------- /NoiseGeneratorOctaves.cpp: -------------------------------------------------------------------------------- 1 | #include "NoiseGeneratorOctaves.h" 2 | 3 | int64_t lFloor(double value) 4 | { 5 | int64_t i = (int64_t)value; 6 | return value < (double)i ? i - 1L : i; 7 | } 8 | 9 | NoiseGeneratorOctaves::NoiseGeneratorOctaves(uint64_t* seed, int octavesIn) 10 | { 11 | octaves = octavesIn; 12 | 13 | for (int i = 0; i < octavesIn; ++i) 14 | { 15 | generatorCollection.emplace_back(seed);//AGAIN MAY NOT WORK RIGHT 16 | } 17 | } 18 | 19 | double* NoiseGeneratorOctaves::generateNoiseOctaves(double* noiseArray, int noiseArrayLength, int xOffset, int yOffset, int zOffset, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale) 20 | { 21 | if (noiseArray == nullptr) 22 | { 23 | noiseArray = new double[xSize * ySize * zSize]; 24 | noiseArrayLength = xSize * ySize * zSize; 25 | for (int i = 0; i < noiseArrayLength; ++i) 26 | { 27 | noiseArray[i] = 0.0; 28 | } 29 | } 30 | else 31 | { 32 | for (int i = 0; i < noiseArrayLength; ++i) 33 | { 34 | noiseArray[i] = 0.0; 35 | } 36 | } 37 | 38 | double d3 = 1.0; 39 | 40 | for (int j = 0; j < octaves; ++j) 41 | { 42 | double d0 = (double)xOffset * d3 * xScale; 43 | double d1 = (double)yOffset * d3 * yScale; 44 | double d2 = (double)zOffset * d3 * zScale; 45 | int64_t k = lFloor(d0); 46 | int64_t l = lFloor(d2); 47 | d0 = d0 - (double)k; 48 | d2 = d2 - (double)l; 49 | k = k % 16777216L; 50 | l = l % 16777216L; 51 | d0 = d0 + (double)k; 52 | d2 = d2 + (double)l; 53 | generatorCollection[j].populateNoiseArray(noiseArray, d0, d1, d2, xSize, ySize, zSize, xScale * d3, yScale * d3, zScale * d3, d3); 54 | d3 /= 2.0; 55 | } 56 | 57 | return noiseArray; 58 | } 59 | 60 | double* NoiseGeneratorOctaves::generateNoiseOctaves(double* noiseArray, int noiseArrayLength, int xOffset, int zOffset, int xSize, int zSize, double xScale, double zScale, double p_76305_10_) 61 | { 62 | return generateNoiseOctaves(noiseArray, noiseArrayLength, xOffset, 10, zOffset, xSize, 1, zSize, xScale, 1.0, zScale); 63 | } -------------------------------------------------------------------------------- /NoiseGeneratorOctaves.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "NoiseGeneratorImproved.h" 5 | 6 | class NoiseGeneratorOctaves 7 | { 8 | public: 9 | NoiseGeneratorOctaves(uint64_t* seed, int octavesIn); 10 | double* generateNoiseOctaves(double* noiseArray, int noiseArrayLength, int xOffset, int yOffset, int zOffset, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale); 11 | double* generateNoiseOctaves(double* noiseArray, int noiseArrayLength, int xOffset, int zOffset, int xSize, int zSize, double xScale, double zScale, double p_76305_10_); 12 | private: 13 | std::vector generatorCollection; 14 | int octaves; 15 | }; -------------------------------------------------------------------------------- /NoiseGeneratorPerlin.cpp: -------------------------------------------------------------------------------- 1 | #include "NoiseGeneratorPerlin.h" 2 | 3 | NoiseGeneratorPerlin::NoiseGeneratorPerlin(uint64_t* p_i45470_1_, int p_i45470_2_) 4 | { 5 | levels = p_i45470_2_; 6 | 7 | for (int i = 0; i < p_i45470_2_; ++i) 8 | { 9 | noiseLevels.emplace_back(p_i45470_1_);//THIS MAY NOT GIVE ORDERING RIGHT???? 10 | } 11 | } 12 | 13 | double NoiseGeneratorPerlin::getValue(double p_151601_1_, double p_151601_3_) 14 | { 15 | double d0 = 0.0; 16 | double d1 = 1.0; 17 | 18 | for (int i = 0; i < levels; ++i) 19 | { 20 | d0 += noiseLevels[i].getValue(p_151601_1_ * d1, p_151601_3_ * d1) / d1; 21 | d1 /= 2.0; 22 | } 23 | 24 | return d0; 25 | } 26 | 27 | double* NoiseGeneratorPerlin::getRegion(double* p_151599_1_, int p_151599_1_length, double p_151599_2_, double p_151599_4_, int p_151599_6_, int p_151599_7_, double p_151599_8_, double p_151599_10_, double p_151599_12_) 28 | { 29 | return getRegion(p_151599_1_, p_151599_1_length, p_151599_2_, p_151599_4_, p_151599_6_, p_151599_7_, p_151599_8_, p_151599_10_, p_151599_12_, 0.5); 30 | } 31 | 32 | double* NoiseGeneratorPerlin::getRegion(double* p_151600_1_, int p_151600_1_length, double p_151600_2_, double p_151600_4_, int p_151600_6_, int p_151600_7_, double p_151600_8_, double p_151600_10_, double p_151600_12_, double p_151600_14_) 33 | { 34 | if (p_151600_1_ != nullptr && p_151600_1_length >= p_151600_6_ * p_151600_7_) 35 | { 36 | for (int i = 0; i < p_151600_1_length; ++i) 37 | { 38 | p_151600_1_[i] = 0.0; 39 | } 40 | } 41 | else 42 | { 43 | p_151600_1_ = new double[p_151600_6_ * p_151600_7_]; 44 | p_151600_1_length = p_151600_6_ * p_151600_7_; 45 | for (int i = 0; i < p_151600_1_length; ++i) 46 | { 47 | p_151600_1_[i] = 0.0; 48 | } 49 | } 50 | 51 | double d1 = 1.0; 52 | double d0 = 1.0; 53 | 54 | for (int j = 0; j < levels; ++j) 55 | { 56 | noiseLevels[j].add(p_151600_1_, p_151600_2_, p_151600_4_, p_151600_6_, p_151600_7_, p_151600_8_ * d0 * d1, p_151600_10_ * d0 * d1, 0.55 / d1); 57 | d0 *= p_151600_12_; 58 | d1 *= p_151600_14_; 59 | } 60 | 61 | return p_151600_1_; 62 | } -------------------------------------------------------------------------------- /NoiseGeneratorPerlin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NoiseGeneratorSimplex.h" 4 | #include 5 | 6 | class NoiseGeneratorPerlin 7 | { 8 | private: 9 | std::vector noiseLevels; 10 | int levels; 11 | 12 | public: 13 | NoiseGeneratorPerlin(uint64_t* p_i45470_1_, int p_i45470_2_); 14 | double getValue(double p_151601_1_, double p_151601_3_); 15 | double* getRegion(double* p_151599_1_, int p_151599_1_length, double p_151599_2_, double p_151599_4_, int p_151599_6_, int p_151599_7_, double p_151599_8_, double p_151599_10_, double p_151599_12_); 16 | double* getRegion(double* p_151600_1_, int p_151600_1_length, double p_151600_2_, double p_151600_4_, int p_151600_6_, int p_151600_7_, double p_151600_8_, double p_151600_10_, double p_151600_12_, double p_151600_14_); 17 | }; 18 | -------------------------------------------------------------------------------- /NoiseGeneratorSimplex.cpp: -------------------------------------------------------------------------------- 1 | #include "NoiseGeneratorSimplex.h" 2 | #include "javarnd.h" 3 | 4 | void NoiseGeneratorSimplex::initGrad3() 5 | { 6 | grad3[0][0] = 1; grad3[0][1] = 1; grad3[0][2] = 0; 7 | grad3[1][0] = -1; grad3[1][1] = 1; grad3[1][2] = 0; 8 | grad3[2][0] = 1; grad3[2][1] = -1; grad3[2][2] = 0; 9 | grad3[3][0] = -1; grad3[3][1] = -1; grad3[3][2] = 0; 10 | grad3[4][0] = 1; grad3[4][1] = 0; grad3[4][2] = 1; 11 | grad3[5][0] = -1; grad3[5][1] = 0; grad3[5][2] = 1; 12 | grad3[6][0] = 1; grad3[6][1] = 0; grad3[6][2] = -1; 13 | grad3[7][0] = -1; grad3[7][1] = 0; grad3[7][2] = -1; 14 | grad3[8][0] = 0; grad3[8][1] = 1; grad3[8][2] = 1; 15 | grad3[9][0] = 0; grad3[9][1] = -1; grad3[9][2] = 1; 16 | grad3[10][0] = 0; grad3[10][1] = 1; grad3[10][2] = -1; 17 | grad3[11][0] = 0; grad3[11][1] = -1; grad3[11][2] = -1; 18 | } 19 | 20 | NoiseGeneratorSimplex::NoiseGeneratorSimplex(uint64_t* seed) 21 | { 22 | initGrad3(); 23 | 24 | xo = nextDouble(seed) * 256.0; 25 | yo = nextDouble(seed) * 256.0; 26 | zo = nextDouble(seed) * 256.0; 27 | 28 | for (int i = 0; i < 256; p[i] = i++) 29 | { 30 | ; 31 | } 32 | 33 | for (int l = 0; l < 256; ++l) 34 | { 35 | int j = nextInt(seed, 256 - l) + l; 36 | int k = p[l]; 37 | p[l] = p[j]; 38 | p[j] = k; 39 | p[l + 256] = p[l]; 40 | } 41 | } 42 | 43 | int NoiseGeneratorSimplex::fastFloor(double value) 44 | { 45 | return value > 0.0 ? (int)value : (int)value - 1; 46 | } 47 | 48 | double NoiseGeneratorSimplex::dot(int* p_151604_0_, double p_151604_1_, double p_151604_3_) 49 | { 50 | return (double)p_151604_0_[0] * p_151604_1_ + (double)p_151604_0_[1] * p_151604_3_; 51 | } 52 | 53 | double NoiseGeneratorSimplex::getValue(double p_151605_1_, double p_151605_3_) 54 | { 55 | double d3 = 0.5 * (SQRT_3 - 1.0); 56 | double d4 = (p_151605_1_ + p_151605_3_) * d3; 57 | int i = fastFloor(p_151605_1_ + d4); 58 | int j = fastFloor(p_151605_3_ + d4); 59 | double d5 = (3.0 - SQRT_3) / 6.0; 60 | double d6 = (double)(i + j) * d5; 61 | double d7 = (double)i - d6; 62 | double d8 = (double)j - d6; 63 | double d9 = p_151605_1_ - d7; 64 | double d10 = p_151605_3_ - d8; 65 | int k; 66 | int l; 67 | 68 | if (d9 > d10) 69 | { 70 | k = 1; 71 | l = 0; 72 | } 73 | else 74 | { 75 | k = 0; 76 | l = 1; 77 | } 78 | 79 | double d11 = d9 - (double)k + d5; 80 | double d12 = d10 - (double)l + d5; 81 | double d13 = d9 - 1.0 + 2.0 * d5; 82 | double d14 = d10 - 1.0 + 2.0 * d5; 83 | int i1 = i & 255; 84 | int j1 = j & 255; 85 | int k1 = p[i1 + p[j1]] % 12; 86 | int l1 = p[i1 + k + p[j1 + l]] % 12; 87 | int i2 = p[i1 + 1 + p[j1 + 1]] % 12; 88 | double d15 = 0.5 - d9 * d9 - d10 * d10; 89 | double d0; 90 | 91 | if (d15 < 0.0) 92 | { 93 | d0 = 0.0; 94 | } 95 | else 96 | { 97 | d15 = d15 * d15; 98 | d0 = d15 * d15 * dot(grad3[k1], d9, d10); 99 | } 100 | 101 | double d16 = 0.5 - d11 * d11 - d12 * d12; 102 | double d1; 103 | 104 | if (d16 < 0.0) 105 | { 106 | d1 = 0.0; 107 | } 108 | else 109 | { 110 | d16 = d16 * d16; 111 | d1 = d16 * d16 * dot(grad3[l1], d11, d12); 112 | } 113 | 114 | double d17 = 0.5 - d13 * d13 - d14 * d14; 115 | double d2; 116 | 117 | if (d17 < 0.0) 118 | { 119 | d2 = 0.0; 120 | } 121 | else 122 | { 123 | d17 = d17 * d17; 124 | d2 = d17 * d17 * dot(grad3[i2], d13, d14); 125 | } 126 | 127 | return 70.0 * (d0 + d1 + d2); 128 | } 129 | 130 | void NoiseGeneratorSimplex::add(double* p_151606_1_, double p_151606_2_, double p_151606_4_, int p_151606_6_, int p_151606_7_, double p_151606_8_, double p_151606_10_, double p_151606_12_) 131 | { 132 | int i = 0; 133 | 134 | for (int j = 0; j < p_151606_7_; ++j) 135 | { 136 | double d0 = (p_151606_4_ + (double)j) * p_151606_10_ + yo; 137 | 138 | for (int k = 0; k < p_151606_6_; ++k) 139 | { 140 | double d1 = (p_151606_2_ + (double)k) * p_151606_8_ + xo; 141 | double d5 = (d1 + d0) * F2; 142 | int l = fastFloor(d1 + d5); 143 | int i1 = fastFloor(d0 + d5); 144 | double d6 = (double)(l + i1) * G2; 145 | double d7 = (double)l - d6; 146 | double d8 = (double)i1 - d6; 147 | double d9 = d1 - d7; 148 | double d10 = d0 - d8; 149 | int j1; 150 | int k1; 151 | 152 | if (d9 > d10) 153 | { 154 | j1 = 1; 155 | k1 = 0; 156 | } 157 | else 158 | { 159 | j1 = 0; 160 | k1 = 1; 161 | } 162 | 163 | double d11 = d9 - (double)j1 + G2; 164 | double d12 = d10 - (double)k1 + G2; 165 | double d13 = d9 - 1.0 + 2.0 * G2; 166 | double d14 = d10 - 1.0 + 2.0 * G2; 167 | int l1 = l & 255; 168 | int i2 = i1 & 255; 169 | int j2 = p[l1 + p[i2]] % 12; 170 | int k2 = p[l1 + j1 + p[i2 + k1]] % 12; 171 | int l2 = p[l1 + 1 + p[i2 + 1]] % 12; 172 | double d15 = 0.5 - d9 * d9 - d10 * d10; 173 | double d2; 174 | 175 | if (d15 < 0.0) 176 | { 177 | d2 = 0.0; 178 | } 179 | else 180 | { 181 | d15 = d15 * d15; 182 | d2 = d15 * d15 * dot(grad3[j2], d9, d10); 183 | } 184 | 185 | double d16 = 0.5 - d11 * d11 - d12 * d12; 186 | double d3; 187 | 188 | if (d16 < 0.0) 189 | { 190 | d3 = 0.0; 191 | } 192 | else 193 | { 194 | d16 = d16 * d16; 195 | d3 = d16 * d16 * dot(grad3[k2], d11, d12); 196 | } 197 | 198 | double d17 = 0.5 - d13 * d13 - d14 * d14; 199 | double d4; 200 | 201 | if (d17 < 0.0) 202 | { 203 | d4 = 0.0; 204 | } 205 | else 206 | { 207 | d17 = d17 * d17; 208 | d4 = d17 * d17 * dot(grad3[l2], d13, d14); 209 | } 210 | 211 | int i3 = i++; 212 | p_151606_1_[i3] += 70.0 * (d2 + d3 + d4) * p_151606_12_; 213 | } 214 | } 215 | } -------------------------------------------------------------------------------- /NoiseGeneratorSimplex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class NoiseGeneratorSimplex 5 | { 6 | public: 7 | 8 | NoiseGeneratorSimplex(uint64_t* random); 9 | 10 | static int fastFloor(double value); 11 | static double dot(int* p_151604_0_, double p_151604_1_, double p_151604_3_); 12 | double getValue(double p_151605_1_, double p_151605_3_); 13 | void add(double* p_151606_1_, double p_151606_2_, double p_151606_4_, int p_151606_6_, int p_151606_7_, double p_151606_8_, double p_151606_10_, double p_151606_12_); 14 | 15 | static constexpr double SQRT_3 = 1.73205080757; 16 | static constexpr double F2 = 0.5 * (SQRT_3 - 1.0); 17 | static constexpr double G2 = (3.0 - SQRT_3) / 6.0; 18 | 19 | double xo, yo, zo; 20 | 21 | private: 22 | void initGrad3(); 23 | int grad3[12][3]; 24 | int p[512]; 25 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a C++ library that mimics the world generation of Minecraft Java Edition across a host of versions. It was originally meant to be used as an optimized replacement for my Terrain Formation Finder project. I haven't done a user-friendly GUI app for this yet (still plan to eventually), but the library is basically fully functional and tested (minus maybe a few small bugs). You should be able link against this and use the interface in Search.h to do searches similar to Terrain Formation Finder. There is a few search options to choose, as well as the new "heightmap search", which only analyzes block chunk height and ignores block type. 2 | 3 | This currently links against a modded version of Cubitect's 'cubiomes' library: github.com/IceTank/cubiomes 4 | 5 | ### How to get this thing working in visual studio 6 | 7 | 1. Git clone this 8 | 2. Git clone this cubiomes fork https://github.com/IceTank/cubiomes into a different folder 9 | 3. Open this project folder in VS 10 | 4. File > New > Project from existing code 11 | 5. Follow the instructions Porject type C++ select cloned repositiory and give it a name for instance 'TerrainFinder' APPLICATION TYPE Console application Release options leave empty then press finish. 12 | 6. File > New > Project from existing code. Select cubiomes cloned repository name: 'cubiomes' type C++ Application type 'Static linked library' leave release options empty. 13 | 7. Close the cubiomes project and reopen the TerrainFinder Project 14 | 8. Solution Folder 'TerrainFinder' Right click > Propertys Select all Configurations All Platforms > c/c++ > Additional include directorys > Add the cubiomes project folder 15 | 9. Solution Folder 'Solution 'THIS PROJECT (x of x projects)'' (at the top) Right click > Add > Existion Project select the cubiomes project file created from the cubiomes project 16 | 10. Solution Folder TerrainFinder > Add > Reference Select cubiomes hit ok 17 | If you get an error COM connection failed or something simelar try this guide: https://developercommunity.visualstudio.com/t/add-a-reference-raise-error-error-hresult-e-fail-h/260196#T-N273537 18 | 11. FormationFinder propertys Select all Platforms and all Targets > Linker > System > SubSystem > CONSOLE(SUBSYSTEM:/CONSOLE) 19 | 12. FormationFinder propertys Select Release all Platforms Linker > Input > Additionally Dependencys > Add /Release/cubiomes.lib 20 | This makes it so FormationFinder looks in its own release Folder for the library. 21 | 13. Try running the project in release mode for x86 architecture. 22 | -------------------------------------------------------------------------------- /Search.cpp: -------------------------------------------------------------------------------- 1 | #include "Search.h" 2 | #include 3 | 4 | void alignFormation(std::vector& formation) 5 | { 6 | int minx = INT_MAX, minz = INT_MAX; 7 | for (auto& block : formation) 8 | { 9 | if (block.getX() < minx) minx = block.getX(); 10 | if (block.getZ() < minz) minz = block.getZ(); 11 | } 12 | std::vector aligned_formation; 13 | for (auto& block : formation) 14 | aligned_formation.push_back(FormationBlock(block.getX() - minx, block.getY(), block.getZ() - minz, block.getBlockId())); 15 | for (auto& block : aligned_formation) 16 | if (block.getX() >= 16 || block.getZ() >= 16) 17 | throw std::runtime_error("Search formation width a maximum of 16 blocks."); 18 | formation = aligned_formation; 19 | } 20 | 21 | void terrainSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback* progresscb, FoundCallback foundcb) 22 | { 23 | if (xminc > xmaxc || ymin > ymax || zminc > zmaxc) 24 | throw std::runtime_error("Search range min bounds must be less than max"); 25 | 26 | std::vector> formations(0); 27 | formations.resize(1); 28 | 29 | formations[0] = formation; 30 | alignFormation(formations[0]); 31 | 32 | if (allRotations) 33 | { 34 | formations.resize(4); 35 | for (int i = 1; i < 4; i++) 36 | { 37 | for (FormationBlock block : formations[i - 1]) 38 | formations[i].push_back(FormationBlock(-1 * block.getZ(), block.getY(), block.getX(), block.getBlockId())); 39 | alignFormation(formations[i]); 40 | } 41 | } 42 | 43 | ChunkGenerator generator(seed, version); 44 | std::pair> chunk = std::make_pair(false, std::make_shared()); 45 | std::pair> chunkxp = std::make_pair(false, std::make_shared()); 46 | std::pair> chunkzp = std::make_pair(false, std::make_shared()); 47 | std::pair> chunkxzp = std::make_pair(false, std::make_shared()); 48 | 49 | for (int x = xminc; x <= xmaxc; x++) 50 | { 51 | if (keep_searching) 52 | if (!(*keep_searching)) 53 | return; 54 | if (progresscb) 55 | (*progresscb)(static_cast(x - xminc) / static_cast(xmaxc - xminc)); 56 | for (int z = zminc; z <= zmaxc; z++) 57 | { 58 | if (z != zminc)//reduce times we need to generate the chunk to 2 instead of 4 59 | { 60 | std::swap(chunk, chunkzp); 61 | std::swap(chunkxp, chunkxzp); 62 | } 63 | else 64 | { 65 | chunk.first = generator.provideChunk(x, z, *chunk.second, biomes); 66 | chunkxp.first = generator.provideChunk(x + 1, z, *chunkxp.second, biomes); 67 | } 68 | chunkzp.first = generator.provideChunk(x, z + 1, *chunkzp.second, biomes); 69 | chunkxzp.first = generator.provideChunk(x + 1, z + 1, *chunkxzp.second, biomes); 70 | 71 | if (!chunk.first || !chunkxp.first || !chunkzp.first || !chunkxzp.first) 72 | continue; 73 | 74 | for (int xb = 0; xb < 16; xb++) 75 | { 76 | for (int zb = 0; zb < 16; zb++) 77 | { 78 | for (int y = ymin; y <= ymax; y++) 79 | { 80 | for (auto& form : formations) 81 | { 82 | bool found = true; 83 | for (auto& block : form) 84 | { 85 | int xrel = xb + block.getX(); 86 | int zrel = zb + block.getZ(); 87 | 88 | if (xrel >= 16 && zrel >= 16) 89 | { 90 | if (chunkxzp.second->getBlock(xrel - 16, y + block.getY(), zrel - 16) != block.getBlockId()) 91 | { 92 | found = false; 93 | break; 94 | } 95 | } 96 | else if (xrel >= 16) 97 | { 98 | if (chunkxp.second->getBlock(xrel - 16, y + block.getY(), zrel) != block.getBlockId()) 99 | { 100 | found = false; 101 | break; 102 | } 103 | } 104 | else if (zrel >= 16) 105 | { 106 | if (chunkzp.second->getBlock(xrel, y + block.getY(), zrel - 16) != block.getBlockId()) 107 | { 108 | found = false; 109 | break; 110 | } 111 | } 112 | else 113 | { 114 | if (chunk.second->getBlock(xrel, y + block.getY(), zrel) != block.getBlockId()) 115 | { 116 | found = false; 117 | break; 118 | } 119 | } 120 | } 121 | if (found) 122 | foundcb(std::make_pair(x * 16 + xb, z * 16 + zb)); 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | } 130 | 131 | void cachedTerrainSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback* progresscb, FoundCallback foundcb) 132 | { 133 | if (xminc > xmaxc || ymin > ymax || zminc > zmaxc) 134 | throw std::runtime_error("Search range min bounds must be less than max"); 135 | 136 | std::vector> formations(0); 137 | formations.resize(1); 138 | 139 | formations[0] = formation; 140 | alignFormation(formations[0]); 141 | 142 | if (allRotations) 143 | { 144 | formations.resize(4); 145 | for (int i = 1; i < 4; i++) 146 | { 147 | for (FormationBlock block : formations[i - 1]) 148 | formations[i].push_back(FormationBlock(-1 * block.getZ(), block.getY(), block.getX(), block.getBlockId())); 149 | alignFormation(formations[i]); 150 | } 151 | } 152 | 153 | ChunkGenerator generator(seed, version); 154 | //std::unordered_map valid_map; 155 | std::unordered_map>>> chunk_cache; //int counts uses (4 total), once accessed 3 additional times delete from cache (except if chunk on search edge uses is probably 2) 156 | std::pair> chunk, chunkxp, chunkzp, chunkxzp; 157 | 158 | for (int x = xminc; x <= xmaxc; x++) 159 | { 160 | if (keep_searching) 161 | if (!(*keep_searching)) 162 | return; 163 | if (progresscb) 164 | (*progresscb)(static_cast(x - xminc) / static_cast(xmaxc - xminc)); 165 | for (int z = zminc; z <= zmaxc; z++) 166 | { 167 | int64_t xlong = x, zlong = z; 168 | int64_t key = (xlong << 32) + zlong, keyxp = ((xlong + 1) << 32) + zlong, keyzp = (xlong << 32) + (zlong + 1), keyxzp = ((xlong + 1) << 32) + (zlong + 1); 169 | 170 | if (std::end(chunk_cache) == chunk_cache.find(key)) 171 | { 172 | auto ch = std::make_shared(); 173 | bool valid = generator.provideChunk(x, z, *ch, biomes); 174 | chunk_cache[key] = std::make_pair(x > xminc && z > zminc ? 2 : 0, chunk = std::make_pair(valid, ch)); 175 | } 176 | else 177 | { 178 | chunk = chunk_cache[key].second; 179 | if (chunk_cache[key].first == 0) 180 | chunk_cache.erase(key); 181 | else 182 | chunk_cache[key].first--; 183 | } 184 | if (std::end(chunk_cache) == chunk_cache.find(keyxp)) 185 | { 186 | auto ch = std::make_shared(); 187 | bool valid = generator.provideChunk(x + 1, z, *ch, biomes); 188 | chunk_cache[keyxp] = std::make_pair((x + 1) < xmaxc && z > zminc ? 2 : 0, chunkxp = std::make_pair(valid, ch));// if the chunk is on the edge of search we won't access it 4 times total but probably just twice 189 | } 190 | else 191 | { 192 | chunkxp = chunk_cache[keyxp].second; 193 | if (chunk_cache[keyxp].first == 0) 194 | chunk_cache.erase(keyxp); 195 | else 196 | chunk_cache[keyxp].first--; 197 | } 198 | if (std::end(chunk_cache) == chunk_cache.find(keyzp)) 199 | { 200 | auto ch = std::make_shared(); 201 | bool valid = generator.provideChunk(x, z + 1, *ch, biomes); 202 | chunk_cache[keyzp] = std::make_pair(x > xminc && (z + 1) < zmaxc ? 2 : 0, chunkzp = std::make_pair(valid, ch)); 203 | } 204 | else 205 | { 206 | chunkzp = chunk_cache[keyzp].second; 207 | if (chunk_cache[keyzp].first == 0) 208 | chunk_cache.erase(keyzp); 209 | else 210 | chunk_cache[keyzp].first--; 211 | } 212 | if (std::end(chunk_cache) == chunk_cache.find(keyxzp)) 213 | { 214 | auto ch = std::make_shared(); 215 | bool valid = generator.provideChunk(x + 1, z + 1, *ch, biomes); 216 | chunk_cache[keyxzp] = std::make_pair((x + 1) < xmaxc && (z + 1) < zmaxc ? 2 : 0, chunkxzp = std::make_pair(valid, ch)); 217 | } 218 | else 219 | { 220 | chunkxzp = chunk_cache[keyxzp].second; 221 | if (chunk_cache[keyxzp].first == 0) 222 | chunk_cache.erase(keyxzp); 223 | else 224 | chunk_cache[keyxzp].first--; 225 | } 226 | 227 | if (!chunk.first || !chunkxp.first || !chunkzp.first || !chunkxzp.first) //biome mismatch of any chunk 228 | continue; 229 | 230 | for (int xb = 0; xb < 16; xb++) 231 | { 232 | for (int zb = 0; zb < 16; zb++) 233 | { 234 | for (int y = ymin; y <= ymax; y++) 235 | { 236 | for (auto& form : formations) 237 | { 238 | bool found = true; 239 | for (auto& block : form) 240 | { 241 | int xrel = xb + block.getX(); 242 | int zrel = zb + block.getZ(); 243 | 244 | if (xrel >= 16 && zrel >= 16) 245 | { 246 | if (chunkxzp.second->getBlock(xrel - 16, y + block.getY(), zrel - 16) != block.getBlockId()) 247 | { 248 | found = false; 249 | break; 250 | } 251 | } 252 | else if (xrel >= 16) 253 | { 254 | if (chunkxp.second->getBlock(xrel - 16, y + block.getY(), zrel) != block.getBlockId()) 255 | { 256 | found = false; 257 | break; 258 | } 259 | } 260 | else if (zrel >= 16) 261 | { 262 | if (chunkzp.second->getBlock(xrel, y + block.getY(), zrel - 16) != block.getBlockId()) 263 | { 264 | found = false; 265 | break; 266 | } 267 | } 268 | else 269 | { 270 | if (chunk.second->getBlock(xrel, y + block.getY(), zrel) != block.getBlockId()) 271 | { 272 | found = false; 273 | break; 274 | } 275 | } 276 | } 277 | if (found) 278 | foundcb(std::make_pair(x * 16 + xb, z * 16 + zb)); 279 | } 280 | } 281 | } 282 | } 283 | } 284 | } 285 | } 286 | 287 | 288 | void heightmapSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback* progresscb, FoundCallback foundcb) 289 | { 290 | if (xminc > xmaxc || ymin > ymax || zminc > zmaxc) 291 | throw std::runtime_error("Search range min bounds must be less than max"); 292 | 293 | std::vector> formations(0); 294 | formations.resize(1); 295 | 296 | formations[0] = formation; 297 | alignFormation(formations[0]); 298 | 299 | if (allRotations) 300 | { 301 | formations.resize(4); 302 | for (int i = 1; i < 4; i++) 303 | { 304 | for (FormationBlock block : formations[i - 1]) 305 | formations[i].push_back(FormationBlock(-1 * block.getZ(), block.getY(), block.getX(), block.getBlockId())); 306 | alignFormation(formations[i]); 307 | } 308 | } 309 | 310 | ChunkGenerator generator(seed, version); 311 | std::pair> chunk = std::make_pair(false, std::make_shared()); 312 | std::pair> chunkxp = std::make_pair(false, std::make_shared()); 313 | std::pair> chunkzp = std::make_pair(false, std::make_shared()); 314 | std::pair> chunkxzp = std::make_pair(false, std::make_shared()); 315 | 316 | //auto base_and_variation = std::make_pair(generator.getBaseHeight(biome), generator.getHeightVariation(biome)); 317 | 318 | for (int x = xminc; x <= xmaxc; x++) 319 | { 320 | if (keep_searching) 321 | if (!(*keep_searching)) 322 | return; 323 | if (progresscb) 324 | (*progresscb)(static_cast(x - xminc) / static_cast(xmaxc - xminc)); 325 | for (int z = zminc; z <= zmaxc; z++) 326 | { 327 | if (z != zminc)//reduce times we need to generate the chunk to 2 instead of 4 328 | { 329 | std::swap(chunk, chunkzp); 330 | std::swap(chunkxp, chunkxzp); 331 | } 332 | else 333 | { 334 | chunk.first = generator.provideChunkHeightmap(x, z, *chunk.second, biomes); 335 | chunkxp.first = generator.provideChunkHeightmap(x + 1, z, *chunkxp.second, biomes); 336 | } 337 | chunkzp.first = generator.provideChunkHeightmap(x, z + 1, *chunkzp.second, biomes); 338 | chunkxzp.first = generator.provideChunkHeightmap(x + 1, z + 1, *chunkxzp.second, biomes); 339 | 340 | if (!chunk.first || !chunkxp.first || !chunkzp.first || !chunkxzp.first) 341 | continue; 342 | 343 | for (int xb = 0; xb < 16; xb++) 344 | { 345 | for (int zb = 0; zb < 16; zb++) 346 | { 347 | for (int y = ymin; y <= ymax; y++) 348 | { 349 | for (auto& form : formations) 350 | { 351 | bool found = true; 352 | for (auto& block : form) 353 | { 354 | int xrel = xb + block.getX(); 355 | int zrel = zb + block.getZ(); 356 | 357 | if (xrel >= 16 && zrel >= 16) 358 | { 359 | if (chunkxzp.second->getBlock(xrel - 16, y + block.getY(), zrel - 16) != block.getBlockId()) 360 | { 361 | found = false; 362 | break; 363 | } 364 | } 365 | else if (xrel >= 16) 366 | { 367 | if (chunkxp.second->getBlock(xrel - 16, y + block.getY(), zrel) != block.getBlockId()) 368 | { 369 | found = false; 370 | break; 371 | } 372 | } 373 | else if (zrel >= 16) 374 | { 375 | if (chunkzp.second->getBlock(xrel, y + block.getY(), zrel - 16) != block.getBlockId()) 376 | { 377 | found = false; 378 | break; 379 | } 380 | } 381 | else 382 | { 383 | if (chunk.second->getBlock(xrel, y + block.getY(), zrel) != block.getBlockId()) 384 | { 385 | found = false; 386 | break; 387 | } 388 | } 389 | } 390 | if (found) 391 | foundcb(std::make_pair(x * 16 + xb, z * 16 + zb)); 392 | } 393 | } 394 | } 395 | } 396 | } 397 | } 398 | } 399 | 400 | void cachedHeightmapSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback* progresscb, FoundCallback foundcb) 401 | { 402 | if (xminc > xmaxc || ymin > ymax || zminc > zmaxc) 403 | throw std::runtime_error("Search range min bounds must be less than max"); 404 | 405 | std::vector> formations(0); 406 | formations.resize(1); 407 | 408 | formations[0] = formation; 409 | alignFormation(formations[0]); 410 | 411 | if (allRotations) 412 | { 413 | formations.resize(4); 414 | for (int i = 1; i < 4; i++) 415 | { 416 | for (FormationBlock block : formations[i - 1]) 417 | formations[i].push_back(FormationBlock(-1 * block.getZ(), block.getY(), block.getX(), block.getBlockId())); 418 | alignFormation(formations[i]); 419 | } 420 | } 421 | 422 | ChunkGenerator generator(seed, version); 423 | std::unordered_map>>> chunk_cache; //int counts uses (4 total), once accessed 3 additional times delete from cache (except if chunk on search edge uses is probably 2) 424 | std::pair> chunk, chunkxp, chunkzp, chunkxzp; 425 | 426 | for (int x = xminc; x <= xmaxc; x++) 427 | { 428 | if (keep_searching) 429 | if (!(*keep_searching)) 430 | return; 431 | if (progresscb) 432 | (*progresscb)(static_cast(x - xminc) / static_cast(xmaxc - xminc)); 433 | for (int z = zminc; z <= zmaxc; z++) 434 | { 435 | int64_t xlong = x, zlong = z; 436 | int64_t key = (xlong << 32) + zlong, keyxp = ((xlong + 1) << 32) + zlong, keyzp = (xlong << 32) + (zlong + 1), keyxzp = ((xlong + 1) << 32) + (zlong + 1); 437 | 438 | if (std::end(chunk_cache) == chunk_cache.find(key)) 439 | { 440 | auto ch = std::make_shared(); 441 | bool valid = generator.provideChunkHeightmap(x, z, *ch, biomes); 442 | chunk_cache[key] = std::make_pair(x > xminc && z > zminc ? 2 : 0, chunk = std::make_pair(valid, ch)); 443 | } 444 | else 445 | { 446 | chunk = chunk_cache[key].second; 447 | if (chunk_cache[key].first == 0) 448 | chunk_cache.erase(key); 449 | else 450 | chunk_cache[key].first--; 451 | } 452 | if (std::end(chunk_cache) == chunk_cache.find(keyxp)) 453 | { 454 | auto ch = std::make_shared(); 455 | bool valid = generator.provideChunkHeightmap(x + 1, z, *ch, biomes); 456 | chunk_cache[keyxp] = std::make_pair((x + 1) < xmaxc && z > zminc ? 2 : 0, chunkxp = std::make_pair(valid, ch));// if the chunk is on the edge of search we won't access it 4 times total but probably just twice 457 | } 458 | else 459 | { 460 | chunkxp = chunk_cache[keyxp].second; 461 | if (chunk_cache[keyxp].first == 0) 462 | chunk_cache.erase(keyxp); 463 | else 464 | chunk_cache[keyxp].first--; 465 | } 466 | if (std::end(chunk_cache) == chunk_cache.find(keyzp)) 467 | { 468 | auto ch = std::make_shared(); 469 | bool valid = generator.provideChunkHeightmap(x, z + 1, *ch, biomes); 470 | chunk_cache[keyzp] = std::make_pair(x > xminc && (z + 1) < zmaxc ? 2 : 0, chunkzp = std::make_pair(valid, ch)); 471 | } 472 | else 473 | { 474 | chunkzp = chunk_cache[keyzp].second; 475 | if (chunk_cache[keyzp].first == 0) 476 | chunk_cache.erase(keyzp); 477 | else 478 | chunk_cache[keyzp].first--; 479 | } 480 | if (std::end(chunk_cache) == chunk_cache.find(keyxzp)) 481 | { 482 | auto ch = std::make_shared(); 483 | bool valid = generator.provideChunkHeightmap(x + 1, z + 1, *ch, biomes); 484 | chunk_cache[keyxzp] = std::make_pair((x + 1) < xmaxc && (z + 1) < zmaxc ? 2 : 0, chunkxzp = std::make_pair(valid, ch)); 485 | } 486 | else 487 | { 488 | chunkxzp = chunk_cache[keyxzp].second; 489 | if (chunk_cache[keyxzp].first == 0) 490 | chunk_cache.erase(keyxzp); 491 | else 492 | chunk_cache[keyxzp].first--; 493 | } 494 | 495 | if (!chunk.first || !chunkxp.first || !chunkzp.first || !chunkxzp.first) //biome mismatch of any chunk 496 | continue; 497 | 498 | for (int xb = 0; xb < 16; xb++) 499 | { 500 | for (int zb = 0; zb < 16; zb++) 501 | { 502 | /*for (int y = ymin; y <= ymax; y++) 503 | {*/ 504 | for (auto& form : formations) 505 | { 506 | int chunky; 507 | 508 | int xrelinit = xb + form[0].getX(); 509 | int zrelinit = zb + form[0].getZ(); 510 | 511 | if (xrelinit >= 16 && zrelinit >= 16) 512 | { 513 | chunky = chunkxzp.second->getHeightmap(xrelinit - 16, zrelinit - 16); 514 | } 515 | else if (xrelinit >= 16) 516 | { 517 | chunky = chunkxp.second->getHeightmap(xrelinit - 16, zrelinit); 518 | } 519 | else if (zrelinit >= 16) 520 | { 521 | chunky = chunkzp.second->getHeightmap(xrelinit, zrelinit - 16); 522 | } 523 | else 524 | { 525 | chunky = chunk.second->getHeightmap(xrelinit, zrelinit); 526 | } 527 | 528 | int y = chunky - form[0].getY(); 529 | 530 | bool found = true; 531 | for (auto& block : form) 532 | { 533 | int xrel = xb + block.getX(); 534 | int zrel = zb + block.getZ(); 535 | 536 | if (xrel >= 16 && zrel >= 16) 537 | { 538 | if (chunkxzp.second->getBlock(xrel - 16, y + block.getY(), zrel - 16) != block.getBlockId()) 539 | { 540 | found = false; 541 | break; 542 | } 543 | } 544 | else if (xrel >= 16) 545 | { 546 | if (chunkxp.second->getBlock(xrel - 16, y + block.getY(), zrel) != block.getBlockId()) 547 | { 548 | found = false; 549 | break; 550 | } 551 | } 552 | else if (zrel >= 16) 553 | { 554 | if (chunkzp.second->getBlock(xrel, y + block.getY(), zrel - 16) != block.getBlockId()) 555 | { 556 | found = false; 557 | break; 558 | } 559 | } 560 | else 561 | { 562 | if (chunk.second->getBlock(xrel, y + block.getY(), zrel) != block.getBlockId()) 563 | { 564 | found = false; 565 | break; 566 | } 567 | } 568 | } 569 | if (found) 570 | foundcb(std::make_pair(x * 16 + xb, z * 16 + zb)); 571 | } 572 | //} 573 | } 574 | } 575 | } 576 | } 577 | } 578 | 579 | void threadedSearch(SearchFunc func, int numThreads, uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback* progresscb, FoundCallback foundcb, FinishedCallback finishedcb) 580 | { 581 | if (numThreads < 0) 582 | throw std::runtime_error("Search threads must be greater than zero"); 583 | 584 | if (xminc > xmaxc || ymin > ymax || zminc > zmaxc) 585 | throw std::runtime_error("Search range min bounds must be less than max"); 586 | 587 | std::unordered_set* biomesptr = nullptr; 588 | if (biomes.size() > 0) 589 | biomesptr = &biomes; 590 | 591 | int width = xmaxc - xminc; 592 | std::vector threads; 593 | for (int i = 0; i < numThreads - 1; i++) 594 | { 595 | threads.emplace_back(func, seed, version, xminc + i * (width / numThreads), xminc + (i + 1) * (width / numThreads) - 1, ymin, ymax, zminc, zmaxc, formation, biomesptr, allRotations, keep_searching, nullptr, foundcb); 596 | } 597 | threads.emplace_back(func, seed, version, xminc + (numThreads - 1) * (width / numThreads), xmaxc, ymin, ymax, zminc, zmaxc, formation, biomesptr, allRotations, keep_searching, progresscb, foundcb); 598 | 599 | for (size_t i = 0; i < threads.size(); i++) 600 | threads[i].join(); 601 | 602 | finishedcb(); 603 | } -------------------------------------------------------------------------------- /Search.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "generator.h" 4 | #include "ChunkGenerator.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class FormationBlock //for heightmap formation, air=0, terrain=1 13 | { 14 | public: 15 | FormationBlock(int x, int y, int z, int blockid) : 16 | x_(x), 17 | y_(y), 18 | z_(z), 19 | blockid_(blockid) 20 | {} 21 | 22 | FormationBlock(const FormationBlock&) = default; 23 | 24 | const int getX() { return x_; } 25 | const int getY() { return y_; } 26 | const int getZ() { return z_; } 27 | const int getBlockId() { return blockid_; } 28 | private: 29 | int x_, y_, z_, blockid_; 30 | 31 | }; 32 | 33 | using ProgressCallback = std::function; 34 | using FoundCallback = std::function)>; 35 | using FinishedCallback = std::function; 36 | using SearchFunc = std::function, std::unordered_set*, bool, std::atomic_bool*, ProgressCallback*, FoundCallback)>; 37 | 38 | void terrainSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback*, FoundCallback); 39 | void cachedTerrainSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback*, FoundCallback); //twice as fast at the cost of a shitload of memory 40 | 41 | void heightmapSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback*, FoundCallback); 42 | void cachedHeightmapSearch(uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set* biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback*, FoundCallback); //twice as fast at the cost of a shitload of memory 43 | 44 | void threadedSearch(SearchFunc func, int numThreads, uint64_t seed, MCversion version, int xminc, int xmaxc, int ymin, int ymax, int zminc, int zmaxc, std::vector formation, std::unordered_set biomes, bool allRotations, std::atomic_bool* keep_searching, ProgressCallback*, FoundCallback, FinishedCallback); -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "generator.h" 2 | #include "layers.h" 3 | #include 4 | #include "ChunkGenerator.h" 5 | #include "Search.h" 6 | #include 7 | #include 8 | 9 | std::ofstream* _output_; 10 | std::mutex _write_locker_; 11 | 12 | void found_main(std::pair location) 13 | { 14 | _write_locker_.lock(); 15 | (*_output_) << "found, X: " << std::get<0>(location) << " Z: " << std::get<1>(location) << std::endl; 16 | _write_locker_.unlock(); 17 | } 18 | 19 | void progress_main(double progress) 20 | { 21 | //std::cout << "Progress: " << progress << std::endl; 22 | } 23 | 24 | int main() 25 | { 26 | initBiomes(); 27 | /*LayerStack stack; 28 | 29 | stack = setupGenerator(MC_1_15); 30 | applySeed(&stack, 8675309LL); 31 | int* map = allocCache(&stack.layers[L_VORONOI_ZOOM_1], 16, 16); 32 | genArea(&stack.layers[L_VORONOI_ZOOM_1], map, 9968, 9936, 16, 16); 33 | 34 | for (int i = 15; i >= 0; i--) 35 | { 36 | for (int j = 0; j < 16; j++) 37 | { 38 | std::cout << map[j*16+i] << " "; 39 | } 40 | std::cout << std::endl; 41 | }*/ 42 | 43 | //std::cout << "Biome: " << *map << std::endl; 44 | 45 | std::cout<< std::numeric_limits::is_iec559 << std::endl; 46 | 47 | ChunkGenerator generator(-4172144997902289642, MC_1_12); 48 | ChunkData chunk; 49 | ChunkHeightmap chunkheight; 50 | generator.provideChunk(2, -5, chunk); 51 | generator.provideChunkHeightmap(2, -5, chunkheight); 52 | 53 | std::cout << std::endl; 54 | 55 | for (int i = 15; i >= 0; i--) 56 | { 57 | for (int j = 0; j < 16; j++) 58 | { 59 | int h = 255; 60 | while (chunk.getBlock(i, h, j) == ChunkGenerator::AIR)h--; 61 | 62 | std::cout << h << " "; 63 | } 64 | std::cout << std::endl; 65 | } 66 | 67 | std::cout << std::endl; 68 | 69 | for (int i = 15; i >= 0; i--) 70 | { 71 | for (int j = 0; j < 16; j++) 72 | { 73 | int h = 255; 74 | while (chunk.getBlock(i, h, j) == ChunkGenerator::AIR)h--; 75 | 76 | std::cout << chunk.getBlock(i, h, j) << " "; 77 | } 78 | std::cout << std::endl; 79 | } 80 | 81 | for (int i = 15; i >= 0; i--) 82 | { 83 | for (int j = 0; j < 16; j++) 84 | { 85 | std::cout << chunkheight.getHeightmap(i, j) << " "; 86 | } 87 | std::cout << std::endl;; 88 | } 89 | 90 | //std::vector formation; 91 | /*formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 92 | formation.push_back(FormationBlock(2, 0, 0, ChunkGenerator::WATER_LILY)); 93 | formation.push_back(FormationBlock(3, 0, 0, ChunkGenerator::WATER_LILY)); 94 | formation.push_back(FormationBlock(4, 0, 0, ChunkGenerator::WATER_LILY)); 95 | formation.push_back(FormationBlock(0, 0, 1, ChunkGenerator::WATER_LILY)); 96 | formation.push_back(FormationBlock(0, 0, 2, ChunkGenerator::WATER_LILY)); 97 | formation.push_back(FormationBlock(0, 0, 4, ChunkGenerator::WATER_LILY)); 98 | formation.push_back(FormationBlock(1, 0, 2, ChunkGenerator::WATER_LILY)); 99 | formation.push_back(FormationBlock(1, 0, 4, ChunkGenerator::WATER_LILY)); 100 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 101 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 102 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 103 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 104 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 105 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 106 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 107 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY)); 108 | formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::WATER_LILY));*/ 109 | //formation.push_back(FormationBlock(0, 0, 0, ChunkGenerator::GRASS)); 110 | 111 | /*formation.push_back(FormationBlock(0, 0, 0, 1)); 112 | formation.push_back(FormationBlock(1, 5, 0, 1)); 113 | formation.push_back(FormationBlock(0, 5, 1, 1)); 114 | formation.push_back(FormationBlock(1, 10, 1, 1));*/ 115 | /*formation.push_back(FormationBlock(0, 1, 0, 0)); 116 | formation.push_back(FormationBlock(1, 6, 0, 0)); 117 | formation.push_back(FormationBlock(0, 6, 1, 0)); 118 | formation.push_back(FormationBlock(1, 11, 1, 0));*/ 119 | //SearchFunc func = cachedTerrainSearch; 120 | //ProgressCallback progresscb = progress_main; 121 | //std::unordered_set biomes; 122 | //biomes.insert(1); 123 | //biomes.insert(3); 124 | //biomes.insert(131); 125 | //biomes.insert(164); 126 | //biomes.insert(1); 127 | //biomes.insert(3); 128 | //_output_ = new std::ofstream(); 129 | //_output_->open("out.txt"); 130 | //threadedSearch(func, 4, -4172144997902289642, MC_1_12, 20000, 40000, 250, 255, 20000, 40000, formation, biomes, true, nullptr, &progresscb, found_main, []() {}); 131 | //cachedSearch(8675309L, -100, 100, 60, 90, -100, 100, formation, nullptr, true); 132 | //_output_->close(); 133 | 134 | return 0; 135 | } 136 | 137 | /* 138 | TODO: 139 | Extra biomes for new versions 140 | --different between all 1.13, 1.14, 1.15?? 141 | --bedrock gen probably wrong for existing biomes 142 | 143 | Map biome id to surface builder type and block config type separately 144 | 145 | hills GTB == mountain SB ??? 146 | 147 | hills -> mountains 148 | 149 | 150 | lib generates stone but actual grass, and correct for 1.12 151 | -noiseVal gen bad? 152 | -swamp SB call screwed up? 153 | */ --------------------------------------------------------------------------------