the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 661 lines 20 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 "CustomLevelSource.h" 12 13const double CustomLevelSource::SNOW_SCALE = 0.3; 14const double CustomLevelSource::SNOW_CUTOFF = 0.5; 15 16CustomLevelSource::CustomLevelSource(Level *level, __int64 seed, bool generateStructures) : generateStructures( generateStructures ) 17{ 18#ifdef _OVERRIDE_HEIGHTMAP 19 m_XZSize = level->getLevelData()->getXZSize(); 20 21 m_heightmapOverride = byteArray( (m_XZSize*16) * (m_XZSize*16) ); 22 23#ifdef _UNICODE 24 wstring path = L"GAME:\\GameRules\\heightmap.bin"; 25 26#else 27#ifdef _WINDOWS64 28 string path = "GameRules\\heightmap.bin"; 29#else 30 string path = "GAME:\\GameRules\\heightmap.bin"; 31#endif 32#endif 33 HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 34 if( file == INVALID_HANDLE_VALUE ) 35 { 36 app.FatalLoadError(); 37 DWORD error = GetLastError(); 38 assert(false); 39 } 40 else 41 { 42 43#ifdef _DURANGO 44 __debugbreak(); // TODO 45 DWORD bytesRead,dwFileSize = 0; 46#else 47 DWORD bytesRead,dwFileSize = GetFileSize(file,NULL); 48#endif 49 if(dwFileSize > m_heightmapOverride.length) 50 { 51 app.DebugPrintf("Heightmap binary is too large!!\n"); 52 __debugbreak(); 53 } 54 BOOL bSuccess = ReadFile(file,m_heightmapOverride.data,dwFileSize,&bytesRead,NULL); 55 56 if(bSuccess==FALSE) 57 { 58 app.FatalLoadError(); 59 } 60 CloseHandle(file); 61 } 62 63 m_waterheightOverride = byteArray( (m_XZSize*16) * (m_XZSize*16) ); 64 65#ifdef _UNICODE 66 wstring waterHeightPath = L"GAME:\\GameRules\\waterheight.bin"; 67 68#else 69#ifdef _WINDOWS64 70 string waterHeightPath = "GameRules\\waterheight.bin"; 71#else 72 string waterHeightPath = "GAME:\\GameRules\\waterheight.bin"; 73#endif 74#endif 75 file = CreateFile(waterHeightPath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 76 if( file == INVALID_HANDLE_VALUE ) 77 { 78 DWORD error = GetLastError(); 79 //assert(false); 80 memset(m_waterheightOverride.data, level->seaLevel, m_waterheightOverride.length); 81 } 82 else 83 { 84 85#ifdef _DURANGO 86 __debugbreak(); // TODO 87 DWORD bytesRead,dwFileSize = 0; 88#else 89 DWORD bytesRead,dwFileSize = GetFileSize(file,NULL); 90#endif 91 if(dwFileSize > m_waterheightOverride.length) 92 { 93 app.DebugPrintf("waterheight binary is too large!!\n"); 94 __debugbreak(); 95 } 96 BOOL bSuccess = ReadFile(file,m_waterheightOverride.data,dwFileSize,&bytesRead,NULL); 97 98 if(bSuccess==FALSE) 99 { 100 app.FatalLoadError(); 101 } 102 CloseHandle(file); 103 } 104 105 caveFeature = new LargeCaveFeature(); 106 strongholdFeature = new StrongholdFeature(); 107 villageFeature = new VillageFeature(m_XZSize); 108 mineShaftFeature = new MineShaftFeature(); 109 scatteredFeature = new RandomScatteredLargeFeature(); 110 canyonFeature = new CanyonFeature(); 111 112 this->level = level; 113 114 random = new Random(seed); 115 pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation 116 perlinNoise3 = new PerlinNoise(random, 4); 117#endif 118} 119 120CustomLevelSource::~CustomLevelSource() 121{ 122#ifdef _OVERRIDE_HEIGHTMAP 123 delete caveFeature; 124 delete strongholdFeature; 125 delete villageFeature; 126 delete mineShaftFeature; 127 delete canyonFeature; 128 129 this->level = level; 130 131 delete random; 132 delete perlinNoise3; 133#endif 134} 135 136void CustomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) 137{ 138#ifdef _OVERRIDE_HEIGHTMAP 139 int xChunks = 16 / CHUNK_WIDTH; 140 int yChunks = Level::maxBuildHeight / CHUNK_HEIGHT; 141 int waterHeight = level->seaLevel; 142 143 int xSize = xChunks + 1; 144 int ySize = Level::maxBuildHeight / CHUNK_HEIGHT + 1; 145 int zSize = xChunks + 1; 146 147 int xMapStart = xOffs + m_XZSize/2; 148 int zMapStart = zOffs + m_XZSize/2; 149 for (int xc = 0; xc < xChunks; xc++) 150 { 151 for (int zc = 0; zc < xChunks; zc++) 152 { 153 for (int yc = 0; yc < yChunks; yc++) 154 { 155 for (int y = 0; y < CHUNK_HEIGHT; y++) 156 { 157 for (int x = 0; x < CHUNK_WIDTH; x++) 158 { 159 for (int z = 0; z < CHUNK_WIDTH; z++) 160 { 161 int mapIndex = (zMapStart * 16 + z + ( zc * CHUNK_WIDTH )) * (m_XZSize * 16) + (xMapStart * 16 + x + ( xc * CHUNK_WIDTH )); 162 int mapHeight = m_heightmapOverride[mapIndex]; 163 waterHeight = m_waterheightOverride[mapIndex]; 164 //app.DebugPrintf("MapHeight = %d, y = %d\n", mapHeight, yc * CHUNK_HEIGHT + y); 165 /////////////////////////////////////////////////////////////////// 166 // 4J - add this chunk of code to make land "fall-off" at the edges of 167 // a finite world - size of that world is currently hard-coded in here 168 const int worldSize = m_XZSize * 16; 169 const int falloffStart = 32; // chunks away from edge were we start doing fall-off 170 const float falloffMax = 128.0f; // max value we need to get to falloff by the edge of the map 171 172 int xxx = ( ( xOffs * 16 ) + x + ( xc * CHUNK_WIDTH ) ); 173 int zzz = ( ( zOffs * 16 ) + z + ( zc * CHUNK_WIDTH ) ); 174 175 // Get distance to edges of world in x 176 int xxx0 = xxx + ( worldSize / 2 ); 177 if( xxx0 < 0 ) xxx0 = 0; 178 int xxx1 = ( ( worldSize / 2 ) - 1 ) - xxx; 179 if( xxx1 < 0 ) xxx1 = 0; 180 181 // Get distance to edges of world in z 182 int zzz0 = zzz + ( worldSize / 2 ); 183 if( zzz0 < 0 ) zzz0 = 0; 184 int zzz1 = ( ( worldSize / 2 ) - 1 ) - zzz; 185 if( zzz1 < 0 ) zzz1 = 0; 186 187 // Get min distance to any edge 188 int emin = xxx0; 189 if (xxx1 < emin ) emin = xxx1; 190 if (zzz0 < emin ) emin = zzz0; 191 if (zzz1 < emin ) emin = zzz1; 192 193 float comp = 0.0f; 194 195 // Calculate how much we want the world to fall away, if we're in the defined region to do so 196 if( emin < falloffStart ) 197 { 198 int falloff = falloffStart - emin; 199 comp = ((float)falloff / (float)falloffStart ) * falloffMax; 200 } 201 // 4J - end of extra code 202 /////////////////////////////////////////////////////////////////// 203 int tileId = 0; 204 // 4J - this comparison used to just be with 0.0f but is now varied by block above 205 if (yc * CHUNK_HEIGHT + y < mapHeight) 206 { 207 tileId = (byte) Tile::stone_Id; 208 } 209 else if (yc * CHUNK_HEIGHT + y < waterHeight) 210 { 211 tileId = (byte) Tile::calmWater_Id; 212 } 213 214 // 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 215 // continues on after the edge of the world. 216 217 if( emin == 0 ) 218 { 219 // This matches code in MultiPlayerChunkCache that makes the geometry which continues at the edge of the world 220 if( yc * CHUNK_HEIGHT + y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::stone_Id; 221 else if( yc * CHUNK_HEIGHT + y < level->getSeaLevel() ) tileId = Tile::calmWater_Id; 222 } 223 224 int indexY = (yc * CHUNK_HEIGHT + y); 225 int offsAdjustment = 0; 226 if(indexY >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) 227 { 228 indexY -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT; 229 offsAdjustment = Level::COMPRESSED_CHUNK_SECTION_TILES; 230 } 231 int offs = ( (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (z + zc * CHUNK_WIDTH) << Level::genDepthBits | indexY) + offsAdjustment; 232 blocks[offs] = tileId; 233 } 234 } 235 } 236 } 237 } 238 } 239#endif 240} 241 242 243void CustomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes) 244{ 245#ifdef _OVERRIDE_HEIGHTMAP 246 int waterHeight = level->seaLevel; 247 int xMapStart = xOffs + m_XZSize/2; 248 int zMapStart = zOffs + m_XZSize/2; 249 250 double s = 1 / 32.0; 251 252 doubleArray depthBuffer(16*16); // 4J - used to be declared with class level scope but moved here for thread safety 253 254 depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); 255 256 for (int x = 0; x < 16; x++) 257 { 258 for (int z = 0; z < 16; z++) 259 { 260 int mapIndex = (zMapStart * 16 + z) * (m_XZSize * 16) + (xMapStart * 16 + x); 261 waterHeight = m_waterheightOverride[mapIndex]; 262 263 Biome *b = biomes[z + x * 16]; 264 float temp = b->getTemperature(); 265 int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); 266 267 int run = -1; 268 269 byte top = b->topMaterial; 270 byte material = b->material; 271 272 LevelGenerationOptions *lgo = app.getLevelGenerationOptions(); 273 if(lgo != NULL) 274 { 275 lgo->getBiomeOverride(b->id,material,top); 276 } 277 278 for (int y = Level::maxBuildHeight - 1; y >= 0; y--) 279 { 280 281 int indexY = y; 282 int offsAdjustment = 0; 283 if(indexY >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) 284 { 285 indexY -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT; 286 offsAdjustment = Level::COMPRESSED_CHUNK_SECTION_TILES; 287 } 288 int offs = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | indexY) + offsAdjustment; 289 290 if (y <= 1 + random->nextInt(2)) // 4J - changed to make the bedrock not have bits you can get stuck in 291 // if (y <= 0 + random->nextInt(5)) 292 { 293 blocks[offs] = (byte) Tile::unbreakable_Id; 294 } 295 else 296 { 297 int old = blocks[offs]; 298 299 if (old == 0) 300 { 301 run = -1; 302 } 303 else if (old == Tile::stone_Id) 304 { 305 if (run == -1) 306 { 307 if (runDepth <= 0) 308 { 309 top = 0; 310 material = (byte) Tile::stone_Id; 311 } 312 else if (y >= waterHeight - 4 && y <= waterHeight + 1) 313 { 314 top = b->topMaterial; 315 material = b->material; 316 if(lgo != NULL) 317 { 318 lgo->getBiomeOverride(b->id,material,top); 319 } 320 } 321 322 if (y < waterHeight && top == 0) 323 { 324 if (temp < 0.15f) top = (byte) Tile::ice_Id; 325 else top = (byte) Tile::calmWater_Id; 326 } 327 328 run = runDepth; 329 if (y >= waterHeight - 1) blocks[offs] = top; 330 else blocks[offs] = material; 331 } 332 else if (run > 0) 333 { 334 run--; 335 blocks[offs] = material; 336 337 // place a few sandstone blocks beneath sand 338 // runs 339 if (run == 0 && material == Tile::sand_Id) 340 { 341 run = random->nextInt(4); 342 material = (byte) Tile::sandStone_Id; 343 } 344 } 345 } 346 } 347 } 348 } 349 } 350 351 delete [] depthBuffer.data; 352#endif 353} 354 355LevelChunk *CustomLevelSource::create(int x, int z) 356{ 357#ifdef _OVERRIDE_HEIGHTMAP 358 return getChunk(x,z); 359#else 360 return NULL; 361#endif 362} 363 364LevelChunk *CustomLevelSource::getChunk(int xOffs, int zOffs) 365{ 366#ifdef _OVERRIDE_HEIGHTMAP 367 random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); 368 369 // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed 370 int blocksSize = Level::maxBuildHeight * 16 * 16; 371 byte *tileData = (byte *)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); 372 XMemSet128(tileData,0,blocksSize); 373 byteArray blocks = byteArray(tileData,blocksSize); 374 // byteArray blocks = byteArray(16 * level->depth * 16); 375 376 // LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J - moved to below 377 378 prepareHeights(xOffs, zOffs, blocks); 379 380 // 4J - Some changes made here to how biomes, temperatures and downfalls are passed around for thread safety 381 BiomeArray biomes; 382 level->getBiomeSource()->getBiomeBlock(biomes, xOffs * 16, zOffs * 16, 16, 16, true); 383 384 buildSurfaces(xOffs, zOffs, blocks, biomes); 385 386 delete [] biomes.data; 387 388 caveFeature->apply(this, level, xOffs, zOffs, blocks); 389 // 4J Stu Design Change - 1.8 gen goes stronghold, mineshaft, village, canyon 390 // this changed in 1.2 to canyon, mineshaft, village, stronghold 391 // This change makes sense as it stops canyons running through other structures 392 canyonFeature->apply(this, level, xOffs, zOffs, blocks); 393 if (generateStructures) 394 { 395 mineShaftFeature->apply(this, level, xOffs, zOffs, blocks); 396 villageFeature->apply(this, level, xOffs, zOffs, blocks); 397 strongholdFeature->apply(this, level, xOffs, zOffs, blocks); 398 scatteredFeature->apply(this, level, xOffs, zOffs, blocks); 399 } 400 // canyonFeature.apply(this, level, xOffs, zOffs, blocks); 401 // townFeature.apply(this, level, xOffs, zOffs, blocks); 402 // addCaves(xOffs, zOffs, blocks); 403 // addTowns(xOffs, zOffs, blocks); 404 405 // levelChunk->recalcHeightmap(); // 4J - removed & moved into its own method 406 407 // 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 408 // now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. 409 LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); 410 XPhysicalFree(tileData); 411 412 return levelChunk; 413#else 414 return NULL; 415#endif 416} 417 418// 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without 419// 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. 420// lightgaps also does light 1 block into the neighbouring chunks, and maybe that is somehow enough to get lighting to propagate round the world, 421// but this just doesn't seem right - this isn't a new fault in the 360 version, have checked that java does the same. 422void CustomLevelSource::lightChunk(LevelChunk *lc) 423{ 424#ifdef _OVERRIDE_HEIGHTMAP 425 lc->recalcHeightmap(); 426#endif 427} 428 429bool CustomLevelSource::hasChunk(int x, int y) 430{ 431 return true; 432} 433 434void CustomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt) 435{ 436#ifdef _OVERRIDE_HEIGHTMAP 437 int xo = xt * 16; 438 int zo = zt * 16; 439 for (int x = 0; x < 16; x++) 440 { 441 int y = level->getSeaLevel(); 442 for (int z = 0; z < 16; z++) 443 { 444 int xp = xo + x + 7; 445 int zp = zo + z + 7; 446 int h = level->getHeightmap(xp, zp); 447 if (h <= 0) 448 { 449 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) 450 { 451 bool hadWater = false; 452 if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater_Id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; 453 if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater_Id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; 454 if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater_Id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; 455 if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater_Id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; 456 if (hadWater) 457 { 458 for (int x2 = -5; x2 <= 5; x2++) 459 { 460 for (int z2 = -5; z2 <= 5; z2++) 461 { 462 int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); 463 464 if (d <= 5) 465 { 466 d = 6 - d; 467 if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater_Id) 468 { 469 int od = level->getData(xp + x2, y, zp + z2); 470 if (od < 7 && od < d) 471 { 472 level->setData(xp + x2, y, zp + z2, d, Tile::UPDATE_CLIENTS); 473 } 474 } 475 } 476 } 477 } 478 if (hadWater) 479 { 480 level->setTileAndData(xp, y, zp, Tile::calmWater_Id, 7, Tile::UPDATE_CLIENTS); 481 for (int y2 = 0; y2 < y; y2++) 482 { 483 level->setTileAndData(xp, y2, zp, Tile::calmWater_Id, 8, Tile::UPDATE_CLIENTS); 484 } 485 } 486 } 487 } 488 } 489 } 490 } 491#endif 492} 493 494// 4J - changed this to used pprandom rather than random, so that we can run it concurrently with getChunk 495void CustomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) 496{ 497#ifdef _OVERRIDE_HEIGHTMAP 498 HeavyTile::instaFall = true; 499 int xo = xt * 16; 500 int zo = zt * 16; 501 502 Biome *biome = level->getBiome(xo + 16, zo + 16); 503 504 if (CustomLevelSource::FLOATING_ISLANDS) 505 { 506 calcWaterDepths(parent, xt, zt); 507 } 508 509 pprandom->setSeed(level->getSeed()); 510 __int64 xScale = pprandom->nextLong() / 2 * 2 + 1; 511 __int64 zScale = pprandom->nextLong() / 2 * 2 + 1; 512 pprandom->setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); 513 514 bool hasVillage = false; 515 516 PIXBeginNamedEvent(0,"Structure postprocessing"); 517 if (generateStructures) 518 { 519 mineShaftFeature->postProcess(level, pprandom, xt, zt); 520 hasVillage = villageFeature->postProcess(level, pprandom, xt, zt); 521 strongholdFeature->postProcess(level, pprandom, xt, zt); 522 scatteredFeature->postProcess(level, random, xt, zt); 523 } 524 PIXEndNamedEvent(); 525 526#if 0 527 PIXBeginNamedEvent(0,"Lakes"); 528 if (!hasVillage && pprandom->nextInt(4) == 0) 529 { 530 int x = xo + pprandom->nextInt(16) + 8; 531 int y = pprandom->nextInt(Level::maxBuildHeight); 532 int z = zo + pprandom->nextInt(16) + 8; 533 534 LakeFeature *calmWater = new LakeFeature(Tile::calmWater_Id); 535 calmWater->place(level, pprandom, x, y, z); 536 delete calmWater; 537 } 538 PIXEndNamedEvent(); 539 540 PIXBeginNamedEvent(0,"Lava"); 541 if (!hasVillage && pprandom->nextInt(8) == 0) 542 { 543 int x = xo + pprandom->nextInt(16) + 8; 544 int y = pprandom->nextInt(pprandom->nextInt(Level::maxBuildHeight - 8) + 8); 545 int z = zo + pprandom->nextInt(16) + 8; 546 if (y < level->seaLevel || pprandom->nextInt(10) == 0) 547 { 548 LakeFeature *calmLava = new LakeFeature(Tile::calmLava_Id); 549 calmLava->place(level, pprandom, x, y, z); 550 delete calmLava; 551 } 552 } 553 PIXEndNamedEvent(); 554#endif 555 556 PIXBeginNamedEvent(0,"Monster rooms"); 557 for (int i = 0; i < 8; i++) { 558 int x = xo + pprandom->nextInt(16) + 8; 559 int y = pprandom->nextInt(Level::maxBuildHeight); 560 int z = zo + pprandom->nextInt(16) + 8; 561 MonsterRoomFeature *mrf = new MonsterRoomFeature(); 562 if (mrf->place(level, pprandom, x, y, z)) 563 { 564 } 565 delete mrf; 566 } 567 PIXEndNamedEvent(); 568 569 PIXBeginNamedEvent(0,"Biome decorate"); 570 biome->decorate(level, pprandom, xo, zo); 571 PIXEndNamedEvent(); 572 573 app.processSchematics(parent->getChunk(xt,zt)); 574 575 MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, pprandom); 576 577 // 4J - brought forward from 1.2.3 to get snow back in taiga biomes 578 xo += 8; 579 zo += 8; 580 for (int x = 0; x < 16; x++) 581 { 582 for (int z = 0; z < 16; z++) 583 { 584 int y = level->getTopRainBlock(xo + x, zo + z); 585 586 if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) 587 { 588 level->setTileAndData(x + xo, y - 1, z + zo, Tile::ice_Id,0, Tile::UPDATE_INVISIBLE); // 4J - changed from setTile, otherwise we end up creating a *lot* of dynamic water tiles as these ice tiles are set 589 } 590 if (level->shouldSnow(x + xo, y, z + zo)) 591 { 592 level->setTileAndData(x + xo, y, z + zo, Tile::topSnow_Id,0, Tile::UPDATE_CLIENTS); 593 } 594 } 595 } 596 597 HeavyTile::instaFall = false; 598#endif 599} 600 601bool CustomLevelSource::save(bool force, ProgressListener *progressListener) 602{ 603 return true; 604} 605 606bool CustomLevelSource::tick() 607{ 608 return false; 609} 610 611bool CustomLevelSource::shouldSave() 612{ 613 return true; 614} 615 616wstring CustomLevelSource::gatherStats() 617{ 618 return L"CustomLevelSource"; 619} 620 621vector<Biome::MobSpawnerData *> *CustomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) 622{ 623#ifdef _OVERRIDE_HEIGHTMAP 624 Biome *biome = level->getBiome(x, z); 625 if (biome == NULL) 626 { 627 return NULL; 628 } 629 if (mobCategory == MobCategory::monster && scatteredFeature->isSwamphut(x, y, z)) 630 { 631 return scatteredFeature->getSwamphutEnemies(); 632 } 633 return biome->getMobs(mobCategory); 634#else 635 return NULL; 636#endif 637} 638 639TilePos *CustomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) 640{ 641#ifdef _OVERRIDE_HEIGHTMAP 642 if (LargeFeature::STRONGHOLD == featureName && strongholdFeature != NULL) 643 { 644 return strongholdFeature->getNearestGeneratedFeature(level, x, y, z); 645 } 646#endif 647 return NULL; 648} 649 650void CustomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) 651{ 652 if (generateStructures) 653 { 654#ifdef _OVERRIDE_HEIGHTMAP 655 mineShaftFeature->apply(this, level, chunkX, chunkZ, NULL); 656 villageFeature->apply(this, level, chunkX, chunkZ, NULL); 657 strongholdFeature->apply(this, level, chunkX, chunkZ, NULL); 658 scatteredFeature->apply(this, level, chunkX, chunkZ, NULL); 659#endif 660 } 661}