MapGen rewrite pt. 1 - has DensityBehavior code.

master
Nicole Collings 2020-07-15 23:25:39 -07:00
parent 4b3a3b36bc
commit 3c560c8ca2
25 changed files with 571 additions and 535 deletions

View File

@ -3,6 +3,7 @@
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CidrRootsConfiguration">
<sourceRoots>
<file path="$PROJECT_DIR$/assets" />
<file path="$PROJECT_DIR$/src" />
<file path="$PROJECT_DIR$/subgames" />
<file path="$PROJECT_DIR$/test" />

View File

@ -30,10 +30,12 @@ out VS_OUT {
vec3 unpackFloat(float src) { return vec3(fract(src) * 2.0f - 1.0f, fract(src * 256.f) * 2.0f - 1.0f, fract(src * 65536.f) * 2.0f - 1.0f); }
void main() {
float sunlightIntensity = 1;
vec3 blockLightColor = (aLight.xyz / MAX_BLOCKLIGHT) * vec3(1 + sunlightIntensity / 4);
vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 1, 1) * (aLight.w / 15.0), 0, 1);
vec3 light = vec3(max(sunlightColor.x, blockLightColor.x), max(sunlightColor.y, blockLightColor.y), max(sunlightColor.z, blockLightColor.z));
// float sunlightIntensity = 1;
// vec3 blockLightColor = (aLight.xyz / MAX_BLOCKLIGHT) * vec3(1 + sunlightIntensity / 4);
// vec3 sunlightColor = clamp(sunlightIntensity * 1.25 * vec3(1, 1, 1) * (aLight.w / 15.0), 0, 1);
// vec3 light = vec3(max(sunlightColor.x, blockLightColor.x), max(sunlightColor.y, blockLightColor.y), max(sunlightColor.z, blockLightColor.z));
vec3 light = vec3(1, 1, 1);
vs_out.pos = aPos;
vs_out.normal = unpackFloat(aNormal);

View File

