diff --git a/src/dusk/entity/entity.c b/src/dusk/entity/entity.c index 661b00d..13ad90b 100644 --- a/src/dusk/entity/entity.c +++ b/src/dusk/entity/entity.c @@ -7,6 +7,7 @@ #include "entity.h" #include "assert/assert.h" +#include "util/memory.h" entity_t ENTITIES[ENTITY_COUNT_MAX] = {0}; @@ -24,6 +25,8 @@ void entityInit(entity_t *entity, const entitytype_t type) { ENTITY_CALLBACKS[type].init, "Entity type has no init callback" ); + + memoryZero(entity, sizeof(entity_t)); entity->type = type; ENTITY_CALLBACKS[type].init(entity); diff --git a/src/dusk/world/chunk.c b/src/dusk/world/chunk.c index 6385c3d..994309f 100644 --- a/src/dusk/world/chunk.c +++ b/src/dusk/world/chunk.c @@ -172,14 +172,20 @@ void chunkMapSetPosition(const uint16_t x, const uint16_t y) { void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { assertNotNull(chunk, "Chunk pointer is null"); + // Zero out the chunk data. + memoryZero(chunk, sizeof(chunk_t)); + + // Set the chunk coordinates. chunk->x = x; chunk->y = y; + // Only load data if the chunk is within bounds. if(x >= WORLD_WIDTH || y >= WORLD_HEIGHT) { memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); return; } + // Is chunk data defined? const chunkdata_t *chunkData = WORLD_CHUNKS[y * WORLD_WIDTH + x]; if(chunkData == NULL) { memorySet(chunk->tiles, 0, sizeof(chunk->tiles)); @@ -201,15 +207,19 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { while(data < chunkData->entities + CHUNK_ENTITY_COUNT_MAX) { if(data->type == ENTITY_TYPE_NULL) break; + // Store that this chunk owns this entity ID. + chunk->entityIDs[chunk->entityCount++] = data->id; + // Check entity isn't loaded (still). entity = ENTITIES; do { - if(entity->id == data->id) break; + if(entity->type != ENTITY_TYPE_NULL && entity->id == data->id) break; entity++; } while(entity < ENTITIES + ENTITY_COUNT_MAX); if(entity != ENTITIES + ENTITY_COUNT_MAX) { // Entity is already loaded, skip it. + printf("Entity ID %u already loaded, skipping...\n", data->id); data++; continue; } @@ -240,5 +250,54 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { } void chunkUnload(chunk_t *chunk) { + uint8_t i; + entity_t *entity; + uint32_t id; assertNotNull(chunk, "Chunk pointer is null"); + + // Iterate over each entity this chunk owns. + i = 0; + while(i < chunk->entityCount) { + id = chunk->entityIDs[i++]; + + // Now, do we need to unload this entity? + bool_t shouldUnload = false; + + // Now, find the entity loaded with this ID. It should be impossible for + // this entity to be unloaded (but may change in future). + entity = ENTITIES; + do { + if(entity->type != ENTITY_TYPE_NULL && entity->id == id) break; + entity++; + } while(entity < ENTITIES + ENTITY_COUNT_MAX); + + // If the entity is still within our chunk bounds, it's getting unloaded + if( + entity->x >= chunk->x * CHUNK_WIDTH * TILE_WIDTH && + entity->x < (chunk->x + 1) * CHUNK_WIDTH * TILE_WIDTH && + entity->y >= chunk->y * CHUNK_HEIGHT * TILE_HEIGHT && + entity->y < (chunk->y + 1) * CHUNK_HEIGHT * TILE_HEIGHT + ) { + shouldUnload = true; + } else { + assertUnreachable( + "Entity has left its chunk bounds, we should not be unloading it but " + "I have yet to implement that properly. It will need to self-manage " + "its own unloading somehow, and also not be in a null chunk " + "when it does so." + ); + } + + // This entity is still in use, leave it loaded. + if(!shouldUnload) continue; + + assertTrue( + entity < ENTITIES + ENTITY_COUNT_MAX, + "Entity ID not found for unloading" + ); + + // NULL the entity type, effectively unloading it. + printf("Unloading entity ID %u\n", entity->id); + entity->type = ENTITY_TYPE_NULL; + } } \ No newline at end of file diff --git a/src/dusk/world/chunk.h b/src/dusk/world/chunk.h index 0b5d277..928544c 100644 --- a/src/dusk/world/chunk.h +++ b/src/dusk/world/chunk.h @@ -20,8 +20,8 @@ typedef struct { uint16_t x, y; tile_t tiles[CHUNK_TILE_COUNT]; - // int32_t entityIDs[CHUNK_ENTITY_COUNT_MAX]; - // uint8_t entityCount; + uint32_t entityIDs[CHUNK_ENTITY_COUNT_MAX]; + uint8_t entityCount; } chunk_t; typedef struct { diff --git a/src/dusk/world/overworld.c b/src/dusk/world/overworld.c index 9b0e16d..88305b6 100644 --- a/src/dusk/world/overworld.c +++ b/src/dusk/world/overworld.c @@ -41,6 +41,15 @@ void overworldUpdate() { entityUpdate(entity++); } while(entity->type != ENTITY_TYPE_NULL); + // Testing, follow player + entity = &ENTITIES[0]; // Player entity + assertTrue( + entity->type == ENTITY_TYPE_PLAYER, + "First entity must be player" + ); + OVERWORLD_CAMERA_X = (uint32_t)floorf(entity->x); + OVERWORLD_CAMERA_Y = (uint32_t)floorf(entity->y); + uint16_t x, y; if(OVERWORLD_CAMERA_X < RENDER_WIDTH / 2) { x = 0; diff --git a/src/duskraylib/display/draw/drawoverworld.c b/src/duskraylib/display/draw/drawoverworld.c index d579cb5..84189bc 100644 --- a/src/duskraylib/display/draw/drawoverworld.c +++ b/src/duskraylib/display/draw/drawoverworld.c @@ -26,13 +26,13 @@ void drawOverworldDraw(void) { if(OVERWORLD_CAMERA_X < RENDER_WIDTH / 2) { DRAW_OVERWORLD_CAMERA.target.x = 0; } else { - DRAW_OVERWORLD_CAMERA.target.x = (OVERWORLD_CAMERA_X - RENDER_WIDTH) / 2; + DRAW_OVERWORLD_CAMERA.target.x = OVERWORLD_CAMERA_X - (RENDER_WIDTH / 2); } if(OVERWORLD_CAMERA_Y < RENDER_HEIGHT / 2) { DRAW_OVERWORLD_CAMERA.target.y = 0; } else { - DRAW_OVERWORLD_CAMERA.target.y = (OVERWORLD_CAMERA_Y - RENDER_HEIGHT) / 2; + DRAW_OVERWORLD_CAMERA.target.y = OVERWORLD_CAMERA_Y - (RENDER_HEIGHT / 2); } BeginMode2D(DRAW_OVERWORLD_CAMERA);