#include "serialization-component.hpp" #include "ecs.hpp" #include "entities.hpp" #include "serialization.hpp" #include "math-helpers.hpp" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "pk.h" #define SRLZTN_FLOAT_WIDTH 10 bool pke_serialize_inst_pos(srlztn_serialize_helper *h, const glm::vec3 pos, const glm::quat quat_rot, const glm::vec3 scale) { if (pos != glm::vec3(0)) { h->o << SRLZTN_POSROT_POS << "[" << std::setw(SRLZTN_FLOAT_WIDTH) << pos[0] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << pos[1] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << pos[2] << "]" << std::endl; } if (quat_rot != glm::quat{}) { h->o << SRLZTN_POSROT_ROT << "[" << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[0] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[1] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[2] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[3] << "]" << std::endl; } if (scale != glm::vec3(1)) { h->o << SRLZTN_POSROT_SCALE << "[" << std::setw(SRLZTN_FLOAT_WIDTH) << scale[0] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << scale[1] << "," << std::setw(SRLZTN_FLOAT_WIDTH) << scale[2] << "]" << std::endl; } return true; } bool pke_deserialize_inst_pos(srlztn_deserialize_helper *h, glm::vec3 &pos, glm::quat &quat_rot, glm::vec3 &scale) { const char *starting_char; uint64_t prefix_len; PK_STN_RES stn_res; if (strstr(h->read_line, SRLZTN_POSROT_POS)) { prefix_len = strlen(SRLZTN_POSROT_POS); starting_char = strchr(h->read_line + prefix_len, '[') + 1; assert(starting_char != nullptr); char *pEnd = nullptr; long index = 0; do { assert(index < 3); stn_res = pk_stn_float_e(&pos[index], starting_char, &pEnd); if (stn_res != PK_STN_RES_SUCCESS) return false; starting_char = pEnd + 1; ++index; } while (*pEnd != ']'); return true; } if (strstr(h->read_line, SRLZTN_POSROT_ROT)) { prefix_len = strlen(SRLZTN_POSROT_ROT); starting_char = strchr(h->read_line + prefix_len, '[') + 1; assert(starting_char != nullptr); char *pEnd = nullptr; long index = 0; do { assert(index < 4); stn_res = pk_stn_float_e(&quat_rot[index], starting_char, &pEnd); if (stn_res != PK_STN_RES_SUCCESS) return false; starting_char = pEnd + 1; ++index; } while (*pEnd != ']'); return true; } if (strstr(h->read_line, SRLZTN_POSROT_SCALE)) { prefix_len = strlen(SRLZTN_POSROT_SCALE); starting_char = strchr(h->read_line + prefix_len, '[') + 1; assert(starting_char != nullptr); char *pEnd = nullptr; long index = 0; do { assert(index < 3); stn_res = pk_stn_float_e(&scale[index], starting_char, &pEnd); if (stn_res != PK_STN_RES_SUCCESS) return false; starting_char = pEnd + 1; ++index; } while (*pEnd != ']'); return true; } return false; } bool pke_serialize_instance(srlztn_serialize_helper *h, const CompInstance *comp) { NULL_CHAR_ARR(handle_str, 23); EntityType *et = nullptr; if (comp->grBindsHandle != GrBindsHandle_MAX) { et = EntityType_FindByEntityHandle(ECS_GetGrBinds(comp->grBindsHandle)->entHandle); } CompInstance c{}; glm::vec3 pos; glm::quat quat_rot; glm::vec3 scale; float mass; PhysicsCollision collisionLayer; PhysicsCollision collisionMask; { mass = comp->bt.rigidBody->getMass(); collisionLayer = PhysicsCollision{static_cast(comp->bt.rigidBody->getBroadphaseProxy()->m_collisionFilterGroup)}; collisionMask = PhysicsCollision{static_cast(comp->bt.rigidBody->getBroadphaseProxy()->m_collisionFilterMask)}; btTransform trans; comp->bt.motionState->getWorldTransform(trans); BulletToGlm(trans.getOrigin(), pos); BulletToGlm(trans.getRotation(), quat_rot); BulletToGlm(comp->bt.rigidBody->getCollisionShape()->getLocalScaling(), scale); } if (comp->instanceHandle != InstanceHandle_MAX) { snprintf(handle_str, 22, "0x%08X 0x%08X", comp->instanceHandle.bucketIndex, comp->instanceHandle.itemIndex); h->o << SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE << handle_str << std::endl; } if (comp->entHandle != InstanceHandle_MAX) { snprintf(handle_str, 22, "0x%08X 0x%08X", comp->entHandle.bucketIndex, comp->entHandle.itemIndex); h->o << SRLZTN_INSTANCE_COMPONENT_HANDLE << handle_str << std::endl; } if (comp->uuid != pk_uuid_zed && comp->uuid != pk_uuid_max) { h->o << SRLZTN_INSTANCE_COMPONENT_UUID << comp->uuid << std::endl; } if (et != nullptr) { h->o << SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE << et->entityTypeCode.val << std::endl; } pke_serialize_inst_pos(h, pos, quat_rot, scale); if (mass != 1) { h->o << SRLZTN_INSTANCE_COMPONENT_MASS << mass << std::endl; } if (collisionLayer != c.physicsLayer) { h->o << SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER << static_cast(collisionLayer) << std::endl; } if (collisionMask != c.physicsMask) { h->o << SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK << static_cast(collisionMask) << std::endl; } if (comp->collisionCallback.name[0] != '\0') { h->o << SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE << comp->collisionCallback.name << std::endl; } return true; } bool pke_deserialize_instance(srlztn_deserialize_helper *h) { uint64_t prefix_len; PK_STN_RES stn_res; NULL_CHAR_ARR(handle_str, 21); EntityType *et_ptr = nullptr; float mass; InstPos inst_pos; CompInstance comp{}; glm::vec3 pos; glm::quat quat_rot; glm::vec3 scale; comp.collisionCallback.name[0] = '\0'; while (h->i.getline(h->read_line, h->read_line_len)) { if (strstr(SRLZTN_OBJ_END, h->read_line)) { if (et_ptr == nullptr) { fprintf(stdout, "[Game::DeserializeInstance] Unknown EntityTypeCode, skipping instance.\n"); break; } btVector3 bt_pos; btQuaternion bt_quat; GlmToBullet(pos, bt_pos); GlmToBullet(quat_rot, bt_quat); GlmToBullet(scale, inst_pos.scale); inst_pos.mass = mass; inst_pos.posRot.setIdentity(); inst_pos.posRot.setOrigin(bt_pos); inst_pos.posRot.setRotation(bt_quat); if (et_ptr->createInstanceCallback.func != nullptr) { /* 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. * Also consider just requiring a generic instance for any given * EntityType. */ // typedef Entity_Base *CreateInst(); // entity = reinterpret_cast(et_ptr->createInstanceCallback.func)(); fprintf(stderr, "[%s] Attempted to call EntityType::createInstanceCallback and we have not yet defined a valid function signature", __FILE__); } else { EntityType_CreateGenericInstance(et_ptr, h->scene, &comp, &inst_pos); // fprintf(stdout ,"[Game::DeserializeInstance] Debug: entTypeCode '%s' does not have a registered callback func to handle instance creation.\n", entTypeCode); } return true; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE); sprintf(handle_str, "%.10s%c%s", h->read_line + prefix_len, '\0', h->read_line + prefix_len + 10); stn_res = pk_stn(&comp.entHandle.bucketIndex, handle_str, 16); if (stn_res != PK_STN_RES_SUCCESS) return false; stn_res = pk_stn(&comp.entHandle.itemIndex, handle_str + 11, 16); if (stn_res != PK_STN_RES_SUCCESS) return false; continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_HANDLE)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_HANDLE); sprintf(handle_str, "%.10s%c%s", h->read_line + prefix_len, '\0', h->read_line + prefix_len + 10); stn_res = pk_stn(&comp.instanceHandle.bucketIndex, handle_str, 16); if (stn_res != PK_STN_RES_SUCCESS) return false; stn_res = pk_stn(&comp.instanceHandle.itemIndex, handle_str + 11, 16); if (stn_res != PK_STN_RES_SUCCESS) return false; continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_UUID)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_UUID); (h->read_line + prefix_len) >> comp.uuid ; continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE); if (strlen(h->read_line + prefix_len) > 1) { et_ptr = EntityType_FindByTypeCode(h->read_line + prefix_len); } continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_MASS)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_MASS); stn_res = pk_stn(&mass, h->read_line + prefix_len); if (stn_res != PK_STN_RES_SUCCESS) return false; continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER); stn_res = pk_stn(&comp.physicsLayer, h->read_line + prefix_len, 10); if (stn_res != PK_STN_RES_SUCCESS) return false; continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK); stn_res = pk_stn(&comp.physicsMask, h->read_line + prefix_len, 10); if (stn_res != PK_STN_RES_SUCCESS) return false; continue; } if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE)) { prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE); strncpy(comp.collisionCallback.name, h->read_line + prefix_len, 16); continue; } if (pke_deserialize_inst_pos(h, pos, quat_rot, scale)) { continue; } } return false; }