Skip to content

Commit

Permalink
Smarter chunk loading
Browse files Browse the repository at this point in the history
  • Loading branch information
Sirvoid committed Aug 31, 2022
1 parent 4e335bc commit 4c9b709
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 66 deletions.
5 changes: 0 additions & 5 deletions client/src/chunk/chunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ typedef struct Chunk{
bool onlyAir;
} Chunk;

typedef struct QueuedChunk {
Chunk *chunk;
int state;
} QueuedChunk;

typedef struct LightNode{
int index;
Chunk *chunk;
Expand Down
2 changes: 1 addition & 1 deletion client/src/gui/screens.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ void Screen_MakeOptions(void) {
if (newDrawDistance != world.drawDistance) {
if(newDrawDistance > world.drawDistance) {
world.drawDistance = newDrawDistance;
World_LoadChunks(false);
World_LoadChunks();
} else {
world.drawDistance = newDrawDistance;
World_Reload();
Expand Down
2 changes: 1 addition & 1 deletion client/src/player.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ void Player_Update() {
if (floor(oldPosition.x / 16) != floor(player.position.x / 16) ||
floor(oldPosition.y / 16) != floor(player.position.y / 16) ||
floor(oldPosition.z / 16) != floor(player.position.z / 16)) {
World_LoadChunks(true);
World_LoadChunks();
}

//Place Camera
Expand Down
104 changes: 48 additions & 56 deletions client/src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void World_LoadSingleplayer(void) {
Screen_Switch(SCREEN_GAME);

world.loadChunks = true;
World_LoadChunks(false);
World_LoadChunks();
}

clock_t updateClock;
Expand All @@ -82,17 +82,24 @@ void World_Update(void) {
}

pthread_mutex_t chunk_mutex;
pthread_mutex_t genChunk_mutex;
void *World_ReadChunksQueues(void *state) {
while(true) {

pthread_mutex_lock(&chunk_mutex);

QueuedChunk *queuedChunk = world.generateChunksQueue;
if(world.loadChunks == true && queuedChunk != NULL) {
Chunk_Generate(queuedChunk->chunk);
if(world.loadChunks == true) {

Vector3 pos = (Vector3) {(int)floor(player.position.x / CHUNK_SIZE_X), (int)floor(player.position.y / CHUNK_SIZE_Y), (int)floor(player.position.z / CHUNK_SIZE_Z)};
int index = World_GetClosestChunkIndex(world.generateChunksQueue, pos);

if(arrlen(world.generateChunksQueue) > 0) arrdel(world.generateChunksQueue, 0);
if(index != -1) {
Chunk_Generate(world.generateChunksQueue[index]);
pthread_mutex_lock(&genChunk_mutex);
arrdel(world.generateChunksQueue, index);
pthread_mutex_unlock(&genChunk_mutex);
}

}

pthread_mutex_unlock(&chunk_mutex);
Expand All @@ -101,22 +108,35 @@ void *World_ReadChunksQueues(void *state) {
return NULL;
}

int World_GetClosestChunkIndex(Chunk* *array, Vector3 pos) {
int arrLength = arrlen(array);
if(arrLength > 0) {
Chunk* queuedChunk = array[0];
int index = 0;
for(int i = 0; i < arrLength; i++) {
if(Vector3Distance(array[i]->position, pos) < Vector3Distance(queuedChunk->position, pos)) {
queuedChunk = array[i];
index = i;
}
}
return index;
}

return -1;
}

void World_QueueChunk(Chunk *chunk) {

if(chunk->hasStartedGenerating == false) {
QueuedChunk queued;
queued.chunk = chunk;
queued.state = 0;
arrput(world.generateChunksQueue, queued);
pthread_mutex_lock(&genChunk_mutex);
arrput(world.generateChunksQueue, chunk);
pthread_mutex_unlock(&genChunk_mutex);

}
chunk->hasStartedGenerating = true;

if(chunk->isBuilding == false) {
QueuedChunk queued;
queued.chunk = chunk;
queued.state = 0;
arrput(world.buildChunksQueue, queued);
arrput(world.buildChunksQueue, chunk);
chunk->isBuilding = true;
}
}
Expand Down Expand Up @@ -164,68 +184,40 @@ void World_UpdateChunks(void) {

int meshUpdatesCount = 4;

for (int i = arrlen(world.buildChunksQueue) - 1; i >= 0; i--) {
Chunk *chunk = world.buildChunksQueue[i].chunk;
for (int i = 0; i < meshUpdatesCount; i++) {
Vector3 pos = (Vector3) {(int)floor(player.position.x / CHUNK_SIZE_X), (int)floor(player.position.y / CHUNK_SIZE_Y), (int)floor(player.position.z / CHUNK_SIZE_Z)};
int index = World_GetClosestChunkIndex(world.buildChunksQueue, pos);
if(index == -1) continue;
Chunk *chunk = world.buildChunksQueue[index];
if(chunk->isLightGenerated == true) {
if(Chunk_AreNeighbourGenerated(chunk) == true) {
Chunk_BuildMesh(chunk);
chunk->isBuilding = false;
arrdel(world.buildChunksQueue, i);
if(--meshUpdatesCount == 0) return;
arrdel(world.buildChunksQueue, index);

continue;
}
}
}

}

void World_LoadChunks(bool loadEdges) {
void World_LoadChunks(void) {

if(!world.loadChunks) return;

Vector3 pos = (Vector3) {(int)floor(player.position.x / CHUNK_SIZE_X), (int)floor(player.position.y / CHUNK_SIZE_Y), (int)floor(player.position.z / CHUNK_SIZE_Z)};

//Create chunks or prepare array of chunks to be sorted
int loadingHeight = fmin(world.drawDistance, 4);
int sortedLength = 0;
struct { Vector3 chunkPos; float dist; } sortedChunks[(world.drawDistance + 1) * 2 * (world.drawDistance + 1) * 2 * (loadingHeight + 1) * 2];
for(int x = -world.drawDistance ; x <= world.drawDistance; x++) {
for(int z = -world.drawDistance ; z <= world.drawDistance; z++) {
for(int y = -loadingHeight ; y <= loadingHeight; y++) {
for(int y = loadingHeight; y >= -loadingHeight; y--) {
for(int x = -world.drawDistance ; x <= world.drawDistance; x++) {
for(int z = -world.drawDistance ; z <= world.drawDistance; z++) {
Vector3 chunkPos = (Vector3) {pos.x + x, pos.y + y, pos.z + z};
if(!loadEdges) {
sortedChunks[sortedLength].chunkPos = chunkPos;
sortedChunks[sortedLength].dist = Vector3Distance(chunkPos, pos);
sortedLength++;
} else if(Vector3Distance(chunkPos, pos) >= world.drawDistance - 1) {
World_AddChunk(chunkPos);
}
World_AddChunk(chunkPos);
}
}
}

if(!loadEdges) {
//Sort array of chunks front to back
for(int i = 1; i < sortedLength; i++) {
int j = i;
while(j > 0 && sortedChunks[j-1].dist > sortedChunks[j].dist) {

struct { Vector3 chunkPos; float dist; } tempC;
tempC.chunkPos = sortedChunks[j].chunkPos;
tempC.dist = sortedChunks[j].dist;

sortedChunks[j] = sortedChunks[j - 1];
sortedChunks[j - 1].chunkPos = tempC.chunkPos;
sortedChunks[j - 1].dist = tempC.dist;
j = j - 1;
}
}

//Create the chunks
for(int i = 0; i < sortedLength; i++) {
World_AddChunk(sortedChunks[i].chunkPos);
}
}

//destroy far chunks
for (int i = hmlen(world.chunks) - 1; i >= 0 ; i--) {
Expand All @@ -247,7 +239,7 @@ void World_LoadChunks(bool loadEdges) {
void World_Reload(void) {
World_Unload();
world.loadChunks = true;
World_LoadChunks(false);
World_LoadChunks();
}

void World_Unload(void) {
Expand Down
8 changes: 5 additions & 3 deletions client/src/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
typedef struct World{
Entity *entities;
struct { long int key; Chunk* value; } *chunks;
QueuedChunk *generateChunksQueue;
QueuedChunk *buildChunksQueue;
Chunk* *generateChunksQueue;
Chunk* *buildChunksQueue;
Material mat;
int drawDistance;
float time;
Expand All @@ -37,13 +37,15 @@ void World_Update(void);
//Build Chunks mesh in queue
void World_UpdateChunks(void);
//Load & Unload Chunks around players.
void World_LoadChunks(bool loadEdges);
void World_LoadChunks(void);
//Read Queue to generate chunks.
void *World_ReadChunksQueues(void *state);
//Queue a chunk to build it.
void World_QueueChunk(Chunk *chunk);
//Add a chunk.
void World_AddChunk(Vector3 position);
//Get closest chunk from position in array
int World_GetClosestChunkIndex(Chunk* *array, Vector3 pos);
//Unload the world.
void World_Unload(void);
//Reload chunks.
Expand Down

0 comments on commit 4c9b709

Please sign in to comment.