Files
dusk/src/rpg/world/map.c
Dominic Masters 903dab49e3
All checks were successful
Build Dusk / build-linux (push) Successful in 44s
Build Dusk / build-psp (push) Successful in 55s
Editor partially started.
2025-11-19 13:00:35 -06:00

188 lines
4.9 KiB
C

/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "map.h"
#include "util/memory.h"
#include "assert/assert.h"
#include "asset/asset.h"
map_t MAP;
errorret_t mapInit() {
memoryZero(&MAP, sizeof(map_t));
// Init the default chunks. In future I'll probably make this based on where
// the player spawns in to save an initial mapSet.
chunkindex_t index = 0;
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
chunk_t *chunk = &MAP.chunks[index];
chunk->position.x = x;
chunk->position.y = y;
chunk->position.z = z;
MAP.chunkOrder[index] = chunk;
errorChain(mapChunkLoad(chunk));
index++;
}
}
}
errorOk();
}
errorret_t mapPositionSet(const chunkpos_t newPos) {
const chunkpos_t curPos = MAP.chunkPosition;
if(chunkPositionIsEqual(curPos, newPos)) {
errorOk();
}
// Determine which chunks remain loaded
chunkindex_t chunksRemaining[MAP_CHUNK_COUNT] = {0};
chunkindex_t chunksFreed[MAP_CHUNK_COUNT] = {0};
uint32_t remainingCount = 0;
uint32_t freedCount = 0;
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
// Will this chunk remain loaded?
chunk_t *chunk = &MAP.chunks[i];
if(
chunk->position.x >= newPos.x &&
chunk->position.x < newPos.x + MAP_CHUNK_WIDTH &&
chunk->position.y >= newPos.y &&
chunk->position.y < newPos.y + MAP_CHUNK_HEIGHT &&
chunk->position.z >= newPos.z &&
chunk->position.z < newPos.z + MAP_CHUNK_DEPTH
) {
// Stays loaded
chunksRemaining[remainingCount++] = i;
continue;
}
// Not remaining loaded
chunksFreed[freedCount++] = i;
}
// Unload the freed chunks
for(chunkindex_t i = 0; i < freedCount; i++) {
chunk_t *chunk = &MAP.chunks[chunksFreed[i]];
mapChunkUnload(chunk);
}
// This can probably be optimized later, for now we check each chunk and see
// if it needs loading or not, and update the chunk order
chunkindex_t orderIndex = 0;
for(chunkunit_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) {
for(chunkunit_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) {
for(chunkunit_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) {
const chunkpos_t newChunkPos = {
newPos.x + xOff, newPos.y + yOff, newPos.z + zOff
};
// Is this chunk already loaded (was not unloaded earlier)?
chunkindex_t chunkIndex = -1;
for(chunkindex_t i = 0; i < remainingCount; i++) {
chunk_t *chunk = &MAP.chunks[chunksRemaining[i]];
if(!chunkPositionIsEqual(chunk->position, newChunkPos)) continue;
chunkIndex = chunksRemaining[i];
break;
}
// Need to load this chunk
if(chunkIndex == -1) {
// Find a freed chunk to reuse
chunkIndex = chunksFreed[--freedCount];
chunk_t *chunk = &MAP.chunks[chunkIndex];
chunk->position = newChunkPos;
errorChain(mapChunkLoad(chunk));
}
MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex];
}
}
}
// Update map position
MAP.chunkPosition = newPos;
errorOk();
}
void mapUpdate() {
}
void mapDispose() {
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
mapChunkUnload(&MAP.chunks[i]);
}
}
void mapChunkUnload(chunk_t* chunk) {
for(uint8_t i = 0; i < chunk->meshCount; i++) {
meshDispose(&chunk->meshes[i]);
}
}
errorret_t mapChunkLoad(chunk_t* chunk) {
char_t buffer[64];
chunk->meshCount = 0;
snprintf(buffer, sizeof(buffer), "map/map/%d_%d_%d.dcf",
chunk->position.x,
chunk->position.y,
chunk->position.z
);
if(!assetFileExists(buffer)) {
memoryZero(chunk->tiles, sizeof(chunk->tiles));
errorOk();
}
errorChain(assetLoad(buffer, chunk));
errorOk();
}
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) {
chunkpos_t relPos = {
position.x - MAP.chunkPosition.x,
position.y - MAP.chunkPosition.y,
position.z - MAP.chunkPosition.z
};
if(
relPos.x < 0 || relPos.y < 0 || relPos.z < 0 ||
relPos.x >= MAP_CHUNK_WIDTH ||
relPos.y >= MAP_CHUNK_HEIGHT ||
relPos.z >= MAP_CHUNK_DEPTH
) {
return -1;
}
return chunkPosToIndex(&relPos);
}
chunk_t* mapGetChunk(const uint8_t index) {
if(index >= MAP_CHUNK_COUNT) return NULL;
return MAP.chunkOrder[index];
}
tile_t mapGetTile(const worldpos_t position) {
chunkpos_t chunkPos;
worldPosToChunkPos(&position, &chunkPos);
chunkindex_t chunkIndex = mapGetChunkIndexAt(chunkPos);
if(chunkIndex == -1) return TILE_SHAPE_NULL;
chunk_t *chunk = mapGetChunk(chunkIndex);
assertNotNull(chunk, "Chunk pointer cannot be NULL");
chunktileindex_t tileIndex = woprldPosToChunkTileIndex(&position);
return chunk->tiles[tileIndex];
}