forked from Kolyah35/minecraft-pe-0.6.1
Restored Java's Debug Screen using partial unused code and ported code, avaliable in options menu as a style Slight Water texture is now overlayed when in water Vignette function has been fixed and can now be toggled in options World Generation now includes Tall Grass and Ferns both Broken Frame Chart Graph found in the source has now been fixed and enabled when debug screen is turned on Pie Chart works now and will appear when debug screen is opened Most changes have not been tested on anything besides windows, will test it
778 lines
24 KiB
C++
Executable File
778 lines
24 KiB
C++
Executable File
#include "RandomLevelSource.h"
|
|
|
|
#include "feature/FeatureInclude.h"
|
|
#include "../Level.h"
|
|
#include "../ChunkPos.h"
|
|
#include "../MobSpawner.h"
|
|
#include "../biome/Biome.h"
|
|
#include "../biome/BiomeSource.h"
|
|
#include "../chunk/LevelChunk.h"
|
|
#include "../material/Material.h"
|
|
#include "../tile/Tile.h"
|
|
#include "../tile/HeavyTile.h"
|
|
#include "../../../util/Random.h"
|
|
#include "../../level/tile/TallGrass.h"
|
|
|
|
const float RandomLevelSource::SNOW_CUTOFF = 0.5f;
|
|
const float RandomLevelSource::SNOW_SCALE = 0.3f;
|
|
static const int MAX_BUFFER_SIZE = 1024;
|
|
|
|
RandomLevelSource::RandomLevelSource(Level* level, long seed, int version, bool spawnMobs)
|
|
: random(seed),
|
|
level(level),
|
|
lperlinNoise1(&random, 16),
|
|
lperlinNoise2(&random, 16),
|
|
perlinNoise1(&random, 8),
|
|
perlinNoise2(&random, 4),
|
|
perlinNoise3(&random, 4),
|
|
scaleNoise(&random, 10),
|
|
depthNoise(&random, 16),
|
|
forestNoise(&random, 8),
|
|
spawnMobs(spawnMobs),
|
|
pnr(NULL), ar(NULL), br(NULL), sr(NULL), dr(NULL), fi(NULL), fis(NULL)
|
|
//biomes(NULL)
|
|
{
|
|
for (int i=0; i<32; ++i)
|
|
for (int j=0; j<32; ++j)
|
|
waterDepths[i][j] = 0;
|
|
|
|
buffer = new float[MAX_BUFFER_SIZE];
|
|
|
|
Random randomCopy = random;
|
|
printf("random.get : %d\n", randomCopy.nextInt());
|
|
}
|
|
|
|
RandomLevelSource::~RandomLevelSource() {
|
|
|
|
// chunks are deleted in the chunk cache instead
|
|
//ChunkMap::iterator it = chunkMap.begin();
|
|
//while (it != chunkMap.end()) {
|
|
// it->second->deleteBlockData(); //@attn: we delete the block data here, for now
|
|
// delete it->second;
|
|
// ++it;
|
|
//}
|
|
|
|
delete[] buffer;
|
|
delete[] pnr;
|
|
delete[] ar;
|
|
delete[] br;
|
|
delete[] sr;
|
|
delete[] dr;
|
|
delete[] fi;
|
|
delete[] fis;
|
|
}
|
|
|
|
/*public*/
|
|
void RandomLevelSource::prepareHeights(int xOffs, int zOffs, unsigned char* blocks, /*Biome*/void* biomes, float* temperatures) {
|
|
|
|
int xChunks = 16 / CHUNK_WIDTH;
|
|
int waterHeight = Level::DEPTH - 64;
|
|
|
|
int xSize = xChunks + 1;
|
|
int ySize = 128 / CHUNK_HEIGHT + 1;
|
|
int zSize = xChunks + 1;
|
|
buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize);
|
|
|
|
for (int xc = 0; xc < xChunks; xc++) {
|
|
for (int zc = 0; zc < xChunks; zc++) {
|
|
for (int yc = 0; yc < 128 / CHUNK_HEIGHT; yc++) {
|
|
float yStep = 1 / (float) CHUNK_HEIGHT;
|
|
float s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)];
|
|
float s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)];
|
|
float s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)];
|
|
float s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)];
|
|
|
|
float s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep;
|
|
float s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep;
|
|
float s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep;
|
|
float s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep;
|
|
|
|
for (int y = 0; y < CHUNK_HEIGHT; y++) {
|
|
float xStep = 1 / (float) CHUNK_WIDTH;
|
|
|
|
float _s0 = s0;
|
|
float _s1 = s1;
|
|
float _s0a = (s2 - s0) * xStep;
|
|
float _s1a = (s3 - s1) * xStep;
|
|
|
|
for (int x = 0; x < CHUNK_WIDTH; x++) {
|
|
int offs = (x + xc * CHUNK_WIDTH) << 11 | (0 + zc * CHUNK_WIDTH) << 7 | (yc * CHUNK_HEIGHT + y);
|
|
int step = 1 << 7;
|
|
float zStep = 1 / (float) CHUNK_WIDTH;
|
|
|
|
float val = _s0;
|
|
float vala = (_s1 - _s0) * zStep;
|
|
for (int z = 0; z < CHUNK_WIDTH; z++) {
|
|
// + (zc * CHUNK_WIDTH + z)];
|
|
float temp = temperatures[(xc * CHUNK_WIDTH + x) * 16 + (zc * CHUNK_WIDTH + z)];
|
|
int tileId = 0;
|
|
if (yc * CHUNK_HEIGHT + y < waterHeight) {
|
|
if (temp < SNOW_CUTOFF && yc * CHUNK_HEIGHT + y >= waterHeight - 1) {
|
|
tileId = Tile::ice->id;
|
|
} else {
|
|
tileId = Tile::calmWater->id;
|
|
}
|
|
}
|
|
if (val > 0) {
|
|
tileId = Tile::rock->id;
|
|
} else {
|
|
}
|
|
|
|
blocks[offs] = (unsigned char) tileId;
|
|
offs += step;
|
|
val += vala;
|
|
}
|
|
_s0 += _s0a;
|
|
_s1 += _s1a;
|
|
}
|
|
|
|
s0 += s0a;
|
|
s1 += s1a;
|
|
s2 += s2a;
|
|
s3 += s3a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, unsigned char* blocks, Biome** biomes) {
|
|
int waterHeight = Level::DEPTH - 64;
|
|
|
|
float s = 1 / 32.0f;
|
|
perlinNoise2.getRegion(sandBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s, s, 1);
|
|
perlinNoise2.getRegion(gravelBuffer, (float)(xOffs * 16), 109.01340f, (float)(zOffs * 16), 16, 1, 16, s, 1, s);
|
|
perlinNoise3.getRegion(depthBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s * 2, s * 2, s * 2);
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
for (int z = 0; z < 16; z++) {
|
|
float temp = 1; // @todo: read temp from BiomeSource
|
|
Biome* b = biomes[x + z * 16];
|
|
bool sand = (sandBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 0;
|
|
bool gravel = (gravelBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 3;
|
|
int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random.nextFloat() * 0.25f);
|
|
|
|
int run = -1;
|
|
|
|
char top = b->topMaterial;
|
|
char material = b->material;
|
|
|
|
for (int y = 127; y >= 0; y--) {
|
|
int offs = (z * 16 + x) * 128 + y;
|
|
|
|
if (y <= 0 + random.nextInt(5)) {
|
|
blocks[offs] = (char) Tile::unbreakable->id;
|
|
} else {
|
|
int old = blocks[offs];
|
|
|
|
if (old == 0) {
|
|
run = -1;
|
|
} else if (old == Tile::rock->id) {
|
|
if (run == -1) {
|
|
if (runDepth <= 0) {
|
|
top = 0;
|
|
material = (char) Tile::rock->id;
|
|
} else if (y >= waterHeight - 4 && y <= waterHeight + 1) {
|
|
top = b->topMaterial;
|
|
material = b->material;
|
|
|
|
//@attn: ?
|
|
if (gravel) {
|
|
top = 0;
|
|
material = (char) Tile::gravel->id;
|
|
}
|
|
if (sand) {
|
|
top = (char) Tile::sand->id;
|
|
material = (char) Tile::sand->id;
|
|
}
|
|
}
|
|
|
|
if (y < waterHeight && top == 0) {
|
|
if (temp < 0.15f)
|
|
top = (char) Tile::ice->id;
|
|
else
|
|
top = (char) Tile::calmWater->id;
|
|
}
|
|
|
|
run = runDepth;
|
|
if (y >= waterHeight - 1) blocks[offs] = top;
|
|
else blocks[offs] = material;
|
|
} else if (run > 0) {
|
|
run--;
|
|
blocks[offs] = material;
|
|
|
|
// place a few sandstone blocks beneath sand
|
|
// runs
|
|
if (run == 0 && material == Tile::sand->id) {
|
|
run = random.nextInt(4);
|
|
material = (char) Tile::sandStone->id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*public*/
|
|
void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) {
|
|
|
|
level->isGeneratingTerrain = true;
|
|
|
|
HeavyTile::instaFall = true;
|
|
int xo = xt * 16;
|
|
int zo = zt * 16;
|
|
|
|
Biome* biome = level->getBiomeSource()->getBiome(xo + 16, zo + 16);
|
|
// Biome* biome = Biome::forest;
|
|
|
|
random.setSeed(level->getSeed());
|
|
int xScale = random.nextInt() / 2 * 2 + 1;
|
|
int zScale = random.nextInt() / 2 * 2 + 1;
|
|
random.setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed());
|
|
|
|
|
|
// @todo - add generation options to enable or disable extra features like lava lakes or water lakes as they affect seed parity with the original vanilla game - shredder
|
|
|
|
// //@todo: hide those chunks if they are aren't visible
|
|
if (random.nextInt(4) == 0) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
LakeFeature feature(Tile::calmWater->id);
|
|
feature.place(level, &random, x, y, z);
|
|
// LOGI("Adding underground lake @ (%d,%d,%d)\n", x, y, z);
|
|
}
|
|
|
|
////@todo: hide those chunks if they are aren't visible
|
|
if (random.nextInt(8) == 0) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(random.nextInt(120) + 8);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
if (y < 64 || random.nextInt(10) == 0) {
|
|
LakeFeature feature(Tile::calmLava->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
}
|
|
|
|
static float totalTime = 0;
|
|
const float st = getTimeS();
|
|
|
|
//for (int i = 0; i < 8; i++) {
|
|
// int x = xo + random.nextInt(16) + 8;
|
|
// int y = random.nextInt(128);
|
|
// int z = zo + random.nextInt(16) + 8;
|
|
// MonsterRoomFeature().place(level, random, x, y, z);
|
|
//}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16);
|
|
ClayFeature feature(32);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::dirt->id, 32);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::gravel->id, 32);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
// @todo - add generation options to enable or disable adjusted ore spawn rates as they affect seed parity with the original vanilla game - shredder
|
|
|
|
// Coal: common, wide Y range, moderate vein size
|
|
for (int i = 0; i < 16; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::coalOre->id, 14);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
// Iron: common, limited to upper underground
|
|
for (int i = 0; i < 14; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(64);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::ironOre->id, 10);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
// Gold: rarer and deeper
|
|
for (int i = 0; i < 2; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(32);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::goldOre->id, 9);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
// Redstone: somewhat common at low depths
|
|
for (int i = 0; i < 6; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(16);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::redStoneOre->id, 8);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
// Emerald (diamond-equivalent): still rare but slightly more than vanilla
|
|
for (int i = 0; i < 3; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(16);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::emeraldOre->id, 6);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
// Lapis: rare and not in very high Y
|
|
for (int i = 0; i < 1; i++) {
|
|
int x = xo + random.nextInt(16);
|
|
int y = random.nextInt(16) + random.nextInt(16);
|
|
int z = zo + random.nextInt(16);
|
|
OreFeature feature(Tile::lapisOre->id, 6);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
const float ss = 0.5f;
|
|
int oFor = (int) ((forestNoise.getValue(xo * ss, zo * ss) / 8 + random.nextFloat() * 4 + 4) / 3);
|
|
int forests = 0;//1; (java: 0)
|
|
if (random.nextInt(10) == 0) forests += 1;
|
|
|
|
if (biome == Biome::forest) forests += oFor + 2; // + 5
|
|
if (biome == Biome::rainForest) forests += oFor + 2; //+ 5
|
|
if (biome == Biome::seasonalForest) forests += oFor + 1; // 2
|
|
if (biome == Biome::taiga) {
|
|
forests += oFor + 1; // + 5
|
|
//LOGI("Biome is taiga!\n");
|
|
}
|
|
|
|
if (biome == Biome::desert) forests -= 20;
|
|
if (biome == Biome::tundra) forests -= 20;
|
|
if (biome == Biome::plains) forests -= 20;
|
|
|
|
for (int i = 0; i < forests; i++) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int z = zo + random.nextInt(16) + 8;
|
|
int y = level->getHeightmap(x, z);
|
|
Feature* tree = biome->getTreeFeature(&random);
|
|
if (tree) {
|
|
tree->init(1, 1, 1);
|
|
tree->place(level, &random, x, y, z);
|
|
delete tree;
|
|
}
|
|
//printf("placing tree at %d, %d, %d\n", x, y, z);
|
|
}
|
|
// for (int i = 0; i < forests; i++) {
|
|
// int x = xo + random.nextInt(16) + 8;
|
|
// int z = zo + random.nextInt(16) + 8;
|
|
//int y = level->getHeightmap(x, z);
|
|
// Feature* tree = biome->getBasicTreeFeature(&random);
|
|
//if (tree) {
|
|
// tree->init(1, 1, 1);
|
|
// tree->place(level, &random, x, y, z);
|
|
// delete tree;
|
|
//}
|
|
////printf("placing tree at %d, %d, %d\n", x, y, z);
|
|
// }
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
FlowerFeature feature(Tile::flower->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
if (random.nextInt(2) == 0) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
FlowerFeature feature(Tile::rose->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
if (random.nextInt(4) == 0) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
FlowerFeature feature(Tile::mushroom1->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
if (random.nextInt(8) == 0) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
FlowerFeature feature(Tile::mushroom2->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
// normally unused in mcpe but how its supposed to do it
|
|
//int grassCount = 1;
|
|
//for (int i = 0; i < grassCount; i++) {
|
|
//int x = xo + random.nextInt(16) + 8;
|
|
//int y = random.nextInt(Level::genDepth);
|
|
//int z = zo + random.nextInt(16) + 8;
|
|
//Feature* grassFeature = biome->getGrassFeature(&random);
|
|
//if (grassFeature) {
|
|
//grassFeature->place(level, &random, x, y, z);
|
|
//delete grassFeature;
|
|
//}
|
|
//}
|
|
|
|
// reworked code from above to generate ferns and shrubs to just like in beta java
|
|
int grassCount = 0;
|
|
|
|
if (biome == Biome::forest) { grassCount = 2; }
|
|
else if (biome == Biome::rainForest) { grassCount = 10; }
|
|
else if (biome == Biome::seasonalForest) { grassCount = 2; }
|
|
else if (biome == Biome::taiga) { grassCount = 1; }
|
|
else if (biome == Biome::plains) { grassCount = 10; }
|
|
|
|
for (int i = 0; i < grassCount; i++) {
|
|
int grassMetadata = TallGrass::TALL_GRASS;
|
|
|
|
|
|
if (biome == Biome::rainForest && random.nextInt(3) != 0) {
|
|
grassMetadata = TallGrass::FERN;
|
|
}
|
|
|
|
int x = xo + random.nextInt(16) + 8;
|
|
|
|
int z = zo + random.nextInt(16) + 8;
|
|
int y = level->getHeightmap(x, z);
|
|
|
|
TallgrassFeature grassFeature(Tile::tallgrass->id, grassMetadata);
|
|
grassFeature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
ReedsFeature feature;
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
|
|
//if (random.nextInt(32) == 0) {
|
|
// int x = xo + random.nextInt(16) + 8;
|
|
// int y = random.nextInt(128);
|
|
// int z = zo + random.nextInt(16) + 8;
|
|
// PumpkinFeature().place(level, random, x, y, z);
|
|
//}
|
|
|
|
int cacti = 0;
|
|
if (biome == Biome::desert) cacti += 5;
|
|
|
|
for (int i = 0; i < cacti; i++) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(128);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
CactusFeature feature;
|
|
//LOGI("Tried creating a cactus at %d, %d, %d\n", x, y, z);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
for (int i = 0; i < 50; i++) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(random.nextInt(120) + 8);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
SpringFeature feature(Tile::water->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
int x = xo + random.nextInt(16) + 8;
|
|
int y = random.nextInt(random.nextInt(random.nextInt(112) + 8) + 8);
|
|
int z = zo + random.nextInt(16) + 8;
|
|
SpringFeature feature(Tile::lava->id);
|
|
feature.place(level, &random, x, y, z);
|
|
}
|
|
|
|
if (spawnMobs && !level->isClientSide)
|
|
MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, &random);
|
|
|
|
//LOGI("Reading temp: 1\n");
|
|
float* temperatures = level->getBiomeSource()->getTemperatureBlock(NULL, xo + 8, zo + 8, 16, 16);
|
|
for (int x = xo + 8; x < xo + 8 + 16; x++)
|
|
for (int z = zo + 8; z < zo + 8 + 16; z++) {
|
|
int xp = x - (xo + 8);
|
|
int zp = z - (zo + 8);
|
|
int y = level->getTopSolidBlock(x, z);
|
|
float temp = temperatures[xp * 16 + zp] - (y - 64) / 64.0f * SNOW_SCALE;
|
|
if (temp < SNOW_CUTOFF) {
|
|
if (y > 0 && y < 128 && level->isEmptyTile(x, y, z) && level->getMaterial(x, y - 1, z)->blocksMotion()) {
|
|
if (level->getMaterial(x, y - 1, z) != Material::ice) level->setTile(x, y, z, Tile::topSnow->id);
|
|
}
|
|
}
|
|
}
|
|
//LOGI("Reading temp: 0 END\n");
|
|
|
|
const float et = getTimeS();
|
|
totalTime += (et-st);
|
|
|
|
//printf("Time to place features: %f. Total %f\n", et - st, totalTime);
|
|
|
|
HeavyTile::instaFall = false;
|
|
|
|
level->isGeneratingTerrain = false;
|
|
}
|
|
|
|
LevelChunk* RandomLevelSource::create(int x, int z) {
|
|
return getChunk(x, z);
|
|
}
|
|
|
|
LevelChunk* RandomLevelSource::getChunk(int xOffs, int zOffs) {
|
|
//static int chunkx = 0;
|
|
int hashedPos = ChunkPos::hashCode(xOffs, zOffs);
|
|
|
|
ChunkMap::iterator it = chunkMap.find(hashedPos);
|
|
if (it != chunkMap.end())
|
|
return it->second;
|
|
|
|
random.setSeed((long)(xOffs * 341872712l + zOffs * 132899541l)); //@fix
|
|
|
|
unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount];
|
|
LevelChunk* levelChunk = new LevelChunk(level, blocks, xOffs, zOffs);
|
|
chunkMap.insert(std::make_pair(hashedPos, levelChunk));
|
|
|
|
Biome** biomes = level->getBiomeSource()->getBiomeBlock(/*biomes, */xOffs * 16, zOffs * 16, 16, 16);
|
|
float* temperatures = level->getBiomeSource()->temperatures;
|
|
prepareHeights(xOffs, zOffs, blocks, 0, temperatures);//biomes, temperatures);
|
|
buildSurfaces(xOffs, zOffs, blocks, biomes);
|
|
|
|
// Carve caves into the chunk
|
|
caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
|
|
canyonFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
|
|
levelChunk->recalcHeightmap();
|
|
|
|
return levelChunk;
|
|
}
|
|
|
|
/*private*/
|
|
float* RandomLevelSource::getHeights(float* buffer, int x, int y, int z, int xSize, int ySize, int zSize) {
|
|
const int size = xSize * ySize * zSize;
|
|
if (size > MAX_BUFFER_SIZE) {
|
|
LOGI("RandomLevelSource::getHeights: TOO LARGE BUFFER REQUESTED: %d (max %d)\n", size, MAX_BUFFER_SIZE);
|
|
}
|
|
|
|
float s = 1 * 684.412f;
|
|
float hs = 1 * 684.412f;
|
|
|
|
float* temperatures = level->getBiomeSource()->temperatures;
|
|
float* downfalls = level->getBiomeSource()->downfalls;
|
|
sr = scaleNoise.getRegion(sr, x, z, xSize, zSize, 1.121f, 1.121f, 0.5f);
|
|
dr = depthNoise.getRegion(dr, x, z, xSize, zSize, 200.0f, 200.0f, 0.5f);
|
|
|
|
pnr = perlinNoise1.getRegion(pnr, (float)x, (float)y, (float)z, xSize, ySize, zSize, s / 80.0f, hs / 160.0f, s / 80.0f);
|
|
ar = lperlinNoise1.getRegion(ar, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s);
|
|
br = lperlinNoise2.getRegion(br, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s);
|
|
|
|
int p = 0;
|
|
int pp = 0;
|
|
|
|
int wScale = 16 / xSize;
|
|
for (int xx = 0; xx < xSize; xx++) {
|
|
int xp = xx * wScale + wScale / 2;
|
|
|
|
for (int zz = 0; zz < zSize; zz++) {
|
|
int zp = zz * wScale + wScale / 2;
|
|
float temperature = temperatures[xp * 16 + zp];
|
|
float downfall = downfalls[xp * 16 + zp] * temperature;
|
|
float dd = 1 - downfall;
|
|
dd = dd * dd;
|
|
dd = dd * dd;
|
|
dd = 1 - dd;
|
|
|
|
float scale = ((sr[pp] + 256.0f) / 512);
|
|
scale *= dd;
|
|
if (scale > 1) scale = 1;
|
|
|
|
|
|
float depth = (dr[pp] / 8000.0f);
|
|
if (depth < 0) depth = -depth * 0.3f;
|
|
depth = depth * 3.0f - 2.0f;
|
|
|
|
if (depth < 0) {
|
|
depth = depth / 2;
|
|
if (depth < -1) depth = -1;
|
|
depth = depth / 1.4f;
|
|
depth /= 2;
|
|
scale = 0;
|
|
} else {
|
|
if (depth > 1) depth = 1;
|
|
depth = depth / 8;
|
|
}
|
|
|
|
if (scale < 0) scale = 0;
|
|
scale = (scale) + 0.5f;
|
|
depth = depth * ySize / 16;
|
|
|
|
float yCenter = ySize / 2.0f + depth * 4;
|
|
|
|
pp++;
|
|
|
|
for (int yy = 0; yy < ySize; yy++) {
|
|
float val = 0;
|
|
|
|
float yOffs = (yy - (yCenter)) * 12 / scale;
|
|
if (yOffs < 0) yOffs *= 4;
|
|
|
|
float bb = ar[p] / 512;
|
|
float cc = br[p] / 512;
|
|
|
|
float v = (pnr[p] / 10 + 1) / 2;
|
|
if (v < 0) val = bb;
|
|
else if (v > 1) val = cc;
|
|
else val = bb + (cc - bb) * v;
|
|
val -= yOffs;
|
|
|
|
if (yy > ySize - 4) {
|
|
float slide = (yy - (ySize - 4)) / (4 - 1.0f);
|
|
val = val * (1 - slide) + -10 * slide;
|
|
}
|
|
|
|
buffer[p] = val;
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
/*private*/
|
|
void RandomLevelSource::calcWaterDepths(ChunkSource* parent, int xt, int zt) {
|
|
int xo = xt * 16;
|
|
int zo = zt * 16;
|
|
for (int x = 0; x < 16; x++) {
|
|
int y = level->getSeaLevel();
|
|
for (int z = 0; z < 16; z++) {
|
|
int xp = xo + x + 7;
|
|
int zp = zo + z + 7;
|
|
int h = level->getHeightmap(xp, zp);
|
|
if (h <= 0) {
|
|
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) {
|
|
bool hadWater = false;
|
|
if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater->id && level->getData(xp - 1, y, zp) < 7)) hadWater = true;
|
|
if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater->id && level->getData(xp + 1, y, zp) < 7)) hadWater = true;
|
|
if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater->id && level->getData(xp, y, zp - 1) < 7)) hadWater = true;
|
|
if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater->id && level->getData(xp, y, zp + 1) < 7)) hadWater = true;
|
|
if (hadWater) {
|
|
for (int x2 = -5; x2 <= 5; x2++) {
|
|
for (int z2 = -5; z2 <= 5; z2++) {
|
|
int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2);
|
|
|
|
if (d <= 5) {
|
|
d = 6 - d;
|
|
if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater->id) {
|
|
int od = level->getData(xp + x2, y, zp + z2);
|
|
if (od < 7 && od < d) {
|
|
level->setData(xp + x2, y, zp + z2, d);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hadWater) {
|
|
level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater->id, 7);
|
|
for (int y2 = 0; y2 < y; y2++) {
|
|
level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater->id, 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RandomLevelSource::hasChunk(int x, int y) {
|
|
//return x >= 0 && x < 16 && y >= 0 && y < 16;
|
|
return true;
|
|
}
|
|
|
|
bool RandomLevelSource::tick() {
|
|
return false;
|
|
}
|
|
|
|
bool RandomLevelSource::shouldSave() {
|
|
return true;
|
|
}
|
|
|
|
std::string RandomLevelSource::gatherStats() {
|
|
return "RandomLevelSource";
|
|
}
|
|
|
|
//bool RandomLevelSource::save(bool force, ProgressListener progressListener) {
|
|
// return true;
|
|
//}
|
|
|
|
Biome::MobList RandomLevelSource::getMobsAt(const MobCategory& mobCategory, int x, int y, int z) {
|
|
BiomeSource* biomeSource = level->getBiomeSource();
|
|
if (biomeSource == NULL) {
|
|
return Biome::MobList();
|
|
}
|
|
// static Stopwatch sw; sw.start();
|
|
Biome* biome = biomeSource->getBiome(x, z);
|
|
// sw.stop();
|
|
// sw.printEvery(10, "getBiome::");
|
|
if (biome == NULL) {
|
|
return Biome::MobList();
|
|
}
|
|
return biome->getMobs(mobCategory);
|
|
}
|
|
|
|
|
|
LevelChunk* PerformanceTestChunkSource::create(int x, int z)
|
|
{
|
|
unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount];
|
|
memset(blocks, 0, LevelChunk::ChunkBlockCount);
|
|
|
|
for (int y = 0; y < 65; y++)
|
|
{
|
|
if (y < 60)
|
|
{
|
|
for (int x = (y + 1) & 1; x < 16; x += 2)
|
|
{
|
|
for (int z = y & 1; z < 16; z += 2)
|
|
{
|
|
blocks[x << 11 | z << 7 | y] = 3;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int x = 0; x < 16; x += 2)
|
|
{
|
|
for (int z = 0; z < 16; z += 2)
|
|
{
|
|
blocks[x << 11 | z << 7 | y] = 3;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
LevelChunk* levelChunk = new LevelChunk(level, blocks, x, z);
|
|
|
|
//caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
|
|
levelChunk->recalcHeightmap();
|
|
|
|
return levelChunk;
|
|
}
|