@ -69,9 +69,8 @@ set(ZEPHA_SRC
game/hud/components/basic/GuiRect.cpp
game/hud/components/basic/GuiRect.h
game/hud/components/basic/GuiGraph.cpp
game/hud/components/basic/GuiGraph.h
def/gen/MapGenJob.h
util/Interp.h
game/hud/components/basic/GuiGraph.h
util/Interp.h
def/gen/NoiseSample.cpp
def/gen/NoiseSample.h
game/graph/frustum/Frustum.cpp

View File

@ -2,13 +2,11 @@
// Created by aurailus on 28/01/19.
//
#include <cmath>
#include <random>
#include "MapGen.h"
#include "BiomeDef.h"
#include "MapGenJob.h"
#include "BiomeAtlas.h"
#include "MapGenProps.h"
#include "NoiseSample.h"
@ -17,321 +15,332 @@
#include "../../world/chunk/Chunk.h"
#include "../../game/scene/world/Schematic.h"
MapGen::MapGen(unsigned int seed, DefinitionAtlas& defs, BiomeAtlas& biomes, std::shared_ptr<MapGenProps> props) :
seed(seed),
MapGen::MapGen(DefinitionAtlas& defs, BiomeAtlas& biomes, unsigned int seed) :
defs(defs),
props(props),
biomes(biomes) {}
biomes(biomes),
props(seed) {}
MapGen::chunk_partials_map MapGen::generateMapBlock(glm::ivec3 mbPos) {
chunk_partials_map chunks {};
for (short i = 3; i >= 0; i--) {
for (short j = 0; j < 4; j++) {
for (short k = 0; k < 4; k++) {
glm::ivec3 pos = glm::ivec3(j, i, k) + (mbPos * 4);
generateChunk(chunks, pos);
}
}
}
generateSunlight(chunks, mbPos);
for (auto& chunk : chunks) {
// Delete MapGenJobs
delete chunk.second.first;
chunk.second.first = nullptr;
}
return chunks;
std::unique_ptr<MapGen::ChunkMap> MapGen::generateChunk(glm::ivec3 pos) {
return generateArea(pos);
}
void MapGen::generateChunk(chunk_partials_map& chunks, glm::ivec3 worldPos) {
if (chunks.count(worldPos) == 0) chunks.insert(std::pair<glm::ivec3, chunk_partial>{worldPos, {new MapGenJob(), new Chunk()}});
auto& chunk = chunks.at(worldPos);
chunk.second->pos = worldPos;
buildDensityMap(chunk.first, worldPos);
buildElevationMap(chunks, chunk);
generateBlocks(chunk);
generateStructures(chunks, chunk);
chunk.second->recalculateRenderableBlocks();
chunk.second->generated = true;
std::unique_ptr<MapGen::ChunkMap> MapGen::generateMapBlock(glm::ivec3 pos) {
return generateArea(Space::Chunk::world::fromMapBlock(pos), 4);
}
void MapGen::buildDensityMap(MapGenJob* job, glm::ivec3 worldPos) {
job->temperature = {}; job->humidity = {}; job->roughness = {};
std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(glm::ivec3 origin, unsigned int size) {
Job job(origin, size);
job->temperature.fill([&](glm::ivec3 pos) {
return props->temperature.GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f); }, 4);
job->humidity.fill([&](glm::ivec3 pos) {
return props->humidity.GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f); }, 4);
job->roughness.fill([&](glm::ivec3 pos) {
return props->roughness.GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f); }, 4);
// Build Biome Prop Maps
NoiseSample volume = {}, heightmap = {};
const auto fill = [&](const noise::module::Module& s) {
return [&](glm::vec3 pos) {
glm::vec3 worldPos = glm::vec3(job.pos) + pos * static_cast<float>(job.size);
return s.GetValue(worldPos.x, 0, worldPos.z);
};
};
volume.fill([&](glm::ivec3 pos) {
auto& biome = biomes.getBiomeAt(job->temperature.get(pos), job->humidity.get(pos), job->roughness.get(pos));
return biome.volume[biome.volume.size() - 1]->GetValue(worldPos.x + pos.x / 16.f, worldPos.y + pos.y / 16.f, worldPos.z + pos.z / 16.f);
}, {4, 4});
job.temperature.populate(fill(props.temperature));
job.roughness.populate(fill(props.roughness));
job.humidity.populate(fill(props.humidity));
heightmap.fill([&](glm::ivec3 pos) {
auto& biome = biomes.getBiomeAt(job->temperature.get(pos), job->humidity.get(pos), job->roughness.get(pos));
return biome.heightmap[biome.heightmap.size() - 1]->GetValue(worldPos.x + pos.x / 16.f, 0, worldPos.z + pos.z / 16.f);
}, 4);
// Generate Biome Topmap
glm::ivec3 lp;
for (int m = 0; m < 4096; m++) {
Vec::indAssignVec(m, lp);
job->density[m] = (volume.get(lp) + heightmap.get(lp)) - (lp.y + worldPos.y * 16);
}
}
std::vector<unsigned int> biomeMap {};
biomeMap.resize((job.size * 16 + 1) * (job.size * 16 + 1));
void MapGen::buildElevationMap(chunk_partials_map& chunks, chunk_partial& chunk) {
glm::ivec3 worldPos = chunk.second->pos;
for (unsigned short i = 0; i < biomeMap.size(); i++) {
glm::vec3 indPos = { i / (job.size * 16 + 1), 0, i % (job.size * 16 + 1)};
glm::vec3 queryPos = indPos / 16.f / static_cast<float>(job.size);
MapGenJob* upperJob = nullptr;
bool createdUpperJob = false;
biomeMap[i] = this->biomes.getBiomeAt(job.temperature.get(queryPos),
job.humidity.get(queryPos), job.roughness.get(queryPos)).index;
}
for (int i = 0; i < 256; i++) {
const int x = i % 16;
const int z = i / 16;
// Generate Heightmap
short depth = 16;
job.heightmap.populate([&](glm::vec3 pos) {
glm::ivec3 blockPos = glm::ivec3(pos * 16.f * static_cast<float>(job.size));
auto& biome = biomes.biomeFromId(biomeMap.at(blockPos.x * (job.size * 16 + 1) + blockPos.z));
glm::vec3 worldPos = glm::vec3(job.pos) + pos * static_cast<float>(job.size);
return biome.heightmap[biome.heightmap.size() - 1]->GetValue(worldPos.x, 0, worldPos.z);
});
if (chunk.first->density[Space::Block::index({x, 15, z})] > 0) {
if (!upperJob) {
glm::ivec3 rel = worldPos + glm::ivec3 {0, 1, 0};
if (chunks.count(rel) != 0) upperJob = chunks.at(rel).first;
else {
upperJob = new MapGenJob();
buildDensityMap(upperJob, rel);
createdUpperJob = true;
// Determine Density Fill Behavior
int chunksBelowHeightmap = 0;
for (unsigned int i = 0; i < job.size; i++) {
for (unsigned int j = 0; j < job.size; j++) {
glm::vec3 queryPos = {i / static_cast<float>(job.size), 0, i / static_cast<float>(job.size)};
if (job.heightmap.get(queryPos) / 16 > job.pos.y + static_cast<int>(job.size) - 1) chunksBelowHeightmap++;
}
}
// bool densityFillBehavior = chunksBelowHeightmap >= pow(job.size, 2) / 4;
bool densityFillBehavior = true;
if (densityFillBehavior) job.volume = NoiseSample({job.size * TERP, (job.size + 1) * TERP}, {1, 1.25});
job.volume.populate([&](glm::vec3 pos) {
glm::ivec3 blockPos = glm::ivec3(pos * 16.f * static_cast<float>(job.size));
auto& biome = biomes.biomeFromId(biomeMap.at(blockPos.x * (job.size * 16 + 1) + blockPos.z));
glm::vec3 worldPos = glm::vec3(job.pos) + pos * static_cast<float>(job.size);
return biome.volume[biome.volume.size() - 1]->GetValue(worldPos.x, worldPos.y, worldPos.z);
});
// Generate Chunks
glm::ivec3 pos {};
for (pos.x = 0; pos.x < job.size; pos.x++)
for (pos.z = 0; pos.z < job.size; pos.z++) {
std::unique_ptr<ChunkData> densityAbove = nullptr;
for (pos.y = job.size - (densityFillBehavior ? 0 : 1); pos.y >= 0; pos.y--) {
if (pos.y == job.size) {
densityAbove = populateChunkDensity(job, pos);
continue;
}
std::unique_ptr<ChunkData> density = populateChunkDensity(job, pos);
std::unique_ptr<ChunkData> depth = populateChunkDepth(job, pos, density, std::move(densityAbove));
populateChunk(job, pos, biomeMap, *depth);
densityAbove = std::move(density);
}
}
for (int j = 0; j < 16; j++) {
if (upperJob->density[Space::Block::index({ x, j, z })] <= 0) {
depth = j;
break;
}
}
}
else depth = 0;
// generateSunlight(chunks, mbPos);
for (int y = 15; y >= 0; y--) {
int ind = Space::Block::index({ x, y, z });
depth = (chunk.first->density[ind] > 0 ? std::min(depth + 1, 16) : 0);
chunk.first->depth[ind] = depth + (chunk.first->density[ind] - static_cast<int>(chunk.first->density[ind]));
}
}
if (createdUpperJob) delete upperJob;
return std::move(job.chunks);
}
void MapGen::generateBlocks(chunk_partial& chunk) {
std::unique_ptr<Chunk> dupe = nullptr;
if (chunk.second->partial) dupe = std::make_unique<Chunk>(*chunk.second);
std::unique_ptr<MapGen::ChunkData> MapGen::populateChunkDensity(MapGen::Job &job, glm::ivec3 localPos) {
auto data = std::make_unique<ChunkData>();
chunk.second->blocks = {};
chunk.second->biomes = {};
std::array<std::array<unsigned short, 16>, 16> biomeArray {};
for (unsigned short x = 0; x < 16; x++) {
biomeArray[x] = {};
for (unsigned short z = 0; z < 16; z++) {
glm::ivec3 lp = {x, 0, z};
biomeArray[x][z] = biomes.getBiomeAt(
chunk.first->temperature.get(lp),
chunk.first->humidity.get(lp),
chunk.first->roughness.get(lp)).index;
}
for (int i = 0; i < 4096; i++) {
glm::ivec3 indPos = Space::Block::fromIndex(i);
glm::vec3 queryPos = (glm::vec3(localPos) + glm::vec3(indPos) / 16.f) / static_cast<float>(job.size);
(*data)[i] = (job.volume.get(queryPos) + job.heightmap.get({queryPos.x, 0, queryPos.z})) - ((job.pos.y + localPos.y) * 16 + indPos.y);
}
for (unsigned short m = 0; m < 4096; m++) {
glm::ivec3 lp = Space::Block::fromIndex(m);
auto& biome = biomes.biomeFromId(biomeArray[lp.x][lp.z]);
unsigned int storedBlock = (chunk.second->blocks.size() <= 0 ? -1 : chunk.second->blocks[chunk.second->blocks.size() - 1]);
unsigned int storedBiome = (chunk.second->biomes.size() <= 0 ? -1 : chunk.second->biomes[chunk.second->biomes.size() - 1]);
if (biome.index != storedBiome) {
chunk.second->biomes.emplace_back(m);
chunk.second->biomes.emplace_back(biome.index);
}
int d = std::floor(chunk.first->depth[m]);
unsigned int targetBlock
= d <= 1 ? DefinitionAtlas::AIR
: d <= 2 ? biome.topBlock
: d <= 4 ? biome.soilBlock
: biome.rockBlock;
if (targetBlock != storedBlock) {
chunk.second->blocks.emplace_back(m);
chunk.second->blocks.emplace_back(targetBlock);
}
}
if (dupe) for (unsigned short i = 0; i < 4096; i++) {
unsigned int b = dupe->getBlock(i);
if (b != DefinitionAtlas::INVALID) chunk.second->setBlock(i, b);
}
return data;
}
void MapGen::generateStructures(chunk_partials_map& chunks, chunk_partial& chunk) {
std::default_random_engine generator(chunk.second->pos.x + chunk.second->pos.y * 30 + chunk.second->pos.z * 3.5);
std::uniform_real_distribution<float> distribution(0, 1);
glm::ivec3 wp = chunk.second->pos;
glm::ivec3 lp;
std::unique_ptr<MapGen::ChunkData> MapGen::populateChunkDepth(Job& job, glm::ivec3 localPos, std::unique_ptr<ChunkData>& chunkDensity, std::unique_ptr<ChunkData> chunkDensityAbove) {
auto data = std::make_unique<ChunkData>();
for (unsigned short i = 0; i < 256; i++) {
unsigned short x = i / 16;
unsigned short z = i % 16;
glm::ivec2 pos = { i / 16, i % 16 };
short depth = 16;
if (distribution(generator) > 0.97) {
for (unsigned short y = 0; y < 16; y++) {
lp = {x, y, z};
unsigned short ind = Space::Block::index(lp);
if (chunk.first->depth[ind] > 0 && chunk.first->depth[ind] <= 1.1) {
glm::ivec3 off = {};
glm::ivec3 p = wp * 16 + lp;
auto biome = biomes.biomeFromId(chunk.second->getBiome(ind));
auto schematic = biome.schematics.size() > 0 ? biome.schematics[0] : nullptr;
if (schematic != nullptr) {
if (!schematic->processed) schematic->process(defs);
for (unsigned int j = 0; j < schematic->length(); j++) {
schematic->assignOffset(j, off);
setBlock(p + off - schematic->origin, schematic->blocks[j], chunks);
}
}
if ((*chunkDensity)[Space::Block::index({pos.x, 15, pos.y})] > 0) {
for (unsigned char j = 0; j < 16; j++) {
if ((*chunkDensityAbove)[Space::Block::index({pos.x, j, pos.y})] <= 0) {
depth = j;
break;
}
}
}
}
}
else {
depth = 0;
}
void MapGen::generateSunlight(MapGen::chunk_partials_map &chunks, glm::ivec3 mbPos) {
std::queue<SunlightNode> sunlightQueue;
glm::ivec3 c {};
for (c.x = 0; c.x < 4; c.x++) {
for (c.z = 0; c.z < 4; c.z++) {
c.y = 3;
Chunk* chunk = chunks[mbPos * 4 + c].second;
glm::ivec3 b {};
for (b.x = 0; b.x < 16; b.x++) {
for (b.z = 0; b.z < 16; b.z++) {
b.y = 15;
while (true) {
unsigned int ind = Space::Block::index(b);
if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates) {
chunk->setLight(ind, 3, 15);
sunlightQueue.emplace(ind, chunk);
}
else {
c.y = 3;
chunk = chunks[mbPos * 4 + c].second;
break;
}
b.y--;
if (b.y < 0) {
b.y = 15;
c.y = c.y ? c.y - 1 : 3;
chunk = chunks[mbPos * 4 + c].second;
if (c.y == 3) break;
}
}
}
}
for (char y = 15; y >= 0; y--) {
unsigned int ind = Space::Block::index({pos.x, y, pos.y});
depth = ((*chunkDensity)[ind] > 0 ? std::min(depth + 1, 16) : 0);
(*data)[ind] = depth + ((*chunkDensity)[ind] - static_cast<int>((*chunkDensity)[ind]));
}
}
propogateSunlightNodes(chunks, sunlightQueue);
return data;
}
bool MapGen::containsWorldPos(Chunk *chunk, glm::ivec3 pos) {
return chunk && Space::Chunk::world::fromBlock(pos) == chunk->pos;
}
void MapGen::populateChunk(Job& job, glm::ivec3 localPos, std::vector<unsigned int> biomeMap, ChunkData& depthMap) {
glm::ivec3 chunkPos = job.pos + localPos;
auto& chunk = *(*job.chunks->emplace(chunkPos, std::make_shared<Chunk>(chunkPos)).first).second;
void MapGen::propogateSunlightNodes(MapGen::chunk_partials_map &chunks, std::queue<SunlightNode> &queue) {
while (!queue.empty()) {
SunlightNode& node = queue.front();
unsigned int cBlockID = -1;
unsigned int cBiomeID = -1;
unsigned char lightLevel = node.chunk->getLight(node.index, 3);
glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
for (unsigned short i = 0; i < 4096; i++) {
glm::ivec3 indPos = Space::Block::fromIndex(i);
for (const auto& i : Vec::adj) {
glm::ivec3 check = worldPos + i;
unsigned int biomeID = biomeMap[(localPos.x * 16 + indPos.x) * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)];
auto& biome = this->biomes.biomeFromId(biomeID);
Chunk* chunk;
if (containsWorldPos(node.chunk, check)) chunk = node.chunk;
else {
glm::ivec3 worldPos = Space::Chunk::world::fromBlock(check);
if (!chunks.count(worldPos)) continue;
chunk = chunks[worldPos].second;
if (!chunk) continue;
}
float depth = depthMap[i];
unsigned int blockID
= depth <= 1 ? DefinitionAtlas::AIR
: depth <= 2 ? biome.topBlock
: depth <= 4 ? biome.soilBlock
: biome.rockBlock;
auto ind = Space::Block::index(check);
if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates && chunk->getLight(ind, 3) + 2 <= lightLevel) {
chunk->setLight(ind, 3, lightLevel - static_cast<int>(!(lightLevel == 15 && i.y == -1)));
queue.emplace(ind, chunk);
}
if (biomeID != cBiomeID) {
chunk.biomes.emplace_back(i);
chunk.biomes.emplace_back(biomeID);
cBiomeID = biomeID;
}
queue.pop();
if (blockID != cBlockID) {
chunk.blocks.emplace_back(i);
chunk.blocks.emplace_back(blockID);
cBlockID = blockID;
}
}
chunk.countRenderableBlocks();
chunk.generated = true;
}
void MapGen::setBlock(glm::ivec3 worldPos, unsigned int block, MapGen::chunk_partials_map &chunks) {
if (block == DefinitionAtlas::INVALID) return;
glm::ivec3 chunkPos = Space::Chunk::world::fromBlock(worldPos);
Chunk* chunk = nullptr;
if (chunks.count(chunkPos)) chunk = chunks.at(chunkPos).second;
else {
chunk = new Chunk();
chunk->pos = chunkPos;
chunk->partial = true;
chunks.insert(std::pair<glm::ivec3, chunk_partial>{chunkPos, {new MapGenJob(), chunk}});
}
unsigned int index = Space::Block::index(worldPos);
if (chunk->getBlock(index) <= DefinitionAtlas::AIR) chunk->setBlock(index, block);
}
std::shared_ptr<Chunk> MapGen::combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b) {
std::shared_ptr<Chunk> src;
std::shared_ptr<Chunk> res;
if (a->generated) {
res = a;
src = b;
}
else {
res = b;
src = a;
}
for (unsigned int i = 0; i < 4096; i++) {
if (src->getBlock(i) > DefinitionAtlas::INVALID) res->setBlock(i, src->getBlock(i));
}
res->generated = src->generated || res->generated;
res->partial = !res->generated;
res->recalculateRenderableBlocks();
return res;
}
//void MapGen::generateStructures(chunk_partials_map& chunks, chunk_partial& chunk) {
// std::default_random_engine generator(chunk.second->pos.x + chunk.second->pos.y * 30 + chunk.second->pos.z * 3.5);
// std::uniform_real_distribution<float> distribution(0, 1);
//
// glm::ivec3 wp = chunk.second->pos;
// glm::ivec3 lp;
//
// for (unsigned short i = 0; i < 256; i++) {
// unsigned short x = i / 16;
// unsigned short z = i % 16;
//
// if (distribution(generator) > 0.97) {
// for (unsigned short y = 0; y < 16; y++) {
// lp = {x, y, z};
// unsigned short ind = Space::Block::index(lp);
//
// if (chunk.first->depth[ind] > 0 && chunk.first->depth[ind] <= 1.1) {
//
// glm::ivec3 off = {};
// glm::ivec3 p = wp * 16 + lp;
//
// auto biome = biomes.biomeFromId(chunk.second->getBiome(ind));
// auto schematic = biome.schematics.size() > 0 ? biome.schematics[0] : nullptr;
//
// if (schematic != nullptr) {
// if (!schematic->processed) schematic->process(defs);
// for (unsigned int j = 0; j < schematic->length(); j++) {
// schematic->assignOffset(j, off);
// setBlock(p + off - schematic->origin, schematic->blocks[j], chunks);
// }
// }
// }
// }
// }
// }
//}
//
//void MapGen::generateSunlight(MapGen::chunk_partials_map &chunks, glm::ivec3 mbPos) {
// std::queue<SunlightNode> sunlightQueue;
//
// glm::ivec3 c {};
// for (c.x = 0; c.x < 4; c.x++) {
// for (c.z = 0; c.z < 4; c.z++) {
// c.y = 3;
// Chunk* chunk = chunks[mbPos * 4 + c].second;
//
// glm::ivec3 b {};
// for (b.x = 0; b.x < 16; b.x++) {
// for (b.z = 0; b.z < 16; b.z++) {
// b.y = 15;
//
// while (true) {
// unsigned int ind = Space::Block::index(b);
// if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates) {
// chunk->setLight(ind, 3, 15);
// sunlightQueue.emplace(ind, chunk);
// }
// else {
// c.y = 3;
// chunk = chunks[mbPos * 4 + c].second;
// break;
// }
//
// b.y--;
// if (b.y < 0) {
// b.y = 15;
// c.y = c.y ? c.y - 1 : 3;
// chunk = chunks[mbPos * 4 + c].second;
// if (c.y == 3) break;
// }
// }
// }
// }
// }
// }
//
// propogateSunlightNodes(chunks, sunlightQueue);
//}
//
//bool MapGen::containsWorldPos(Chunk *chunk, glm::ivec3 pos) {
// return chunk && Space::Chunk::world::fromBlock(pos) == chunk->pos;
//}
//
//void MapGen::propogateSunlightNodes(MapGen::chunk_partials_map &chunks, std::queue<SunlightNode> &queue) {
// while (!queue.empty()) {
// SunlightNode& node = queue.front();
//
// unsigned char lightLevel = node.chunk->getLight(node.index, 3);
// glm::ivec3 worldPos = node.chunk->pos * 16 + Space::Block::fromIndex(node.index);
//
// for (const auto& i : Vec::adj) {
// glm::ivec3 check = worldPos + i;
//
// Chunk* chunk;
// if (containsWorldPos(node.chunk, check)) chunk = node.chunk;
// else {
// glm::ivec3 worldPos = Space::Chunk::world::fromBlock(check);
// if (!chunks.count(worldPos)) continue;
// chunk = chunks[worldPos].second;
// if (!chunk) continue;
// }
//
// auto ind = Space::Block::index(check);
// if (defs.blockFromId(chunk->getBlock(ind)).lightPropagates && chunk->getLight(ind, 3) + 2 <= lightLevel) {
// chunk->setLight(ind, 3, lightLevel - static_cast<int>(!(lightLevel == 15 && i.y == -1)));
// queue.emplace(ind, chunk);
// }
// }
//
// queue.pop();
// }
//}
//
//void MapGen::setBlock(glm::ivec3 worldPos, unsigned int block, MapGen::chunk_partials_map &chunks) {
// if (block == DefinitionAtlas::INVALID) return;
//
// glm::ivec3 chunkPos = Space::Chunk::world::fromBlock(worldPos);
// Chunk* chunk = nullptr;
//
// if (chunks.count(chunkPos)) chunk = chunks.at(chunkPos).second;
// else {
// chunk = new Chunk();
// chunk->pos = chunkPos;
// chunk->partial = true;
// chunks.insert(std::pair<glm::ivec3, chunk_partial>{chunkPos, {new MapGenJob(), chunk}});
// }
//
// unsigned int index = Space::Block::index(worldPos);
// if (chunk->getBlock(index) <= DefinitionAtlas::AIR) chunk->setBlock(index, block);
//}
//
//std::shared_ptr<Chunk> MapGen::combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b) {
// std::shared_ptr<Chunk> src;
// std::shared_ptr<Chunk> res;
//
// if (a->generated) {
// res = a;
// src = b;
// }
// else {
// res = b;
// src = a;
// }
//
// for (unsigned int i = 0; i < 4096; i++) {
// if (src->getBlock(i) > DefinitionAtlas::INVALID) res->setBlock(i, src->getBlock(i));
// }
//
// res->generated = src->generated || res->generated;
// res->partial = !res->generated;
// res->recalculateRenderableBlocks();
// return res;
//}

View File

@ -10,57 +10,82 @@
#include <glm/vec3.hpp>
#include <unordered_map>
#include "MapGenProps.h"
#include "NoiseSample.h"
#include "../../util/Vec.h"
class Chunk;
class MapGenJob;
class BiomeAtlas;
class MapGenProps;
class DefinitionAtlas;
class MapGen {
public:
typedef std::pair<MapGenJob*, Chunk*> chunk_partial;
typedef std::unordered_map<glm::ivec3, chunk_partial, Vec::ivec3> chunk_partials_map;
constexpr static unsigned int BIOP = 4; // Biome Prop Precision
constexpr static unsigned int TERP = 4; // Terrain Map Precision
MapGen(unsigned int seed, DefinitionAtlas& atlas, BiomeAtlas& biome, std::shared_ptr<MapGenProps> props);
chunk_partials_map generateMapBlock(glm::ivec3 mbPos);
typedef std::unordered_map<glm::ivec3, std::shared_ptr<Chunk>, Vec::ivec3> ChunkMap;
// Combine two chunk partials, or a chunk and a chunk partial.
// If both are partials `b` takes preference, if one is a fully generated chunk the partial takes preference.
static std::shared_ptr<Chunk> combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b);
private:
struct SunlightNode {
SunlightNode(unsigned short index, Chunk* chunk) : index(index), chunk(chunk) {};
unsigned short index;
Chunk* chunk;
struct Job {
Job(glm::ivec3 pos, unsigned int size) :
pos(pos), size(size),
volume {size * TERP}, heightmap {{size * TERP, 0}},
temperature {{size * BIOP, 0}}, roughness {{size * BIOP, 0}}, humidity {{size * BIOP, 0}} {}
glm::ivec3 pos {};
unsigned int size {};
std::unique_ptr<ChunkMap> chunks = std::make_unique<ChunkMap>();
NoiseSample volume, heightmap;
NoiseSample temperature, humidity, roughness;
};
// Generate a chunk at `worldPos`, and place it and any partials in `chunks`.
void generateChunk(chunk_partials_map& chunks, glm::ivec3 worldPos);
typedef std::array<float, 4096> ChunkData;
// Build the density map for a job.
void buildDensityMap(MapGenJob* job, glm::ivec3 worldPos);
MapGen(DefinitionAtlas& atlas, BiomeAtlas& biome, unsigned int seed);
// Build the elevation map for a chunk, which uses the `chunks` array for efficiency.
void buildElevationMap(chunk_partials_map& chunks, chunk_partial& chunk);
std::unique_ptr<ChunkMap> generateChunk(glm::ivec3 pos);
std::unique_ptr<ChunkMap> generateMapBlock(glm::ivec3 pos);
std::unique_ptr<ChunkMap> generateArea(glm::ivec3 origin, unsigned int size = 1);
// Generate blocks and structures on a chunk, respectively. generateStructures can create partials.
void generateBlocks(chunk_partial& chunk);
void generateStructures(chunk_partials_map& chunks, chunk_partial& chunk);
// // Combine two chunk partials, or a chunk and a chunk partial.
// // If both are partials `b` takes preference, if one is a fully generated chunk the partial takes preference.
// static std::shared_ptr<Chunk> combinePartials(std::shared_ptr<Chunk> a, std::shared_ptr<Chunk> b);
private:
// struct SunlightNode {
// SunlightNode(unsigned short index, Chunk* chunk) : index(index), chunk(chunk) {};
// unsigned short index;
// Chunk* chunk;
// };
// Generate sunlight on the mapgen threads to speed up perf
void generateSunlight(chunk_partials_map& chunks, glm::ivec3 mbPos);
static bool containsWorldPos(Chunk *chunk, glm::ivec3 pos);
void propogateSunlightNodes(chunk_partials_map& chunks, std::queue<SunlightNode>& queue);
static std::unique_ptr<ChunkData> populateChunkDensity(Job& job, glm::ivec3 localPos);
static std::unique_ptr<ChunkData> populateChunkDepth(Job& job, glm::ivec3 localPos, std::unique_ptr<ChunkData>& chunkDensity, std::unique_ptr<ChunkData> chunkDensityAbove);
// Place block in the `chunks` array, creates a partial if necessary.
static void setBlock(glm::ivec3 worldPos, unsigned int block, chunk_partials_map& chunks);
void populateChunk(Job& job, glm::ivec3 localPos, std::vector<unsigned int> biomeMap, ChunkData& depthMap);
// // Builds the temperature, humidity, roughness, density, and depth maps.
// void buildNoisemaps(Job& job);
// // Generate a chunk at pos and insert it into the partials map.
// void buildChunk(glm::ivec3 pos, Job& job, ChunkMap& chunks);
// // Fill a ChunkData struct with data.
// static void fillChunkData(glm::ivec3 pos, Job& job, ChunkData& data, Chunk& chunk, ChunkMap& chunks);
// // Fill a Chunk with Blocks based on the Data object.
// void fillBlocks(glm::ivec3 pos, Job &job, ChunkData& data, Chunk& chunk);
// // Fill a Chunk with Structures based on the Data object.
// void generateStructures(glm::ivec3 pos, Job& job, ChunkData& data, Chunk& chunk, ChunkMap& chunks);
// // Generate sunlight on the mapgen threads to speed up perf
// void generateSunlight(ChunkMap& chunks, glm::ivec3 mbPos);
// static bool containsWorldPos(Chunk *chunk, glm::ivec3 pos);
// void propogateSunlightNodes(ChunkMap& chunks, std::queue<SunlightNode>& queue);
//
// // Place block in the `chunks` array, creates a partial if necessary.
// static void setBlock(glm::ivec3 worldPos, unsigned int block, ChunkMap& chunks);
unsigned int seed = 0;
DefinitionAtlas& defs;
BiomeAtlas& biomes;
std::shared_ptr<MapGenProps> props;
MapGenProps props;
};

View File

@ -1,17 +0,0 @@
//
// Created by aurailus on 13/02/19.
//
#pragma once
#include <array>
#include "NoiseSample.h"
class MapGenJob {
public:
std::array<float, 4096> density {};
std::array<float, 4096> depth {};
NoiseSample temperature, humidity, roughness;
};

View File

@ -8,6 +8,7 @@ MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
temperatureBase.SetSeed(seed);
temperatureBase.SetFrequency(0.02);
temperatureBase.SetOctaveCount(4);
temperatureTurbulence.SetSeed(seed);
temperatureTurbulence.SetSourceModule(0, temperatureBase);
temperatureTurbulence.SetRoughness(4);
temperatureTurbulence.SetFrequency(0.2);
@ -18,6 +19,7 @@ MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
humidityBase.SetSeed(seed + 1);
humidityBase.SetFrequency(0.02);
humidityBase.SetOctaveCount(4);
humidityTurbulence.SetSeed(seed + 1);
humidityTurbulence.SetSourceModule(0, humidityBase);
humidityTurbulence.SetRoughness(4);
humidityTurbulence.SetFrequency(0.2);
@ -28,6 +30,7 @@ MapGenProps::MapGenProps(unsigned int seed) : seed(seed) {
roughnessBase.SetSeed(seed - 1);
roughnessBase.SetFrequency(0.02);
roughnessBase.SetOctaveCount(4);
roughnessTurbulence.SetSeed(seed - 1);
roughnessTurbulence.SetSourceModule(0, roughnessBase);
roughnessTurbulence.SetRoughness(4);
roughnessTurbulence.SetFrequency(0.2);

View File

@ -7,66 +7,54 @@
#include "NoiseSample.h"
#include "../../util/Interp.h"
#include "../../util/Util.h"
void NoiseSample::fill(const NoiseSample::fill_function &fun, float precision) {
fill(fun, {precision, 1});
}
NoiseSample::NoiseSample(unsigned int precision, float scaleBy) : NoiseSample({precision, precision}, {scaleBy, scaleBy}) {}
void NoiseSample::fill(const NoiseSample::fill_function &fun, glm::ivec2 precision) {
this->precision = precision;
reserve();
float offsetH = 16.f / precision.x;
float offsetV = 16.f / precision.y;
// Iterate over the array
for (int i = 0; i <= precision.x; i++) {
for (int j = 0; j <= (precision.y == 1 ? 0 : precision.y); j++) {
for (int k = 0; k <= precision.x; k++) {
set({i, j, k}, fun({ offsetH * i, offsetV * j, offsetH * k }));
NoiseSample::NoiseSample(glm::ivec2 precision, glm::vec2 scaleBy) :
precision(precision.x, precision.y, precision.x),
scaleBy(scaleBy.x, scaleBy.y, scaleBy.x) {
// Reserve space in the vector.
for (unsigned int i = 0; i < this->precision.y + 1; i++) {
data.emplace_back();
for (unsigned int j = 0; j < this->precision.x + 1; j++) {
data[i].emplace_back();
for (unsigned int k = 0; k < this->precision.z + 1; k++) {
data[i][j].emplace_back();
}
}
}
}
float NoiseSample::get(glm::ivec3 localPos) {
assert(precision.x != 0);
assert(precision.y != 0);
glm::vec3 prec3 {precision.x, precision.y, precision.x};
if (localPos.x == 16) localPos.x = 15;
if (localPos.y == 16) localPos.y = 15;
if (localPos.z == 16) localPos.z = 15;
glm::ivec3 base = localPos / (glm::ivec3(16) / glm::ivec3(prec3));
const glm::vec3 factor = glm::floor(glm::mod(glm::vec3(localPos), (glm::vec3(16.f) / prec3))) / 16.f * prec3;
const auto& x0y0 = data[base.x][base.y];
const auto& x1y0 = data[base.x + 1][base.y];
//No Vertical Interpolation
if (precision.y <= 1) return Interp::bilerp(x0y0[base.z], x1y0[base.z], x0y0[base.z + 1], x1y0[base.z + 1], factor.x, factor.z);
const auto& x0y1 = data[base.x][base.y + 1];
const auto& x1y1 = data[base.x + 1][base.y + 1];
return Interp::trilerp(
x0y0[base.z], x1y0[base.z], x0y0[base.z + 1], x1y0[base.z + 1],
x0y1[base.z], x1y1[base.z], x0y1[base.z + 1], x1y1[base.z + 1], factor.x, factor.z, factor.y);
void NoiseSample::populate(const NoiseSample::fill_function &fn) {
glm::vec3 pos;
for (pos.x = 0; pos.x <= precision.x; pos.x++)
for (pos.y = 0; pos.y <= precision.y; pos.y++)
for (pos.z = 0; pos.z <= precision.z; pos.z++) {
glm::vec3 queryPos = pos / glm::vec3(precision) * scaleBy;
if (queryPos.y == NAN) queryPos.y = 0;
data[pos.y][pos.x][pos.z] = fn(queryPos);
}
}
void NoiseSample::set(glm::ivec3 localPos, float value) {
data[localPos.x][localPos.y][localPos.z] = value;
}
float NoiseSample::get(glm::vec3 pos) {
glm::vec3 scaled = pos * glm::vec3(precision) / scaleBy;
void NoiseSample::reserve() {
data.reserve(precision.x + 1);
for (unsigned int i = 0; i <= precision.x; i++) {
std::vector<std::vector<float>> subdata;
subdata.reserve(precision.y + 1);
for (int j = 0; j <= precision.y; j++)
subdata.emplace_back(precision.x + 1);
data.push_back(subdata);
}
}
glm::vec3 a = glm::floor(scaled);
glm::vec3 factor = scaled - glm::floor(scaled);
glm::vec3 b = {fmin(a.x + ceil(factor.x), precision.x), fmin(a.y + ceil(factor.y), precision.y), fmin(a.z + ceil(factor.z), precision.z)};
assert(a.x + factor.x <= precision.x && a.y + factor.y <= precision.y && a.z + factor.z <= precision.z);
const auto& p00 = data[a.y][a.x];
const auto& p10 = data[a.y][b.x];
// No vertical interpolation
if (precision.y == 0) return Interp::bilerp(p00[a.z], p10[a.z], p00[b.z], p10[b.z], factor.x, factor.z);
const auto& p01 = data[b.y][a.x];
const auto& p11 = data[b.y][b.x];
return Interp::trilerp(p00[a.z], p10[a.z], p00[b.z], p10[b.z],
p01[a.z], p11[a.z], p01[b.z], p11[b.z], factor.x, factor.z, factor.y);
}

View File

@ -11,19 +11,18 @@
class NoiseSample {
public:
typedef std::function<float(glm::ivec3 pos)> fill_function;
typedef std::function<float(glm::vec3 pos)> fill_function;
NoiseSample() = default;
NoiseSample(unsigned int precision, float scaleBy = 1);
NoiseSample(glm::ivec2 precision, glm::vec2 scaleBy = {1, 1});
void fill(const fill_function& fun, float precision);
void fill(const fill_function& fun, glm::ivec2 precision);
float get(glm::ivec3 localPos);
void set(glm::ivec3 localPos, float value);
void populate(const fill_function& fn);
float get(glm::vec3 pos);
private:
void reserve();
unsigned int length;
std::vector<std::vector<std::vector<float>>> data {};
glm::ivec2 precision {};
glm::ivec3 precision {};
glm::vec3 scaleBy;
};

View File

@ -7,10 +7,11 @@
#include "MeshPart.h"
#include "../texture/AtlasRef.h";
#include "../texture/AtlasRef.h"
MeshPart::MeshPart(const std::vector<BlockModelVertex>& vertices, const std::vector<unsigned int>& indices,
std::shared_ptr<AtlasRef> texture, unsigned int blendInd, std::shared_ptr<AtlasRef> blendMask) :
std::shared_ptr<AtlasRef> texture, unsigned int blendInd, std::shared_ptr<AtlasRef> blendMask) :
vertices(vertices),
indices(indices),
texture(texture),

View File

@ -11,7 +11,8 @@
MeshGenStream::MeshGenStream(ClientGame& game, LocalDimension &dimension) :
game(game),
dimension(dimension) {
dimension(dimension),
noiseSampler({NoiseSample {16}, NoiseSample {16}, NoiseSample {16}}) {
queuedTasks.reserve(static_cast<unsigned long>(TOTAL_QUEUE_SIZE));
@ -24,11 +25,10 @@ MeshGenStream::MeshGenStream(ClientGame& game, LocalDimension &dimension) :
offsetTurbulence.SetFrequency(4.0);
offsetTurbulence.SetPower(0.125);
noiseSampler = { NoiseSample {}, NoiseSample {}, NoiseSample {} };
//8 is just a random value to offset results
noiseSampler[0].fill([&](glm::ivec3 pos) -> float { return offsetTurbulence.GetValue(pos.x + 8, pos.y, pos.z); }, {16, 16});
noiseSampler[1].fill([&](glm::ivec3 pos) -> float { return offsetTurbulence.GetValue(pos.x, pos.y + 8, pos.z); }, {16, 16});
noiseSampler[2].fill([&](glm::ivec3 pos) -> float { return offsetTurbulence.GetValue(pos.x, pos.y, pos.z + 8); }, {16, 16});
// 8 is just a random value to offset results
noiseSampler[0].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x + 8, pos.y, pos.z); });
noiseSampler[1].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x, pos.y + 8, pos.z); });
noiseSampler[2].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x, pos.y, pos.z + 8); });
threads.reserve(THREADS);
for (int i = 0; i < THREADS; i++) threads.emplace_back(game, noiseSampler);

View File

@ -6,15 +6,11 @@
#include "../../../net/PacketView.h"
#include "../../../def/ClientGame.h"
#include "../../../def/gen/MapGen.h"
#include "../../../world/chunk/Chunk.h"
WorldInterpolationStream::WorldInterpolationStream(unsigned int seed, ClientGame& game) :
props(std::make_shared<MapGenProps>(seed)),
gen(new MapGen(seed, game.defs, game.biomes, props)) {
WorldInterpolationStream::WorldInterpolationStream(unsigned int seed, ClientGame& game) {
threads.reserve(THREADS);
for (int i = 0; i < THREADS; i++) threads.emplace_back(gen);
for (int i = 0; i < THREADS; i++) threads.emplace_back(game, seed);
}
void WorldInterpolationStream::queuePacket(std::unique_ptr<PacketView> p) {
@ -34,14 +30,15 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
auto finishedChunks = std::make_unique<std::vector<std::shared_ptr<Chunk>>>();
// auto finishedMapBlocks = std::make_unique<std::vector<std::shared_ptr<MeshFarMap>>>();
for (auto& t : threads) {
for (auto& u : t.tasks) {
if (u.locked) continue;
for (unsigned int i = 0; i < THREAD_QUEUE_SIZE; i++) {
for (auto& t : threads) {
auto& j = t.jobs[i];
if (j.locked) continue;
if (u.chunk != nullptr) {
finishedChunks->push_back(u.chunk);
u.chunk = nullptr;
u.job = JobType::EMPTY;
if (j.chunk != nullptr) {
finishedChunks->push_back(j.chunk);
j.chunk = nullptr;
j.job = JobType::EMPTY;
}
// else if (u.mapblock != nullptr) {
// finishedMapBlocks->push_back(u.mapblock);
@ -54,9 +51,9 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
auto packet = std::move(*it);
queuedPacketTasks.erase(it);
u.job = JobType::PACKET;
u.packet = std::move(packet);
u.locked = true;
j.job = JobType::PACKET;
j.packet = std::move(packet);
j.locked = true;
}
else if (!queuedInterpTasks.empty()) {
auto it = queuedInterpTasks.begin();
@ -64,9 +61,9 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
queuedInterpTasks.erase(it);
queuedInterpMap.erase(pos);
u.job = JobType::FARMAP;
u.mapBlockPos = pos;
u.locked = true;
j.job = JobType::FARMAP;
j.mapBlockPos = pos;
j.locked = true;
}
}
}
@ -74,24 +71,25 @@ std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> WorldInterpolationStream::u
return finishedChunks;
}
WorldInterpolationStream::Thread::Thread(MapGen* gen) : gen(gen),
WorldInterpolationStream::Thread::Thread(ClientGame& game, unsigned int seed) :
gen(game.defs, game.biomes, seed),
thread(std::bind(&WorldInterpolationStream::Thread::exec, this)) {}
void WorldInterpolationStream::Thread::exec() {
while (!kill) {
bool empty = true;
for (Job& u : tasks) {
for (Job& u : jobs) {
if (u.locked) {
if (u.job == JobType::PACKET) {
empty = false;
u.chunk = std::make_shared<Chunk>();
u.chunk->deserialize(u.packet->d);
u.locked = false;
break;
}
else if (u.job == JobType::FARMAP) {
throw std::runtime_error("Farmap no exist yet.");
}
// break;
}
}
if (empty) std::this_thread::sleep_for(std::chrono::milliseconds(1));

View File

@ -12,17 +12,16 @@
#include <unordered_set>
#include "../../../util/Vec.h"
#include "../../../def/gen/MapGen.h"
class Chunk;
class MapGen;
class ClientGame;
class MapGenProps;
class PacketView;
class WorldInterpolationStream {
public:
static const int THREADS = 4;
static const int THREAD_QUEUE_SIZE = 32;
static const int THREAD_QUEUE_SIZE = 64;
WorldInterpolationStream(unsigned int seed, ClientGame& game);
@ -55,19 +54,17 @@ private:
};
struct Thread {
explicit Thread(MapGen* gen);
explicit Thread(ClientGame& game, unsigned int seed);
void exec();
MapGen* gen;
std::vector<Job> tasks = std::vector<Job>(THREAD_QUEUE_SIZE);
bool kill = false;
std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE);
MapGen gen;
std::thread thread;
};
std::shared_ptr<MapGenProps> props;
MapGen* gen;
std::vector<Thread> threads;
std::list<std::unique_ptr<PacketView>> queuedPacketTasks;
std::unordered_set<glm::vec3, Vec::vec3> queuedInterpMap;

View File

@ -68,11 +68,11 @@ ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefin
default: break;
case MeshMod::OFFSET_X:
vis.x += blockOffsets[0].get(off) * mod.second; break;
vis.x += blockOffsets[0].get(vis / 16.f) * mod.second; break;
case MeshMod::OFFSET_Y:
vis.y += blockOffsets[1].get(off) * mod.second; break;
vis.y += blockOffsets[1].get(vis / 16.f) * mod.second; break;
case MeshMod::OFFSET_Z:
vis.z += blockOffsets[2].get(off) * mod.second; break;
vis.z += blockOffsets[2].get(vis / 16.f) * mod.second; break;
}
}

View File

@ -6,14 +6,10 @@
#include "../../../def/ServerGame.h"
#include "../../../world/chunk/Chunk.h"
#include "../../../def/gen/MapGenProps.h"
ServerGenStream::ServerGenStream(unsigned int seed, ServerGame& game) :
props(std::make_shared<MapGenProps>(seed)),
gen(seed, game.defs, game.biomes, props) {
ServerGenStream::ServerGenStream(unsigned int seed, ServerGame& game) {
threads.reserve(THREADS);
for (int i = 0; i < THREADS; i++) threads.emplace_back(&gen);
for (int i = 0; i < THREADS; i++) threads.emplace_back(game, seed);
}
bool ServerGenStream::queue(glm::vec3 pos) {
@ -28,14 +24,15 @@ bool ServerGenStream::queue(glm::vec3 pos) {
std::unique_ptr<std::vector<ServerGenStream::FinishedBlockJob>> ServerGenStream::update() {
auto finishedChunks = std::make_unique<std::vector<FinishedBlockJob>>();
for (auto& t : threads) {
for (auto& u : t.tasks) {
if (u.locked) continue;
for (unsigned int i = 0; i < THREAD_QUEUE_SIZE; i++) {
for (auto& t : threads) {
auto& j = t.jobs[i];
if (j.locked) continue;
if (!u.chunks.empty()) {
finishedChunks->push_back({u.pos, {}});
for (auto chunk : u.chunks) finishedChunks->back().chunks.push_back(std::shared_ptr<Chunk>(chunk.second.second));
u.chunks.clear();
if (j.generated) {
finishedChunks->push_back({j.pos, {}});
for (auto chunkPair : *j.generated) finishedChunks->back().chunks.push_back(chunkPair.second);
j.generated = nullptr;
}
if (!queuedTasks.empty()) {
@ -44,8 +41,8 @@ std::unique_ptr<std::vector<ServerGenStream::FinishedBlockJob>> ServerGenStream:
queuedTasks.erase(it);
queuedMap.erase(pos);
u.pos = pos;
u.locked = true;
j.pos = pos;
j.locked = true;
}
}
}
@ -53,18 +50,18 @@ std::unique_ptr<std::vector<ServerGenStream::FinishedBlockJob>> ServerGenStream:
return finishedChunks;
}
ServerGenStream::Thread::Thread(MapGen *gen) : gen(gen),
ServerGenStream::Thread::Thread(ServerGame& game, unsigned int seed) :
gen(game.defs, game.biomes, seed),
thread(std::bind(&ServerGenStream::Thread::exec, this)) {}
void ServerGenStream::Thread::exec() {
while (!kill) {
bool empty = true;
for (Job& u : tasks) {
if (u.locked) {
for (Job& j : jobs) {
if (j.locked) {
empty = false;
u.chunks = gen->generateMapBlock(u.pos);
u.locked = false;
break;
j.generated = gen.generateMapBlock(j.pos);
j.locked = false;
}
}
if (empty) std::this_thread::sleep_for(std::chrono::milliseconds(1));

View File

@ -14,7 +14,7 @@ class ServerGame;
class ServerGenStream {
public:
static const int THREADS = 4;
static const int THREADS = 6;
static const int THREAD_QUEUE_SIZE = 6;
struct FinishedBlockJob {
@ -35,23 +35,21 @@ private:
bool locked = false;
glm::ivec3 pos {};
MapGen::chunk_partials_map chunks {};
std::unique_ptr<MapGen::ChunkMap> generated = nullptr;
};
struct Thread {
explicit Thread(MapGen* gen);
explicit Thread(ServerGame& game, unsigned int seed);
void exec();
MapGen* gen;
std::vector<Job> tasks = std::vector<Job>(THREAD_QUEUE_SIZE);
bool kill = false;
std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE);
MapGen gen;
std::thread thread;
};
std::shared_ptr<MapGenProps> props;
MapGen gen;
std::vector<Thread> threads;
std::list<glm::vec3> queuedTasks;
std::unordered_set<glm::vec3, Vec::vec3> queuedMap;

View File

@ -73,17 +73,17 @@ void ServerWorld::update(double delta) {
std::unordered_set<glm::ivec3, Vec::ivec3> changed {};
for (auto& mb : *finished) {
for (const auto& chunk : mb.chunks) {
for (auto& data : *finished) {
for (const auto& chunk : data.chunks) {
changed.insert(chunk->pos);
dimension.setChunk(chunk);
// fileManip->commitChunk(*chunk);
}
auto resend = dimension.calculateEdgeLight(mb.pos);
changed.insert(resend.begin(), resend.end());
// auto resend = dimension.calculateEdgeLight(mb.pos);
// changed.insert(resend.begin(), resend.end());
dimension.getMapBlock(mb.pos)->generated = true;
auto mb = dimension.getMapBlock(data.pos)->generated = true;
}
for (auto& chunk : changed) {

View File

@ -30,29 +30,30 @@ namespace Space {
};
}
inline glm::ivec3 sectionFromGlobal(glm::ivec3 pos, int size) {
inline glm::ivec3 sectionFromGlobal(glm::ivec3 pos, float size) {
return {
std::floor(static_cast<float>(pos.x) / size),
std::floor(static_cast<float>(pos.y) / size),
std::floor(static_cast<float>(pos.z) / size)};
std::floor(static_cast<float>(pos.z) / size)
};
}
}
namespace Region {
namespace world {
// Get a Region engine position from a MapBlock's world position.
static inline glm::ivec3 fromMapBlock(const glm::ivec3& mapBlock) {
return sectionFromGlobal(mapBlock, REGION_SIZE);
// Get a Region world position from a MapBlock's world position.
static inline glm::ivec3 fromMapBlock(const glm::ivec3& pos) {
return sectionFromGlobal(pos, REGION_SIZE);
}
// Get a Region engine position from a Chunk's world position.
static inline glm::ivec3 fromChunk(const glm::ivec3 &chunk) {
return sectionFromGlobal(chunk, REGION_CHUNK_LENGTH);
// Get a Region world position from a Chunk's world position.
static inline glm::ivec3 fromChunk(const glm::ivec3& pos) {
return sectionFromGlobal(pos, REGION_CHUNK_LENGTH);
}
// Get a Region engine position from a Block's world position.
static inline glm::ivec3 fromBlock(const glm::ivec3 &chunk) {
return sectionFromGlobal(chunk, REGION_BLOCK_LENGTH);
// Get a Region world position from a Block's world position.
static inline glm::ivec3 fromBlock(const glm::ivec3& pos) {
return sectionFromGlobal(pos, REGION_BLOCK_LENGTH);
}
}
}
@ -66,14 +67,19 @@ namespace Space {
}
namespace world {
// Get a MapBlock engine position from a Chunk's world position.
static inline glm::ivec3 fromChunk(const glm::ivec3 &chunk) {
return sectionFromGlobal(chunk, MAPBLOCK_SIZE);
// Get a MapBlock world position from a Region's world position.
static inline glm::ivec3 fromRegion(const glm::ivec3& pos) {
return sectionFromGlobal(pos, 1.f / REGION_SIZE);
}
// Get a MapBlock engine position from a Block's world position.
static inline glm::ivec3 fromBlock(const glm::ivec3 &vec) {
return sectionFromGlobal(vec, MAPBLOCK_BLOCK_LENGTH);
// Get a MapBlock world position from a Chunk's world position.
static inline glm::ivec3 fromChunk(const glm::ivec3 &pos) {
return sectionFromGlobal(pos, MAPBLOCK_SIZE);
}
// Get a MapBlock world position from a Block's world position.
static inline glm::ivec3 fromBlock(const glm::ivec3 &pos) {
return sectionFromGlobal(pos, MAPBLOCK_BLOCK_LENGTH);
}
}
@ -99,6 +105,16 @@ namespace Space {
}
namespace world {
// Get a Chunk world position from a Regions's world position.
static inline glm::ivec3 fromRegion(const glm::ivec3& pos) {
return sectionFromGlobal(pos, 1.f / REGION_CHUNK_LENGTH);
}
// Get a Chunk world position from a MapBlock's world position.
static inline glm::ivec3 fromMapBlock(const glm::ivec3& pos) {
return sectionFromGlobal(pos, 1.f / MAPBLOCK_CHUNK_LENGTH);
}
// Get a Chunk world position from a Block's world position.
static inline glm::ivec3 fromBlock(const glm::ivec3& pos) {
return sectionFromGlobal(pos, CHUNK_BLOCK_LENGTH);
@ -140,6 +156,23 @@ namespace Space {
static inline glm::ivec3 toRegion(const glm::ivec3& pos) {
return localFromGlobal(pos, REGION_BLOCK_LENGTH);
}
namespace World {
// Get a Block world position from a Regions's world position.
static inline glm::ivec3 fromRegion(const glm::ivec3& pos) {
return sectionFromGlobal(pos, 1.f / REGION_BLOCK_LENGTH);
}
// Get a Block world position from a MapBlock's world position.
static inline glm::ivec3 fromMapBlock(const glm::ivec3& pos) {
return sectionFromGlobal(pos, 1.f / MAPBLOCK_BLOCK_LENGTH);
}
// Get a Block world position from a Chunk's world position.
static inline glm::ivec3 fromChunk(const glm::ivec3& pos) {
return sectionFromGlobal(pos, CHUNK_BLOCK_LENGTH);
}
}
}
// Get the index of a Block within its Chunk from its local or world position.

View File

@ -47,7 +47,7 @@ std::shared_ptr<Chunk> DimensionBase::getChunk(glm::ivec3 chunkPosition) {
void DimensionBase::setChunk(std::shared_ptr<Chunk> chunk) {
auto mapBlock = getOrCreateMapBlock(Space::MapBlock::world::fromChunk(chunk->pos));
(*mapBlock).set(Space::Chunk::index(chunk->pos), chunk);
mapBlock->set(Space::Chunk::index(chunk->pos), chunk);
}
void DimensionBase::removeChunk(glm::ivec3 pos){
@ -86,6 +86,6 @@ std::shared_ptr<MapBlock> DimensionBase::getOrCreateMapBlock(glm::ivec3 mapBlock
unsigned int index = Space::MapBlock::index(mapBlockPosition);
if ((*region)[index] != nullptr) return (*region)[index];
(*region).set(index, std::make_shared<MapBlock>(mapBlockPosition));
region->set(index, std::make_shared<MapBlock>(mapBlockPosition));
return (*region)[index];
}

View File

@ -49,8 +49,9 @@ bool ServerDimension::setBlock(glm::ivec3 pos, unsigned int block) {
void ServerDimension::setChunk(std::shared_ptr<Chunk> chunk) {
// Combine partials if there are any
std::shared_ptr<Chunk> existing = getChunk(chunk->pos);
if (existing != nullptr) chunk = MapGen::combinePartials(chunk, existing);
//TODO: Reimplement partial handling
// std::shared_ptr<Chunk> existing = getChunk(chunk->pos);
// if (existing != nullptr) chunk = MapGen::combinePartials(chunk, existing);
Dimension::setChunk(chunk);
glm::vec3 mb = Space::MapBlock::world::fromChunk(chunk->pos);

View File

@ -12,27 +12,26 @@
#include "../../net/Serializer.h"
#include "../../net/Deserializer.h"
Chunk::Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes) :
Chunk(blocks, biomes, {0, 0, 0}) {}
Chunk::Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes, glm::ivec3 pos) :
blocks(std::move(blocks)), biomes(std::move(biomes)),
generated(true), pos(pos) {
recalculateRenderableBlocks();
}
Chunk::Chunk(const Chunk& o) :
partial(o.partial),
generated(o.generated),
dirty(o.dirty),
shouldRender(o.shouldRender),
pos(o.pos),
dirty(o.dirty),
blocks(o.blocks),
biomes(o.biomes),
blockLight(o.blockLight),
partial(o.partial),
sunLight(o.sunLight),
generated(o.generated),
blockLight(o.blockLight),
shouldRender(o.shouldRender),
renderableBlocks(o.renderableBlocks) {}
Chunk::Chunk(glm::ivec3 pos) : pos(pos) {}
Chunk::Chunk(glm::ivec3 pos, const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes) :
blocks(std::move(blocks)), biomes(std::move(biomes)),
generated(true), pos(pos) {
countRenderableBlocks();
}
bool Chunk::setBlock(unsigned int ind, unsigned int blk) {
if (!RIE::write(ind, blk, blocks, 4096)) return false;
if (blk == DefinitionAtlas::AIR && !(renderableBlocks = std::max(renderableBlocks - 1, 0))) shouldRender = false;
@ -99,10 +98,10 @@ void Chunk::deserialize(Deserializer& d) {
this->sunLight[i] = sl.s;
}
recalculateRenderableBlocks();
countRenderableBlocks();
}
void Chunk::recalculateRenderableBlocks() {
void Chunk::countRenderableBlocks() {
shouldRender = false;
renderableBlocks = 0;

View File

@ -35,9 +35,9 @@ public:
typedef union { char ch; SunLight s; } sunlight_union;
Chunk() = default;
explicit Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes);
Chunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes, glm::ivec3 pos);
Chunk(const Chunk& o);
explicit Chunk(glm::ivec3 pos);
Chunk(glm::ivec3 pos, const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes);
inline std::unique_lock<std::mutex> aquireLock();
@ -65,7 +65,7 @@ public:
std::string serialize();
void deserialize(Deserializer& d);
void recalculateRenderableBlocks();
void countRenderableBlocks();
bool partial = false;
bool generated = false;
@ -73,8 +73,7 @@ public:
bool dirty = true;
bool shouldRender = true;
glm::ivec3 pos;
glm::ivec3 pos {};
private:
std::mutex m;

View File

@ -12,16 +12,16 @@ zepha.register_block("@aurailus:tnt:tnt", {
pick = 2
},
drop = "@aurailus:tnt:tnt",
on_break = function(pos)
local amp = 20
for i = -amp, amp do
for j = -amp, amp do
for k = -amp, amp do
if V{i, j, k}:distance(V()) < amp then
zepha.set_block(pos + offset, "air")
end
end
end
end
end
-- on_break = function(pos)
-- local amp = 20
-- for i = -amp, amp do
-- for j = -amp, amp do
-- for k = -amp, amp do
-- if V{i, j, k}:distance(V()) < amp then
-- zepha.set_block(pos + offset, "air")
-- end
-- end
-- end
-- end
-- end
})

View File

@ -1,7 +1,11 @@
zepha.register_block("zeus:default:sandstone", {
name = "Sandstone",
model = "base:block",
textures = {"zeus:default:sandstone"},
textures = {
"zeus:default:sandstone_top",
"zeus:default:sandstone_top",
"zeus:default:sandstone"
},
toughness = {
hand = 14,
pick = 3

View File

@ -48,7 +48,7 @@ TEST_CASE("Chunk", "[engine]") {
SECTION("Blocks") {
SECTION("Exact index = 0, strip one after") {
Chunk b {{0, 1, 1, 0}, {}};
Chunk b {{}, {0, 1, 1, 0}, {}};
b.setBlock(0, 2);
@ -60,7 +60,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Exact index, last block same, strip one after") {
Chunk b {{0, 1, 1, 0, 2, 5}, {}};
Chunk b {{}, {0, 1, 1, 0, 2, 5}, {}};
b.setBlock(1, 1);
@ -72,7 +72,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Exact index, last block same, strip two after") {
Chunk b {{0, 1, 2, 0, 4, 5}, {}};
Chunk b {{}, {0, 1, 2, 0, 4, 5}, {}};
b.setBlock(2, 1);
@ -96,7 +96,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Exact index, last block same, no strip after") {
Chunk b {{0, 1, 1, 0}, {}};
Chunk b {{}, {0, 1, 1, 0}, {}};
b.setBlock(1, 1);
@ -108,7 +108,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Exact index, last block different, strip one after") {
Chunk b {{0, 1, 1, 0, 2, 5}, {}};
Chunk b {{}, {0, 1, 1, 0, 2, 5}, {}};
b.setBlock(1, 2);
@ -122,7 +122,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Exact index, last block different, strip two after") {
Chunk b {{0, 1, 2, 0, 4, 5}, {}};
Chunk b {{}, {0, 1, 2, 0, 4, 5}, {}};
b.setBlock(2, 2);
@ -164,7 +164,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Exact index, last block different, no strip after") {
Chunk b {{0, 1, 1, 0}, {}};
Chunk b {{}, {0, 1, 1, 0}, {}};
b.setBlock(1, 2);
@ -178,7 +178,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Greater index, last block same, strip one after") {
Chunk b {{0, 1, 1, 0, 3, 5}, {}};
Chunk b {{}, {0, 1, 1, 0, 3, 5}, {}};
b.setBlock(2, 0);
@ -193,7 +193,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Greater index, last block same, strip two after") {
Chunk b {{0, 1, 2, 0, 5, 5}, {}};
Chunk b {{}, {0, 1, 2, 0, 5, 5}, {}};
b.setBlock(3, 0);
@ -208,7 +208,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Greater index, last block same, no strip after") {
Chunk b {{0, 1, 3, 0}, {}};
Chunk b {{}, {0, 1, 3, 0}, {}};
b.setBlock(1, 1);
@ -222,7 +222,7 @@ TEST_CASE("Chunk", "[engine]") {
SECTION("Greater index, last block different, strip one after") {
SECTION("Indexed block different") {
Chunk b {{0, 1, 1, 0, 3, 5}, {}};
Chunk b {{}, {0, 1, 1, 0, 3, 5}, {}};
b.setBlock(2, 2);
@ -238,7 +238,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Indexed block same") {
Chunk b {{0, 1, 1, 0, 3, 5}, {}};
Chunk b {{}, {0, 1, 1, 0, 3, 5}, {}};
b.setBlock(2, 5);
@ -253,7 +253,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("Greater index, last block different, strip three after") {
Chunk b {{0, 1, 2, 0, 6, 6}, {}};
Chunk b {{}, {0, 1, 2, 0, 6, 6}, {}};
b.setBlock(3, 5);
@ -305,7 +305,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("No index found in loop, last block different, not end of chunk") {
Chunk b {{0, 1, 2, 0}, {}};
Chunk b {{}, {0, 1, 2, 0}, {}};
b.setBlock(6, 6);
@ -321,7 +321,7 @@ TEST_CASE("Chunk", "[engine]") {
}
SECTION("No index found in loop, last block different, end of chunk") {
Chunk b {{0, 1, 2, 0}, {}};
Chunk b {{}, {0, 1, 2, 0}, {}};
b.setBlock(4095, 6);