the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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}