#include "DefaultWorldGenerator.hpp" #include "Block.hpp" #include "Chunk.hpp" #include "voxel.hpp" #define FNL_IMPL #include #include #include #include #include #include #include #include #include #include #include #include // will be refactored in generators update const int SEA_LEVEL = 55; enum class MAPS { SAND, TREE, CLIFF, HEIGHT }; #define MAPS_LEN 4 class Map2D { int x, z; int w, d; float* heights[MAPS_LEN]; public: Map2D(int x, int z, int w, int d) : x(x), z(z), w(w), d(d) { for (int i = 0; i < MAPS_LEN; i++) heights[i] = new float[w * d]; } ~Map2D() { for (int i = 0; i < MAPS_LEN; i++) delete[] heights[i]; } inline float get(MAPS map, int x, int z) { x -= this->x; z -= this->z; if (x < 0 || z < 0 || x >= w || z >= d) { throw std::runtime_error("out of heightmap"); } return heights[(int)map][z * w + x]; } inline void set(MAPS map, int x, int z, float value) { x -= this->x; z -= this->z; if (x < 0 || z < 0 || x >= w || z >= d) { throw std::runtime_error("out of heightmap"); } heights[(int)map][z * w + x] = value; } }; float calc_height(fnl_state* noise, int cur_x, int cur_z) { float height = 0; height += fnlGetNoise2D( noise, cur_x * 0.0125f * 8 - 125567, cur_z * 0.0125f * 8 + 3546 ); height += fnlGetNoise2D( noise, cur_x * 0.025f * 8 + 4647, cur_z * 0.025f * 8 - 3436 ) * 0.5f; height += fnlGetNoise2D( noise, cur_x * 0.05f * 8 - 834176, cur_z * 0.05f * 8 + 23678 ) * 0.25f; height += fnlGetNoise2D( noise, cur_x * 0.2f * 8 + fnlGetNoise2D( noise, cur_x * 0.1f * 8 - 23557, cur_z * 0.1f * 8 - 6568 ) * 50, cur_z * 0.2f * 8 + fnlGetNoise2D( noise, cur_x * 0.1f * 8 + 4363, cur_z * 0.1f * 8 + 4456 ) * 50 ) * fnlGetNoise2D(noise, cur_x * 0.01f - 834176, cur_z * 0.01f + 23678) * 0.25; height += fnlGetNoise2D(noise, cur_x * 0.1f * 8 - 3465, cur_z * 0.1f * 8 + 4534) * 0.125f; height *= fnlGetNoise2D(noise, cur_x * 0.1f + 1000, cur_z * 0.1f + 1000) * 0.5f + 0.5f; height += 1.0f; height *= 64.0f; return height; } int generate_tree( fnl_state* noise, PseudoRandom* random, Map2D& heights, // Map2D& humidity, int cur_x, int cur_y, int cur_z, int tileSize, blockid_t idWood, blockid_t idLeaves ) { const int tileX = floordiv(cur_x, tileSize); const int tileZ = floordiv(cur_z, tileSize); random->setSeed(tileX * 4325261 + tileZ * 12160951 + tileSize * 9431111); int randomX = (random->rand() % (tileSize / 2)) - tileSize / 4; int randomZ = (random->rand() % (tileSize / 2)) - tileSize / 4; int centerX = tileX * tileSize + tileSize / 2 + randomX; int centerZ = tileZ * tileSize + tileSize / 2 + randomZ; bool gentree = (random->rand() % 10) < heights.get(MAPS::TREE, centerX, centerZ) * 13; if (!gentree) return 0; int height = (int)(heights.get(MAPS::HEIGHT, centerX, centerZ)); if (height < SEA_LEVEL + 1) return 0; int lx = cur_x - centerX; int radius = random->rand() % 4 + 2; int ly = cur_y - height - 3 * radius; int lz = cur_z - centerZ; if (lx == 0 && lz == 0 && cur_y - height < (3 * radius + radius / 2)) return idWood; if (lx * lx + ly * ly / 2 + lz * lz < radius * radius) return idLeaves; return 0; } void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed) { const int treesTile = 12; fnl_state noise = fnlCreateState(); noise.noise_type = FNL_NOISE_OPENSIMPLEX2; noise.seed = seed * 60617077 % 25896307; PseudoRandom randomtree; PseudoRandom randomgrass; int padding = 8; Map2D heights( cx * CHUNK_W - padding, cz * CHUNK_D - padding, CHUNK_W + padding * 2, CHUNK_D + padding * 2 ); for (int z = -padding; z < CHUNK_D + padding; z++) { for (int x = -padding; x < CHUNK_W + padding; x++) { int cur_x = x + cx * CHUNK_W; int cur_z = z + cz * CHUNK_D; float height = calc_height(&noise, cur_x, cur_z); float hum = fnlGetNoise2D(&noise, cur_x * 0.3 + 633, cur_z * 0.3); float sand = fnlGetNoise2D(&noise, cur_x * 0.1 - 633, cur_z * 0.1 + 1000); float cliff = pow((sand + abs(sand)) / 2, 2); float w = pow(fmax(-abs(height - SEA_LEVEL) + 4, 0) / 6, 2) * cliff; float h1 = -abs(height - SEA_LEVEL - 0.03); float h2 = abs(height - SEA_LEVEL + 0.04); float h = (h1 + h2) * 100; height += (h * w); heights.set(MAPS::HEIGHT, cur_x, cur_z, height); heights.set(MAPS::TREE, cur_x, cur_z, hum); heights.set(MAPS::SAND, cur_x, cur_z, sand); heights.set(MAPS::CLIFF, cur_x, cur_z, cliff); } } for (int z = 0; z < CHUNK_D; z++) { int cur_z = z + cz * CHUNK_D; for (int x = 0; x < CHUNK_W; x++) { int cur_x = x + cx * CHUNK_W; float height = heights.get(MAPS::HEIGHT, cur_x, cur_z); for (int cur_y = 0; cur_y < CHUNK_H; cur_y++) { // int cur_y = y; int id = cur_y < SEA_LEVEL ? idWater : BLOCK_AIR; blockstate state {}; if ((cur_y == (int)height) && (SEA_LEVEL - 2 < cur_y)) { id = idGrassBlock; } else if (cur_y < (height - 6)) { id = idStone; } else if (cur_y < height) { id = idDirt; } else { int tree = generate_tree( &noise, &randomtree, heights, cur_x, cur_y, cur_z, treesTile, idWood, idLeaves ); if (tree) { id = tree; state.rotation = BLOCK_DIR_UP; } } float sand = fmax( heights.get(MAPS::SAND, cur_x, cur_z), heights.get(MAPS::CLIFF, cur_x, cur_z) ); if (((height - (1.1 - 0.2 * pow(height - 54, 4)) + (5 * sand)) < cur_y + (height - 0.01 - (int)height)) && (cur_y < height)) { id = idSand; } if (cur_y <= 2) id = idBazalt; randomgrass.setSeed(cur_x, cur_z); if ((id == 0) && ((height > SEA_LEVEL + 0.4) || (sand > 0.1)) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 56000)) { id = idGrass; } if ((id == 0) && (height > SEA_LEVEL + 0.4) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 65000)) { id = idFlower; } if ((height > SEA_LEVEL + 1) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 65533)) { id = idWood; state.rotation = BLOCK_DIR_UP; } voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state; } } } }