#include "project.hpp" #include "entities.hpp" #include "helpers.hpp" #include #include #include const long projReadLineLength = 128; char projReadLine[projReadLineLength]; const char* const PKE_PROJ_FILE_BEGIN = ":PKPB:"; const char* const PKE_PROJ_FILE_END = ":PKPE:"; const char* const PKE_PROJ_FILE_VERSION = ":0:"; const char* const PKE_PROJ_FILE_OBJ_END = ""; const char* const PKE_PROJ_FILE_OBJ_PROJECT_SETTINGS = "ProjectSettings:"; const char* const PKE_PROJ_FILE_OBJ_ENTITY_TYPE = "EntityType:"; const char* const PKE_PROJ_FILE_OBJ_ASSET = "Asset:"; const char* const PKE_PROJ_FILE_PROJ_SETTINGS_DEFAULT_SCENE_NAME = "PkeSet::DefaultSceneName: "; const char* const PKE_PROJ_FILE_PROJ_SETTINGS_SCENE_COUNT = "PkeSet::SceneCount: "; const char* const PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_BEGIN = "PkeSet::Scenes: ["; 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_COLLISION_CALLBACK_SIGNATURE = "CollisionCallbackSignature: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_BEGIN = "EntityHandleDetails: {"; const char* const PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_END = "EntityHandleDetails: }"; const char* const PKE_PROJ_FILE_ENTITY_TYPE_TEXTURE_ASSET_KEY = "TextureAssetKey: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT = "StartingInstanceCount: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_MASS = "BT::StartingMass: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_LAYER = "BT::StartingCollisionLayer: "; const char* const PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_MASK = "BT::StartingCollisionMask: "; const char* const PKE_PROJ_FILE_ASSET_KEY = "Asset::Key: "; const char* const PKE_PROJ_FILE_ASSET_BASE_PATH = "Asset::BasePath: "; const char* const PKE_PROJ_FILE_ASSET_TYPE = "Asset::Type: "; /* void Proj_SerializeProjectSettings(std::ofstream &stream) { PkeProjectSettings ps{}; if (strncmp(ps.defaultSceneName, pkeProjectSettings.defaultSceneName, strlen(pkeProjectSettings.defaultSceneName)) != 0) { stream << PKE_PROJ_FILE_PROJ_SETTINGS_DEFAULT_SCENE_NAME << ps.defaultSceneName << std::endl; } if (ps.sceneCount != pkeProjectSettings.sceneCount) { stream << PKE_PROJ_FILE_PROJ_SETTINGS_SCENE_COUNT << ps.sceneCount << std::endl; } if (ps.scenes != nullptr) { stream << PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_BEGIN << std::endl; for (long i = 0; i < ps.sceneCount; ++i) { if (ps.scenes[i].length > 0) { stream << ps.scenes[i].val << std::endl; } } stream << PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_END << std::endl; } } */ void Proj_SerializeEntityType(std::ofstream &stream, const EntityType &et) { NULL_CHAR_ARR(handleStr, 19); NULL_CHAR_ARR(modelAssetKey, AssetKeyLength + 1); NULL_CHAR_ARR(textureAssetKey, AssetKeyLength + 1); snprintf(handleStr, 19, "0x%016lX", et.entityHandle.hash); snprintf(modelAssetKey, AssetKeyLength + 1, "%s", et.modelAssetKey); EntityType e{}; if (modelAssetKey[0] != '\0') stream << PKE_PROJ_FILE_ENTITY_TYPE_MODEL_ASSET_KEY << modelAssetKey << std::endl; if (et.entityTypeCode != e.entityTypeCode) stream << PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE << et.entityTypeCode << std::endl; if (et.entityHandle != e.entityHandle) stream << PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE << handleStr << std::endl; for (size_t i = 0; i < et.detailsCount; ++i) { const EntityTypeDetails &etd = et.details[i]; snprintf(textureAssetKey, AssetKeyLength + 1, "%s", etd.textureAssetKey); CompGrBinds *grBinds = ECS_GetGrBinds(etd.entityHandle); stream << PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_BEGIN << std::endl; if (textureAssetKey[0] != '\0') stream << PKE_PROJ_FILE_ENTITY_TYPE_TEXTURE_ASSET_KEY << textureAssetKey << std::endl; if (etd.startingInstanceCount != e.details[0].startingInstanceCount) stream << PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT << etd.startingInstanceCount << std::endl; if (etd.bt.startingMass != e.details[0].bt.startingMass) stream << PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_MASS << etd.bt.startingMass << std::endl; if (etd.bt.startingCollisionLayer != e.details[0].bt.startingCollisionLayer) stream << PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_LAYER << static_cast(etd.bt.startingCollisionLayer) << std::endl; if (etd.bt.startingCollisionMask != e.details[0].bt.startingCollisionMask) stream << PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_MASK << static_cast(etd.bt.startingCollisionMask) << std::endl; if (grBinds) { if (grBinds->collisionCallback.name[0] != '\0') { stream << PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE << grBinds->collisionCallback.name << std::endl; } } stream << PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_END << std::endl; } } void Proj_SerializeAsset(std::ofstream &stream, const Asset &asset) { NULL_CHAR_ARR(keyStr, AssetKeyLength + 1); snprintf(keyStr, AssetKeyLength + 1, "%s", asset.key); Asset a{}; if (keyStr[0] != '\0') { stream << PKE_PROJ_FILE_ASSET_KEY << keyStr << std::endl; } if (asset.basePath != nullptr) { stream << PKE_PROJ_FILE_ASSET_BASE_PATH << asset.basePath << std::endl; } if (asset.type != a.type) { stream << PKE_PROJ_FILE_ASSET_TYPE << static_cast(asset.type) << std::endl; } } /* void Proj_ParseProjectSettings(std::ifstream &stream) { while (stream.getline(projReadLine, projReadLineLength)) { if (strcmp(PKE_PROJ_FILE_OBJ_END, projReadLine) == 0) { return; } if (strncmp(projReadLine, PKE_PROJ_FILE_PROJ_SETTINGS_DEFAULT_SCENE_NAME, strlen(PKE_PROJ_FILE_PROJ_SETTINGS_DEFAULT_SCENE_NAME)) == 0) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_PROJ_SETTINGS_DEFAULT_SCENE_NAME); uint64_t len = strlen(projReadLine + prefixLen) + 1; char *val = Pke_New(len); memset(reinterpret_cast(val), '\0', len); memcpy(val, projReadLine + prefixLen, len); pkeProjectSettings.defaultSceneName = val; continue; } if (strncmp(projReadLine, PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_BEGIN, strlen(PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_BEGIN)) == 0) { DynArray sceneFiles{16}; while (stream.getline(projReadLine, projReadLineLength)) { if (strcmp(PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_END, projReadLine) == 0) { pkeProjectSettings.sceneCount = sceneFiles.Count(); pkeProjectSettings.scenes = Pke_New(sceneFiles.Count()); memcpy(reinterpret_cast(pkeProjectSettings.scenes), reinterpret_cast(sceneFiles.GetPtr()), sizeof(cpkstr) * sceneFiles.Count()); break; } pkeProjectSettings.sceneCount += 1; uint64_t len = strlen(projReadLine) + 1; char *val = Pke_New(len); memset(val, '\0', len); memcpy(val, projReadLine, len - 1); auto &str = sceneFiles.Push(); str.length = len - 1; str.val = val; } } } } */ void Proj_ParseEntityType(std::ifstream &stream) { char collisionSig[CallbackSignatureLength + 1]; collisionSig[0] = '\0'; EntityType et{}; uint8_t detailCount = 0; while (stream.getline(projReadLine, projReadLineLength)) { if (strcmp(PKE_PROJ_FILE_OBJ_END, projReadLine) == 0) { int64_t existingEntityTypeIndex = EntityType_FindByTypeCode(et.entityTypeCode); if (existingEntityTypeIndex != -1) { continue; } et.entityHandle = ECS_CreateEntity(); GlobalEntityTypes.Push(et); CompGrBinds *grBinds = ECS_GetGrBinds(et.entityHandle); if (grBinds) { strncpy(grBinds->collisionCallback.name, collisionSig, CallbackSignatureLength); PkePlugin_SetSignatureFunc(&grBinds->collisionCallback); } return; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_MODEL_ASSET_KEY)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_MODEL_ASSET_KEY); strncpy(et.modelAssetKey, projReadLine + prefixLen, AssetKeyLength); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_TYPE_CODE); uint64_t len = strlen(projReadLine + prefixLen) + 1; char *val = Pke_New(len); memset(reinterpret_cast(val), '\0', len); memcpy(val, projReadLine + prefixLen, len); et.entityTypeCode = val; continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE); STR2NUM_ERROR result = str2num(et.entityHandle.hash, projReadLine + prefixLen); assert(result == STR2NUM_ERROR::SUCCESS); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_BEGIN)) { EntityTypeDetails &etd = et.details[detailCount]; while (stream.getline(projReadLine, projReadLineLength)) { if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_END)) { detailCount += 1; break; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_TEXTURE_ASSET_KEY)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_TEXTURE_ASSET_KEY); strncpy(etd.textureAssetKey, projReadLine + prefixLen, AssetKeyLength); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_STARTING_INSTANCE_COUNT); STR2NUM_ERROR result = str2num(etd.startingInstanceCount, projReadLine + prefixLen); assert(result == STR2NUM_ERROR::SUCCESS); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_MASS)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_MASS); STR2NUM_ERROR result = str2num(etd.bt.startingMass, projReadLine + prefixLen); assert(result == STR2NUM_ERROR::SUCCESS); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_LAYER)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_LAYER); PhysicsCollision_T val = static_cast(etd.bt.startingCollisionLayer); STR2NUM_ERROR result = str2num(val, projReadLine + prefixLen); etd.bt.startingCollisionLayer = PhysicsCollision{val}; assert(result == STR2NUM_ERROR::SUCCESS); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_MASK)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_PHYSICS_STARTING_COLLISION_MASK); PhysicsCollision_T val = static_cast(etd.bt.startingCollisionMask); STR2NUM_ERROR result = str2num(val, projReadLine + prefixLen); etd.bt.startingCollisionMask = PhysicsCollision{val}; assert(result == STR2NUM_ERROR::SUCCESS); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE); strncpy(collisionSig, projReadLine + prefixLen, CallbackSignatureLength + 1); continue; } } continue; } } } void Proj_ParseAssset(std::ifstream &stream) { char keyStr[AssetKeyLength + 1]; keyStr[AssetKeyLength] = '\0'; char basePath[256]; basePath[0] = '\0'; basePath[255] = '\0'; AssetType at{PKE_ASSET_TYPE_UNSET}; while (stream.getline(projReadLine, projReadLineLength)) { if (strcmp(projReadLine, PKE_PROJ_FILE_OBJ_END) == 0) { AM_Register(keyStr, at, basePath); return; } if (strstr(projReadLine, PKE_PROJ_FILE_ASSET_KEY) != nullptr) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ASSET_KEY); strncpy(keyStr, projReadLine + prefixLen, AssetKeyLength); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ASSET_BASE_PATH) != nullptr) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ASSET_BASE_PATH); uint64_t strLen = strlen(projReadLine) - prefixLen; strncpy(basePath, projReadLine + prefixLen, strLen + 1); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ASSET_TYPE) != nullptr) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ASSET_TYPE); AssetType_T val{}; STR2NUM_ERROR result = str2num(val, projReadLine + prefixLen); at = AssetType{val}; assert(result == STR2NUM_ERROR::SUCCESS); continue; } } } void PkeProject_Load(const char *filePath) { const char *safeFilePath = filePath == nullptr ? PKE_PROJ_DEFAULT_FILENAME : filePath; std::ifstream f(safeFilePath); if (!f.is_open()) { fprintf(stderr, "While attempting to load project file, failed to open requested file for reading: %s", safeFilePath); return; } memset(projReadLine, '\0', projReadLineLength); while (f.getline(projReadLine, projReadLineLength)) { /* if (strcmp(PKE_PROJ_FILE_OBJ_PROJECT_SETTINGS, projReadLine) == 0) { Proj_ParseProjectSettings(f); continue; } */ if (strcmp(PKE_PROJ_FILE_OBJ_ASSET, projReadLine) == 0) { Proj_ParseAssset(f); continue; } if (strcmp(PKE_PROJ_FILE_OBJ_ENTITY_TYPE, projReadLine) == 0) { Proj_ParseEntityType(f); continue; } } f.close(); } void PkeProject_Save(const char *filePath) { const char *safeFilePath = filePath == nullptr ? PKE_PROJ_DEFAULT_FILENAME : filePath; std::ofstream f(safeFilePath); if (!f.is_open()) { fprintf(stderr, "While attempting to save project file, failed to open requested file for writing: %s", safeFilePath); return; } f << PKE_PROJ_FILE_BEGIN << std::endl; f << PKE_PROJ_FILE_VERSION << std::endl; f << "" << std::endl; /* f << PKE_PROJ_FILE_OBJ_PROJECT_SETTINGS << std::endl; Proj_SerializeProjectSettings(f); f << PKE_PROJ_FILE_OBJ_END << std::endl; */ auto assetB = AM_GetBucketCount(); for (long b = 0; b < assetB; ++b) { uint64_t assetI = 0; auto *assets = AM_GetAssets(b, assetI); for (long i = 0; i < assetI; ++i) { bool isGlobalAsset = false; for (long k = 0; k < EngineDefinedAssetCount; ++k) { if (strncmp(EngineDefinedAssets[k], assets[i].key, AssetKeyLength) == 0) { isGlobalAsset = true; break; } } if (isGlobalAsset) continue; f << PKE_PROJ_FILE_OBJ_ASSET << std::endl; Proj_SerializeAsset(f, assets[i]); f << PKE_PROJ_FILE_OBJ_END << std::endl; } } for (long i = 0; i < GlobalEntityTypes.Count(); ++i) { f << PKE_PROJ_FILE_OBJ_ENTITY_TYPE << std::endl; const auto &et = GlobalEntityTypes[i]; const CompGrBinds *grBinds = ECS_GetGrBinds(et.entityHandle); Proj_SerializeEntityType(f, et); f << PKE_PROJ_FILE_OBJ_END << std::endl; } f << PKE_PROJ_FILE_END << std::endl; f.flush(); f.close(); }