BugFixes, Optimizations, Speed Improvements

#Fixes
* Fix Segfault when you go back to previously generated chunks
* Make dimension & BlockChunks use shared_ptrs (finally)
* MeshGenStream no longer unnecessarily duplicates BlockChunks
* Different Vertical Gen Range to Horizontal

# Clean Up
* Convert most MeshGenerator functions to using references (safety)
* Optimize Flora noise
* Remove raw C array Mesh Initializer (it was messy)
* Pre-generate ActiveRange positions and remove runtime sorting
master
aurailus 2019-04-08 19:18:03 -07:00
parent a1e5f39652
commit 5e9a0774be
27 changed files with 230 additions and 218 deletions

View File

@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
set (CMAKE_CXX_STANDARD 14)
set (PROJECT_NAME "Zeus")
#set (CMAKE_CXX_FLAGS "--coverage")
#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined")
#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-recover=address")
project (${PROJECT_NAME})

View File

@ -15,7 +15,7 @@ Client::Client(int width, int height) {
}
void Client::start(char* path) {
// Start Local Server
//Start Local Server
if (path != nullptr) {
int pid = fork();
if (pid == 0) {
@ -57,10 +57,13 @@ void Client::loop() {
state->deltaTime = now - timeElapsed;
timeElapsed = now;
count ++;
if (count == 20) {
if (count == 5) {
Scene* g = new GameScene(state);
sceneManager.setScene(g); //Main Menu Scene here eventually
count = 8;
}
else {
count++;
}
glfwPollEvents();

View File

@ -12,11 +12,7 @@ Mesh::Mesh() {
}
void Mesh::create(std::vector<float>* vertices, std::vector<unsigned int>* indices) {
create(&(*vertices)[0], &(*indices)[0], (unsigned int)vertices->size(), (unsigned int)indices->size());
}
void Mesh::create(float *vertices, unsigned int *indices, unsigned int vertCount, unsigned int indCount) {
this->indCount = indCount;
this->indCount = (int)indices->size();
glGenVertexArrays(1, &VAO);
@ -25,22 +21,20 @@ void Mesh::create(float *vertices, unsigned int *indices, unsigned int vertCount
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
//Have to multiply by indCount because indices is a pointer to *one* number, not the entire array.
//Could also be sizeof(unsigned int) * indCount
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indCount, indices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indCount * sizeof(unsigned int), &indices->front(), GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertCount, vertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, vertices->size() * sizeof(float), &vertices->front(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 8, nullptr);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, nullptr);
glEnableVertexAttribArray(0); //If dynamic amounts of attrib arrays are needed, then do these before drawing
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 8, (void*)(sizeof(vertices[0]) * 3));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (void*)(sizeof(float) * 3));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 8, (void*)(sizeof(vertices[0]) * 5));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (void*)(sizeof(float) * 5));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);

View File

@ -13,7 +13,6 @@ public:
Mesh();
void create(std::vector<float>* vertices, std::vector<unsigned int>* indices);
void create(float *vertices, unsigned int *indices, unsigned int vertCount, unsigned int indCount);
void draw();
void cleanup();

View File

@ -26,6 +26,8 @@ public:
std::cerr << "State doesn't define cleanup method!" << std::endl;
};
virtual ~Scene() = default;
ClientState* state;
};

View File

@ -23,11 +23,13 @@ Scene* SceneManager::getScene() {
}
void SceneManager::cleanupScene() {
scene->cleanup();
delete scene;
scene = nullptr;
if (scene != nullptr) {
scene->cleanup();
delete scene;
scene = nullptr;
}
}
SceneManager::~SceneManager() {
if (scene != nullptr) cleanupScene();
cleanupScene();
}

View File

