From 76be2fa3abafd25c979e63aebbef54f319c048e2 Mon Sep 17 00:00:00 2001 From: yyy257 <170938825+yyy257@users.noreply.github.com> Date: Wed, 29 May 2024 09:39:27 +0000 Subject: [PATCH 1/3] Fix local player pointer randomly becoming corrupted after spawning an item --- source/game/game_state.h | 1 + source/network/client_interface.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/source/game/game_state.h b/source/game/game_state.h index f28f0c3c..84cc3771 100644 --- a/source/game/game_state.h +++ b/source/game/game_state.h @@ -55,6 +55,7 @@ struct game_state { struct camera camera; struct camera_ray_result camera_hit; struct world world; + uint32_t local_player_id; struct entity* local_player; dict_entity_t entities; uint64_t world_time; diff --git a/source/network/client_interface.c b/source/network/client_interface.c index 3f7a8d6e..800b68cb 100644 --- a/source/network/client_interface.c +++ b/source/network/client_interface.c @@ -129,6 +129,7 @@ void clin_process(struct client_rpc* call) { gstate.local_player = dict_entity_safe_get( gstate.entities, call->payload.world_reset.local_entity); + gstate.local_player_id = call->payload.world_reset.local_entity; entity_local_player(call->payload.world_reset.local_entity, gstate.local_player, &gstate.world); @@ -221,6 +222,8 @@ void clin_process(struct client_rpc* call) { case CRPC_SPAWN_ITEM: { struct entity* e = dict_entity_safe_get( gstate.entities, call->payload.spawn_item.entity_id); + gstate.local_player = dict_entity_safe_get( + gstate.entities, gstate.local_player_id); entity_item(call->payload.spawn_item.entity_id, e, false, &gstate.world, call->payload.spawn_item.item); e->teleport(e, call->payload.spawn_item.pos); From e9255ba86d250f0a2a06acb5a9b6f2f72ccbd2b1 Mon Sep 17 00:00:00 2001 From: yyy257 <170938825+yyy257@users.noreply.github.com> Date: Wed, 29 May 2024 14:28:32 +0200 Subject: [PATCH 2/3] Entity dictionary entries are now pointers, so entities don't get moved around in memory --- source/entity/entity.c | 6 +++--- source/entity/entity.h | 4 ++-- source/game/game_state.h | 1 - source/network/client_interface.c | 23 ++++++++++++++--------- source/network/server_local.c | 9 +++++++-- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/source/entity/entity.c b/source/entity/entity.c index 9211d55b..c48aeb57 100644 --- a/source/entity/entity.c +++ b/source/entity/entity.c @@ -306,7 +306,7 @@ void entities_client_tick(dict_entity_t dict) { dict_entity_it(it, dict); while(!dict_entity_end_p(it)) { - struct entity* e = &dict_entity_ref(it)->value; + struct entity* e = dict_entity_ref(it)->value; if(e->tick_client) e->tick_client(e); @@ -321,11 +321,11 @@ void entities_client_render(dict_entity_t dict, struct camera* c, dict_entity_it(it, dict); while(!dict_entity_end_p(it)) { - struct entity* e = &dict_entity_ref(it)->value; + struct entity* e = dict_entity_ref(it)->value; if(e->render && glm_vec3_distance2(e->pos, (vec3) {c->x, c->y, c->z}) < glm_pow2(32.0F)) e->render(e, c->view, tick_delta); dict_entity_next(it); } -} \ No newline at end of file +} diff --git a/source/entity/entity.h b/source/entity/entity.h index 421edd77..e36c74c5 100644 --- a/source/entity/entity.h +++ b/source/entity/entity.h @@ -66,7 +66,7 @@ struct entity { } data; }; -DICT_DEF2(dict_entity, uint32_t, M_BASIC_OPLIST, struct entity, M_POD_OPLIST) +DICT_DEF2(dict_entity, uint32_t, M_BASIC_OPLIST, struct entity*, M_POD_OPLIST) #include "../world.h" @@ -100,4 +100,4 @@ bool entity_aabb_intersection(struct entity* e, struct AABB* a); void entity_try_move(struct entity* e, vec3 pos, vec3 vel, struct AABB* bbox, size_t coord, bool* collision_xz, bool* on_ground); -#endif \ No newline at end of file +#endif diff --git a/source/game/game_state.h b/source/game/game_state.h index 84cc3771..f28f0c3c 100644 --- a/source/game/game_state.h +++ b/source/game/game_state.h @@ -55,7 +55,6 @@ struct game_state { struct camera camera; struct camera_ray_result camera_hit; struct world world; - uint32_t local_player_id; struct entity* local_player; dict_entity_t entities; uint64_t world_time; diff --git a/source/network/client_interface.c b/source/network/client_interface.c index 800b68cb..b66aa518 100644 --- a/source/network/client_interface.c +++ b/source/network/client_interface.c @@ -127,9 +127,11 @@ void clin_process(struct client_rpc* call) { gstate.world_loaded = false; gstate.world.dimension = call->payload.world_reset.dimension; - gstate.local_player = dict_entity_safe_get( + struct entity** local_player_ptr = dict_entity_safe_get( gstate.entities, call->payload.world_reset.local_entity); - gstate.local_player_id = call->payload.world_reset.local_entity; + *local_player_ptr = malloc(sizeof(struct entity)); + assert(*local_player_ptr); + gstate.local_player = *local_player_ptr; entity_local_player(call->payload.world_reset.local_entity, gstate.local_player, &gstate.world); @@ -220,10 +222,11 @@ void clin_process(struct client_rpc* call) { break; case CRPC_SPAWN_ITEM: { - struct entity* e = dict_entity_safe_get( + struct entity** e_ptr = dict_entity_safe_get( gstate.entities, call->payload.spawn_item.entity_id); - gstate.local_player = dict_entity_safe_get( - gstate.entities, gstate.local_player_id); + *e_ptr = malloc(sizeof(struct entity)); + struct entity* e = *e_ptr; + assert(e); entity_item(call->payload.spawn_item.entity_id, e, false, &gstate.world, call->payload.spawn_item.item); e->teleport(e, call->payload.spawn_item.pos); @@ -232,8 +235,8 @@ void clin_process(struct client_rpc* call) { if(gstate.local_player && call->payload.pickup_item.collector_id == gstate.local_player->id) { - struct entity* e = dict_entity_get( - gstate.entities, call->payload.pickup_item.entity_id); + struct entity* e = *(dict_entity_get( + gstate.entities, call->payload.pickup_item.entity_id)); if(e) glm_vec3_copy((vec3) {gstate.camera.x, gstate.camera.y - 0.2F, @@ -242,12 +245,14 @@ void clin_process(struct client_rpc* call) { } } break; case CRPC_ENTITY_DESTROY: + free(*dict_entity_get(gstate.entities, + call->payload.entity_destroy.entity_id)); dict_entity_erase(gstate.entities, call->payload.entity_destroy.entity_id); break; case CRPC_ENTITY_MOVE: { - struct entity* e = dict_entity_get( - gstate.entities, call->payload.entity_move.entity_id); + struct entity* e = *(dict_entity_get( + gstate.entities, call->payload.entity_move.entity_id)); if(e) glm_vec3_copy(call->payload.entity_move.pos, e->network_pos); } break; diff --git a/source/network/server_local.c b/source/network/server_local.c index 97822573..84420b07 100644 --- a/source/network/server_local.c +++ b/source/network/server_local.c @@ -36,7 +36,11 @@ struct entity* server_local_spawn_item(vec3 pos, struct item_data* it, bool throw, struct server_local* s) { uint32_t entity_id = entity_gen_id(s->entities); - struct entity* e = dict_entity_safe_get(s->entities, entity_id); + struct entity** e_ptr = dict_entity_safe_get(s->entities, entity_id); + *e_ptr = malloc(sizeof(struct entity)); + struct entity* e = *e_ptr; + assert(e); + entity_item(entity_id, e, true, &s->world, *it); e->teleport(e, pos); @@ -344,7 +348,7 @@ static void server_local_update(struct server_local* s) { while(!dict_entity_end_p(it)) { uint32_t key = dict_entity_ref(it)->key; - struct entity* e = &dict_entity_ref(it)->value; + struct entity* e = dict_entity_ref(it)->value; if(e->tick_server) { bool remove = (e->delay_destroy == 0) || e->tick_server(e, s); @@ -356,6 +360,7 @@ static void server_local_update(struct server_local* s) { .payload.entity_destroy.entity_id = key, }); + free(e); dict_entity_erase(s->entities, key); } else if(e->delay_destroy < 0) { clin_rpc_send(&(struct client_rpc) { From 1e686d6bf9d44e2bcb88cd7dfbc8328b2f7bc9ca Mon Sep 17 00:00:00 2001 From: yyy257 <170938825+yyy257@users.noreply.github.com> Date: Wed, 29 May 2024 15:02:34 +0200 Subject: [PATCH 3/3] Fix memory leak on world unload --- source/network/client_interface.c | 8 ++++++++ source/network/server_local.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/source/network/client_interface.c b/source/network/client_interface.c index b66aa518..db80fa5e 100644 --- a/source/network/client_interface.c +++ b/source/network/client_interface.c @@ -116,6 +116,14 @@ void clin_process(struct client_rpc* call) { } } + dict_entity_it_t it; + dict_entity_it(it, gstate.entities); + + while(!dict_entity_end_p(it)) { + free(dict_entity_ref(it)->value); + dict_entity_next(it); + } + dict_entity_reset(gstate.entities); gstate.windows[WINDOWC_INVENTORY] diff --git a/source/network/server_local.c b/source/network/server_local.c index 84420b07..a4715f17 100644 --- a/source/network/server_local.c +++ b/source/network/server_local.c @@ -290,6 +290,13 @@ static void server_local_process(struct server_rpc* call, void* user) { level_archive_write_inventory(&s->level, &s->player.inventory); level_archive_write(&s->level, LEVEL_TIME, &s->world_time); + dict_entity_it_t it; + dict_entity_it(it, s->entities); + + while(!dict_entity_end_p(it)) { + free(dict_entity_ref(it)->value); + dict_entity_next(it); + } dict_entity_reset(s->entities); server_world_destroy(&s->world); level_archive_destroy(&s->level);