the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 914 lines 28 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.level.h" 3#include "net.minecraft.world.level.biome.h" 4#include "net.minecraft.world.level.levelgen.h" 5#include "net.minecraft.world.level.levelgen.feature.h" 6#include "net.minecraft.world.level.levelgen.structure.h" 7#include "net.minecraft.world.level.levelgen.synth.h" 8#include "net.minecraft.world.level.tile.h" 9#include "net.minecraft.world.level.storage.h" 10#include "net.minecraft.world.entity.h" 11#include "RandomLevelSource.h" 12 13#ifdef __PS3__ 14#include "..\Minecraft.Client\PS3\SPU_Tasks\PerlinNoise\PerlinNoiseJob.h" 15#include "C4JSpursJob.h" 16static PerlinNoise_DataIn g_lperlinNoise1_SPU __attribute__((__aligned__(16))); 17static PerlinNoise_DataIn g_lperlinNoise2_SPU __attribute__((__aligned__(16))); 18static PerlinNoise_DataIn g_perlinNoise1_SPU __attribute__((__aligned__(16))); 19static PerlinNoise_DataIn g_scaleNoise_SPU __attribute__((__aligned__(16))); 20static PerlinNoise_DataIn g_depthNoise_SPU __attribute__((__aligned__(16))); 21//#define DISABLE_SPU_CODE 22 23#endif 24 25 26const double RandomLevelSource::SNOW_SCALE = 0.3; 27const double RandomLevelSource::SNOW_CUTOFF = 0.5; 28 29RandomLevelSource::RandomLevelSource(Level *level, __int64 seed, bool generateStructures) : generateStructures( generateStructures ) 30{ 31 m_XZSize = level->getLevelData()->getXZSize(); 32#ifdef _LARGE_WORLDS 33 level->getLevelData()->getMoatFlags(&m_classicEdgeMoat, &m_smallEdgeMoat, &m_mediumEdgeMoat); 34#endif 35 caveFeature = new LargeCaveFeature(); 36 strongholdFeature = new StrongholdFeature(); 37 villageFeature = new VillageFeature(m_XZSize); 38 mineShaftFeature = new MineShaftFeature(); 39 scatteredFeature = new RandomScatteredLargeFeature(); 40 canyonFeature = new CanyonFeature(); 41 42 this->level = level; 43 44 random = new Random(seed); 45 pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation 46 lperlinNoise1 = new PerlinNoise(random, 16); 47 lperlinNoise2 = new PerlinNoise(random, 16); 48 perlinNoise1 = new PerlinNoise(random, 8); 49 perlinNoise3 = new PerlinNoise(random, 4); 50 51 scaleNoise = new PerlinNoise(random, 10); 52 depthNoise = new PerlinNoise(random, 16); 53 54 if (FLOATING_ISLANDS) 55 { 56 floatingIslandScale = new PerlinNoise(random, 10); 57 floatingIslandNoise = new PerlinNoise(random, 16); 58 } 59 else 60 { 61 floatingIslandScale = NULL; 62 floatingIslandNoise = NULL; 63 } 64 65 forestNoise = new PerlinNoise(random, 8); 66} 67 68RandomLevelSource::~RandomLevelSource() 69{ 70 delete caveFeature; 71 delete strongholdFeature; 72 delete villageFeature; 73 delete mineShaftFeature; 74 delete scatteredFeature; 75 delete canyonFeature; 76 77 this->level = level; 78 79 delete random;; 80 delete lperlinNoise1; 81 delete lperlinNoise2; 82 delete perlinNoise1; 83 delete perlinNoise3; 84 85 delete scaleNoise; 86 delete depthNoise; 87 88 if (FLOATING_ISLANDS) 89 { 90 delete floatingIslandScale; 91 delete floatingIslandNoise; 92 } 93 94 delete forestNoise; 95 96 if( pows.data != NULL ) delete [] pows.data; 97} 98 99 100int g_numPrepareHeightCalls = 0; 101LARGE_INTEGER g_totalPrepareHeightsTime = {0,0}; 102LARGE_INTEGER g_averagePrepareHeightsTime = {0, 0}; 103 104 105 106 107 108 109#ifdef _LARGE_WORLDS 110 111int RandomLevelSource::getMinDistanceToEdge(int xxx, int zzz, int worldSize, float falloffStart) 112{ 113 // Get distance to edges of world in x 114 // we have to do a proper line dist check here 115 int min = -worldSize/2; 116 int max = (worldSize/2)-1; 117 118 // // only check if either x or z values are within the falloff 119 // if(xxx > (min - falloffStart) 120 121 Vec3* topLeft = Vec3::newTemp(min, 0, min); 122 Vec3* topRight = Vec3::newTemp(max, 0, min); 123 Vec3* bottomLeft = Vec3::newTemp(min, 0, max); 124 Vec3* bottomRight = Vec3::newTemp(max, 0, max); 125 126 float closest = falloffStart; 127 float dist; 128 // make sure we're in range of the edges before we do a full distance check 129 if( (xxx > (min-falloffStart) && xxx < (min+falloffStart)) || 130 (xxx > (max-falloffStart) && xxx < (max+falloffStart)) ) 131 { 132 Vec3* point = Vec3::newTemp(xxx, 0, zzz); 133 if(xxx>0) 134 dist = point->distanceFromLine(topRight, bottomRight); 135 else 136 dist = point->distanceFromLine(topLeft, bottomLeft); 137 closest = dist; 138 } 139 140 // make sure we're in range of the edges before we do a full distance check 141 if( (zzz > (min-falloffStart) && zzz < (min+falloffStart)) || 142 (zzz > (max-falloffStart) && zzz < (max+falloffStart)) ) 143 { 144 Vec3* point = Vec3::newTemp(xxx, 0, zzz); 145 if(zzz>0) 146 dist = point->distanceFromLine(bottomLeft, bottomRight); 147 else 148 dist = point->distanceFromLine(topLeft, topRight); 149 if(dist<closest) 150 closest = dist; 151 } 152 153 return closest; 154} 155 156 157float RandomLevelSource::getHeightFalloff(int xxx, int zzz, int* pEMin) 158{ 159 /////////////////////////////////////////////////////////////////// 160 // 4J - add this chunk of code to make land "fall-off" at the edges of 161 // a finite world - size of that world is currently hard-coded in here 162 const int worldSize = m_XZSize * 16; 163 const int falloffStart = 32; // chunks away from edge were we start doing fall-off 164 const float falloffMax = 128.0f; // max value we need to get to falloff by the edge of the map 165 166 float comp = 0.0f; 167 int emin = getMinDistanceToEdge(xxx, zzz, worldSize, falloffStart); 168 // check if we have a larger world that should have moats 169 int expandedWorldSizes[3] = {LEVEL_WIDTH_CLASSIC*16, 170 LEVEL_WIDTH_SMALL*16, 171 LEVEL_WIDTH_MEDIUM*16}; 172 bool expandedMoatValues[3] = {m_classicEdgeMoat, m_smallEdgeMoat, m_mediumEdgeMoat}; 173 for(int i=0;i<3;i++) 174 { 175 if(expandedMoatValues[i] && (worldSize > expandedWorldSizes[i])) 176 { 177 // this world has been expanded, with moat settings, so we need fallofs at this edges too 178 int eminMoat = getMinDistanceToEdge(xxx, zzz, expandedWorldSizes[i], falloffStart); 179 if(eminMoat < emin) 180 { 181 emin = eminMoat; 182 } 183 } 184 } 185 186 // Calculate how much we want the world to fall away, if we're in the defined region to do so 187 if( emin < falloffStart ) 188 { 189 int falloff = falloffStart - emin; 190 comp = ((float)falloff / (float)falloffStart ) * falloffMax; 191 } 192 *pEMin = emin; 193 return comp; 194 // 4J - end of extra code 195 /////////////////////////////////////////////////////////////////// 196} 197 198#else 199 200 201// MGH - go back to using the simpler version for PS3/vita/360, as it was causing a lot of slow down on the tuturial generation 202float RandomLevelSource::getHeightFalloff(int xxx, int zzz, int* pEMin) 203{ 204 /////////////////////////////////////////////////////////////////// 205 // 4J - add this chunk of code to make land "fall-off" at the edges of 206 // a finite world - size of that world is currently hard-coded in here 207 const int worldSize = m_XZSize * 16; 208 const int falloffStart = 32; // chunks away from edge were we start doing fall-off 209 const float falloffMax = 128.0f; // max value we need to get to falloff by the edge of the map 210 211 // Get distance to edges of world in x 212 int xxx0 = xxx + ( worldSize / 2 ); 213 if( xxx0 < 0 ) xxx0 = 0; 214 int xxx1 = ( ( worldSize / 2 ) - 1 ) - xxx; 215 if( xxx1 < 0 ) xxx1 = 0; 216 217 // Get distance to edges of world in z 218 int zzz0 = zzz + ( worldSize / 2 ); 219 if( zzz0 < 0 ) zzz0 = 0; 220 int zzz1 = ( ( worldSize / 2 ) - 1 ) - zzz; 221 if( zzz1 < 0 ) zzz1 = 0; 222 223 // Get min distance to any edge 224 int emin = xxx0; 225 if (xxx1 < emin ) emin = xxx1; 226 if (zzz0 < emin ) emin = zzz0; 227 if (zzz1 < emin ) emin = zzz1; 228 229 float comp = 0.0f; 230 231 // Calculate how much we want the world to fall away, if we're in the defined region to do so 232 if( emin < falloffStart ) 233 { 234 int falloff = falloffStart - emin; 235 comp = ((float)falloff / (float)falloffStart ) * falloffMax; 236 } 237 // 4J - end of extra code 238 /////////////////////////////////////////////////////////////////// 239 *pEMin = emin; 240 return comp; 241} 242 243#endif // _LARGE_WORLDS 244 245void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) 246{ 247 LARGE_INTEGER startTime; 248 int xChunks = 16 / CHUNK_WIDTH; 249 int yChunks = Level::genDepth / CHUNK_HEIGHT; 250 int waterHeight = level->seaLevel; 251 252 int xSize = xChunks + 1; 253 int ySize = Level::genDepth / CHUNK_HEIGHT + 1; 254 int zSize = xChunks + 1; 255 256 BiomeArray biomes; // 4J created locally here for thread safety, java has this as a class member 257 258 level->getBiomeSource()->getRawBiomeBlock(biomes, xOffs * CHUNK_WIDTH - 2, zOffs * CHUNK_WIDTH - 2, xSize + 5, zSize + 5); 259 260 doubleArray buffer; // 4J - used to be declared with class level scope but tidying up for thread safety reasons 261 buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize, biomes); 262 263 QueryPerformanceCounter(&startTime); 264 for (int xc = 0; xc < xChunks; xc++) 265 { 266 for (int zc = 0; zc < xChunks; zc++) 267 { 268 for (int yc = 0; yc < yChunks; yc++) 269 { 270 double yStep = 1 / (double) CHUNK_HEIGHT; 271 double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; 272 double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; 273 double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; 274 double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; 275 276 double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; 277 double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; 278 double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; 279 double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; 280 281 for (int y = 0; y < CHUNK_HEIGHT; y++) 282 { 283 double xStep = 1 / (double) CHUNK_WIDTH; 284 285 double _s0 = s0; 286 double _s1 = s1; 287 double _s0a = (s2 - s0) * xStep; 288 double _s1a = (s3 - s1) * xStep; 289 290 for (int x = 0; x < CHUNK_WIDTH; x++) 291 { 292 int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); 293 int step = 1 << Level::genDepthBits; 294 offs -= step; 295 double zStep = 1 / (double) CHUNK_WIDTH; 296 297 double val = _s0; 298 double vala = (_s1 - _s0) * zStep; 299 val -= vala; 300 for (int z = 0; z < CHUNK_WIDTH; z++) 301 { 302// 4J Stu - I have removed all uses of the new getHeightFalloff function for now as we had some problems with PS3/PSVita world generation 303// I have fixed the non large worlds method, however we will be happier if the current builds go out with completely old code 304// We can put the new code back in mid-november 2014 once those PS3/Vita builds are gone (and the PS4 doesn't have world enlarging in these either anyway) 305 int xxx = ( ( xOffs * 16 ) + x + ( xc * CHUNK_WIDTH ) ); 306 int zzz = ( ( zOffs * 16 ) + z + ( zc * CHUNK_WIDTH ) ); 307 int emin; 308 float comp = getHeightFalloff(xxx, zzz, &emin); 309 310 311 // 4J - slightly rearranged this code (as of java 1.0.1 merge) to better fit with 312 // changes we've made edge-of-world things - original sets blocks[offs += step] directly 313 // here rather than setting a tileId 314 int tileId = 0; 315 // 4J - this comparison used to just be with 0.0f but is now varied by block above 316 if ((val += vala) > comp) 317 { 318 tileId = (byte) Tile::stone_Id; 319 } 320 else if (yc * CHUNK_HEIGHT + y < waterHeight) 321 { 322 tileId = (byte) Tile::calmWater_Id; 323 } 324 325 // 4J - more extra code to make sure that the column at the edge of the world is just water & rock, to match the infinite sea that 326 // continues on after the edge of the world. 327 328 if( emin == 0 ) 329 { 330 // This matches code in MultiPlayerChunkCache that makes the geometry which continues at the edge of the world 331 if( yc * CHUNK_HEIGHT + y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::stone_Id; 332 else if( yc * CHUNK_HEIGHT + y < level->getSeaLevel() ) tileId = Tile::calmWater_Id; 333 } 334 335 blocks[offs += step] = tileId; 336 } 337 _s0 += _s0a; 338 _s1 += _s1a; 339 } 340 341 s0 += s0a; 342 s1 += s1a; 343 s2 += s2a; 344 s3 += s3a; 345 } 346 } 347 } 348 } 349 LARGE_INTEGER endTime; 350 QueryPerformanceCounter(&endTime); 351 LARGE_INTEGER timeInFunc; 352 timeInFunc.QuadPart = endTime.QuadPart - startTime.QuadPart; 353 g_numPrepareHeightCalls++; 354 g_totalPrepareHeightsTime.QuadPart += timeInFunc.QuadPart; 355 g_averagePrepareHeightsTime.QuadPart = g_totalPrepareHeightsTime.QuadPart / g_numPrepareHeightCalls; 356 357 delete [] buffer.data; 358 delete [] biomes.data; 359 360 361} 362 363 364void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes) 365{ 366 int waterHeight = level->seaLevel; 367 368 double s = 1 / 32.0; 369 370 doubleArray depthBuffer(16*16); // 4J - used to be declared with class level scope but moved here for thread safety 371 372 depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); 373 374 for (int x = 0; x < 16; x++) 375 { 376 for (int z = 0; z < 16; z++) 377 { 378 Biome *b = biomes[z + x * 16]; 379 float temp = b->getTemperature(); 380 int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); 381 382 int run = -1; 383 384 byte top = b->topMaterial; 385 byte material = b->material; 386 387 LevelGenerationOptions *lgo = app.getLevelGenerationOptions(); 388 if(lgo != NULL) 389 { 390 lgo->getBiomeOverride(b->id,material,top); 391 } 392 393 for (int y = Level::genDepthMinusOne; y >= 0; y--) 394 { 395 int offs = (z * 16 + x) * Level::genDepth + y; 396 397 if (y <= 1 + random->nextInt(2)) // 4J - changed to make the bedrock not have bits you can get stuck in 398 // if (y <= 0 + random->nextInt(5)) 399 { 400 blocks[offs] = (byte) Tile::unbreakable_Id; 401 } 402 else 403 { 404 int old = blocks[offs]; 405 406 if (old == 0) 407 { 408 run = -1; 409 } 410 else if (old == Tile::stone_Id) 411 { 412 if (run == -1) 413 { 414 if (runDepth <= 0) 415 { 416 top = 0; 417 material = (byte) Tile::stone_Id; 418 } 419 else if (y >= waterHeight - 4 && y <= waterHeight + 1) 420 { 421 top = b->topMaterial; 422 material = b->material; 423 if(lgo != NULL) 424 { 425 lgo->getBiomeOverride(b->id,material,top); 426 } 427 } 428 429 if (y < waterHeight && top == 0) 430 { 431 if (temp < 0.15f) top = (byte) Tile::ice_Id; 432 else top = (byte) Tile::calmWater_Id; 433 } 434 435 run = runDepth; 436 if (y >= waterHeight - 1) blocks[offs] = top; 437 else blocks[offs] = material; 438 } 439 else if (run > 0) 440 { 441 run--; 442 blocks[offs] = material; 443 444 // place a few sandstone blocks beneath sand runs 445 if (run == 0 && material == Tile::sand_Id) 446 { 447 run = random->nextInt(4); 448 material = (byte) Tile::sandStone_Id; 449 } 450 } 451 } 452 } 453 } 454 } 455 } 456 457 delete [] depthBuffer.data; 458 459} 460 461LevelChunk *RandomLevelSource::create(int x, int z) 462{ 463 return getChunk(x,z); 464} 465 466LevelChunk *RandomLevelSource::getChunk(int xOffs, int zOffs) 467{ 468 random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); 469 470 // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed 471 int blocksSize = Level::genDepth * 16 * 16; 472 byte *tileData = (byte *)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); 473 XMemSet128(tileData,0,blocksSize); 474 byteArray blocks = byteArray(tileData,blocksSize); 475 // byteArray blocks = byteArray(16 * level->depth * 16); 476 477 // LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J - moved to below 478 479 prepareHeights(xOffs, zOffs, blocks); 480 481 // 4J - Some changes made here to how biomes, temperatures and downfalls are passed around for thread safety 482 BiomeArray biomes; 483 level->getBiomeSource()->getBiomeBlock(biomes, xOffs * 16, zOffs * 16, 16, 16, true); 484 485 buildSurfaces(xOffs, zOffs, blocks, biomes); 486 487 delete [] biomes.data; 488 489 caveFeature->apply(this, level, xOffs, zOffs, blocks); 490 // 4J Stu Design Change - 1.8 gen goes stronghold, mineshaft, village, canyon 491 // this changed in 1.2 to canyon, mineshaft, village, stronghold 492 // This change makes sense as it stops canyons running through other structures 493 canyonFeature->apply(this, level, xOffs, zOffs, blocks); 494 if (generateStructures) 495 { 496 mineShaftFeature->apply(this, level, xOffs, zOffs, blocks); 497 villageFeature->apply(this, level, xOffs, zOffs, blocks); 498 strongholdFeature->apply(this, level, xOffs, zOffs, blocks); 499 scatteredFeature->apply(this, level, xOffs, zOffs, blocks); 500 } 501 // canyonFeature.apply(this, level, xOffs, zOffs, blocks); 502 // townFeature.apply(this, level, xOffs, zOffs, blocks); 503 // addCaves(xOffs, zOffs, blocks); 504 // addTowns(xOffs, zOffs, blocks); 505 506 // levelChunk->recalcHeightmap(); // 4J - removed & moved into its own method 507 508 // 4J - this now creates compressed block data from the blocks array passed in, so moved it until after the blocks are actually finalised. We also 509 // now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. 510 LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); 511 XPhysicalFree(tileData); 512 513 return levelChunk; 514} 515 516// 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without 517// doing this, then loads of the lightgaps() calls will fail to add any lights, because adding a light checks if the cache has this chunk in. 518// lightgaps also does light 1 block into the neighbouring chunks, and maybe that is somehow enough to get lighting to propagate round the world, 519// but this just doesn't seem right - this isn't a new fault in the 360 version, have checked that java does the same. 520void RandomLevelSource::lightChunk(LevelChunk *lc) 521{ 522 lc->recalcHeightmap(); 523} 524 525 526doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize, BiomeArray& biomes) 527{ 528 if (buffer.data == NULL) 529 { 530 buffer = doubleArray(xSize * ySize * zSize); 531 } 532 if (pows.data == NULL) 533 { 534 pows = floatArray(5 * 5); 535 for (int xb = -2; xb <= 2; xb++) 536 { 537 for (int zb = -2; zb <= 2; zb++) 538 { 539 float ppp = 10.0f / Mth::sqrt(xb * xb + zb * zb + 0.2f); 540 pows[xb + 2 + (zb + 2) * 5] = ppp; 541 } 542 } 543 } 544 545 double s = 1 * 684.412; 546 double hs = 1 * 684.412; 547 548 doubleArray pnr, ar, br, sr, dr, fi, fis; // 4J - used to be declared with class level scope but moved here for thread safety 549 550 if (FLOATING_ISLANDS) 551 { 552 fis = floatingIslandScale->getRegion(fis, x, y, z, xSize, 1, zSize, 1.0, 0, 1.0); 553 fi = floatingIslandNoise->getRegion(fi, x, y, z, xSize, 1, zSize, 500.0, 0, 500.0); 554 } 555 556#if defined __PS3__ && !defined DISABLE_SPU_CODE 557 C4JSpursJobQueue::Port port("C4JSpursJob_PerlinNoise"); 558 C4JSpursJob_PerlinNoise perlinJob1(&g_scaleNoise_SPU); 559 C4JSpursJob_PerlinNoise perlinJob2(&g_depthNoise_SPU); 560 C4JSpursJob_PerlinNoise perlinJob3(&g_perlinNoise1_SPU); 561 C4JSpursJob_PerlinNoise perlinJob4(&g_lperlinNoise1_SPU); 562 C4JSpursJob_PerlinNoise perlinJob5(&g_lperlinNoise2_SPU); 563 564 g_scaleNoise_SPU.set(scaleNoise, sr, x, z, xSize, zSize, 1.121, 1.121, 0.5); 565 g_depthNoise_SPU.set(depthNoise, dr, x, z, xSize, zSize, 200.0, 200.0, 0.5); 566 g_perlinNoise1_SPU.set(perlinNoise1, pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 160.0, s / 80.0); 567 g_lperlinNoise1_SPU.set(lperlinNoise1, ar, x, y, z, xSize, ySize, zSize, s, hs, s); 568 g_lperlinNoise2_SPU.set(lperlinNoise2, br, x, y, z, xSize, ySize, zSize, s, hs, s); 569 570 port.submitJob(&perlinJob1); 571 port.submitJob(&perlinJob2); 572 port.submitJob(&perlinJob3); 573 port.submitJob(&perlinJob4); 574 port.submitJob(&perlinJob5); 575 port.waitForCompletion(); 576#else 577 sr = scaleNoise->getRegion(sr, x, z, xSize, zSize, 1.121, 1.121, 0.5); 578 dr = depthNoise->getRegion(dr, x, z, xSize, zSize, 200.0, 200.0, 0.5); 579 pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 160.0, s / 80.0); 580 ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); 581 br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); 582 583#endif 584 585 x = z = 0; 586 587 int p = 0; 588 int pp = 0; 589 590 for (int xx = 0; xx < xSize; xx++) 591 { 592 for (int zz = 0; zz < zSize; zz++) 593 { 594 float sss = 0; 595 float ddd = 0; 596 float pow = 0; 597 598 int rr = 2; 599 600 Biome *mb = biomes[(xx + 2) + (zz + 2) * (xSize + 5)]; 601 for (int xb = -rr; xb <= rr; xb++) 602 { 603 for (int zb = -rr; zb <= rr; zb++) 604 { 605 Biome *b = biomes[(xx + xb + 2) + (zz + zb + 2) * (xSize + 5)]; 606 float ppp = pows[xb + 2 + (zb + 2) * 5] / (b->depth + 2); 607 if (b->depth > mb->depth) 608 { 609 ppp /= 2; 610 } 611 sss += b->scale * ppp; 612 ddd += b->depth * ppp; 613 pow += ppp; 614 } 615 } 616 sss /= pow; 617 ddd /= pow; 618 619 sss = sss * 0.9f + 0.1f; 620 ddd = (ddd * 4 - 1) / 8.0f; 621 622 double rdepth = (dr[pp] / 8000.0); 623 if (rdepth < 0) rdepth = -rdepth * 0.3; 624 rdepth = rdepth * 3.0 - 2.0; 625 626 if (rdepth < 0) 627 { 628 rdepth = rdepth / 2; 629 if (rdepth < -1) rdepth = -1; 630 rdepth = rdepth / 1.4; 631 rdepth /= 2; 632 } 633 else 634 { 635 if (rdepth > 1) rdepth = 1; 636 rdepth = rdepth / 8; 637 } 638 639 pp++; 640 641 for (int yy = 0; yy < ySize; yy++) 642 { 643 double depth = ddd; 644 double scale = sss; 645 646 depth += rdepth * 0.2; 647 depth = depth * ySize / 16.0; 648 649 double yCenter = ySize / 2.0 + depth * 4; 650 651 double val = 0; 652 653 double yOffs = (yy - (yCenter)) * 12 * 128 / Level::genDepth / scale; 654 655 if (yOffs < 0) yOffs *= 4; 656 657 double bb = ar[p] / 512; 658 double cc = br[p] / 512; 659 660 double v = (pnr[p] / 10 + 1) / 2; 661 if (v < 0) val = bb; 662 else if (v > 1) val = cc; 663 else val = bb + (cc - bb) * v; 664 val -= yOffs; 665 666 if (yy > ySize - 4) 667 { 668 double slide = (yy - (ySize - 4)) / (4 - 1.0f); 669 val = val * (1 - slide) + -10 * slide; 670 } 671 672 buffer[p] = val; 673 p++; 674 } 675 } 676 } 677 678 delete [] pnr.data; 679 delete [] ar.data; 680 delete [] br.data; 681 delete [] sr.data; 682 delete [] dr.data; 683 delete [] fi.data; 684 delete [] fis.data; 685 686 return buffer; 687 688} 689 690bool RandomLevelSource::hasChunk(int x, int y) 691{ 692 return true; 693} 694 695void RandomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt) 696{ 697 int xo = xt * 16; 698 int zo = zt * 16; 699 for (int x = 0; x < 16; x++) 700 { 701 int y = level->getSeaLevel(); 702 for (int z = 0; z < 16; z++) 703 { 704 int xp = xo + x + 7; 705 int zp = zo + z + 7; 706 int h = level->getHeightmap(xp, zp); 707 if (h <= 0) 708 { 709 if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) 710 { 711 bool hadWater = false; 712 if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater_Id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; 713 if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater_Id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; 714 if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater_Id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; 715 if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater_Id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; 716 if (hadWater) 717 { 718 for (int x2 = -5; x2 <= 5; x2++) 719 { 720 for (int z2 = -5; z2 <= 5; z2++) 721 { 722 int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); 723 724 if (d <= 5) 725 { 726 d = 6 - d; 727 if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater_Id) 728 { 729 int od = level->getData(xp + x2, y, zp + z2); 730 if (od < 7 && od < d) 731 { 732 level->setData(xp + x2, y, zp + z2, d, Tile::UPDATE_ALL); 733 } 734 } 735 } 736 } 737 } 738 if (hadWater) 739 { 740 level->setTileAndData(xp, y, zp, Tile::calmWater_Id, 7, Tile::UPDATE_CLIENTS); 741 for (int y2 = 0; y2 < y; y2++) 742 { 743 level->setTileAndData(xp, y2, zp, Tile::calmWater_Id, 8, Tile::UPDATE_CLIENTS); 744 } 745 } 746 } 747 } 748 } 749 } 750 } 751 752} 753 754// 4J - changed this to used pprandom rather than random, so that we can run it concurrently with getChunk 755void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) 756{ 757 HeavyTile::instaFall = true; 758 int xo = xt * 16; 759 int zo = zt * 16; 760 761 Biome *biome = level->getBiome(xo + 16, zo + 16); 762 763 if (FLOATING_ISLANDS) 764 { 765 calcWaterDepths(parent, xt, zt); 766 } 767 768 pprandom->setSeed(level->getSeed()); 769 __int64 xScale = pprandom->nextLong() / 2 * 2 + 1; 770 __int64 zScale = pprandom->nextLong() / 2 * 2 + 1; 771 pprandom->setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); 772 773 bool hasVillage = false; 774 775 PIXBeginNamedEvent(0,"Structure postprocessing"); 776 if (generateStructures) 777 { 778 mineShaftFeature->postProcess(level, pprandom, xt, zt); 779 hasVillage = villageFeature->postProcess(level, pprandom, xt, zt); 780 strongholdFeature->postProcess(level, pprandom, xt, zt); 781 scatteredFeature->postProcess(level, random, xt, zt); 782 } 783 PIXEndNamedEvent(); 784 785 PIXBeginNamedEvent(0,"Lakes"); 786 if (biome != Biome::desert && biome != Biome::desertHills) 787 { 788 if (!hasVillage && pprandom->nextInt(4) == 0) 789 { 790 int x = xo + pprandom->nextInt(16) + 8; 791 int y = pprandom->nextInt(Level::genDepth); 792 int z = zo + pprandom->nextInt(16) + 8; 793 794 LakeFeature calmWater(Tile::calmWater_Id); 795 calmWater.place(level, pprandom, x, y, z); 796 } 797 } 798 PIXEndNamedEvent(); 799 800 PIXBeginNamedEvent(0,"Lava"); 801 if (!hasVillage && pprandom->nextInt(8) == 0) 802 { 803 int x = xo + pprandom->nextInt(16) + 8; 804 int y = pprandom->nextInt(pprandom->nextInt(Level::genDepth - 8) + 8); 805 int z = zo + pprandom->nextInt(16) + 8; 806 if (y < level->seaLevel || pprandom->nextInt(10) == 0) 807 { 808 LakeFeature calmLava(Tile::calmLava_Id); 809 calmLava.place(level, pprandom, x, y, z); 810 } 811 } 812 PIXEndNamedEvent(); 813 814 PIXBeginNamedEvent(0,"Monster rooms"); 815 for (int i = 0; i < 8; i++) 816 { 817 int x = xo + pprandom->nextInt(16) + 8; 818 int y = pprandom->nextInt(Level::genDepth); 819 int z = zo + pprandom->nextInt(16) + 8; 820 MonsterRoomFeature mrf; 821 mrf.place(level, pprandom, x, y, z); 822 } 823 PIXEndNamedEvent(); 824 825 PIXBeginNamedEvent(0,"Biome decorate"); 826 biome->decorate(level, pprandom, xo, zo); 827 PIXEndNamedEvent(); 828 829 PIXBeginNamedEvent(0,"Process Schematics"); 830 app.processSchematics(parent->getChunk(xt,zt)); 831 PIXEndNamedEvent(); 832 833 PIXBeginNamedEvent(0,"Post process mobs"); 834 MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, pprandom); 835 PIXEndNamedEvent(); 836 837 PIXBeginNamedEvent(0,"Update ice and snow"); 838 // 4J - brought forward from 1.2.3 to get snow back in taiga biomes 839 xo += 8; 840 zo += 8; 841 for (int x = 0; x < 16; x++) 842 { 843 for (int z = 0; z < 16; z++) 844 { 845 int y = level->getTopRainBlock(xo + x, zo + z); 846 847 if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) 848 { 849 level->setTileAndData(x + xo, y - 1, z + zo, Tile::ice_Id, 0, Tile::UPDATE_CLIENTS); 850 } 851 if (level->shouldSnow(x + xo, y, z + zo)) 852 { 853 level->setTileAndData(x + xo, y, z + zo, Tile::topSnow_Id, 0, Tile::UPDATE_CLIENTS); 854 } 855 } 856 } 857 PIXEndNamedEvent(); 858 859 HeavyTile::instaFall = false; 860} 861 862bool RandomLevelSource::save(bool force, ProgressListener *progressListener) 863{ 864 return true; 865} 866 867bool RandomLevelSource::tick() 868{ 869 return false; 870} 871 872bool RandomLevelSource::shouldSave() 873{ 874 return true; 875} 876 877wstring RandomLevelSource::gatherStats() 878{ 879 return L"RandomLevelSource"; 880} 881 882vector<Biome::MobSpawnerData *> *RandomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) 883{ 884 Biome *biome = level->getBiome(x, z); 885 if (biome == NULL) 886 { 887 return NULL; 888 } 889 if (mobCategory == MobCategory::monster && scatteredFeature->isSwamphut(x, y, z)) 890 { 891 return scatteredFeature->getSwamphutEnemies(); 892 } 893 return biome->getMobs(mobCategory); 894} 895 896TilePos *RandomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) 897{ 898 if (LargeFeature::STRONGHOLD == featureName && strongholdFeature != NULL) 899 { 900 return strongholdFeature->getNearestGeneratedFeature(level, x, y, z); 901 } 902 return NULL; 903} 904 905void RandomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) 906{ 907 if (generateStructures) 908 { 909 mineShaftFeature->apply(this, level, chunkX, chunkZ, NULL); 910 villageFeature->apply(this, level, chunkX, chunkZ, NULL); 911 strongholdFeature->apply(this, level, chunkX, chunkZ, NULL); 912 scatteredFeature->apply(this, level, chunkX, chunkZ, NULL); 913 } 914}