@ -118,6 +118,8 @@ void GameScene::draw() {
state->renderer->draw(entity);
}
prevTexture = nullptr;
//TEMPORARY
for (auto &entity : playerEntities) {
auto newTexture = entity->getTexture();
@ -130,6 +132,8 @@ void GameScene::draw() {
state->renderer->draw(entity);
}
prevTexture = nullptr;
state->renderer->enableGuiShader();
for (auto &entity : guiEntities) {

View File

@ -9,7 +9,7 @@
#include "../../../generic/helpers/VecUtils.h"
LocalWorld::LocalWorld(BlockAtlas *atlas) :
meshGenStream(atlas),
meshGenStream(*atlas, dimension),
worldGenStream(55) {
blockAtlas = atlas;
@ -19,7 +19,7 @@ void LocalWorld::loadChunkPacket(Packet *p) {
worldGenStream.pushBack(p);
}
void LocalWorld::commitChunk(glm::vec3 pos, BlockChunk *c) {
void LocalWorld::commitChunk(glm::vec3 pos, std::shared_ptr<BlockChunk> c) {
dimension.addChunk(pos, c);
attemptMeshChunk(pos);
}
@ -58,29 +58,6 @@ bool LocalWorld::getAdjacentExists(glm::vec3 pos, glm::vec3 otherPos) {
return false;
}
std::vector<bool>* LocalWorld::getAdjacentsCull(glm::vec3 pos) {
auto culls = new std::vector<bool>();
culls->reserve(1536); //256 * 6
auto vectors = VecUtils::getCardinalVectors();
for (int i = 0; i < vectors.size(); i++) {
auto chunk = getChunk(pos + vectors[i]);
for (int j = 0; j < 16; j++) {
for (int k = 0; k < 16; k++) {
int x = (i == 0) ? 0 : (i == 1) ? 15 : (i <= 3) ? j : k;
int y = (i == 2) ? 0 : (i == 3) ? 15 : j;
int z = (i == 4) ? 0 : (i == 5) ? 15 : k;
auto block = chunk->getBlock(x, y, z);
culls->push_back(blockAtlas->getBlock(block)->isCulling());
}
}
}
return culls;
}
void LocalWorld::update() {
//Create Finished Messages
auto finishedMeshes = meshGenStream.update();
@ -114,8 +91,7 @@ void LocalWorld::update() {
glm::vec3 pos = *it;
if (!meshGenStream.isQueued(pos)) {
moreSpace = meshGenStream.tryToQueue(
std::pair<BlockChunk*, std::vector<bool>*>{getChunk(pos), getAdjacentsCull(pos)});
moreSpace = meshGenStream.tryToQueue(pos);
}
pendingMesh.erase(it);
@ -161,7 +137,7 @@ bool LocalWorld::solidAt(glm::vec3 pos) {
return blockAtlas->getBlock(blockId)->isSolid();
}
BlockChunk* LocalWorld::getChunk(glm::vec3 chunkPos) {
std::shared_ptr<BlockChunk> LocalWorld::getChunk(glm::vec3 chunkPos) {
return dimension.getChunk(chunkPos);
}

View File

@ -31,7 +31,7 @@ public:
void update();
//Pushes chunk to the list unless one already exists, then tries to mesh it.
void commitChunk(glm::vec3 pos, BlockChunk *c);
void commitChunk(glm::vec3 pos, std::shared_ptr<BlockChunk>);
//Attempts to regenerate a chunk mesh.
void remeshChunk(glm::vec3 pos);
@ -42,11 +42,10 @@ public:
void attemptMeshChunk(glm::vec3 pos);
//This function also updates the chunk that is being checked's adjacent data, so maybe a rename is in order.
bool getAdjacentExists(glm::vec3 pos, glm::vec3 myPos);
std::vector<bool>* getAdjacentsCull(glm::vec3 pos);
std::unordered_map<glm::vec3, MeshChunk*, VecUtils::compareFunc>* getMeshChunks();
BlockChunk* getChunk(glm::vec3 chunkPos);
std::shared_ptr<BlockChunk> getChunk(glm::vec3 chunkPos);
int getBlock(glm::vec3 pos);
void setBlock(glm::vec3 pos, int block);

View File

@ -7,16 +7,15 @@
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
MeshGenStream::MeshGenStream() = default;
MeshGenStream::MeshGenStream(BlockAtlas &a, Dimension &d) :
atlas(a),
dimension(d) {
MeshGenStream::MeshGenStream(BlockAtlas* atlas) {
queuedTasks.reserve((unsigned long) TOTAL_QUEUE_SIZE);
this->atlas = atlas;
threads.reserve(THREADS);
for (int i = 0; i < THREADS; i++) {
threads.emplace_back(this->atlas);
threads.emplace_back(atlas);
}
}
@ -28,12 +27,12 @@ bool MeshGenStream::isQueued(glm::vec3 pos) {
return (bool) queuedMap.count(pos);
}
bool MeshGenStream::tryToQueue(std::pair<BlockChunk*, std::vector<bool>*> data) {
bool MeshGenStream::tryToQueue(glm::vec3 pos) {
unsigned long sizeOfQueue = queuedTasks.size();
if (sizeOfQueue < TOTAL_QUEUE_SIZE && !queuedMap.count(data.first->pos)) {
queuedTasks.push_back(data);
queuedMap.insert(data.first->pos);
if (sizeOfQueue < TOTAL_QUEUE_SIZE && !queuedMap.count(pos)) {
queuedTasks.push_back(pos);
queuedMap.insert(pos);
}
return sizeOfQueue + 1 < TOTAL_QUEUE_SIZE;
@ -53,12 +52,12 @@ std::vector<MeshGenStream::MeshDetails>* MeshGenStream::update() {
if (!queuedTasks.empty()) {
auto it = queuedTasks.begin();
auto data = *it;
glm::vec3 pos = *it;
queuedTasks.erase(it);
queuedMap.erase(data.first->pos);
queuedMap.erase(pos);
u.chunk = data.first;
u.adjacent = data.second;
u.chunk = dimension.getChunk(pos);
u.adjacent = getAdjacentsCull(pos);
//Lock it in to allow the thread to edit it.
u.unlocked = false;
@ -69,8 +68,8 @@ std::vector<MeshGenStream::MeshDetails>* MeshGenStream::update() {
return finishedChunks;
}
MeshGenStream::Thread::Thread(BlockAtlas* atlas) {
this->atlas = atlas;
MeshGenStream::Thread::Thread(BlockAtlas &atlas) :
atlas(atlas) {
thread = new std::thread(MeshGenStream::threadFunction, this);
thread->detach();
@ -88,7 +87,7 @@ void MeshGenStream::threadFunction(MeshGenStream::Thread *thread) {
u.vertices = new std::vector<float>();
u.indices = new std::vector<unsigned int>();
MeshGenerator().build(u.chunk, thread->atlas, u.adjacent, *u.vertices, *u.indices);
MeshGenerator().build(u.chunk, thread->atlas, *u.adjacent, *u.vertices, *u.indices);
delete u.adjacent;
@ -112,4 +111,27 @@ MeshGenStream::~MeshGenStream() {
}
}
std::vector<bool>* MeshGenStream::getAdjacentsCull(glm::vec3 pos) {
auto culls = new std::vector<bool>();
culls->reserve(1536); //256 * 6
auto vectors = VecUtils::getCardinalVectors();
for (int i = 0; i < vectors.size(); i++) {
auto chunk = dimension.getChunk(pos + vectors[i]);
for (int j = 0; j < 16; j++) {
for (int k = 0; k < 16; k++) {
int x = (i == 0) ? 0 : (i == 1) ? 15 : (i <= 3) ? j : k;
int y = (i == 2) ? 0 : (i == 3) ? 15 : j;
int z = (i == 4) ? 0 : (i == 5) ? 15 : k;
auto block = chunk->getBlock(x, y, z);
culls->push_back(atlas.getBlock(block)->isCulling());
}
}
}
return culls;
}
#pragma clang diagnostic pop

View File

@ -13,6 +13,7 @@
#include "../../../generic/blocks/BlockAtlas.h"
#include "../../graphics/mesh/MeshGenerator.h"
#include "../../../generic/helpers/VecUtils.h"
#include "../../../generic/world/Dimension.h"
class MeshGenStream {
public:
@ -20,15 +21,14 @@ public:
static const int THREADS = 4;
static const int TOTAL_QUEUE_SIZE = THREADS * THREAD_QUEUE_SIZE;
MeshGenStream();
explicit MeshGenStream(BlockAtlas* atlas);
explicit MeshGenStream(BlockAtlas& a, Dimension& d);
~MeshGenStream();
bool spaceInQueue();
bool isQueued(glm::vec3 pos);
//Attempt to add `pos` to the pre-thread queue.
//Will return a boolean stating if there is more space left in the queue.
bool tryToQueue(std::pair<BlockChunk*, std::vector<bool>*> data);
bool tryToQueue(glm::vec3 pos);
struct MeshDetails {
std::vector<float>* vertices;
@ -47,7 +47,7 @@ public:
std::vector<MeshDetails>* update();
struct Unit {
BlockChunk* chunk = nullptr;
std::shared_ptr<BlockChunk> chunk = nullptr;
std::vector<bool>* adjacent = nullptr;
std::vector<float>* vertices = nullptr;
@ -57,9 +57,9 @@ public:
};
struct Thread {
explicit Thread(BlockAtlas* atlas);
explicit Thread(BlockAtlas &atlas);
BlockAtlas* atlas;
BlockAtlas &atlas;
std::thread* thread;
bool keepAlive = true;
@ -69,11 +69,13 @@ public:
std::vector<Thread> threads;
private:
std::vector<bool>* getAdjacentsCull(glm::vec3 pos);
static void threadFunction(Thread* thread);
BlockAtlas* atlas;
Dimension& dimension;
BlockAtlas& atlas;
std::vector<std::pair<BlockChunk*, std::vector<bool>*>> queuedTasks;
std::vector<glm::vec3> queuedTasks;
std::unordered_set<glm::vec3, VecUtils::compareFunc> queuedMap;
};

View File

@ -20,15 +20,15 @@ bool WorldInterpolationStream::pushBack(Packet *p) {
queuedTasks.push_back(p);
}
std::vector<BlockChunk*> WorldInterpolationStream::update() {
std::vector<BlockChunk*> finishedChunks;
std::vector<std::shared_ptr<BlockChunk>> WorldInterpolationStream::update() {
std::vector<std::shared_ptr<BlockChunk>> finishedChunks;
for (auto& t : threads) {
for (auto& u : t.tasks) {
if (!u.unlocked) continue;
if (u.chunk != nullptr) {
finishedChunks.push_back(u.chunk);
finishedChunks.push_back(std::shared_ptr<BlockChunk>(u.chunk));
u.chunk = nullptr;
}
@ -37,6 +37,11 @@ std::vector<BlockChunk*> WorldInterpolationStream::update() {
Packet* p = *it;
queuedTasks.erase(it);
if (p == nullptr) {
cerr << "NULL PACKET IN THE WORLD INTERPOLATION STREAM! (" << __LINE__ << ")" << std::endl;
continue;
}
u.packet = p;
//Lock it to allow the thread to edit it.
u.unlocked = false;

View File

@ -26,7 +26,7 @@ public:
//Will return a vector of BlockChunk pointers containing finished chunks.
//Frees up the threads and starts new tasks.
std::vector<BlockChunk*> update();
std::vector<std::shared_ptr<BlockChunk>> update();
struct Unit {
Packet* packet = nullptr;

View File

@ -8,32 +8,32 @@ MeshGenerator::MeshGenerator() {
indOffset = 0;
}
BlockDef* blockData(int ind, BlockChunk* chunk, BlockAtlas* atlas) {
return atlas->getBlock(chunk->getBlock(ind));
BlockDef* blockData(int ind, BlockChunk &chunk, BlockAtlas& atlas) {
return atlas.getBlock(chunk.getBlock(ind));
}
BlockDef* blockData(glm::vec3* pos, BlockChunk* chunk, BlockAtlas* atlas) {
return atlas->getBlock(chunk->getBlock(pos));
BlockDef* blockData(glm::vec3 &pos, BlockChunk &chunk, BlockAtlas &atlas) {
return atlas.getBlock(chunk.getBlock(&pos));
}
bool faceOcculudedAt(glm::vec3* pos, BlockChunk* chunk, BlockAtlas* atlas, std::vector<bool>* bools) {
if (pos->x < 0 || pos->x > 15 || pos->y < 0 || pos->y > 15 || pos->z < 0 || pos->z > 15) {
bool faceOcculudedAt(glm::vec3 &pos, BlockChunk &chunk, BlockAtlas &atlas, std::vector<bool> &bools) {
if (pos.x < 0 || pos.x > 15 || pos.y < 0 || pos.y > 15 || pos.z < 0 || pos.z > 15) {
if (pos->x == -1) return (*bools)[ 256 + (int)pos->y * 16 + (int)pos->z];
if (pos->x == 16) return (*bools)[ + (int)pos->y * 16 + (int)pos->z];
if (pos.x == -1) return bools[ 256 + (int)pos.y * 16 + (int)pos.z];
if (pos.x == 16) return bools[ + (int)pos.y * 16 + (int)pos.z];
if (pos->y == -1) return (*bools)[ 768 + (int)pos->x * 16 + (int)pos->z];
if (pos->y == 16) return (*bools)[ 512 + (int)pos->x * 16 + (int)pos->z];
if (pos.y == -1) return bools[ 768 + (int)pos.x * 16 + (int)pos.z];
if (pos.y == 16) return bools[ 512 + (int)pos.x * 16 + (int)pos.z];
if (pos->z == -1) return (*bools)[1280 + (int)pos->y * 16 + (int)pos->x];
if (pos->z == 16) return (*bools)[1024 + (int)pos->y * 16 + (int)pos->x];
if (pos.z == -1) return bools[1280 + (int)pos.y * 16 + (int)pos.x];
if (pos.z == 16) return bools[1024 + (int)pos.y * 16 + (int)pos.x];
return false;
}
return blockData(pos, chunk, atlas)->isCulling();
}
void MeshGenerator::build(BlockChunk* chunk, BlockAtlas* atlas, std::vector<bool>* adjacents,
void MeshGenerator::build(const std::shared_ptr<BlockChunk> &chunk, BlockAtlas &atlas, std::vector<bool> &adjacents,
std::vector<float> &vertices, std::vector<unsigned int> &indices) {
Timer t("Mesh Generation");
@ -45,68 +45,66 @@ void MeshGenerator::build(BlockChunk* chunk, BlockAtlas* atlas, std::vector<bool
glm::vec3 check;
for (int i = 0; i < 4096; i++) {
if (blockData(i, chunk, atlas)->getModel()->visible) {
if (blockData(i, *chunk, atlas)->getModel()->visible) {
ArrayTrans3D::indAssignVec(i, off);
BlockModel* model = blockData(i, chunk, atlas)->getModel();
BlockModel* model = blockData(i, *chunk, atlas)->getModel();
check.x = off.x - 1; check.y = off.y; check.z = off.z;
if (!faceOcculudedAt(&check, chunk, atlas, adjacents))
addFaces(off, &vertices, &indices, &model->leftFaces);
if (!faceOcculudedAt(check, *chunk, atlas, adjacents))
addFaces(off, vertices, indices, model->leftFaces);
check.x = off.x + 1; check.y = off.y; check.z = off.z;
if (!faceOcculudedAt(&check, chunk, atlas, adjacents))
addFaces(off, &vertices, &indices, &model->rightFaces);
if (!faceOcculudedAt(check, *chunk, atlas, adjacents))
addFaces(off, vertices, indices, model->rightFaces);
check.x = off.x; check.y = off.y - 1; check.z = off.z;
if (!faceOcculudedAt(&check, chunk, atlas, adjacents))
addFaces(off, &vertices, &indices, &model->bottomFaces);
if (!faceOcculudedAt(check, *chunk, atlas, adjacents))
addFaces(off, vertices, indices, model->bottomFaces);
check.x = off.x; check.y = off.y + 1; check.z = off.z;
if (!faceOcculudedAt(&check, chunk, atlas, adjacents))
addFaces(off, &vertices, &indices, &model->topFaces);
if (!faceOcculudedAt(check, *chunk, atlas, adjacents))
addFaces(off, vertices, indices, model->topFaces);
check.x = off.x; check.y = off.y; check.z = off.z - 1;
if (!faceOcculudedAt(&check, chunk, atlas, adjacents))
addFaces(off, &vertices, &indices, &model->backFaces);
if (!faceOcculudedAt(check, *chunk, atlas, adjacents))
addFaces(off, vertices, indices, model->backFaces);
check.x = off.x; check.y = off.y; check.z = off.z + 1;
if (!faceOcculudedAt(&check, chunk, atlas, adjacents))
addFaces(off, &vertices, &indices, &model->frontFaces);
if (!faceOcculudedAt(check, *chunk, atlas, adjacents))
addFaces(off, vertices, indices, model->frontFaces);
addFaces(off, &vertices, &indices, &model->noCulledFaces);
addFaces(off, vertices, indices, model->noCulledFaces);
}
}
vertices.shrink_to_fit();
indices.shrink_to_fit();
// t.printElapsedMs();
}
void MeshGenerator::addFaces(glm::vec3 &offset, vector<float>* vertices, vector<unsigned int>* indices, vector<MeshPart*>* meshParts) {
for (MeshPart *mp : *meshParts) {
void MeshGenerator::addFaces(glm::vec3 &offset, vector<float> &vertices, vector<unsigned int> &indices, vector<MeshPart*> &meshParts) {
for (MeshPart *mp : meshParts) {
MeshVertexIter *vertexIter = mp->getVertexIterator();
while (vertexIter->hasNext()) {
Vertex *vertex = vertexIter->next();
vertices->push_back(vertex->pos->x + offset.x);
vertices->push_back(vertex->pos->y + offset.y);
vertices->push_back(vertex->pos->z + offset.z);
vertices.push_back(vertex->pos->x + offset.x);
vertices.push_back(vertex->pos->y + offset.y);
vertices.push_back(vertex->pos->z + offset.z);
vertices->push_back(vertex->tex->x);
vertices->push_back(vertex->tex->y);
vertices.push_back(vertex->tex->x);
vertices.push_back(vertex->tex->y);
vertices->push_back(vertex->nml->x);
vertices->push_back(vertex->nml->y);
vertices->push_back(vertex->nml->z);
vertices.push_back(vertex->nml->x);
vertices.push_back(vertex->nml->y);
vertices.push_back(vertex->nml->z);
}
MeshIndexIter *indexIter = mp->getIndexIterator();
while (indexIter->hasNext()) {
unsigned int index = indexIter->next();
indices->push_back(indOffset + index);
indices.push_back(indOffset + index);
}
indOffset += mp->getVertexCount();
}

View File

@ -27,14 +27,14 @@ const int CHUNK_SIZE = 16;
class MeshGenerator {
public:
MeshGenerator();
void build(BlockChunk* chunk, BlockAtlas* atlas, std::vector<bool>* adjacents,
std::vector<float> &vertices, std::vector<unsigned int> &indices);
void build(const std::shared_ptr<BlockChunk> &chunk, BlockAtlas &atlas, std::vector<bool> &adjacents,
std::vector<float> &vertices, std::vector<unsigned int> &indices);
~MeshGenerator();
private:
unsigned int indOffset;
void addFaces(glm::vec3 &offset, vector<float>* vertices, vector<unsigned int>* indices, vector<MeshPart*>* meshParts);
void addFaces(glm::vec3 &offset, vector<float> &vertices, vector<unsigned int> &indices, vector<MeshPart*> &meshParts);
void cleanup();
};

View File

@ -31,7 +31,7 @@ void ServerConnection::update(Player &player, std::vector<PlayerEntity*>& player
break;
}
case ENET_EVENT_TYPE_RECEIVE: {
Packet* p = new Packet(event.packet);
auto p = new Packet(event.packet);
switch (p->type) {
case Packet::PLAYER_INFO: {

View File

@ -121,9 +121,9 @@ void MapGen::getDensityMap(MapGenJob &job) {
}
void MapGen::fillChunk(MapGenJob &job) {
auto grass_sample = NoiseSample::getSample(&grassFinal, job.pos, 16, 1, true);
auto flora_type_sample = NoiseSample::getSample(&floraFinal, job.pos, 4, 1, true);
auto flora_density_sample = NoiseSample::getSample(&floraDensity, job.pos, 8, 1, true);
auto grass_sample = NoiseSample::getSample(&grassFinal, job.pos, 16, 0, true);
auto flora_type_sample = NoiseSample::getSample(&floraFinal, job.pos, 4, 0, true);
auto flora_density_sample = NoiseSample::getSample(&floraDensity, job.pos, 8, 0, true);
glm::vec3 lp;

View File

@ -8,6 +8,7 @@
#include <vec3.hpp>
#include <array>
#include <memory>
#include "../helpers/TransPos.h"
#include "../blocks/BlockChunk.h"
@ -16,15 +17,15 @@ class MapBlock {
public:
explicit MapBlock(glm::vec3 pos);
C* operator[](int index);
void set(int index, C* block);
std::shared_ptr<C> operator[](int index);
void set(int index, std::shared_ptr<C> chunk);
~MapBlock();
~MapBlock() = default;
private:
glm::vec3 pos {};
const static int arrayLength = TransPos::MAPBLOCK_SIZE * TransPos::MAPBLOCK_SIZE * TransPos::MAPBLOCK_SIZE;
std::array<C*, arrayLength> blockChunks;
std::array<std::shared_ptr<C>, arrayLength> blockChunks;
};
template<class C>
@ -37,20 +38,13 @@ MapBlock<C>::MapBlock(glm::vec3 pos) {
}
template<class C>
C* MapBlock<C>::operator[](int index) {
std::shared_ptr<C> MapBlock<C>::operator[](int index) {
return blockChunks[index];
}
template<class C>
void MapBlock<C>::set(int index, C* chunk) {
void MapBlock<C>::set(int index, std::shared_ptr<C> chunk) {
blockChunks[index] = chunk;
}
template<class C>
MapBlock<C>::~MapBlock() {
for (int i = 0; i < arrayLength; i++) {
delete blockChunks[i];
}
}
#endif //ZEUS_MAPBLOCK_H

View File

@ -15,8 +15,8 @@ class RegionHandler {
public:
RegionHandler() = default;
void addChunk(glm::vec3 pos, T* chunk);
T* getChunk(glm::vec3 pos);
void addChunk(glm::vec3 pos, std::shared_ptr<T> chunk);
std::shared_ptr<T> getChunk(glm::vec3 pos);
Region<T>* getRegion(glm::vec3 pos);

View File

@ -1,5 +1,5 @@
template <class T>
void RegionHandler<T>::addChunk(glm::vec3 pos, T *chunk) {
void RegionHandler<T>::addChunk(glm::vec3 pos, std::shared_ptr<T> chunk) {
glm::vec3 regionPos = TransPos::Dimension::regionFromVec(pos);
if (!regions.count(regionPos)) regions.insert({regionPos, new Region<T>(regionPos)});
@ -12,12 +12,11 @@ void RegionHandler<T>::addChunk(glm::vec3 pos, T *chunk) {
glm::vec3 chunkPos = TransPos::Dimension::chunkOffsetFromMapBlock(pos);
unsigned int chunkInd = TransPos::chunkIndFromVec(chunkPos);
delete (*mapBlock)[chunkInd];
mapBlock->set(chunkInd, chunk);
}
template <class T>
T *RegionHandler<T>::getChunk(glm::vec3 pos) {
std::shared_ptr<T> RegionHandler<T>::getChunk(glm::vec3 pos) {
glm::vec3 regionPos = TransPos::Dimension::regionFromVec(pos);
if (!regions.count(regionPos)) return nullptr;

View File

@ -45,4 +45,6 @@ ServerPlayer* ConnectionList::createPlayer(ServerPeer *peer, std::string uuid) {
packet.sendTo(peer->peer, PacketChannel::PLAYER_INFO);
world->addPlayer(player);
return player;
}

View File

@ -48,15 +48,15 @@ void ServerPlayer::setPos(glm::vec3 pos) {
}
std::pair<glm::vec3, glm::vec3> ServerPlayer::getBounds() {
glm::vec3 minBounds(chunkPos.x - ACTIVE_RANGE, chunkPos.y - ACTIVE_RANGE, chunkPos.z - ACTIVE_RANGE);
glm::vec3 maxBounds(chunkPos.x + ACTIVE_RANGE, chunkPos.y + ACTIVE_RANGE, chunkPos.z + ACTIVE_RANGE);
glm::vec3 minBounds(chunkPos.x - ACTIVE_RANGE_H, chunkPos.y - ACTIVE_RANGE_H, chunkPos.z - ACTIVE_RANGE_H);
glm::vec3 maxBounds(chunkPos.x + ACTIVE_RANGE_H, chunkPos.y + ACTIVE_RANGE_H, chunkPos.z + ACTIVE_RANGE_H);
return {minBounds, maxBounds};
}
std::pair<glm::vec3, glm::vec3> ServerPlayer::getOldBounds() {
glm::vec3 minBounds(lastChunkPos.x - ACTIVE_RANGE, lastChunkPos.y - ACTIVE_RANGE, lastChunkPos.z - ACTIVE_RANGE);
glm::vec3 maxBounds(lastChunkPos.x + ACTIVE_RANGE, lastChunkPos.y + ACTIVE_RANGE, lastChunkPos.z + ACTIVE_RANGE);
glm::vec3 minBounds(lastChunkPos.x - ACTIVE_RANGE_H, lastChunkPos.y - ACTIVE_RANGE_H, lastChunkPos.z - ACTIVE_RANGE_H);
glm::vec3 maxBounds(lastChunkPos.x + ACTIVE_RANGE_H, lastChunkPos.y + ACTIVE_RANGE_H, lastChunkPos.z + ACTIVE_RANGE_H);
return {minBounds, maxBounds};
}

View File

@ -12,7 +12,8 @@
class ServerPlayer {
public:
const static int ACTIVE_RANGE = 24;
const static int ACTIVE_RANGE_H = 25;
const static int ACTIVE_RANGE_V = 8;
//TODO: Refactor instances of UUID to username, or create seperate username flag
explicit ServerPlayer(ServerPeer* peer, std::string uuid);

View File

@ -8,6 +8,28 @@
#include "../../generic/network/PacketChannel.h"
#include "../../client/engine/Timer.h"
World::World(unsigned int seed) : genStream(seed) {
//Pregenerate chunk generation order
generateOrder.reserve((unsigned long)pow(ServerPlayer::ACTIVE_RANGE_H * 2, 3));
for (int i = 0; i <= ServerPlayer::ACTIVE_RANGE_H; i++) {
for (int j = 0; j <= i; j++) {
for (int k = -ServerPlayer::ACTIVE_RANGE_V; k <= ServerPlayer::ACTIVE_RANGE_V; k++) {
for (int l = -1; l <= 1; l += 2) {
for (int m = -1; m <= 1; m += 2) {
for (int n = 0; n <= 1; n++) {
generateOrder.emplace_back((n ? l*i : m*j), k, (n ? m*j : l*i));
}
}
}
}
}
}
std::cout << "Generated Chunk Queue is " << generateOrder.size() << " chunks long.";
}
void World::addPlayer(ServerPlayer *player) {
Timer t("New Chunk Allocation");
@ -16,25 +38,14 @@ void World::addPlayer(ServerPlayer *player) {
auto bounds = player->getBounds();
auto pos = player->getChunkPos();
std::vector<glm::vec3> toGenerate;
toGenerate.reserve((unsigned long)pow(ServerPlayer::ACTIVE_RANGE, 3));
for (int i = (int)bounds.first.x; i <= (int)bounds.second.x; i++) {
for (int j = (int)bounds.first.y; j <= (int)bounds.second.y; j++) {
for (int k = (int) bounds.first.z; k <= (int) bounds.second.z; k++) {
toGenerate.emplace_back(i, j, k);
}
for (const auto &c : generateOrder) {
glm::vec3 chunkPos = {c.x + pos.x, c.y + pos.y, c.z + pos.z};
if (dimension.getChunk(chunkPos) != nullptr) {
sendChunk(chunkPos, *player->peer);
}
else {
generate(chunkPos);
}
}
std::sort(toGenerate.begin(), toGenerate.end(), [&](glm::vec3 a, glm::vec3 b) {
using namespace std;
return max(max(abs(a.x - pos.x), abs(a.y - pos.y)), abs(a.z - pos.z)) <
max(max(abs(b.x - pos.x), abs(b.y - pos.y)), abs(b.z - pos.z));
});
for (glm::vec3 tPos : toGenerate) {
generate(tPos);
}
t.printElapsedMs();
@ -48,40 +59,30 @@ void World::playerChangedChunks(ServerPlayer *player) {
auto bounds = player->getBounds();
auto oldBounds = player->getOldBounds();
std::vector<glm::vec3> toGenerate;
toGenerate.reserve((unsigned long)pow(ServerPlayer::ACTIVE_RANGE, 3));
int generated = 0;
for (int i = (int)bounds.first.x; i <= (int)bounds.second.x; i++) {
for (int j = (int)bounds.first.y; j <= (int)bounds.second.y; j++) {
for (int k = (int) bounds.first.z; k <= (int) bounds.second.z; k++) {
glm::vec3 tPos(i, j, k);
if (!player->isInBounds(tPos, oldBounds)) {
toGenerate.push_back(tPos);
}
for (const auto &c : generateOrder) {
glm::vec3 chunkPos = {c.x + pos.x, c.y + pos.y, c.z + pos.z};
if (!player->isInBounds(chunkPos, oldBounds)) {
if (dimension.getChunk(chunkPos) != nullptr) {
sendChunk(chunkPos, *player->peer);
}
else {
generate(chunkPos);
generated++;
}
}
}
std::sort(toGenerate.begin(), toGenerate.end(), [&](glm::vec3 a, glm::vec3 b) {
using namespace std;
return max(max(abs(a.x - pos.x), abs(a.y - pos.y)), abs(a.z - pos.z)) <
max(max(abs(b.x - pos.x), abs(b.y - pos.y)), abs(b.z - pos.z));
});
for (glm::vec3 tPos : toGenerate) {
generate(tPos);
}
printf("[INFO] %s moved, generating %d chunks.\n",
player->getUsername().c_str(), (int)toGenerate.size());
player->getUsername().c_str(), generated);
t.printElapsedMs();
player->changedChunks = false;
}
void World::generate(glm::vec3 pos) {
if(!generateQueueMap.count(pos) && !chunkMap.count(pos)) {
if(!generateQueueMap.count(pos) && !dimension.getChunk(pos)) {
generateQueueMap.insert(pos);
generateQueueList.push_back(pos);
}
@ -103,29 +104,13 @@ void World::update() {
generatedChunks = (int)finished.size();
for (auto chunk : finished) {
bool didCalcSerialized = false;
std::string serialized;
dimension.addChunk(chunk->pos, chunk);
for (auto player : players) {
auto bounds = player->getBounds();
if (player->isInBounds(chunk->pos, bounds)) {
//Serialize the chunk
if (!didCalcSerialized) {
serialized = chunk->serialize();
didCalcSerialized = true;
}
//Send the Chunk to the player
Packet r(Packet::CHUNK_INFO);
Serializer::encodeInt(r.data, (int)chunk->pos.x);
Serializer::encodeInt(r.data, (int)chunk->pos.y);
Serializer::encodeInt(r.data, (int)chunk->pos.z);
Serializer::encodeString(r.data, serialized);
r.sendTo(player->peer->peer, PacketChannel::WORLD_INFO);
sendChunk(chunk->pos, *player->peer);
}
}
}
@ -136,8 +121,28 @@ void World::update() {
for (auto player : players) {
r.sendTo(player->peer->peer, PacketChannel::SERVER_INFO);
//Run update method for players
if (player->changedChunks) {
playerChangedChunks(player);
}
}
}
}
void World::sendChunk(glm::vec3 pos, ServerPeer &peer) {
auto chunk = dimension.getChunk(pos);
if (chunk != nullptr) {
auto serialized = chunk->serialize();
Packet r(Packet::CHUNK_INFO);
Serializer::encodeInt(r.data, (int) chunk->pos.x);
Serializer::encodeInt(r.data, (int) chunk->pos.y);
Serializer::encodeInt(r.data, (int) chunk->pos.z);
Serializer::encodeString(r.data, serialized);
r.sendTo(peer.peer, PacketChannel::WORLD_INFO);
}
else {
std::cerr << "Tried to send null chunk at " << pos.x << ", " << pos.y << ", " << pos.z << std::endl;
}
}

View File

@ -12,9 +12,11 @@
#include "../ServerPlayer.h"
#include "WorldGenStream.h"
#include "../../generic/helpers/VecUtils.h"
#include "../../generic/world/Dimension.h"
class World {
public:
explicit World(unsigned int seed) : genStream(seed) {};
explicit World(unsigned int seed);
void addPlayer(ServerPlayer* player);
void update();
@ -23,18 +25,20 @@ public:
private:
void playerChangedChunks(ServerPlayer* player);
void generate(glm::vec3 pos);
void sendChunk(glm::vec3 pos, ServerPeer& peer);
WorldGenStream genStream;
std::vector<ServerPlayer*> players;
std::unordered_map<glm::vec3, BlockChunk*, VecUtils::compareFunc> chunkMap;
std::vector<std::pair<glm::vec3, BlockChunk*>> chunkList;
Dimension dimension;
std::unordered_set<glm::vec3, VecUtils::compareFunc> generateQueueMap;
std::vector<glm::vec3> generateQueueList;
int generatedChunks = 0;
std::vector<glm::vec3> generateOrder;
};

View File

@ -27,15 +27,15 @@ bool WorldGenStream::tryToQueue(glm::vec3 pos) {
return sizeOfQueue + 1 < TOTAL_QUEUE_SIZE;
}
std::vector<BlockChunk*> WorldGenStream::update() {
std::vector<BlockChunk*> finishedChunks;
std::vector<std::shared_ptr<BlockChunk>> WorldGenStream::update() {
std::vector<std::shared_ptr<BlockChunk>> finishedChunks;
for (auto& t : threads) {
for (auto& u : t.tasks) {
if (!u.unlocked) continue;
if (u.chunk != nullptr) {
finishedChunks.push_back(u.chunk);
finishedChunks.push_back(std::shared_ptr<BlockChunk>(u.chunk));
u.chunk = nullptr;
}

View File

@ -31,7 +31,7 @@ public:
//Will return a vector of BlockChunk pointers containing finished chunks.
//Frees up the threads and starts new tasks.
std::vector<BlockChunk*> update();
std::vector<std::shared_ptr<BlockChunk>> update();
struct Unit {
glm::vec3 pos {0, 0, 0};