#include "level.hpp" #include "ecs.hpp" #include "pk.h" #include "scene.hpp" #include "static-ui.hpp" struct level_mstr { pk_membucket *bkt; pk_bkt_arr_t bc; } level_mstr; void pke_level_init() { level_mstr.bkt = pk_mem_bucket_create("pk_bkt_arr level", 1024 * 1024, PK_MEMBUCKET_FLAG_NONE); new (&level_mstr.bc) pk_bkt_arr_t{ pk_bkt_arr_handle_MAX_constexpr, level_mstr.bkt, level_mstr.bkt }; } void pke_level_teardown() { pk_bkt_arr_teardown(&level_mstr.bc); pk_mem_bucket_destroy(level_mstr.bkt); } /* pke_level *pke_level_Get_Inner(LevelHandle handle) { if ( || handle.itemIndex >= level_mstr.bc.limits.itemIndex || (handle.bucketIndex == handle.bucketIndex) { } return &level_mstr.bc.buckets[handle.bucketIndex][handle.itemIndex]; } */ pke_level *pke_level_create(const char *levelName, pk_uuid level_uuid, pk_uuid ev_mgr_uuid) { NULL_CHAR_ARR(safe_name, LEVEL_NAME_MAX_LEN + 1); pke_level *lvl; bool valid; size_t len = strlen(levelName); size_t start = len <= (LEVEL_NAME_MAX_LEN - 1) ? 0 : len - (LEVEL_NAME_MAX_LEN - 1); sprintf(safe_name, pke_level_name_printf_format, levelName + start); /* 2025-09-05 JCB * There used to be logic here enforcing names unique level names. * I'm replacing it with a uuid check that ignores pk_uuid_zed */ pk_iter_t it{}; valid = level_uuid != pk_uuid_zed && pk_bkt_arr_iter_begin(&level_mstr.bc, &it); while (valid == true) { if (it->uuid == level_uuid) { fprintf(stderr, "[pke_level_Create] Failed to create new level: uuid already exists."); return nullptr; } valid = pk_bkt_arr_iter_increment(&level_mstr.bc, &it); } LevelHandle level_handle { pk_bkt_arr_new_handle(&level_mstr.bc) }; if (level_handle == LevelHandle_MAX) { fprintf(stderr, "[pke_level_Create] Failed to create new level handle from BucketContainer"); return nullptr; } lvl = &level_mstr.bc[level_handle]; new (lvl) pke_level{}; lvl->uuid = level_uuid; ECS_CreateEntity(lvl); lvl->levelHandle = level_handle; (void)ev_mgr_uuid; // ECS_CreateEvManager(lvl, ev_mgr_uuid); // TODO if (lvl->bkt == nullptr) { lvl->bkt = pk_mem_bucket_create(levelName, PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); } return lvl; } pke_level *pke_level_get(LevelHandle handle) { return &level_mstr.bc[handle]; } pke_level *pke_level_get_by_name(const char *levelName) { NULL_CHAR_ARR(safe_name, LEVEL_NAME_MAX_LEN + 1); auto len = strlen(levelName); auto start = len <= (LEVEL_NAME_MAX_LEN - 1) ? 0 : len - (LEVEL_NAME_MAX_LEN - 1); sprintf(safe_name, pke_level_name_printf_format, levelName + start); using LevelFindFn = pk_tmpln_2; LevelFindFn scene_find_cb{}; scene_find_cb.func = [&safe_name](const struct pke_level *user_obj_data, const struct pke_level *arr_obj_data) { (void)user_obj_data; return memcmp(safe_name, arr_obj_data->name, PK_MIN(strlen(safe_name), LEVEL_NAME_MAX_LEN)) == 0; }; LevelHandle handle { pk_bkt_arr_find_first_handle(&level_mstr.bc, &LevelFindFn::invoke, &scene_find_cb, NULL) }; if (handle == LevelHandle_MAX) return nullptr; return &level_mstr.bc[handle]; } struct pk_bkt_arr *pke_level_get_levels() { return &level_mstr.bc; } void pke_level_tick(double delta) { (void)delta; pk_iter_t iter; bool b; b = pk_bkt_arr_iter_begin(&level_mstr.bc, &iter); while (b == true) { if (iter->isMarkedForRemoval) { pk_arr_reset(&iter->scene_instances); pk_arr_reset(&iter->cameras); pk_arr_reset(&iter->root_ui_boxes); pk_arr_reset(&iter->input_handles); pk_bkt_arr_free_handle(&level_mstr.bc, iter->levelHandle); new (&*iter) pke_level{}; } b = pk_bkt_arr_iter_increment(&level_mstr.bc, &iter); } } void pke_level_teardown(pke_level *level) { uint32_t u; assert(level != nullptr); if (level->pke_cb_teardown.func != nullptr) { level->pke_cb_teardown.func(); } ECS_MarkForRemoval(level); for (u = 0; u < level->scene_instances.next; ++u) { ECS_MarkForRemoval(pke_scene_get_by_handle(level->scene_instances[u].scene_handle)); } for (u = 0; u < level->cameras.next; ++u) { ECS_MarkForRemoval(level->cameras[u]); } for (u = 0; u < level->input_handles.next; ++u) { pke_input_deactivate_set(level->input_handles[u]); pke_input_unregister_set(level->input_handles[u]); } for (u = 0; u < level->root_ui_boxes.next; ++u) { ECS_MarkForRemoval(level->root_ui_boxes[u]); } if (level->file_path.reserved > 0) { pk_delete_arr(level->file_path.val, level->file_path.reserved); } if (level->bkt != nullptr) { pk_mem_bucket_destroy(level->bkt); } } void pke_level_register_camera(pke_level *level, PkeCamera *camera) { assert(level != nullptr); assert(camera != nullptr); pk_arr_append_t(&level->cameras, camera); } void pke_level_register_input_action_set(pke_level *level, pke_input_action_set_handle handle) { assert(level != nullptr); assert(handle != pke_input_action_set_handle_MAX); pk_arr_append_t(&level->input_handles, handle); } void pke_level_register_root_ui_box(pke_level *level, pke_ui_box *box) { assert(level != nullptr); assert(box != nullptr); pk_arr_append_t(&level->root_ui_boxes, box); } bool find_box_fn(void *user_data, void *item) { (void)user_data; void *box = *reinterpret_cast(item); return user_data == box; } void pke_level_unregister_root_ui_box(pke_level *level, pke_ui_box *box) { assert(level != nullptr); assert(box != nullptr); uint32_t idx = pk_arr_find_first_index(&level->root_ui_boxes, box, find_box_fn); if (idx < level->root_ui_boxes.next) { pk_arr_remove_at(&level->root_ui_boxes, idx); } else { fprintf(stderr, "[pke_level_unregister_root_ui_box] attempted to unregister ui box that was not registered with level '%*s'!\n", LEVEL_NAME_MAX_LEN, level->name); } }