diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-27 11:58:47 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-27 11:58:47 -0400 |
| commit | e4604d5b84a71ac3cc8fe1a148d0a6250c7a715c (patch) | |
| tree | 0f768c8b5d0b96cb459f92c7795c6c9353710ed1 | |
| parent | 11057d2aa423f9b565f3fead4c260999d1bdb53e (diff) | |
pke: generate uuid and save to project+scene files
| -rw-r--r-- | editor/editor.cpp | 39 | ||||
| -rw-r--r-- | src/components.hpp | 2 | ||||
| -rw-r--r-- | src/ecs.cpp | 9 | ||||
| -rw-r--r-- | src/game.cpp | 41 | ||||
| -rw-r--r-- | src/project.cpp | 10 | ||||
| -rw-r--r-- | src/scene.cpp | 15 |
6 files changed, 87 insertions, 29 deletions
diff --git a/editor/editor.cpp b/editor/editor.cpp index 2de4772..159a828 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -57,7 +57,7 @@ const char* const dbgCtrl_ImGui_Toggle = "debug-imgui-toggle"; // TODO editor state (scene vs level) struct editor_master { pke_scene *active_scene; - pk_str target_scene_name; + pk_str target_scene_path; bool shouldLoadScene = false; bool shouldSaveScene = false; } editor_mstr; @@ -186,20 +186,29 @@ void PkeEditor_Tick(double delta) { }); PkeThreads_Enqueue(threadPoolHandle, task); } - if (editor_mstr.shouldSaveScene && editor_mstr.active_scene->file_path.val) { + if (editor_mstr.shouldSaveScene && editor_mstr.active_scene) { + NULL_CHAR_ARR(file_path, 256); editor_mstr.shouldSaveScene = false; - Game_SaveSceneFile(editor_mstr.active_scene->file_path.val); + if (editor_mstr.active_scene->file_path.val) { + sprintf(file_path, "%.255s", editor_mstr.active_scene->file_path.val); + } else { + sprintf(file_path, "%.16s", editor_mstr.active_scene->name); + } + Game_SaveSceneFile(file_path); shouldRebuildProjectDir = true; } - if (editor_mstr.target_scene_name.val != nullptr) { + if (editor_mstr.target_scene_path.val != nullptr) { if (editor_mstr.active_scene != nullptr) { pke_scene_remove(editor_mstr.active_scene->scene_handle); } ActiveCamera = &NullCamera; - Game_LoadSceneFile(editor_mstr.target_scene_name.val); - editor_mstr.active_scene = pke_scene_get_by_name(editor_mstr.target_scene_name.val); - pk_delete<char>(editor_mstr.target_scene_name.val, editor_mstr.target_scene_name.reserved); - editor_mstr.target_scene_name = {}; + Game_LoadSceneFile(editor_mstr.target_scene_path.val); + std::filesystem::path p(editor_mstr.target_scene_path.val); + editor_mstr.active_scene = pke_scene_get_by_name(p.stem().c_str()); + if (editor_mstr.active_scene) { + editor_mstr.active_scene->file_path = editor_mstr.target_scene_path; + } + editor_mstr.target_scene_path = {}; return; } @@ -305,7 +314,9 @@ void PkeEditor_Tick(double delta) { while (entityInstancesToCreate.Count() > 0) { EntityType *et = entityInstancesToCreate.Pop(); if (et->createInstanceCallback.func) { - reinterpret_cast<void(*)()>(et->createInstanceCallback.func)(); + // TODO function signature + // reinterpret_cast<void(*)()>(et->createInstanceCallback.func)(); + fprintf(stderr, "[%s] Attempted to call EntityType::createInstanceCallback without a function signature", __FILE__); } else { EntityType_CreateGenericInstance(et, PkeLevel_Get(pkeSettings.rt.activeLevel), nullptr); } @@ -1606,11 +1617,11 @@ void BuildDirRecursive(const std::filesystem::directory_entry &de, fsEntry *dirF void BuildProjectMenuRecursive(fsEntry &entry) { if (entry.type == 1) { if (ImGui::Selectable(entry.name, false, ImGuiSelectableFlags_AllowDoubleClick) && ImGui::IsMouseDoubleClicked(0)) { - assert(editor_mstr.target_scene_name.val == nullptr); - editor_mstr.target_scene_name.length = strlen(entry.name); - editor_mstr.target_scene_name.reserved = editor_mstr.target_scene_name.length + 1; - editor_mstr.target_scene_name.val = pk_new<char>(editor_mstr.target_scene_name.reserved); - strcpy(editor_mstr.target_scene_name.val, entry.name); + assert(editor_mstr.target_scene_path.val == nullptr); + editor_mstr.target_scene_path.length = strlen(entry.name); + editor_mstr.target_scene_path.reserved = editor_mstr.target_scene_path.length + 1; + editor_mstr.target_scene_path.val = pk_new<char>(editor_mstr.target_scene_path.reserved); + strncpy(editor_mstr.target_scene_path.val, entry.name, editor_mstr.target_scene_path.reserved); ActiveCamera = &NullCamera; } } else if (entry.type == 0) { diff --git a/src/components.hpp b/src/components.hpp index 326b0e6..f4e7c7f 100644 --- a/src/components.hpp +++ b/src/components.hpp @@ -28,6 +28,7 @@ constexpr LevelHandle LevelHandle_MAX = LevelHandle{ pk_handle_MAX_constexpr }; struct Entity_Base { EntityHandle handle = EntityHandle_MAX; EntityHandle parentHandle = EntityHandle_MAX; + pk_uuid uuid = pk_uuid_max; bool isMarkedForRemoval = false; }; @@ -65,6 +66,7 @@ struct CompInstance { EntityHandle entHandle = EntityHandle_MAX; GrBindsHandle grBindsHandle = GrBindsHandle_MAX; InstanceHandle instanceHandle = InstanceHandle_MAX; + pk_uuid uuid = pk_uuid_max; uint32_t index = ECS_UNSET_VAL_32; PhysicsCollision physicsLayer = PhysicsCollision{1}; PhysicsCollision physicsMask = PhysicsCollision{1}; diff --git a/src/ecs.cpp b/src/ecs.cpp index 4174bd0..048669d 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -5,6 +5,7 @@ #include "game-settings.hpp" #include "math-helpers.hpp" #include "physics.hpp" +#include "pk.h" #include "window.hpp" #include <btBulletDynamicsCommon.h> @@ -68,6 +69,10 @@ void ECS_Init() { } Entity_Base *ECS_CreateGenericEntity() { + /* 2025-03-26 - JCB + * The only place this is called immediately calls ECS_CreateEntity afterwards. + * There is no need to generate a uuid + */ pk_handle newHandle{Buckets_NewHandle(ecs.bc.generics)}; return &ecs.bc.generics.buckets[newHandle.bucketIndex][newHandle.itemIndex]; } @@ -78,6 +83,7 @@ EntityHandle ECS_CreateEntity(Entity_Base *entity, Entity_Base *parentEntity) { EntityHandle entityHandle{Buckets_NewHandle(ecs.bc.entityPtrs)}; entity->handle = entityHandle; if (parentEntity) entity->parentHandle = parentEntity->handle; + if (entity->uuid == pk_uuid_max || entity->uuid == pk_uuid_zed) entity->uuid = pk_uuid_new_v7(); ecs.bc.entityPtrs.buckets[entityHandle.bucketIndex][entityHandle.itemIndex] = entity; return entityHandle; } @@ -443,6 +449,9 @@ CompInstance *ECS_CreateInstance(Entity_Base *entity, CompGrBinds *entityTypeGrB new (comp) CompInstance{}; comp->entHandle = entity->handle; comp->instanceHandle = instanceHandle; + // TODO this should be passed in - currently generating a new one each time + // Consider making a Component_Base that has a UUID, and pass in similar to ECS_CreateEntity + if (comp->uuid == pk_uuid_zed || comp->uuid == pk_uuid_max) comp->uuid = pk_uuid_new_v7(); if (entityTypeGrBinds != nullptr) { comp->grBindsHandle = entityTypeGrBinds->grBindsHandle; diff --git a/src/game.cpp b/src/game.cpp index 2edea8c..630495a 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -54,6 +54,7 @@ const char *PKE_FILE_OBJ_CAMERA = "Camera:"; const char *PKE_FILE_INSTANCE_HANDLE = "Inst::InstHandle: "; const char *PKE_FILE_INSTANCE_ENTITY_HANDLE = "EntityHandle: "; const char *PKE_FILE_INSTANCE_ENTITY_TYPE_CODE = "EntityTypeCode: "; +const char *PKE_FILE_INSTANCE_UUID = "UUID: "; const char *PKE_FILE_INSTANCE_POS_POS = "InstPos::Pos: "; const char *PKE_FILE_INSTANCE_POS_ROT = "InstPos::Rot: "; const char *PKE_FILE_INSTANCE_POS_SCALE = "InstPos::Scale: "; @@ -68,6 +69,7 @@ const char *PKE_FILE_CAMERA_POS = "Cam::Pos: "; const char *PKE_FILE_CAMERA_ROT = "Cam::Rot: "; const char *PKE_FILE_CAMERA_TARGET = "Cam::Target: "; const char *PKE_FILE_CAMERA_TYPE = "Cam::Type: "; +const char *PKE_FILE_CAMERA_UUID = "Cam::UUID: "; const char *PKE_FILE_CAMERA_ORIENTATION = "Cam::Orientation: "; const char *PKE_FILE_CAMERA_INSTANCE_HANDLE = "Cam::InstanceHandle: "; const char *PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE = "Cam::TargetInstanceHandle: "; @@ -76,6 +78,9 @@ const char *PKE_FILE_CAMERA_IS_PRIMARY = "Cam::IsPrimary: "; void SerializeCamera(std::ostream &stream, const PkeCamera &cam) { NULL_CHAR_ARR(handleStr, 23); PkeCamera c{}; + if (cam.uuid != pk_uuid_zed && cam.uuid != pk_uuid_max) { + stream << PKE_FILE_CAMERA_UUID << cam.uuid << std::endl; + } if (cam.type != c.type) { stream << PKE_FILE_CAMERA_TYPE << int(static_cast<PkeCameraType_T>(cam.type)) << std::endl; } @@ -115,6 +120,9 @@ void SerializeInstance(std::ostream &stream, const CompInstance &comp) { snprintf(handleStr, 22, "0x%08X 0x%08X", comp.instanceHandle.bucketIndex, comp.instanceHandle.itemIndex); stream << PKE_FILE_INSTANCE_HANDLE << handleStr << std::endl; } + if (comp.uuid != pk_uuid_zed && comp.uuid != pk_uuid_max) { + stream << PKE_FILE_INSTANCE_UUID << comp.uuid << std::endl; + } if (et != nullptr) { stream << PKE_FILE_INSTANCE_ENTITY_TYPE_CODE << et->entityTypeCode.val << std::endl; } else if (PkeCamera_Get(comp.entHandle)) { @@ -286,8 +294,17 @@ void DeserializeInstance(Entity_Base *parentEntity, std::istream &stream) { if (skipEntCreate == false) { if (etPtr != nullptr && etPtr->createInstanceCallback.func != nullptr) { - typedef Entity_Base *CreateInst(); - entity = reinterpret_cast<CreateInst*>(etPtr->createInstanceCallback.func)(); + /* TODO 2025-03-27 JCB + * We have not yet defined what the appropriate callback signature + * for creating an entity instance is. + * What should be passed as arguments? What would need to be passed + * that couldn't be accessed globally? + * Consider changing this callback to trigger after creating a + * generic instance, rather than *creating* it. + */ + // typedef Entity_Base *CreateInst(); + // entity = reinterpret_cast<CreateInst*>(etPtr->createInstanceCallback.func)(); + fprintf(stderr, "[%s] Attempted to call EntityType::createInstanceCallback and we have not yet defined a valid function signature", __FILE__); } else { entity = EntityType_CreateGenericInstance(etPtr, parentEntity, &comp, &mapping.newInstance); fprintf(stdout ,"[Game::DeserializeInstance] Debug: entTypeCode '%s' does not have a registered callback func to handle instance creation.\n", entTypeCode); @@ -444,21 +461,23 @@ void Game_SaveSceneFile(const char *sceneFilePath) { } stream << PKE_FILE_END << std::endl; - } - catch (...) { - failed = true; + } catch (std::exception e) { + fprintf(stderr, "[%s][Game_SaveSceneFile] Failed to serialize scene file: %s\n", __FILE__, e.what()); + failed = false; + } catch (...) { + fprintf(stderr, "[%s][Game_SaveSceneFile] Failed to serialize scene file, uncaught exception.\n", __FILE__); + failed = false; } if (failed == false) { std::ofstream f(sceneFilePath); - if (f.is_open()) { - f << stream.str(); - - f.flush(); - f.close(); - } else { + if (!f.is_open()) { failed = true; + } else { + f << stream.str(); } + f.flush(); + f.close(); } if (failed) { diff --git a/src/project.cpp b/src/project.cpp index e8679c8..d371f68 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -29,6 +29,7 @@ const char* const PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_END = "PkeSet::Scenes: ]"; const char* const PKE_PROJ_FILE_ENTITY_TYPE_MODEL_ASSET_KEY = "ModelAssetKey: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE = "EntityTypeCode: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE = "EntityHandle: "; +const char* const PKE_PROJ_FILE_ENTITY_TYPE_UUID = "UUID: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_CREATE_INSTANCE_CALLBACK_SIGNATURE = "InstanceCreateCallbackSignature: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE = "CollisionCallbackSignature: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_BEGIN = "EntityHandleDetails: {"; @@ -77,6 +78,9 @@ void Proj_SerializeEntityType(std::ostream &stream, const EntityType &et) { stream << PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE << et.entityTypeCode.val << std::endl; if (et.handle != e.handle) stream << PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE << handleStr << std::endl; + if (et.uuid != pk_uuid_zed && et.uuid != pk_uuid_max) { + stream << PKE_PROJ_FILE_ENTITY_TYPE_UUID << et.uuid << std::endl; + } if (et.createInstanceCallback.name[0] != '\0') { stream << PKE_PROJ_FILE_ENTITY_TYPE_CREATE_INSTANCE_CALLBACK_SIGNATURE << et.createInstanceCallback.name << std::endl; } @@ -404,7 +408,11 @@ void PkeProject_Save(const char *filePath) { } stream << PKE_PROJ_FILE_END << std::endl; + } catch (std::exception e) { + fprintf(stderr, "[%s][PkeProject_Save] Failed to serialize project file: %s\n", __FILE__, e.what()); + failed = false; } catch (...) { + fprintf(stderr, "[%s][PkeProject_Save] Failed to serialize project file, uncaught exception.\n", __FILE__); failed = false; } @@ -412,6 +420,8 @@ void PkeProject_Save(const char *filePath) { std::ofstream f(saveFilePath); if (!f.is_open()) { failed = true; + } else { + f << stream.str(); } f.flush(); f.close(); diff --git a/src/scene.cpp b/src/scene.cpp index 0e5a22c..f4df916 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -2,7 +2,10 @@ #include "scene.hpp" #include "bucketed-array.hpp" #include "ecs.hpp" -#include <cstring> + +#include <string.h> + +#include <filesystem> struct pke_scene_master { BucketContainer<pke_scene, SceneHandle> bc; @@ -17,7 +20,11 @@ void pke_scene_master_teardown() { } pke_scene *pke_scene_create(const char *scene_name) { - struct pke_scene *scene = pke_scene_get_by_name(scene_name); + NULL_CHAR_ARR(safe_scene_name, SCENE_NAME_MAX_LEN); + size_t offset; + std::filesystem::path p(scene_name); + sprintf(safe_scene_name, "%.15s", p.stem().c_str()); + struct pke_scene *scene = pke_scene_get_by_name(safe_scene_name); if (scene != nullptr) { fprintf(stderr, "[pke_scene_create] failed to create scene: pke_scene::name already in use."); return nullptr; @@ -31,9 +38,9 @@ pke_scene *pke_scene_create(const char *scene_name) { ECS_CreateEntity(scene); scene->scene_handle = scene_handle; - size_t offset = (strlen(scene_name) > SCENE_NAME_MAX_LEN ? strlen(scene_name) - SCENE_NAME_MAX_LEN : 0); + offset = (strlen(safe_scene_name) > SCENE_NAME_MAX_LEN ? strlen(safe_scene_name) - SCENE_NAME_MAX_LEN : 0); for (int i = 0; i < SCENE_NAME_MAX_LEN; ++i) { - scene->name[i] = scene_name[i + offset]; + scene->name[i] = safe_scene_name[i + offset]; } return scene; } |
