mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
593 lines
16 KiB
C++
593 lines
16 KiB
C++
#include "stdafx.h"
|
||
#include "net.minecraft.world.level.h"
|
||
#include "net.minecraft.world.level.storage.h"
|
||
#include "net.minecraft.world.level.biome.h"
|
||
#include "net.minecraft.world.level.newbiome.layer.h"
|
||
#include "System.h"
|
||
#include "BiomeSource.h"
|
||
#include "ClimateLayer.h"
|
||
#include "..\Minecraft.Client\Minecraft.h"
|
||
#include "..\Minecraft.Client\ProgressRenderer.h"
|
||
|
||
void BiomeSource::_init()
|
||
{
|
||
layer = nullptr;
|
||
zoomedLayer = nullptr;
|
||
|
||
cache = new BiomeCache(this);
|
||
|
||
playerSpawnBiomes.push_back(Biome::plains);
|
||
playerSpawnBiomes.push_back(Biome::forest);
|
||
playerSpawnBiomes.push_back(Biome::forestHills);
|
||
playerSpawnBiomes.push_back(Biome::taiga);
|
||
playerSpawnBiomes.push_back(Biome::taigaHills);
|
||
playerSpawnBiomes.push_back(Biome::jungle);
|
||
playerSpawnBiomes.push_back(Biome::jungleHills);
|
||
playerSpawnBiomes.push_back(Biome::desert);
|
||
playerSpawnBiomes.push_back(Biome::extremeHills);
|
||
playerSpawnBiomes.push_back(Biome::swampland);
|
||
playerSpawnBiomes.push_back(Biome::iceFlats);
|
||
playerSpawnBiomes.push_back(Biome::iceMountains);
|
||
playerSpawnBiomes.push_back(Biome::mushroomIsland);
|
||
playerSpawnBiomes.push_back(Biome::mushroomIslandShore);
|
||
playerSpawnBiomes.push_back(Biome::beaches);
|
||
playerSpawnBiomes.push_back(Biome::desertHills);
|
||
playerSpawnBiomes.push_back(Biome::smallerExtremeHills);
|
||
}
|
||
|
||
void BiomeSource::_init(int64_t seed, LevelType *generator)
|
||
{
|
||
_init();
|
||
|
||
LayerArray layers = Layer::getDefaultLayers(seed, generator);
|
||
layer = layers[0];
|
||
zoomedLayer = layers[1];
|
||
|
||
delete [] layers.data;
|
||
}
|
||
|
||
BiomeSource::BiomeSource()
|
||
{
|
||
_init();
|
||
}
|
||
|
||
// 4J added
|
||
BiomeSource::BiomeSource(int64_t seed, LevelType *generator)
|
||
{
|
||
_init(seed, generator);
|
||
}
|
||
|
||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||
BiomeSource::BiomeSource(Level *level)
|
||
{
|
||
_init(level->getSeed(), level->getLevelData()->getGenerator());
|
||
}
|
||
|
||
BiomeSource::~BiomeSource()
|
||
{
|
||
delete cache;
|
||
}
|
||
|
||
Biome *BiomeSource::getBiome(ChunkPos *cp)
|
||
{
|
||
return getBiome(cp->x << 4, cp->z << 4);
|
||
}
|
||
|
||
Biome *BiomeSource::getBiome(int x, int z)
|
||
{
|
||
return cache->getBiome(x, z);
|
||
}
|
||
|
||
float BiomeSource::getDownfall(int x, int z) const
|
||
{
|
||
return cache->getDownfall(x, z);
|
||
}
|
||
|
||
// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only.
|
||
floatArray BiomeSource::getDownfallBlock(int x, int z, int w, int h) const
|
||
{
|
||
floatArray downfalls;
|
||
getDownfallBlock(downfalls, x, z, w, h);
|
||
return downfalls;
|
||
}
|
||
|
||
// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only.
|
||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||
void BiomeSource::getDownfallBlock(floatArray &downfalls, int x, int z, int w, int h) const
|
||
{
|
||
IntCache::releaseAll();
|
||
//if (downfalls == nullptr || downfalls->length < w * h)
|
||
if (downfalls.data == nullptr || downfalls.length < w * h)
|
||
{
|
||
if(downfalls.data != nullptr) delete [] downfalls.data;
|
||
downfalls = floatArray(w * h);
|
||
}
|
||
|
||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
float d = static_cast<float>(Biome::biomes[result[i]]->getDownfallInt()) / 65536.0f;
|
||
if (d > 1) d = 1;
|
||
downfalls[i] = d;
|
||
}
|
||
}
|
||
|
||
BiomeCache::Block *BiomeSource::getBlockAt(int x, int y)
|
||
{
|
||
return cache->getBlockAt(x, y);
|
||
}
|
||
|
||
float BiomeSource::getTemperature(int x, int y, int z) const
|
||
{
|
||
return scaleTemp(cache->getTemperature(x, z), y);
|
||
}
|
||
|
||
// 4J - brought forward from 1.2.3
|
||
float BiomeSource::scaleTemp(float temp, int y ) const
|
||
{
|
||
return temp;
|
||
}
|
||
|
||
floatArray BiomeSource::getTemperatureBlock(int x, int z, int w, int h) const
|
||
{
|
||
floatArray temperatures;
|
||
getTemperatureBlock(temperatures, x, z, w, h);
|
||
return temperatures;
|
||
}
|
||
|
||
// 4J - note that caller is responsible for deleting returned array. temperatures array is for output only.
|
||
// 4J - removal of separate temperature & downfall layers brought forward from 1.2.3
|
||
void BiomeSource::getTemperatureBlock(floatArray& temperatures, int x, int z, int w, int h) const
|
||
{
|
||
IntCache::releaseAll();
|
||
//if (temperatures == null || temperatures.length < w * h) {
|
||
if (temperatures.data == nullptr || temperatures.length < w * h)
|
||
{
|
||
if( temperatures.data != nullptr ) delete [] temperatures.data;
|
||
temperatures = floatArray(w * h);
|
||
}
|
||
|
||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
float t = static_cast<float>(Biome::biomes[result[i]]->getTemperatureInt()) / 65536.0f;
|
||
if (t > 1) t = 1;
|
||
temperatures[i] = t;
|
||
}
|
||
}
|
||
|
||
BiomeArray BiomeSource::getRawBiomeBlock(int x, int z, int w, int h) const
|
||
{
|
||
BiomeArray biomes;
|
||
getRawBiomeBlock(biomes, x, z, w, h);
|
||
return biomes;
|
||
}
|
||
|
||
// 4J added
|
||
void BiomeSource::getRawBiomeIndices(intArray &biomes, int x, int z, int w, int h) const
|
||
{
|
||
IntCache::releaseAll();
|
||
|
||
intArray result = layer->getArea(x, z, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
biomes[i] = result[i];
|
||
}
|
||
}
|
||
|
||
void BiomeSource::getRawBiomeBlock(BiomeArray &biomes, int x, int z, int w, int h) const
|
||
{
|
||
IntCache::releaseAll();
|
||
//if (biomes == null || biomes.length < w * h)
|
||
if (biomes.data == nullptr || biomes.length < w * h)
|
||
{
|
||
if(biomes.data != nullptr) delete [] biomes.data;
|
||
biomes = BiomeArray(w * h);
|
||
}
|
||
|
||
intArray result = layer->getArea(x, z, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
biomes[i] = Biome::biomes[result[i]];
|
||
#ifndef _CONTENT_PACKAGE
|
||
if(biomes[i] == nullptr)
|
||
{
|
||
app.DebugPrintf("Tried to assign null biome %d\n", result[i]);
|
||
__debugbreak();
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
|
||
|
||
BiomeArray BiomeSource::getBiomeBlock(int x, int z, int w, int h) const
|
||
{
|
||
if (w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||
{
|
||
return cache->getBiomeBlockAt(x, z);
|
||
}
|
||
BiomeArray biomes;
|
||
getBiomeBlock(biomes, x, z, w, h, true);
|
||
return biomes;
|
||
}
|
||
|
||
// 4J - caller is responsible for deleting biomes array
|
||
void BiomeSource::getBiomeBlock(BiomeArray& biomes, int x, int z, int w, int h, bool useCache) const
|
||
{
|
||
IntCache::releaseAll();
|
||
//if (biomes == null || biomes.length < w * h)
|
||
if (biomes.data == nullptr || biomes.length < w * h)
|
||
{
|
||
if(biomes.data != nullptr) delete [] biomes.data;
|
||
biomes = BiomeArray(w * h);
|
||
}
|
||
|
||
if (useCache && w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||
{
|
||
BiomeArray tmp = cache->getBiomeBlockAt(x, z);
|
||
System::arraycopy(tmp, 0, &biomes, 0, w * h);
|
||
delete tmp.data; // MGH - added, the caching creates this array from the indices now.
|
||
//return biomes;
|
||
}
|
||
|
||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
biomes[i] = Biome::biomes[result[i]];
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
byteArray BiomeSource::getBiomeIndexBlock(int x, int z, int w, int h) const
|
||
{
|
||
if (w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||
{
|
||
return cache->getBiomeIndexBlockAt(x, z);
|
||
}
|
||
byteArray biomeIndices;
|
||
getBiomeIndexBlock(biomeIndices, x, z, w, h, true);
|
||
return biomeIndices;
|
||
}
|
||
|
||
// 4J - caller is responsible for deleting biomes array
|
||
void BiomeSource::getBiomeIndexBlock(byteArray& biomeIndices, int x, int z, int w, int h, bool useCache) const
|
||
{
|
||
IntCache::releaseAll();
|
||
//if (biomes == null || biomes.length < w * h)
|
||
if (biomeIndices.data == nullptr || biomeIndices.length < w * h)
|
||
{
|
||
if(biomeIndices.data != nullptr) delete [] biomeIndices.data;
|
||
biomeIndices = byteArray(w * h);
|
||
}
|
||
|
||
if (useCache && w == 16 && h == 16 && (x & 0xf) == 0 && (z & 0xf) == 0)
|
||
{
|
||
byteArray tmp = cache->getBiomeIndexBlockAt(x, z);
|
||
System::arraycopy(tmp, 0, &biomeIndices, 0, w * h);
|
||
//return biomes;
|
||
}
|
||
|
||
intArray result = zoomedLayer->getArea(x, z, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
biomeIndices[i] = static_cast<byte>(result[i]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Checks if an area around a block contains only the specified biomes.
|
||
* Useful for placing elements like towns.
|
||
*
|
||
* This is a bit of a rough check, to make it as fast as possible. To ensure
|
||
* NO other biomes, add a margin of at least four blocks to the radius
|
||
*/
|
||
bool BiomeSource::containsOnly(int x, int z, int r, vector<Biome *> allowed)
|
||
{
|
||
IntCache::releaseAll();
|
||
int x0 = ((x - r) >> 2);
|
||
int z0 = ((z - r) >> 2);
|
||
int x1 = ((x + r) >> 2);
|
||
int z1 = ((z + r) >> 2);
|
||
|
||
int w = x1 - x0 + 1;
|
||
int h = z1 - z0 + 1;
|
||
|
||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||
for (int i = 0; i < w * h; i++)
|
||
{
|
||
Biome *b = Biome::biomes[biomes[i]];
|
||
if (find(allowed.begin(), allowed.end(), b) == allowed.end()) return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Checks if an area around a block contains only the specified biome.
|
||
* Useful for placing elements like towns.
|
||
*
|
||
* This is a bit of a rough check, to make it as fast as possible. To ensure
|
||
* NO other biomes, add a margin of at least four blocks to the radius
|
||
*/
|
||
bool BiomeSource::containsOnly(int x, int z, int r, Biome *allowed)
|
||
{
|
||
IntCache::releaseAll();
|
||
int x0 = ((x - r) >> 2);
|
||
int z0 = ((z - r) >> 2);
|
||
int x1 = ((x + r) >> 2);
|
||
int z1 = ((z + r) >> 2);
|
||
|
||
int w = x1 - x0;
|
||
int h = z1 - z0;
|
||
int biomesCount = w*h;
|
||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||
for (unsigned int i = 0; i < biomesCount; i++)
|
||
{
|
||
Biome *b = Biome::biomes[biomes[i]];
|
||
if (allowed != b) return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Finds the specified biome within the radius. This will return a random
|
||
* position if several are found. This test is fairly rough.
|
||
*
|
||
* Returns null if the biome wasn't found
|
||
*/
|
||
TilePos *BiomeSource::findBiome(int x, int z, int r, Biome *toFind, Random *random)
|
||
{
|
||
IntCache::releaseAll();
|
||
int x0 = ((x - r) >> 2);
|
||
int z0 = ((z - r) >> 2);
|
||
int x1 = ((x + r) >> 2);
|
||
int z1 = ((z + r) >> 2);
|
||
|
||
int w = x1 - x0 + 1;
|
||
int h = z1 - z0 + 1;
|
||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||
TilePos *res = nullptr;
|
||
int found = 0;
|
||
int biomesCount = w*h;
|
||
for (unsigned int i = 0; i < biomesCount; i++)
|
||
{
|
||
int xx = x0 + i % w;
|
||
int zz = z0 + i / w;
|
||
Biome *b = Biome::biomes[biomes[i]];
|
||
if (b == toFind)
|
||
{
|
||
if (res == nullptr || random->nextInt(found + 1) == 0)
|
||
{
|
||
res = new TilePos(xx, 0, zz);
|
||
found++;
|
||
}
|
||
}
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* Finds one of the specified biomes within the radius. This will return a
|
||
* random position if several are found. This test is fairly rough.
|
||
*
|
||
* Returns null if the biome wasn't found
|
||
*/
|
||
TilePos *BiomeSource::findBiome(int x, int z, int r, vector<Biome *> allowed, Random *random)
|
||
{
|
||
IntCache::releaseAll();
|
||
int x0 = ((x - r) >> 2);
|
||
int z0 = ((z - r) >> 2);
|
||
int x1 = ((x + r) >> 2);
|
||
int z1 = ((z + r) >> 2);
|
||
|
||
int w = x1 - x0 + 1;
|
||
int h = z1 - z0 + 1;
|
||
MemSect(50);
|
||
intArray biomes = layer->getArea(x0, z0, w, h);
|
||
TilePos *res = nullptr;
|
||
int found = 0;
|
||
for (unsigned int i = 0; i < w * h; i++)
|
||
{
|
||
int xx = (x0 + i % w) << 2;
|
||
int zz = (z0 + i / w) << 2;
|
||
Biome *b = Biome::biomes[biomes[i]];
|
||
if (find(allowed.begin(), allowed.end(), b) != allowed.end())
|
||
{
|
||
if (res == nullptr || random->nextInt(found + 1) == 0)
|
||
{
|
||
delete res;
|
||
res = new TilePos(xx, 0, zz);
|
||
found++;
|
||
}
|
||
}
|
||
}
|
||
MemSect(0);
|
||
|
||
return res;
|
||
}
|
||
|
||
void BiomeSource::update()
|
||
{
|
||
cache->update();
|
||
}
|
||
|
||
//#define DEBUG_SEEDS 50
|
||
const int MAX_SEED_ATTEMPTS = 100;
|
||
|
||
// 4J added - find a seed for this biomesource that matches certain criteria
|
||
#ifdef __PSVITA__
|
||
int64_t 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
|
||
#else
|
||
int64_t BiomeSource::findSeed(LevelType *generator)
|
||
#endif
|
||
{
|
||
|
||
int64_t bestSeed = 0;
|
||
|
||
ProgressRenderer *mcprogress = Minecraft::GetInstance()->progressRenderer;
|
||
mcprogress->progressStage(IDS_PROGRESS_NEW_WORLD_SEED);
|
||
|
||
#if 0//ndef _CONTENT_PACKAGE
|
||
if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableBiomeOverride))
|
||
{
|
||
// Do nothing
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
#ifdef DEBUG_SEEDS
|
||
for( int k = 0; k < DEBUG_SEEDS; k++ )
|
||
#endif
|
||
{
|
||
// Try and genuinely random this search up
|
||
Random *pr = new Random(System::nanoTime());
|
||
|
||
// Raw biome data has one result per 4x4 group of tiles.
|
||
// 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
|
||
// in the edge region in case they later get removed
|
||
static const int biomeWidth = ( 64 * 2 ) - 16; // Should be even so we can offset evenly
|
||
static const int biomeOffset = -( biomeWidth / 2 );
|
||
|
||
// Storage for our biome indices
|
||
intArray indices = intArray( biomeWidth * biomeWidth );
|
||
|
||
// Storage for the fractional amounts of each biome that will be calculated
|
||
float toCompare[Biome::BIOME_COUNT];
|
||
|
||
bool matchFound = false;
|
||
int tryCount = 0;
|
||
|
||
// Just keeping trying to generate seeds until we find one that matches our criteria
|
||
do
|
||
{
|
||
int64_t seed = System::currentTimeMillis() ^ (tryCount << 32) ^ (int64_t)pr->nextLong();
|
||
BiomeSource *biomeSource = new BiomeSource(seed,generator);
|
||
|
||
biomeSource->getRawBiomeIndices(indices, biomeOffset, biomeOffset, biomeWidth, biomeWidth);
|
||
getFracs(indices, toCompare);
|
||
|
||
matchFound = getIsMatch( toCompare );
|
||
|
||
if( matchFound ) bestSeed = seed;
|
||
|
||
delete biomeSource;
|
||
tryCount++;
|
||
|
||
mcprogress->progressStagePercentage( tryCount % 100 );
|
||
#ifdef __PSVITA__
|
||
} while (!matchFound && *pServerRunning && tryCount < MAX_SEED_ATTEMPTS);
|
||
#else
|
||
} while (!matchFound && tryCount < MAX_SEED_ATTEMPTS);
|
||
#endif
|
||
|
||
// Clean up
|
||
delete pr;
|
||
delete indices.data;
|
||
|
||
#if 1//def DEBUG_SEEDS
|
||
//app.DebugPrintf("%d: %d tries taken, seed used is %lld\n", k, tryCount, bestSeed);
|
||
|
||
int size = 64 * 16;
|
||
|
||
BiomeSource *biomeSource = new BiomeSource(bestSeed, generator);
|
||
BiomeArray biomes = biomeSource->getBiomeBlock(-27 * 16, -27 * 16, size, size);
|
||
|
||
unsigned int *pixels = new unsigned int[size * size];
|
||
for(int i = 0; i < size * size; i++ )
|
||
{
|
||
int id = biomes[i]->id;
|
||
|
||
// Create following colours:
|
||
// 0 ocean 0000 black
|
||
// 1 plains 0001 pastel cyan
|
||
// 2 desert 0010 green
|
||
// 3 extreme hills 0011 yellow
|
||
// 4 forest 0100 blue
|
||
// 5 taiga 0101 magenta
|
||
// 6 swamps 0110 cyan
|
||
// 7 river 0111 white
|
||
// 8 hell 1000 grey
|
||
// 9 end biome 1001 white
|
||
// 10 frozen ocean 1010 pastel green
|
||
// 11 frozen river 1011 pastel yellow
|
||
// 12 ice flats 1100 pastel blue
|
||
// 13 ice mountains 1101 pastel magenta
|
||
// 14 mushroom island 1110 red
|
||
// 15 mushroom shore 1111 pastel red
|
||
|
||
if( id == 1 ) id = 14;
|
||
else if ( id == 14 ) id = 1;
|
||
else if( id == 9 ) id = 15;
|
||
else if( id == 15 ) id = 9;
|
||
pixels[i] = 0xff000000;
|
||
if( id & 1 ) pixels[i] |= 0x00ff0000;
|
||
if( id & 2 ) pixels[i] |= 0x0000ff00;
|
||
if( id & 4 ) pixels[i] |= 0x000000ff;
|
||
if( id & 8 ) pixels[i] |= 0x00808080;
|
||
}
|
||
D3DXIMAGE_INFO srcInfo;
|
||
//srcInfo.Format = D3DFMT_LIN_A8R8G8B8;
|
||
//srcInfo.ImageFileFormat = D3DXIFF_BMP;
|
||
srcInfo.Width = size;
|
||
srcInfo.Height = size;
|
||
|
||
char buf[256];
|
||
sprintf(buf,"GAME:\\BiomeTest%d.bmp", bestSeed);
|
||
RenderManager.SaveTextureData(buf, &srcInfo, (int *)pixels);
|
||
|
||
delete [] pixels;
|
||
delete biomes.data;
|
||
delete biomeSource;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return bestSeed;
|
||
}
|
||
|
||
// 4J added - get the fractional amounts of each biome type in the given indices
|
||
void BiomeSource::getFracs(intArray indices, float *fracs)
|
||
{
|
||
for( int i = 0; i < Biome::BIOME_COUNT; i++ )
|
||
{
|
||
fracs[i] = 0.0f;
|
||
}
|
||
|
||
for( int i = 0; i < indices.length; i++ )
|
||
{
|
||
fracs[indices[i]] += 1.0f;
|
||
}
|
||
|
||
for( int i = 0; i < Biome::BIOME_COUNT; i++ )
|
||
{
|
||
fracs[i] /= static_cast<float>(indices.length);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// 4J added - determine if this particular set of fractional amounts of biome types matches are requirements
|
||
bool BiomeSource::getIsMatch(float* frac)
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> 50%
|
||
if (frac[0] > 0.5f) return false;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
//static const int required[] = { 1, 2, 4, 5 }; // plains, desert, forest, taiga
|
||
//for (int i : required) {
|
||
// if (frac[i] < 0.01f) return false;
|
||
//}
|
||
|
||
int typeCount = 0;
|
||
for (int i = 0; i < Biome::BIOME_COUNT; i++) {
|
||
if (i == 15 || i == 17 || i == 18 || i == 19 || i == 22) continue;
|
||
if (frac[i] > 0.001f) typeCount++;
|
||
}
|
||
return typeCount >= 6;
|
||
}
|