#include "project.hpp" #include "plugins.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_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: {"; 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%08X 0x%08X", et.handle.bucketIndex, et.handle.itemIndex); 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.val != e.entityTypeCode.val) 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.createInstanceCallback.name[0] != '\0') { stream << PKE_PROJ_FILE_ENTITY_TYPE_CREATE_INSTANCE_CALLBACK_SIGNATURE << et.createInstanceCallback.name << std::endl; } for (size_t i = 0; i < et.detailsCount; ++i) { const EntityTypeDetails &etd = et.details[i]; snprintf(textureAssetKey, AssetKeyLength + 1, "%s", etd.textureAssetKey); 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 (etd.grBinds) { if (etd.grBinds->collisionCallback.name[0] != '\0') { stream << PKE_PROJ_FILE_ENTITY_TYPE_COLLISION_CALLBACK_SIGNATURE << etd.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 (memset(projReadLine, 0, projReadLineLength), 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 = pk_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 (memset(projReadLine, 0, projReadLineLength), stream.getline(projReadLine, projReadLineLength)) { if (strcmp(PKE_PROJ_FILE_PROJ_SETTINGS_SCENES_END, projReadLine) == 0) { pkeProjectSettings.sceneCount = sceneFiles.Count(); pkeProjectSettings.scenes = pk_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 = pk_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'; char createInstanceSig[CallbackSignatureLength + 1]; createInstanceSig[0] = '\0'; EntityType et{}; int64_t detailCount = 0; while (memset(projReadLine, 0, projReadLineLength), stream.getline(projReadLine, projReadLineLength)) { if (strcmp(PKE_PROJ_FILE_OBJ_END, projReadLine) == 0) { EntityType *existingPtr = EntityType_FindByTypeCode(et.entityTypeCode.val); if (existingPtr != nullptr) { // TODO leaks et.EntityTypeCode continue; } EntityType *etPtr = EntityType_Create(); strncpy(etPtr->modelAssetKey, et.modelAssetKey, AssetKeyLength); etPtr->entityTypeCode = et.entityTypeCode; if (createInstanceSig[0] == '\0') { strncpy(etPtr->createInstanceCallback.name, createInstanceSig, CallbackSignatureLength); PkePlugin_SetSignatureFunc(&etPtr->createInstanceCallback); } else { etPtr->createInstanceCallback.name[0] = 'd'; etPtr->createInstanceCallback.func = reinterpret_cast(EntityType_CreateGenericInstance); } for (int64_t i = 0; i < detailCount; ++i) { etPtr->details[i] = et.details[i]; strncpy(etPtr->details[i].textureAssetKey, et.details[i].textureAssetKey, AssetKeyLength); } EntityType_Load(*etPtr); for (int64_t i = 0; i < detailCount; ++i) { strncpy(etPtr->details[i].grBinds->collisionCallback.name, collisionSig, CallbackSignatureLength); PkePlugin_SetSignatureFunc(&etPtr->details[i].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 = pk_new(len); memset(reinterpret_cast(val), '\0', len); memcpy(val, projReadLine + prefixLen, len); et.entityTypeCode.val = val; continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_ENTITY_HANDLE); // 0x00000000 0x00000000 projReadLine[prefixLen + 10] = '\0'; STR2NUM_ERROR result1 = str2num(et.handle.bucketIndex, projReadLine + prefixLen + 2, 16); STR2NUM_ERROR result2 = str2num(et.handle.itemIndex, projReadLine + prefixLen + 11, 16); assert(result1 == STR2NUM_ERROR::SUCCESS); assert(result2 == STR2NUM_ERROR::SUCCESS); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_CREATE_INSTANCE_CALLBACK_SIGNATURE)) { uint64_t prefixLen = strlen(PKE_PROJ_FILE_ENTITY_TYPE_CREATE_INSTANCE_CALLBACK_SIGNATURE); strncpy(createInstanceSig, projReadLine + prefixLen, CallbackSignatureLength + 1); continue; } if (strstr(projReadLine, PKE_PROJ_FILE_ENTITY_TYPE_DETAILS_BEGIN)) { EntityTypeDetails &etd = et.details[detailCount]; while (memset(projReadLine, 0, projReadLineLength), 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 (memset(projReadLine, 0, projReadLineLength), 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 (memset(projReadLine, 0, projReadLineLength), 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; } } const auto entBucketCount = EntityType_GetBucketCount(); for (pk_handle_bucket_index_T b = 0; b < entBucketCount; ++b) { pk_handle_item_index_T itemCount = 0; auto *entities = EntityType_GetEntityTypes(b, itemCount); for (pk_handle_item_index_T i = 0; i < itemCount; ++i) { if (entities[i].modelAssetKey[0] == '\0') { continue; } f << PKE_PROJ_FILE_OBJ_ENTITY_TYPE << std::endl; Proj_SerializeEntityType(f, entities[i]); f << PKE_PROJ_FILE_OBJ_END << std::endl; } } f << PKE_PROJ_FILE_END << std::endl; f.flush(); f.close(); }