diff --git a/code/game/header/entity_view.h b/code/game/header/entity_view.h index 9d12aa9..9607bb9 100644 --- a/code/game/header/entity_view.h +++ b/code/game/header/entity_view.h @@ -38,6 +38,8 @@ typedef struct entity_view { // TODO(zaklaus): Find a way to stream dynamic arrays uint8_t blocks_used; uint8_t blocks[256]; + uint32_t color; + uint8_t is_dirty; int64_t tex; // NOTE(zaklaus): internals diff --git a/code/game/header/world/world.h b/code/game/header/world/world.h index 9ef8398..2e060c0 100644 --- a/code/game/header/world/world.h +++ b/code/game/header/world/world.h @@ -36,6 +36,7 @@ typedef struct { uint8_t active_layer_id; ecs_world_t *ecs; ecs_query_t *ecs_update; + ecs_entity_t chunk_handle; ecs_entity_t *chunk_mapping; librg_world *tracker; world_pkt_reader_proc *reader_proc; @@ -62,8 +63,17 @@ ecs_entity_t world_chunk_mapping(librg_chunk id); typedef struct { uint32_t id; uint8_t block_id; - ecs_entity_t chunk_id; + ecs_entity_t chunk_e; + int64_t chunk_id; float ox, oy; } world_block_lookup; -world_block_lookup world_block_from_realpos(float x, float y); \ No newline at end of file +world_block_lookup world_block_from_realpos(float x, float y); +world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx); +int64_t world_chunk_from_realpos(float x, float y); +int64_t world_chunk_from_entity(ecs_entity_t id); +void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id); +uint8_t *world_chunk_get_blocks(int64_t id); +void world_chunk_mark_dirty(ecs_entity_t e); +uint8_t world_chunk_is_dirty(ecs_entity_t e); + diff --git a/code/game/source/game.c b/code/game/source/game.c index db91e3d..4e9de6d 100644 --- a/code/game/source/game.c +++ b/code/game/source/game.c @@ -33,7 +33,7 @@ static WORLD_PKT_READER(pkt_reader) { pkt_header header = {0}; uint32_t ok = pkt_header_decode(&header, data, datalen); header.udata = udata; - + if (ok && header.ok) { return pkt_handlers[header.id].handler(&header) >= 0; } else { @@ -111,7 +111,7 @@ void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t world_viewers_init(num_viewers); active_viewer = &world_viewers[0]; camera_reset(); - + if (game_mode == GAMEKIND_CLIENT) { world_setup_pkt_handlers(pkt_reader, mp_pkt_writer); network_init(); @@ -135,7 +135,7 @@ int8_t game_is_networked() { void game_shutdown() { world_viewers_destroy(); - + if (game_mode == GAMEKIND_CLIENT) { network_client_disconnect(); network_destroy(); @@ -152,12 +152,12 @@ void game_input() { platform_input(); } -void game_update() { +void game_update() { if (game_mode == GAMEKIND_CLIENT) { network_client_tick(); } else world_update(); - + game_world_cleanup_entities(); } @@ -179,14 +179,14 @@ void game_world_cleanup_entities(void) { static uint64_t last_removal_time = 0; if (last_removal_time > zpl_time_rel_ms()) return; last_removal_time = zpl_time_rel_ms() + GAME_ENT_REMOVAL_TIME; - + for (int i = 0; i < zpl_buffer_count(world_viewers); i += 1){ entity_view_tbl *view = &world_viewers[i].entities; uint32_t deletions = 0; - + for (int j = 0; j < zpl_array_count(view->entries); j += 1) { if (deletions > GAME_ENT_REMOVAL_TRESHOLD) return; - + entity_view *e = &view->entries[j].value; if (e->tran_effect == ETRAN_REMOVE) { entity_view_tbl_remove(view, e->ent_id); diff --git a/code/game/source/platform_raylib.c b/code/game/source/platform_raylib.c index d69a681..4e7deb0 100644 --- a/code/game/source/platform_raylib.c +++ b/code/game/source/platform_raylib.c @@ -172,7 +172,7 @@ void DEBUG_draw_ground(uint64_t key, entity_view * data) { DrawTextureRec(tex.texture, (Rectangle){0, 0, tex.texture.width, -tex.texture.height}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); if (zoom_overlay_tran > 0.02f) { - DrawRectangleEco(x, y, size-offset, size-offset, ColorAlpha(ColorFromHSV(key*x, 0.13f, 0.89f), data->tran_time*zoom_overlay_tran*0.75f)); + DrawRectangleEco(x, y, size-offset, size-offset, ColorAlpha(ColorFromHSV(data->color, 0.13f, 0.89f), data->tran_time*zoom_overlay_tran*0.75f)); DrawTextEco(TextFormat("%d %d", (int)data->x, (int)data->y), (int16_t)x+15, (int16_t)y+15, 200 , ColorAlpha(BLACK, data->tran_time*zoom_overlay_tran), 0.0); diff --git a/code/game/source/world/blocks.c b/code/game/source/world/blocks.c index 682fd3f..ad7736e 100644 --- a/code/game/source/world/blocks.c +++ b/code/game/source/world/blocks.c @@ -112,6 +112,8 @@ void *blocks_get_chunk_tex(uint64_t id) { } void blocks_remove_chunk_tex(uint64_t id) { - UnloadRenderTexture(*blocks__chunk_tbl_get(&baked_chunks, id)); + RenderTexture2D *tex = blocks__chunk_tbl_get(&baked_chunks, id); + if (!tex) return; + UnloadRenderTexture(*tex); blocks__chunk_tbl_remove(&baked_chunks, id); } \ No newline at end of file diff --git a/code/game/source/world/world.c b/code/game/source/world/world.c index 6f55d81..d7e150a 100644 --- a/code/game/source/world/world.c +++ b/code/game/source/world/world.c @@ -19,6 +19,7 @@ entity_view world_build_entity_view(int64_t e) { ECS_IMPORT(world_ecs(), Net); entity_view view = {0}; + // TODO(zaklaus): branch out based on ECS tags const Position *pos = ecs_get(world_ecs(), e, Position); if (pos) { @@ -34,12 +35,15 @@ entity_view world_build_entity_view(int64_t e) { view.vy = vel->y; } - const Chunk *chpos = ecs_get(world_ecs(), e, Chunk); - if (chpos) { + + if (ecs_get(world_ecs(), e, Chunk)) { + Chunk *chpos = ecs_get_mut(world_ecs(), e, Chunk, 0); view.kind = EKIND_CHUNK; view.x = chpos->x; view.y = chpos->y; view.blocks_used = 1; + view.is_dirty = chpos->is_dirty; + chpos->is_dirty = false; for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) { view.blocks[i] = world.block_mapping[chpos->id][i]; @@ -84,7 +88,7 @@ int32_t tracker_write_update(librg_world *w, librg_event *e) { // NOTE(zaklaus): exclude chunks from updates as they never move // TODO(zaklaus): use dirty flag to send updates if chunk changes { - if (view.kind == EKIND_CHUNK) { + if (view.kind == EKIND_CHUNK && !view.is_dirty) { return LIBRG_WRITE_REJECT; } } @@ -141,6 +145,7 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) { world.ecs_update = ecs_query_new(world.ecs, "net.ClientInfo, general.Position"); world.chunk_mapping = zpl_malloc(sizeof(ecs_entity_t)*zpl_square(chunk_amount)); world.block_mapping = zpl_malloc(sizeof(uint8_t*)*zpl_square(chunk_amount)); + world.chunk_handle = ecs_typeid(Chunk); int32_t world_build_status = worldgen_test(&world); ZPL_ASSERT(world_build_status >= 0); @@ -154,6 +159,7 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) { world.chunk_mapping[i] = e; world.block_mapping[i] = zpl_malloc(sizeof(uint8_t)*zpl_square(chunk_size)); chunk->id = i; + chunk->is_dirty = false; for (int y = 0; y < chunk_size; y += 1) { for (int x = 0; x < chunk_size; x += 1) { @@ -226,6 +232,8 @@ static void world_tracker_update(uint8_t ticker, uint32_t freq, uint8_t radius) int32_t world_update() { + ECS_IMPORT(world.ecs, General); + profile (PROF_UPDATE_SYSTEMS) { ecs_progress(world.ecs, 0.0f); } @@ -308,10 +316,53 @@ world_block_lookup world_block_from_realpos(float x, float y) { world_block_lookup lookup = { .id = block_idx, .block_id = block_id, - .chunk_id = e, + .chunk_id = chunk_id, + .chunk_e = e, .ox = box, .oy = boy, }; return lookup; } + +world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx) { + uint8_t block_id = world.block_mapping[id][block_idx]; + + world_block_lookup lookup = { + .id = block_idx, + .block_id = block_id, + .chunk_id = id, + .chunk_e = world.chunk_mapping[id], + }; + + return lookup; +} + +int64_t world_chunk_from_realpos(float x, float y) { + librg_chunk chunk_id = librg_chunk_from_realpos(world.tracker, x, y, 0); + return world.chunk_mapping[chunk_id]; +} + +int64_t world_chunk_from_entity(ecs_entity_t id) { + return librg_entity_chunk_get(world.tracker, id); +} + +void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id) { + assert(block_idx >= 0 && block_idx < zpl_square(world.chunk_size)); + world.block_mapping[id][block_idx] = block_id; +} + +uint8_t *world_chunk_get_blocks(int64_t id) { + return world.block_mapping[id]; +} + +void world_chunk_mark_dirty(ecs_entity_t e) { + Chunk *chunk = (Chunk *)ecs_get_mut_w_entity(world.ecs, e, world.chunk_handle, NULL); + if (chunk) chunk->is_dirty = true; +} + +uint8_t world_chunk_is_dirty(ecs_entity_t e) { + Chunk *chunk = (Chunk *)ecs_get_mut_w_entity(world.ecs, e, world.chunk_handle, NULL); + if (chunk) return chunk->is_dirty; + return false; +} \ No newline at end of file diff --git a/code/game/source/world_view.c b/code/game/source/world_view.c index f8e31ea..15ed5bd 100644 --- a/code/game/source/world_view.c +++ b/code/game/source/world_view.c @@ -40,6 +40,8 @@ int32_t tracker_read_update(librg_world *w, librg_event *e) { data.layer_id = view->active_layer_id; predict_receive_update(d, &data); entity_view_update_or_create(&view->entities, entity_id, data); + entity_view_remove_chunk_texture(&view->entities, entity_id); + entity_view_update_chunk_texture(&view->entities, entity_id, view); return 0; } @@ -53,6 +55,7 @@ int32_t tracker_read_create(librg_world *w, librg_event *e) { data.ent_id = entity_id; data.layer_id = view->active_layer_id; data.tran_time = 0.0f; + data.color = rand(); // TODO(zaklaus): feed from server if (data.flag & EFLAG_INTERP) { data.tx = data.x; data.ty = data.y; diff --git a/code/modules/modules/general.h b/code/modules/modules/general.h index 9933bc2..d0441bf 100644 --- a/code/modules/modules/general.h +++ b/code/modules/modules/general.h @@ -12,7 +12,7 @@ ECS_STRUCT(Chunk, { uint32_t id; int16_t x; int16_t y; - //ecs_vector(uint8_t) blocks; + uint8_t is_dirty; }); ECS_STRUCT(Drawable, { diff --git a/code/modules/source/controllers.c b/code/modules/source/controllers.c index 1e0a8b7..895074c 100644 --- a/code/modules/source/controllers.c +++ b/code/modules/source/controllers.c @@ -4,6 +4,8 @@ #include "modules/general.h" #include "modules/physics.h" +#include "world/blocks.h" + #define PLR_MOVE_SPEED 50.0 #define PLR_MOVE_SPEED_MULT 4.0 @@ -32,6 +34,20 @@ void DemoNPCMoveAround(ecs_iter_t *it) { } } +void DemoPlaceIceBlock(ecs_iter_t *it) { + Input *in = ecs_column(it, Input, 1); + Position *p = ecs_column(it, Position, 2); + uint8_t watr_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER); + + for (int i = 0; i < it->count; i++) { + if (in[i].use) { + world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y); + world_chunk_replace_block(l.chunk_id, l.id, watr_id); + world_chunk_mark_dirty(l.chunk_e); + } + } +} + void ControllersImport(ecs_world_t *ecs) { ECS_MODULE(ecs, Controllers); ecs_set_name_prefix(ecs, "Controllers"); @@ -48,6 +64,7 @@ void ControllersImport(ecs_world_t *ecs) { ECS_TAG(ecs, EcsDemoNPC); ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, Input, physics.Velocity); + ECS_SYSTEM(ecs, DemoPlaceIceBlock, EcsOnLoad, Input, general.Position); ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, physics.Velocity, EcsDemoNPC); ECS_PREFAB(ecs, Base, general.Position, physics.Velocity, Input, EcsActor); diff --git a/code/modules/source/general.c b/code/modules/source/general.c index fab4bf3..6b77b5c 100644 --- a/code/modules/source/general.c +++ b/code/modules/source/general.c @@ -3,14 +3,14 @@ void GeneralImport(ecs_world_t *ecs) { ECS_MODULE(ecs, General); ecs_set_name_prefix(ecs, "General"); - + ECS_IMPORT(ecs, FlecsMeta); - + ECS_META(ecs, Position); ECS_META(ecs, Chunk); ECS_META(ecs, Vector2D); ECS_META(ecs, Drawable); - + ECS_SET_COMPONENT(Chunk); ECS_SET_COMPONENT(Vector2D); ECS_SET_COMPONENT(Position);