diff --git a/code/game/CMakeLists.txt b/code/game/CMakeLists.txt index 3f650cd..d68d03a 100644 --- a/code/game/CMakeLists.txt +++ b/code/game/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(eco2d src/entity_view.c src/packet.c src/player.c + src/vehicle.c src/signal_handling.c src/profiler.c src/debug_ui.c diff --git a/code/game/src/debug_ui.c b/code/game/src/debug_ui.c index 17bccc9..423aade 100644 --- a/code/game/src/debug_ui.c +++ b/code/game/src/debug_ui.c @@ -89,6 +89,16 @@ static debug_item items[] = { } } }, + { + .kind = DITEM_LIST, + .name = "debug actions", + .list = { + .items = (debug_item[]) { + { .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar }, + { .kind = DITEM_END }, + } + } + }, { .kind = DITEM_LIST, .name = "profilers", diff --git a/code/game/src/debug_ui_actions.c b/code/game/src/debug_ui_actions.c index 7db24be..89ae57d 100644 --- a/code/game/src/debug_ui_actions.c +++ b/code/game/src/debug_ui_actions.c @@ -1,8 +1,14 @@ #include "debug_ui.h" #include "raylib.h" +#include "vehicle.h" #include "game.h" static inline void ActExitGame(void) { game_request_close(); +} + +static inline void +ActSpawnCar(void) { + vehicle_spawn(); } \ No newline at end of file diff --git a/code/game/src/entity.c b/code/game/src/entity.c index 082688d..724e1d7 100644 --- a/code/game/src/entity.c +++ b/code/game/src/entity.c @@ -10,14 +10,12 @@ #include "zpl.h" uint64_t entity_spawn(uint16_t class_id) { - ECS_IMPORT(world_ecs(), Components); - ecs_entity_t e = ecs_new(world_ecs(), 0); - ecs_set(world_ecs(), e, Velocity, {0}); - ecs_set(world_ecs(), e, Classify, { .id = class_id }); - ecs_add(world_ecs(), e, Walking); - Position *pos = ecs_get_mut(world_ecs(), e, Position, NULL); + w_ecs_set(e, Velocity, {0}); + w_ecs_set(e, Classify, { .id = class_id }); + w_ecs_add(e, Walking); + Position *pos = w_ecs_get_mut(e, Position, NULL); #if 1 pos->x=rand() % world_dim(); pos->y=rand() % world_dim(); diff --git a/code/game/src/entity_view.h b/code/game/src/entity_view.h index 60dcc82..e59b0cb 100644 --- a/code/game/src/entity_view.h +++ b/code/game/src/entity_view.h @@ -7,6 +7,7 @@ typedef enum { EKIND_SERVER = 0, EKIND_PLAYER, + EKIND_VEHICLE, EKIND_DEMO_NPC, EKIND_MONSTER, EKIND_CHUNK, diff --git a/code/game/src/game.c b/code/game/src/game.c index 9996633..ea0fd4a 100644 --- a/code/game/src/game.c +++ b/code/game/src/game.c @@ -81,7 +81,7 @@ world_view *game_world_view_get_active(void) { void game_world_view_cycle_active(int8_t dir) { uint16_t idx = (uint16_t)(active_viewer - world_viewers); - game_world_view_set_active_by_idx((idx+dir)%zpl_buffer_count(world_viewers)); + game_world_view_set_active_by_idx(zpl_max(0, (idx+dir)%zpl_buffer_count(world_viewers))); } void game_world_view_set_active_by_idx(uint16_t idx) { ZPL_ASSERT(idx >= 0 && idx < zpl_buffer_count(world_viewers)); diff --git a/code/game/src/packets/pkt_00_init.c b/code/game/src/packets/pkt_00_init.c index 73ad6fd..b618804 100644 --- a/code/game/src/packets/pkt_00_init.c +++ b/code/game/src/packets/pkt_00_init.c @@ -28,13 +28,12 @@ size_t pkt_00_init_send(uint16_t view_id) { } int32_t pkt_00_init_handler(pkt_header *header) { - ECS_IMPORT(world_ecs(), Components); pkt_00_init table; PKT_IF(pkt_msg_decode(header, pkt_00_init_desc, pkt_pack_desc_args(pkt_00_init_desc), PKT_STRUCT_PTR(&table))); uint64_t peer_id = (uint64_t)header->udata; uint64_t ent_id = player_spawn(NULL); - ecs_set(world_ecs(), ent_id, ClientInfo, {.peer = ent_id, .view_id = header->view_id }); + w_ecs_set(ent_id, ClientInfo, {.peer = ent_id, .view_id = header->view_id }); pkt_01_welcome_send(peer_id, header->view_id, ent_id, world_chunk_size(), world_chunk_amount()); return 0; } diff --git a/code/game/src/packets/pkt_send_keystate.c b/code/game/src/packets/pkt_send_keystate.c index 4d7bcde..4b9de44 100644 --- a/code/game/src/packets/pkt_send_keystate.c +++ b/code/game/src/packets/pkt_send_keystate.c @@ -32,11 +32,9 @@ int32_t pkt_send_keystate_handler(pkt_header *header) { pkt_send_keystate table; PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table))); ecs_entity_t e = PKT_GET_ENT(header); - ecs_world_t *ecs = world_ecs(); - ECS_IMPORT(ecs, Components); - Input *i = ecs_get_mut(world_ecs(), e, Input, NULL); - if (i) { + Input *i = w_ecs_get_mut(e, Input, NULL); + if (i && !i->is_blocked) { i->x = table.x; i->y = table.y; i->use = table.use; diff --git a/code/game/src/player.c b/code/game/src/player.c index d288c11..67b9ad0 100644 --- a/code/game/src/player.c +++ b/code/game/src/player.c @@ -19,14 +19,12 @@ uint64_t player_spawn(char *name) { name = zpl_bprintf("player_%d", e); } - ECS_IMPORT(world_ecs(), Components); - ecs_set(world_ecs(), e, EcsName, {.alloc_value = name }); - ecs_add(world_ecs(), e, EcsClient); - ecs_set(world_ecs(), e, ClientInfo, {0}); - ecs_set(world_ecs(), e, Input, {0}); - ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP}); - ecs_add(world_ecs(), e, Player); + w_ecs_add(e, EcsClient); + w_ecs_set(e, ClientInfo, {0}); + w_ecs_set(e, Input, {0}); + w_ecs_set(e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP}); + w_ecs_add(e, Player); librg_entity_owner_set(world_tracker(), e, (int64_t)e); @@ -36,3 +34,6 @@ uint64_t player_spawn(char *name) { void player_despawn(uint64_t ent_id) { entity_despawn(ent_id); } + +void player_freeze(uint64_t id, uint8_t state, uint8_t clear) { +} \ No newline at end of file diff --git a/code/game/src/player.h b/code/game/src/player.h index cd6b611..dd6ce50 100644 --- a/code/game/src/player.h +++ b/code/game/src/player.h @@ -3,3 +3,5 @@ uint64_t player_spawn(char *name); void player_despawn(uint64_t ent_id); + +void player_freeze(uint64_t id, uint8_t state, uint8_t clear); \ No newline at end of file diff --git a/code/game/src/vehicle.c b/code/game/src/vehicle.c new file mode 100644 index 0000000..d35988b --- /dev/null +++ b/code/game/src/vehicle.c @@ -0,0 +1,17 @@ +#include "vehicle.h" +#include "entity.h" +#include "entity_view.h" +#include "world/world.h" + +#include "modules/components.h" + +uint64_t vehicle_spawn(void) { + ecs_entity_t e = entity_spawn(EKIND_VEHICLE); + + w_ecs_add(e, Vehicle); + return (uint64_t)e; +} + +void vehicle_despawn(uint64_t ent_id) { + entity_despawn(ent_id); +} diff --git a/code/game/src/vehicle.h b/code/game/src/vehicle.h new file mode 100644 index 0000000..5ca9daa --- /dev/null +++ b/code/game/src/vehicle.h @@ -0,0 +1,7 @@ +#pragma once +#include "system.h" + +uint64_t vehicle_spawn(void); +void vehicle_despawn(uint64_t id); + + diff --git a/code/game/src/world/world.c b/code/game/src/world/world.c index 3ef96c7..78a9d47 100644 --- a/code/game/src/world/world.c +++ b/code/game/src/world/world.c @@ -10,39 +10,44 @@ #include "packets/pkt_send_librg_update.h" +ZPL_TABLE(static, world_snapshot, world_snapshot_, entity_view); + static world_data world = {0}; -static Components const *ecs_components; +static world_snapshot streamer_snapshot; +static ecs_entity_t components_handle; entity_view world_build_entity_view(int64_t e) { - ECS_IMPORT(world.ecs, Components); + entity_view *cached_ev = world_snapshot_get(&streamer_snapshot, e); + if (cached_ev) return *cached_ev; + entity_view view = {0}; - const Classify *classify = ecs_get(world.ecs, e, Classify); + const Classify *classify = w_ecs_get(e, Classify); assert(classify); view.kind = classify->id; - const Position *pos = ecs_get(world.ecs, e, Position); + const Position *pos = w_ecs_get(e, Position); if (pos) { view.x = pos->x; view.y = pos->y; } - const Velocity *vel = ecs_get(world.ecs, e, Velocity); + const Velocity *vel = w_ecs_get(e, Velocity); if (vel) { view.flag |= EFLAG_INTERP; view.vx = vel->x; view.vy = vel->y; } - const Health *health = ecs_get(world.ecs, e, Health); + const Health *health = w_ecs_get(e, Health); if (health) { view.hp = health->hp; view.max_hp = health->max_hp; } - if (ecs_get(world.ecs, e, Chunk)) { - Chunk *chpos = ecs_get_mut(world.ecs, e, Chunk, 0); + if (w_ecs_get(e, Chunk)) { + Chunk *chpos = w_ecs_get_mut(e, Chunk, 0); view.x = chpos->x; view.y = chpos->y; view.blocks_used = 1; @@ -54,6 +59,7 @@ entity_view world_build_entity_view(int64_t e) { } } + world_snapshot_set(&streamer_snapshot, e, view); return view; } @@ -90,7 +96,6 @@ int32_t tracker_write_update(librg_world *w, librg_event *e) { entity_view view = world_build_entity_view(entity_id); // 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 && !view.is_dirty) { return LIBRG_WRITE_REJECT; @@ -149,7 +154,8 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) { world.ecs_update = ecs_query_new(world.ecs, "components.ClientInfo, components.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)); - ecs_components = ecs_get(world.ecs, ecs_typeid(Components), Components); + components_handle = ecs_typeid(Components); + world_snapshot_init(&streamer_snapshot, zpl_heap()); int32_t world_build_status = worldgen_test(&world); ZPL_ASSERT(world_build_status >= 0); @@ -190,6 +196,7 @@ int32_t world_destroy(void) { zpl_mfree(world.block_mapping[i]); } zpl_mfree(world.block_mapping); + world_snapshot_destroy(&streamer_snapshot); zpl_memset(&world, 0, sizeof(world)); zpl_printf("[INFO] World was destroyed.\n"); return WORLD_ERROR_NONE; @@ -202,8 +209,6 @@ static void world_tracker_update(uint8_t ticker, uint32_t freq, uint8_t radius) world.tracker_update[ticker] = zpl_time_rel_ms() + freq; profile(PROF_WORLD_WRITE) { - ECS_IMPORT(world.ecs, Components); - ecs_iter_t it = ecs_query_iter(world.ecs_update); static char buffer[WORLD_LIBRG_BUFSIZ] = {0}; world.active_layer_id = ticker; @@ -230,13 +235,18 @@ static void world_tracker_update(uint8_t ticker, uint32_t freq, uint8_t radius) pkt_send_librg_update((uint64_t)p[i].peer, p[i].view_id, ticker, buffer, datalen); } } + + // NOTE(zaklaus): clear out our streaming snapshot + // TODO(zaklaus): move this to zpl + { + zpl_array_clear(streamer_snapshot.hashes); + zpl_array_clear(streamer_snapshot.entries); + } } } int32_t world_update() { - ECS_IMPORT(world.ecs, Components); - profile (PROF_UPDATE_SYSTEMS) { ecs_progress(world.ecs, 0.0f); } @@ -273,11 +283,12 @@ ecs_world_t * world_ecs() { return world.ecs; } -Components const* world_components(void) { - return ecs_components; +Components const *world_components(void) { + ecs_entity_t ecs_typeid(Components) = components_handle; + return ecs_get(world.ecs, ecs_typeid(Components), Components); } -librg_world * world_tracker() { +librg_world *world_tracker() { return world.tracker; } @@ -366,15 +377,15 @@ uint8_t *world_chunk_get_blocks(int64_t id) { void world_chunk_mark_dirty(ecs_entity_t e) { bool was_added=false; - Chunk *chunk = (Chunk *)ecs_get_mut_w_entity(world.ecs, e, ecs_components->ecs_typeid(Chunk), &was_added); + Chunk *chunk = w_ecs_get_mut(e, Chunk, &was_added); assert(!was_added); if (chunk) chunk->is_dirty = true; } uint8_t world_chunk_is_dirty(ecs_entity_t e) { bool was_added=false; - Chunk *chunk = (Chunk *)ecs_get_mut_w_entity(world.ecs, e, ecs_components->ecs_typeid(Chunk), &was_added); + Chunk *chunk = w_ecs_get_mut(e, Chunk, &was_added); assert(!was_added); if (chunk) return chunk->is_dirty; return false; -} \ No newline at end of file +} diff --git a/code/game/src/world/world.h b/code/game/src/world/world.h index 8bbafa2..c593117 100644 --- a/code/game/src/world/world.h +++ b/code/game/src/world/world.h @@ -3,6 +3,7 @@ #include "librg.h" #include "packet.h" #include "flecs/flecs.h" +#include "flecs/flecs_meta.h" #include "modules/components.h" #define WORLD_ERROR_NONE +0x0000 @@ -52,9 +53,9 @@ int32_t world_read(void* data, uint32_t datalen, void *udata); int32_t world_write(pkt_header *pkt, void *udata); uint32_t world_buf(uint8_t const **ptr, uint32_t *width); -ecs_world_t * world_ecs(void); -Components const* world_components(void); -librg_world * world_tracker(void); +ecs_world_t *world_ecs(void); +Components const *world_components(void); +librg_world *world_tracker(void); uint16_t world_chunk_size(void); uint16_t world_chunk_amount(void); @@ -78,3 +79,20 @@ 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); +// NOTE(zaklaus): flecs wrappers for easier world access + +#define w_ecs_set(entity, component, ...)\ +ecs_set_ptr_w_entity(world_ecs(), entity, world_components()->ecs_typeid(component), sizeof(component), &(component)__VA_ARGS__) + +#define w_ecs_add(entity, component)\ +ecs_add_type(world_ecs(), entity, world_components()->ecs_type(component)) + +#define w_ecs_get(entity, component)\ +((const component*)ecs_get_w_entity(world_ecs(), entity, world_components()->ecs_typeid(component))) + +#define w_ecs_get_ref(ref, entity, component)\ +((const component*)ecs_get_ref_w_entity(world_ecs(), ref, entity, world_components()->ecs_typeid(component))) + +#define w_ecs_get_mut(entity, component, is_added)\ +((component*)ecs_get_mut_w_entity(world_ecs(), entity, world_components()->ecs_typeid(component), is_added)) + diff --git a/code/modules/modules/components.c b/code/modules/modules/components.c index b1dc1ee..629b709 100644 --- a/code/modules/modules/components.c +++ b/code/modules/modules/components.c @@ -13,6 +13,7 @@ void ComponentsImport(ecs_world_t *ecs) { ECS_META(ecs, Input); ECS_META(ecs, Health); ECS_META(ecs, Classify); + ECS_META(ecs, Vehicle); ECS_TAG(ecs, Walking); ECS_TAG(ecs, Flying); @@ -37,6 +38,7 @@ void ComponentsImport(ecs_world_t *ecs) { ECS_SET_COMPONENT(Input); ECS_SET_COMPONENT(Health); ECS_SET_COMPONENT(Classify); + ECS_SET_COMPONENT(Vehicle); ECS_SET_ENTITY(EcsClient); ECS_SET_ENTITY(Walking); ECS_SET_ENTITY(Flying); diff --git a/code/modules/modules/components.h b/code/modules/modules/components.h index 5451806..efa463e 100644 --- a/code/modules/modules/components.h +++ b/code/modules/modules/components.h @@ -26,6 +26,7 @@ ECS_STRUCT(Input, { float y; uint8_t use; uint8_t sprint; + uint8_t is_blocked; }); ECS_STRUCT(ClientInfo, { @@ -46,6 +47,10 @@ ECS_STRUCT(Classify, { uint16_t id; }); +ECS_STRUCT(Vehicle, { + uint64_t seats[4]; + }); + typedef struct { ECS_DECLARE_COMPONENT(Chunk); ECS_DECLARE_COMPONENT(Position); @@ -56,6 +61,7 @@ typedef struct { ECS_DECLARE_COMPONENT(ClientInfo); ECS_DECLARE_COMPONENT(Health); ECS_DECLARE_COMPONENT(Classify); + ECS_DECLARE_COMPONENT(Vehicle); ECS_DECLARE_ENTITY(EcsActor); ECS_DECLARE_ENTITY(EcsPlayer); ECS_DECLARE_ENTITY(EcsBuilder); @@ -78,6 +84,7 @@ ECS_IMPORT_COMPONENT(handles, Velocity);\ ECS_IMPORT_COMPONENT(handles, ClientInfo);\ ECS_IMPORT_COMPONENT(handles, Health);\ ECS_IMPORT_COMPONENT(handles, Classify);\ +ECS_IMPORT_COMPONENT(handles, Vehicle);\ ECS_IMPORT_TYPE(handles, Player);\ ECS_IMPORT_TYPE(handles, Builder);\ ECS_IMPORT_TYPE(handles, Movement);\ diff --git a/code/modules/modules/systems.c b/code/modules/modules/systems.c index 2db17c4..0e27cf7 100644 --- a/code/modules/modules/systems.c +++ b/code/modules/modules/systems.c @@ -149,7 +149,6 @@ void MovementImpulse(ecs_iter_t *it) { void DemoNPCMoveAround(ecs_iter_t *it) { Velocity *v = ecs_column(it, Velocity, 1); - for (int i = 0; i < it->count; i++) { v[i].x = zpl_lerp(v[i].x, (rand()%3-1)*DEMO_NPC_MOVE_SPEED, DEMO_NPC_CHANGEDIR_FACTOR); v[i].y = zpl_lerp(v[i].y, (rand()%3-1)*DEMO_NPC_MOVE_SPEED, DEMO_NPC_CHANGEDIR_FACTOR);