the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 641 lines 17 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.level.h" 3#include "net.minecraft.world.level.storage.h" 4#include "net.minecraft.world.level.biome.h" 5#include "net.minecraft.world.level.newbiome.layer.h" 6#include "System.h" 7#include "BiomeSource.h" 8#include "..\Minecraft.Client\Minecraft.h" 9#include "..\Minecraft.Client\ProgressRenderer.h" 10 11// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3 12void BiomeSource::_init() 13{ 14 layer = nullptr; 15 zoomedLayer = nullptr; 16 17 cache = new BiomeCache(this); 18 19 playerSpawnBiomes.push_back(Biome::forest); 20 playerSpawnBiomes.push_back(Biome::taiga); 21 // 4J-PB - Moving forward plains as a spawnable biome (mainly for the Superflat world) 22 playerSpawnBiomes.push_back(Biome::plains); 23 playerSpawnBiomes.push_back(Biome::taigaHills); 24 playerSpawnBiomes.push_back(Biome::forestHills); 25 playerSpawnBiomes.push_back(Biome::jungle); 26 playerSpawnBiomes.push_back(Biome::jungleHills); 27} 28 29void BiomeSource::_init(__int64 seed, LevelType *generator) 30{ 31 _init(); 32 33 LayerArray layers = Layer::getDefaultLayers(seed, generator); 34 layer = layers[0]; 35 zoomedLayer = layers[1]; 36 37 delete [] layers.data; 38} 39 40BiomeSource::BiomeSource() 41{ 42 _init(); 43} 44 45// 4J added 46BiomeSource::BiomeSource(__int64 seed, LevelType *generator) 47{ 48 _init(seed, generator); 49} 50 51// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3 52BiomeSource::BiomeSource(Level *level) 53{ 54 _init(level->getSeed(), level->getLevelData()->getGenerator()); 55} 56 57BiomeSource::~BiomeSource() 58{ 59 delete cache; 60} 61 62Biome *BiomeSource::getBiome(ChunkPos *cp) 63{ 64 return getBiome(cp->x << 4, cp->z << 4); 65} 66 67Biome *BiomeSource::getBiome(int x, int z) 68{ 69 return cache->getBiome(x, z); 70} 71 72float BiomeSource::getDownfall(int x, int z) const 73{ 74 return cache->getDownfall(x, z); 75} 76 77// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only. 78floatArray BiomeSource::getDownfallBlock(int x, int z, int w, int h) const 79{ 80 floatArray downfalls; 81 getDownfallBlock(downfalls, x, z, w, h); 82 return downfalls; 83} 84 85// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only. 86// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3 87void BiomeSource::getDownfallBlock(floatArray &downfalls, int x, int z, int w, int h) const 88{ 89 IntCache::releaseAll(); 90 //if (downfalls == NULL || downfalls->length < w * h) 91 if (downfalls.data == NULL || downfalls.length < w * h) 92 { 93 if(downfalls.data != NULL) delete [] downfalls.data; 94 downfalls = floatArray(w * h); 95 } 96 97 intArray result = zoomedLayer->getArea(x, z, w, h); 98 for (int i = 0; i < w * h; i++) 99 { 100 float d = (float) Biome::biomes[result[i]]->getDownfallInt() / 65536.0f; 101 if (d > 1) d = 1; 102 downfalls[i] = d; 103 } 104} 105 106BiomeCache::Block *BiomeSource::getBlockAt(int x, int y) 107{ 108 return cache->getBlockAt(x, y); 109} 110 111float BiomeSource::getTemperature(int x, int y, int z) const 112{ 113 return scaleTemp(cache->getTemperature(x, z), y); 114} 115 116// 4J - brought forward from 1.2.3 117float BiomeSource::scaleTemp(float temp, int y ) const 118{ 119 return temp; 120} 121 122floatArray BiomeSource::getTemperatureBlock(int x, int z, int w, int h) const 123{ 124 floatArray temperatures; 125 getTemperatureBlock(temperatures, x, z, w, h); 126 return temperatures; 127} 128 129// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only. 130// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3 131void BiomeSource::getTemperatureBlock(floatArray& temperatures, int x, int z, int w, int h) const 132{ 133 IntCache::releaseAll(); 134 //if (temperatures == null || temperatures.length < w * h) { 135 if (temperatures.data == NULL || temperatures.length < w * h) 136 { 137 if( temperatures.data != NULL ) delete [] temperatures.data; 138 temperatures = floatArray(w * h); 139 } 140 141 intArray result = zoomedLayer->getArea(x, z, w, h); 142 for (int i = 0; i < w * h; i++) 143 { 144 float t = (float) Biome::biomes[result[i]]->getTemperatureInt() / 65536.0f; 145 if (t > 1) t = 1; 146 temperatures[i] = t; 147 } 148} 149 150BiomeArray BiomeSource::getRawBiomeBlock(int x, int z, int w, int h) const 151{ 152 BiomeArray biomes; 153 getRawBiomeBlock(biomes, x, z, w, h); 154 return biomes; 155} 156 157// 4J added 158void BiomeSource::getRawBiomeIndices(intArray &biomes, int x, int z, int w, int h) const 159{ 160 IntCache::releaseAll(); 161 162 intArray result = layer->getArea(x, z, w, h); 163 for (int i = 0; i < w * h; i++) 164 { 165 biomes[i] = result[i]; 166 } 167} 168 169void BiomeSource::getRawBiomeBlock(BiomeArray &biomes, int x, int z, int w, int h) const 170{ 171 IntCache::releaseAll(); 172 //if (biomes == null || biomes.length < w * h) 173 if (biomes.data == NULL || biomes.length < w * h) 174 { 175 if(biomes.data != NULL) delete [] biomes.data; 176 biomes = BiomeArray(w * h); 177 } 178 179 intArray result = layer->getArea(x, z, w, h); 180 for (int i = 0; i < w * h; i++) 181 { 182 biomes[i] = Biome::biomes[result[i]]; 183#ifndef _CONTENT_PACKAGE 184 if(biomes[i] == NULL) 185 { 186 app.DebugPrintf("Tried to assign null biome %d\n", result[i]); 187 __debugbreak(); 188 } 189#endif 190 } 191} 192 193 194 195BiomeArray BiomeSource::getBiomeBlock(int x, int z, int w, int h) const 196{ 197 if (w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0) 198 { 199 return cache->getBiomeBlockAt(x, z); 200 } 201 BiomeArray biomes; 202 getBiomeBlock(biomes, x, z, w, h, true); 203 return biomes; 204} 205 206// 4J - caller is responsible for deleting biomes array 207void BiomeSource::getBiomeBlock(BiomeArray& biomes, int x, int z, int w, int h, bool useCache) const 208{ 209 IntCache::releaseAll(); 210 //if (biomes == null || biomes.length < w * h) 211 if (biomes.data == NULL || biomes.length < w * h) 212 { 213 if(biomes.data != NULL) delete [] biomes.data; 214 biomes = BiomeArray(w * h); 215 } 216 217 if (useCache && w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0) 218 { 219 BiomeArray tmp = cache->getBiomeBlockAt(x, z); 220 System::arraycopy(tmp, 0, &biomes, 0, w * h); 221 delete tmp.data; // MGH - added, the caching creates this array from the indices now. 222 //return biomes; 223 } 224 225 intArray result = zoomedLayer->getArea(x, z, w, h); 226 for (int i = 0; i < w * h; i++) 227 { 228 biomes[i] = Biome::biomes[result[i]]; 229 } 230} 231 232 233 234 235byteArray BiomeSource::getBiomeIndexBlock(int x, int z, int w, int h) const 236{ 237 if (w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0) 238 { 239 return cache->getBiomeIndexBlockAt(x, z); 240 } 241 byteArray biomeIndices; 242 getBiomeIndexBlock(biomeIndices, x, z, w, h, true); 243 return biomeIndices; 244} 245 246// 4J - caller is responsible for deleting biomes array 247void BiomeSource::getBiomeIndexBlock(byteArray& biomeIndices, int x, int z, int w, int h, bool useCache) const 248{ 249 IntCache::releaseAll(); 250 //if (biomes == null || biomes.length < w * h) 251 if (biomeIndices.data == NULL || biomeIndices.length < w * h) 252 { 253 if(biomeIndices.data != NULL) delete [] biomeIndices.data; 254 biomeIndices = byteArray(w * h); 255 } 256 257 if (useCache && w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0) 258 { 259 byteArray tmp = cache->getBiomeIndexBlockAt(x, z); 260 System::arraycopy(tmp, 0, &biomeIndices, 0, w * h); 261 //return biomes; 262 } 263 264 intArray result = zoomedLayer->getArea(x, z, w, h); 265 for (int i = 0; i < w * h; i++) 266 { 267 biomeIndices[i] = (byte)result[i]; 268 } 269} 270 271/** 272* Checks if an area around a block contains only the specified biomes. 273* Useful for placing elements like towns. 274* 275* This is a bit of a rough check, to make it as fast as possible. To ensure 276* NO other biomes, add a margin of at least four blocks to the radius 277*/ 278bool BiomeSource::containsOnly(int x, int z, int r, vector<Biome *> allowed) 279{ 280 IntCache::releaseAll(); 281 int x0 = ((x - r) >> 2); 282 int z0 = ((z - r) >> 2); 283 int x1 = ((x + r) >> 2); 284 int z1 = ((z + r) >> 2); 285 286 int w = x1 - x0 + 1; 287 int h = z1 - z0 + 1; 288 289 intArray biomes = layer->getArea(x0, z0, w, h); 290 for (int i = 0; i < w * h; i++) 291 { 292 Biome *b = Biome::biomes[biomes[i]]; 293 if (find(allowed.begin(), allowed.end(), b) == allowed.end()) return false; 294 } 295 296 return true; 297} 298 299/** 300* Checks if an area around a block contains only the specified biome. 301* Useful for placing elements like towns. 302* 303* This is a bit of a rough check, to make it as fast as possible. To ensure 304* NO other biomes, add a margin of at least four blocks to the radius 305*/ 306bool BiomeSource::containsOnly(int x, int z, int r, Biome *allowed) 307{ 308 IntCache::releaseAll(); 309 int x0 = ((x - r) >> 2); 310 int z0 = ((z - r) >> 2); 311 int x1 = ((x + r) >> 2); 312 int z1 = ((z + r) >> 2); 313 314 int w = x1 - x0; 315 int h = z1 - z0; 316 int biomesCount = w*h; 317 intArray biomes = layer->getArea(x0, z0, w, h); 318 for (unsigned int i = 0; i < biomesCount; i++) 319 { 320 Biome *b = Biome::biomes[biomes[i]]; 321 if (allowed != b) return false; 322 } 323 324 return true; 325} 326 327/** 328* Finds the specified biome within the radius. This will return a random 329* position if several are found. This test is fairly rough. 330* 331* Returns null if the biome wasn't found 332*/ 333TilePos *BiomeSource::findBiome(int x, int z, int r, Biome *toFind, Random *random) 334{ 335 IntCache::releaseAll(); 336 int x0 = ((x - r) >> 2); 337 int z0 = ((z - r) >> 2); 338 int x1 = ((x + r) >> 2); 339 int z1 = ((z + r) >> 2); 340 341 int w = x1 - x0 + 1; 342 int h = z1 - z0 + 1; 343 intArray biomes = layer->getArea(x0, z0, w, h); 344 TilePos *res = NULL; 345 int found = 0; 346 int biomesCount = w*h; 347 for (unsigned int i = 0; i < biomesCount; i++) 348 { 349 int xx = x0 + i % w; 350 int zz = z0 + i / w; 351 Biome *b = Biome::biomes[biomes[i]]; 352 if (b == toFind) 353 { 354 if (res == NULL || random->nextInt(found + 1) == 0) 355 { 356 res = new TilePos(xx, 0, zz); 357 found++; 358 } 359 } 360 } 361 362 return res; 363} 364 365/** 366* Finds one of the specified biomes within the radius. This will return a 367* random position if several are found. This test is fairly rough. 368* 369* Returns null if the biome wasn't found 370*/ 371TilePos *BiomeSource::findBiome(int x, int z, int r, vector<Biome *> allowed, Random *random) 372{ 373 IntCache::releaseAll(); 374 int x0 = ((x - r) >> 2); 375 int z0 = ((z - r) >> 2); 376 int x1 = ((x + r) >> 2); 377 int z1 = ((z + r) >> 2); 378 379 int w = x1 - x0 + 1; 380 int h = z1 - z0 + 1; 381 MemSect(50); 382 intArray biomes = layer->getArea(x0, z0, w, h); 383 TilePos *res = NULL; 384 int found = 0; 385 for (unsigned int i = 0; i < w * h; i++) 386 { 387 int xx = (x0 + i % w) << 2; 388 int zz = (z0 + i / w) << 2; 389 Biome *b = Biome::biomes[biomes[i]]; 390 if (find(allowed.begin(), allowed.end(), b) != allowed.end()) 391 { 392 if (res == NULL || random->nextInt(found + 1) == 0) 393 { 394 delete res; 395 res = new TilePos(xx, 0, zz); 396 found++; 397 } 398 } 399 } 400 MemSect(0); 401 402 return res; 403} 404 405void BiomeSource::update() 406{ 407 cache->update(); 408} 409 410//#define DEBUG_SEEDS 50 411 412// 4J added - find a seed for this biomesource that matches certain criteria 413#ifdef __PSVITA__ 414__int64 BiomeSource::findSeed(LevelType *generator, bool* pServerRunning) // MGH - added pRunning, so we can early out of this on Vita as it can take up to 60 secs 415#else 416__int64 BiomeSource::findSeed(LevelType *generator) 417#endif 418{ 419 420 __int64 bestSeed = 0; 421 422 ProgressRenderer *mcprogress = Minecraft::GetInstance()->progressRenderer; 423 mcprogress->progressStage(IDS_PROGRESS_NEW_WORLD_SEED); 424 425#ifndef _CONTENT_PACKAGE 426 if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableBiomeOverride)) 427 { 428 // Do nothing 429 } 430 else 431#endif 432 { 433#ifdef DEBUG_SEEDS 434 for( int k = 0; k < DEBUG_SEEDS; k++ ) 435#endif 436 { 437 // Try and genuinely random this search up 438 Random *pr = new Random(System::nanoTime()); 439 440 // Raw biome data has one result per 4x4 group of tiles. 441 // Removing a border of 8 from each side since we'll be doing special things at the edge to turn our world into an island, and so don't want to count things 442 // in the edge region in case they later get removed 443 static const int biomeWidth = ( 54 * 4 ) - 16; // Should be even so we can offset evenly 444 static const int biomeOffset = -( biomeWidth / 2 ); 445 446 // Storage for our biome indices 447 intArray indices = intArray( biomeWidth * biomeWidth ); 448 449 // Storage for the fractional amounts of each biome that will be calculated 450 float toCompare[Biome::BIOME_COUNT]; 451 452 bool matchFound = false; 453 int tryCount = 0; 454 455 // Just keeping trying to generate seeds until we find one that matches our criteria 456 do 457 { 458 __int64 seed = pr->nextLong(); 459 BiomeSource *biomeSource = new BiomeSource(seed,generator); 460 461 biomeSource->getRawBiomeIndices(indices, biomeOffset, biomeOffset, biomeWidth, biomeWidth); 462 getFracs(indices, toCompare); 463 464 matchFound = getIsMatch( toCompare ); 465 466 if( matchFound ) bestSeed = seed; 467 468 delete biomeSource; 469 tryCount++; 470 471 mcprogress->progressStagePercentage( tryCount % 100 ); 472#ifdef __PSVITA__ 473 } while (!matchFound && *pServerRunning); 474#else 475 } while (!matchFound); 476#endif 477 478 // Clean up 479 delete pr; 480 delete indices.data; 481 482#ifdef DEBUG_SEEDS 483 app.DebugPrintf("%d: %d tries taken, seed used is %lld\n", k, tryCount, bestSeed); 484 485 BiomeSource *biomeSource = new BiomeSource(bestSeed); 486 BiomeArray biomes = biomeSource->getBiomeBlock(-27 * 16, -27 * 16, 54 * 16, 54 * 16); 487 488 unsigned int *pixels = new unsigned int[54 * 16 * 54 * 16]; 489 for(int i = 0; i < 54 * 16 * 54 * 16; i++ ) 490 { 491 int id = biomes[i]->id; 492 493 // Create following colours: 494 // 0 ocean 0000 black 495 // 1 plains 0001 pastel cyan 496 // 2 desert 0010 green 497 // 3 extreme hills 0011 yellow 498 // 4 forest 0100 blue 499 // 5 taiga 0101 magenta 500 // 6 swamps 0110 cyan 501 // 7 river 0111 white 502 // 8 hell 1000 grey 503 // 9 end biome 1001 white 504 // 10 frozen ocean 1010 pastel green 505 // 11 frozen river 1011 pastel yellow 506 // 12 ice flats 1100 pastel blue 507 // 13 ice mountains 1101 pastel magenta 508 // 14 mushroom island 1110 red 509 // 15 mushroom shore 1111 pastel red 510 511 if( id == 1 ) id = 14; 512 else if ( id == 14 ) id = 1; 513 else if( id == 9 ) id = 15; 514 else if( id == 15 ) id = 9; 515 pixels[i] = 0xff000000; 516 if( id & 1 ) pixels[i] |= 0x00ff0000; 517 if( id & 2 ) pixels[i] |= 0x0000ff00; 518 if( id & 4 ) pixels[i] |= 0x000000ff; 519 if( id & 8 ) pixels[i] |= 0x00808080; 520 } 521 D3DXIMAGE_INFO srcInfo; 522 srcInfo.Format = D3DFMT_LIN_A8R8G8B8; 523 srcInfo.ImageFileFormat = D3DXIFF_BMP; 524 srcInfo.Width = 54 * 16; 525 srcInfo.Height = 54 * 16; 526 527 char buf[256]; 528 sprintf(buf,"GAME:\\BiomeTest%d.bmp",k); 529 RenderManager.SaveTextureData(buf, &srcInfo, (int *)pixels); 530 531 delete [] pixels; 532 delete biomes.data; 533 delete biomeSource; 534#endif 535 } 536 } 537 538 return bestSeed; 539} 540 541// 4J added - get the fractional amounts of each biome type in the given indices 542void BiomeSource::getFracs(intArray indices, float *fracs) 543{ 544 for( int i = 0; i < Biome::BIOME_COUNT; i++ ) 545 { 546 fracs[i] = 0.0f; 547 } 548 549 for( int i = 0; i < indices.length; i++ ) 550 { 551 fracs[indices[i]] += 1.0f; 552 } 553 554 for( int i = 0; i < Biome::BIOME_COUNT; i++ ) 555 { 556 fracs[i] /= (float)(indices.length); 557 } 558} 559 560 561 562// 4J added - determine if this particular set of fractional amounts of biome types matches are requirements 563bool BiomeSource::getIsMatch(float *frac) 564{ 565 // A true for a particular biome type here marks it as one that *has* to be present 566 static const bool critical[Biome::BIOME_COUNT] = { 567 true, // ocean 568 true, // plains 569 true, // desert 570 false, // extreme hills 571 true, // forest 572 true, // taiga 573 true, // swamps 574 false, // river 575 false, // hell 576 false, // end biome 577 false, // frozen ocean 578 false, // frozen river 579 false, // ice flats 580 false, // ice mountains 581 true, // mushroom island / shore 582 false, // mushroom shore (combined with above) 583 false, // beach 584 false, // desert hills (combined with desert) 585 false, // forest hills (combined with forest) 586 false, // taiga hills (combined with taga) 587 false, // small extreme hills 588 true, // jungle 589 false, // jungle hills (combined with jungle) 590 }; 591 592 593 // Don't want more than 15% ocean 594 if( frac[0] > 0.15f ) 595 { 596 return false; 597 } 598 599 // Consider mushroom shore & islands as the same by finding max 600 frac[14] = ( ( frac[15] > frac[14] ) ? frac[15] : frac[14] ); 601 602 // Merge desert and desert hills 603 frac[2] = ( ( frac[17] > frac[2] ) ? frac[17] : frac[2] ); 604 605 // Merge forest and forest hills 606 frac[4] = ( ( frac[18] > frac[4] ) ? frac[18] : frac[4] ); 607 608 // Merge taiga and taiga hills 609 frac[5] = ( ( frac[19] > frac[5] ) ? frac[19] : frac[5] ); 610 611 // Merge jungle and jungle hills 612 frac[21] = ( ( frac[22] > frac[21] ) ? frac[22] : frac[21] ); 613 614 // Loop through all biome types, and: 615 // (1) count them 616 // (2) give up if one of the critical ones is missing 617 618 int typeCount = 0; 619 for( int i = 0; i < Biome::BIOME_COUNT; i++ ) 620 { 621 // We want to skip some where we have merged with another type 622 if(i == 15 || i == 17 || i == 18 || i == 19 || i == 22) continue; 623 624 // Consider 0.1% as being "present" - this equates an area of about 3 chunks 625 if( frac[i] > 0.001f ) 626 { 627 typeCount++; 628 } 629 else 630 { 631 // If a critical biome is missing, just give up 632 if( critical[i] ) 633 { 634 return false; 635 } 636 } 637 } 638 639 // Consider as suitable if we've got all the critical ones, and in total 9 or more - currently there's 8 critical so this just forces at least 1 more others 640 return ( typeCount >= 9 ); 641}