the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 565 lines 16 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.level.h" 3#include "net.minecraft.world.level.tile.h" 4#include "net.minecraft.world.entity.h" 5#include "net.minecraft.world.level.levelgen.feature.h" 6#include "net.minecraft.world.level.storage.h" 7#include "BiomeSource.h" 8#include "HellRandomLevelSource.h" 9 10HellRandomLevelSource::HellRandomLevelSource(Level *level, __int64 seed) 11{ 12 int xzSize = level->getLevelData()->getXZSize(); 13 int hellScale = level->getLevelData()->getHellScale(); 14 m_XZSize = ceil((float)xzSize / hellScale); 15 16 netherBridgeFeature = new NetherBridgeFeature(); 17 caveFeature = new LargeHellCaveFeature(); 18 19 this->level = level; 20 21 random = new Random(seed); 22 pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation 23 lperlinNoise1 = new PerlinNoise(random, 16); 24 lperlinNoise2 = new PerlinNoise(random, 16); 25 perlinNoise1 = new PerlinNoise(random, 8); 26 perlinNoise2 = new PerlinNoise(random, 4); 27 perlinNoise3 = new PerlinNoise(random, 4); 28 29 scaleNoise = new PerlinNoise(random, 10); 30 depthNoise = new PerlinNoise(random, 16); 31} 32 33HellRandomLevelSource::~HellRandomLevelSource() 34{ 35 delete netherBridgeFeature; 36 delete caveFeature; 37 38 delete random; 39 delete pprandom; // 4J added 40 delete lperlinNoise1; 41 delete lperlinNoise2; 42 delete perlinNoise1; 43 delete perlinNoise2; 44 delete perlinNoise3; 45 46 delete scaleNoise; 47 delete depthNoise; 48} 49 50void HellRandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) 51{ 52 int xChunks = 16 / CHUNK_WIDTH; 53 int waterHeight = 32; 54 55 int xSize = xChunks + 1; 56 int ySize = Level::genDepth / CHUNK_HEIGHT + 1; 57 int zSize = xChunks + 1; 58 doubleArray buffer; // 4J - used to be declared with class level scope but tidying up for thread safety reasons 59 buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); 60 61 for (int xc = 0; xc < xChunks; xc++) 62 { 63 for (int zc = 0; zc < xChunks; zc++) 64 { 65 for (int yc = 0; yc < Level::genDepth / CHUNK_HEIGHT; yc++) 66 { 67 double yStep = 1 / (double) CHUNK_HEIGHT; 68 double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; 69 double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; 70 double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; 71 double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; 72 73 double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; 74 double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; 75 double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; 76 double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; 77 78 for (int y = 0; y < CHUNK_HEIGHT; y++) 79 { 80 double xStep = 1 / (double) CHUNK_WIDTH; 81 82 double _s0 = s0; 83 double _s1 = s1; 84 double _s0a = (s2 - s0) * xStep; 85 double _s1a = (s3 - s1) * xStep; 86 87 for (int x = 0; x < CHUNK_WIDTH; x++) 88 { 89 int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); 90 int step = 1 << Level::genDepthBits; 91 double zStep = 1 / (double) CHUNK_WIDTH; 92 93 double val = _s0; 94 double vala = (_s1 - _s0) * zStep; 95 for (int z = 0; z < CHUNK_WIDTH; z++) 96 { 97 int tileId = 0; 98 if (yc * CHUNK_HEIGHT + y < waterHeight) 99 { 100 tileId = Tile::calmLava_Id; 101 } 102 if (val > 0) 103 { 104 tileId = Tile::netherRack_Id; 105 } 106 107 blocks[offs] = (byte) tileId; 108 offs += step; 109 val += vala; 110 } 111 _s0 += _s0a; 112 _s1 += _s1a; 113 } 114 115 s0 += s0a; 116 s1 += s1a; 117 s2 += s2a; 118 s3 += s3a; 119 } 120 } 121 } 122 } 123 delete [] buffer.data; 124} 125 126void HellRandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks) 127{ 128 int waterHeight = Level::genDepth - 64; 129 130 double s = 1 / 32.0; 131 132 doubleArray sandBuffer(16*16); // 4J - used to be declared with class level scope but moved here for thread safety 133 doubleArray gravelBuffer(16*16); 134 doubleArray depthBuffer(16*16); 135 136 sandBuffer = perlinNoise2->getRegion(sandBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s, s, 1); 137 gravelBuffer = perlinNoise2->getRegion(gravelBuffer, xOffs * 16, 109, zOffs * 16, 16, 1, 16, s, 1, s); 138 depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); 139 140 for (int x = 0; x < 16; x++) 141 { 142 for (int z = 0; z < 16; z++) 143 { 144 bool sand = (sandBuffer[x + z * 16] + random->nextDouble() * 0.2) > 0; 145 bool gravel = (gravelBuffer[x + z * 16] + random->nextDouble() * 0.2) > 0; 146 int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); 147 148 int run = -1; 149 150 byte top = (byte) Tile::netherRack_Id; 151 byte material = (byte) Tile::netherRack_Id; 152 153 for (int y = Level::genDepthMinusOne; y >= 0; y--) 154 { 155 int offs = (z * 16 + x) * Level::genDepth + y; 156 157 // 4J Build walls around the level 158 bool blockSet = false; 159 if(xOffs <= -(m_XZSize/2)) 160 { 161 if( z - random->nextInt( 4 ) <= 0 || xOffs < -(m_XZSize/2) ) 162 { 163 blocks[offs] = (byte) Tile::unbreakable_Id; 164 blockSet = true; 165 } 166 } 167 if(zOffs <= -(m_XZSize/2)) 168 { 169 if( x - random->nextInt( 4 ) <= 0 || zOffs < -(m_XZSize/2)) 170 { 171 blocks[offs] = (byte) Tile::unbreakable_Id; 172 blockSet = true; 173 } 174 } 175 if(xOffs >= (m_XZSize/2)-1) 176 { 177 if( z + random->nextInt(4) >= 15 || xOffs > (m_XZSize/2)) 178 { 179 blocks[offs] = (byte) Tile::unbreakable_Id; 180 blockSet = true; 181 } 182 } 183 if(zOffs >= (m_XZSize/2)-1) 184 { 185 if( x + random->nextInt(4) >= 15 || zOffs > (m_XZSize/2) ) 186 { 187 blocks[offs] = (byte) Tile::unbreakable_Id; 188 blockSet = true; 189 } 190 } 191 if( blockSet ) continue; 192 // End 4J Extra to build walls around the level 193 194 if (y >= Level::genDepthMinusOne - random->nextInt(5) || y <= 0 + random->nextInt(5)) 195 { 196 blocks[offs] = (byte) Tile::unbreakable_Id; 197 } 198 else 199 { 200 int old = blocks[offs]; 201 202 if (old == 0) 203 { 204 run = -1; 205 } 206 else if (old == Tile::netherRack_Id) 207 { 208 if (run == -1) 209 { 210 if (runDepth <= 0) 211 { 212 top = 0; 213 material = (byte) Tile::netherRack_Id; 214 } 215 else if (y >= waterHeight - 4 && y <= waterHeight + 1) 216 { 217 top = (byte) Tile::netherRack_Id; 218 material = (byte) Tile::netherRack_Id; 219 if (gravel) top = (byte) Tile::gravel_Id; 220 if (gravel) material = (byte) Tile::netherRack_Id; 221 if (sand) 222 { 223 // 4J Stu - Make some nether wart spawn outside of the nether fortresses 224 if(random->nextInt(16) == 0) 225 { 226 top = (byte) Tile::netherStalk_Id; 227 228 // Place the nether wart on top of the soul sand 229 y += 1; 230 int genDepthMinusOne = Level::genDepthMinusOne; // Take into local int for PS4 as min takes a reference to the const int there and then needs the value to exist for the linker 231 y = min(y, genDepthMinusOne); 232 runDepth += 1; 233 offs = (z * 16 + x) * Level::genDepth + y; 234 } 235 else 236 { 237 top = (byte) Tile::soulsand_Id; 238 } 239 } 240 if (sand) material = (byte) Tile::soulsand_Id; 241 } 242 243 if (y < waterHeight && top == 0) top = (byte) Tile::calmLava_Id; 244 245 run = runDepth; 246 // 4J Stu - If sand, then allow adding nether wart at heights below the water level 247 if (y >= waterHeight - 1 || sand) blocks[offs] = top; 248 else blocks[offs] = material; 249 } 250 else if (run > 0) 251 { 252 run--; 253 blocks[offs] = material; 254 } 255 } 256 } 257 } 258 } 259 } 260 delete [] sandBuffer.data; 261 delete [] gravelBuffer.data; 262 delete [] depthBuffer.data; 263} 264 265LevelChunk *HellRandomLevelSource::create(int x, int z) 266{ 267 return getChunk(x,z); 268} 269 270LevelChunk *HellRandomLevelSource::getChunk(int xOffs, int zOffs) 271{ 272 random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); 273 274 // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed 275 int blocksSize = Level::genDepth * 16 * 16; 276 byte *tileData = (byte *)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); 277 XMemSet128(tileData,0,blocksSize); 278 byteArray blocks = byteArray(tileData,blocksSize); 279 // byteArray blocks = byteArray(16 * level->depth * 16); 280 281 prepareHeights(xOffs, zOffs, blocks); 282 buildSurfaces(xOffs, zOffs, blocks); 283 284 caveFeature->apply(this, level, xOffs, zOffs, blocks); 285 netherBridgeFeature->apply(this, level, xOffs, zOffs, blocks); 286 287 // 4J - this now creates compressed block data from the blocks array passed in, so needs to be after data is finalised. 288 // Also now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. 289 LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); 290 levelChunk->setCheckAllLight(); 291 XPhysicalFree(tileData); 292 return levelChunk; 293} 294 295// 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without 296// 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. 297// lightgaps also does light 1 block into the neighbouring chunks, and maybe that is somehow enough to get lighting to propagate round the world, 298// but this just doesn't seem right - this isn't a new fault in the 360 version, have checked that java does the same. 299void HellRandomLevelSource::lightChunk(LevelChunk *lc) 300{ 301 lc->recalcHeightmap(); 302} 303 304doubleArray HellRandomLevelSource::getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize) 305{ 306 if (buffer.data == NULL) 307 { 308 buffer = doubleArray(xSize * ySize * zSize); 309 } 310 311 double s = 1 * 684.412; 312 double hs = 1 * 684.412 * 3; 313 314 doubleArray pnr, ar, br, sr, dr, fi, fis; // 4J - used to be declared with class level scope but moved here for thread safety 315 316 sr = scaleNoise->getRegion(sr, x, y, z, xSize, 1, zSize, 1.0, 0, 1.0); 317 dr = depthNoise->getRegion(dr, x, y, z, xSize, 1, zSize, 100.0, 0, 100.0); 318 319 pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 60.0, s / 80.0); 320 ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); 321 br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); 322 323 int p = 0; 324 int pp = 0; 325 doubleArray yoffs = doubleArray(ySize); 326 for (int yy = 0; yy < ySize; yy++) 327 { 328 yoffs[yy] = cos(yy * PI * 6 / (double) ySize) * 2; 329 330 double dd = yy; 331 if (yy > ySize / 2) 332 { 333 dd = (ySize - 1) - yy; 334 } 335 if (dd < 4) { 336 dd = 4 - dd; 337 yoffs[yy] -= dd * dd * dd * 10; 338 } 339 } 340 341 for (int xx = 0; xx < xSize; xx++) 342 { 343 for (int zz = 0; zz < zSize; zz++) 344 { 345 double scale = ((sr[pp] + 256.0) / 512); 346 if (scale > 1) scale = 1; 347 348 double floating = 0; 349 350 double depth = (dr[pp] / 8000.0); 351 if (depth < 0) depth = -depth; 352 depth = depth * 3.0 - 3.0; 353 354 if (depth < 0) 355 { 356 depth = depth / 2; 357 if (depth < -1) depth = -1; 358 depth = depth / 1.4; 359 depth /= 2; 360 scale = 0; 361 } 362 else 363 { 364 if (depth > 1) depth = 1; 365 depth = depth / 6; 366 } 367 scale = (scale) + 0.5; 368 depth = depth * ySize / 16; 369 pp++; 370 371 for (int yy = 0; yy < ySize; yy++) 372 { 373 double val = 0; 374 375 double yOffs = yoffs[yy]; 376 377 double bb = ar[p] / 512; 378 double cc = br[p] / 512; 379 380 double v = (pnr[p] / 10 + 1) / 2; 381 if (v < 0) val = bb; 382 else if (v > 1) val = cc; 383 else val = bb + (cc - bb) * v; 384 val -= yOffs; 385 386 if (yy > ySize - 4) 387 { 388 double slide = (yy - (ySize - 4)) / (4 - 1.0f); 389 val = val * (1 - slide) + -10 * slide; 390 } 391 392 if (yy < floating) 393 { 394 double slide = (floating - yy) / (4); 395 if (slide < 0) slide = 0; 396 if (slide > 1) slide = 1; 397 val = val * (1 - slide) + -10 * slide; 398 } 399 400 buffer[p] = val; 401 p++; 402 } 403 } 404 } 405 406 delete [] pnr.data; 407 delete [] ar.data; 408 delete [] br.data; 409 delete [] sr.data; 410 delete [] dr.data; 411 delete [] fi.data; 412 delete [] fis.data; 413 delete [] yoffs.data; 414 415 return buffer; 416} 417 418bool HellRandomLevelSource::hasChunk(int x, int y) 419{ 420 return true; 421} 422 423void HellRandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) 424{ 425 HeavyTile::instaFall = true; 426 int xo = xt * 16; 427 int zo = zt * 16; 428 429 // 4J - added. The original java didn't do any setting of the random seed here. We'll be running our postProcess in parallel with getChunk etc. so 430 // we need to use a separate random - have used the same initialisation code as used in RandomLevelSource::postProcess to make sure this random value 431 // is consistent for each world generation. Also changed all uses of random here to pprandom. 432 pprandom->setSeed(level->getSeed()); 433 __int64 xScale = pprandom->nextLong() / 2 * 2 + 1; 434 __int64 zScale = pprandom->nextLong() / 2 * 2 + 1; 435 pprandom->setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); 436 437 netherBridgeFeature->postProcess(level, pprandom, xt, zt); 438 439 for (int i = 0; i < 8; i++) 440 { 441 int x = xo + pprandom->nextInt(16) + 8; 442 int y = pprandom->nextInt(Level::genDepth - 8) + 4; 443 int z = zo + pprandom->nextInt(16) + 8; 444 HellSpringFeature(Tile::lava_Id, false).place(level, pprandom, x, y, z); 445 } 446 447 int count = pprandom->nextInt(pprandom->nextInt(10) + 1) + 1; 448 449 for (int i = 0; i < count; i++) 450 { 451 int x = xo + pprandom->nextInt(16) + 8; 452 int y = pprandom->nextInt(Level::genDepth - 8) + 4; 453 int z = zo + pprandom->nextInt(16) + 8; 454 HellFireFeature().place(level, pprandom, x, y, z); 455 } 456 457 count = pprandom->nextInt(pprandom->nextInt(10) + 1); 458 for (int i = 0; i < count; i++) 459 { 460 int x = xo + pprandom->nextInt(16) + 8; 461 int y = pprandom->nextInt(Level::genDepth - 8) + 4; 462 int z = zo + pprandom->nextInt(16) + 8; 463 LightGemFeature().place(level, pprandom, x, y, z); 464 } 465 466 for (int i = 0; i < 10; i++) 467 { 468 int x = xo + pprandom->nextInt(16) + 8; 469 int y = pprandom->nextInt(Level::genDepth); 470 int z = zo + pprandom->nextInt(16) + 8; 471 HellPortalFeature().place(level, pprandom, x, y, z); 472 } 473 474 if (pprandom->nextInt(1) == 0) 475 { 476 int x = xo + pprandom->nextInt(16) + 8; 477 int y = pprandom->nextInt(Level::genDepth); 478 int z = zo + pprandom->nextInt(16) + 8; 479 FlowerFeature(Tile::mushroom_brown_Id).place(level, pprandom, x, y, z); 480 } 481 482 if (pprandom->nextInt(1) == 0) 483 { 484 int x = xo + pprandom->nextInt(16) + 8; 485 int y = pprandom->nextInt(Level::genDepth); 486 int z = zo + pprandom->nextInt(16) + 8; 487 FlowerFeature(Tile::mushroom_red_Id).place(level, pprandom, x, y, z); 488 } 489 490 OreFeature quartzFeature(Tile::netherQuartz_Id, 13, Tile::netherRack_Id); 491 for (int i = 0; i < 16; i++) 492 { 493 int x = xo + pprandom->nextInt(16); 494 int y = pprandom->nextInt(Level::genDepth - 20) + 10; 495 int z = zo + pprandom->nextInt(16); 496 quartzFeature.place(level, pprandom, x, y, z); 497 } 498 499 for (int i = 0; i < 16; i++) 500 { 501 int x = xo + random->nextInt(16); 502 int y = random->nextInt(Level::genDepth - 20) + 10; 503 int z = zo + random->nextInt(16); 504 HellSpringFeature hellSpringFeature(Tile::lava_Id, true); 505 hellSpringFeature.place(level, random, x, y, z); 506 } 507 508 HeavyTile::instaFall = false; 509 510 app.processSchematics(parent->getChunk(xt,zt)); 511 512} 513 514bool HellRandomLevelSource::save(bool force, ProgressListener *progressListener) 515{ 516 return true; 517} 518 519bool HellRandomLevelSource::tick() 520{ 521 return false; 522} 523 524bool HellRandomLevelSource::shouldSave() 525{ 526 return true; 527} 528 529wstring HellRandomLevelSource::gatherStats() 530{ 531 return L"HellRandomLevelSource"; 532} 533 534vector<Biome::MobSpawnerData *> *HellRandomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) 535{ 536 // check if the coordinates is within a netherbridge 537 if (mobCategory == MobCategory::monster) 538 { 539 if(netherBridgeFeature->isInsideFeature(x, y, z)) 540 { 541 return netherBridgeFeature->getBridgeEnemies(); 542 } 543 if ((netherBridgeFeature->isInsideBoundingFeature(x, y, z) && level->getTile(x, y - 1, z) == Tile::netherBrick_Id)) 544 { 545 return netherBridgeFeature->getBridgeEnemies(); 546 } 547 } 548 549 Biome *biome = level->getBiome(x, z); 550 if (biome == NULL) 551 { 552 return NULL; 553 } 554 return biome->getMobs(mobCategory); 555} 556 557TilePos *HellRandomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) 558{ 559 return NULL; 560} 561 562void HellRandomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) 563{ 564 netherBridgeFeature->apply(this, level, chunkX, chunkZ, NULL); 565}