void PxSerialization::createSerialObjectIds(PxCollection& collection, const PxSerialObjectId base) { PxSerialObjectId localBase = base; PxU32 nbObjects = collection.getNbObjects(); for (PxU32 i = 0; i < nbObjects; ++i) { while(collection.find(localBase)) { localBase++; } PxBase& s = collection.getObject(i); if(PX_SERIAL_OBJECT_ID_INVALID == collection.getId(s)) { collection.addId(s, localBase); localBase++; } } }
bool PxSerialization::isSerializable(PxCollection& collection, PxSerializationRegistry& sr, const PxCollection* externalReferences) { PxCollection* subordinateCollection = PxCreateCollection(); PX_ASSERT(subordinateCollection); for(PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); if(serializer->isSubordinate()) subordinateCollection->add(s); if(externalReferences) { PxSerialObjectId id = collection.getId(s); if(id != PX_SERIAL_OBJECT_ID_INVALID) { PxBase* object = externalReferences->find(id); if(object && (object != &s)) { subordinateCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Reference id %llu used both in current collection and in externalReferences. " "Please use unique identifiers.", id); return false; } } } } PxCollection* requiresCollection = PxCreateCollection(); PX_ASSERT(requiresCollection); RequiresCallback requiresCallback0(*requiresCollection); for (PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback0); Cm::Collection* cmRequiresCollection = static_cast<Cm::Collection*>(requiresCollection); for(PxU32 j = 0; j < cmRequiresCollection->getNbObjects(); ++j) { PxBase& s0 = cmRequiresCollection->getObject(j); if(subordinateCollection->contains(s0)) { subordinateCollection->remove(s0); continue; } bool requiredIsInCollection = collection.contains(s0); if(!requiredIsInCollection) { if(externalReferences) { if(!externalReferences->contains(s0)) { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s references a missing object of type %s. " "The missing object needs to be added to either the current collection or the externalReferences collection.", s.getConcreteTypeName(), s0.getConcreteTypeName()); } else if(externalReferences->getId(s0) == PX_SERIAL_OBJECT_ID_INVALID) { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s in externalReferences collection requires an id.", s0.getConcreteTypeName()); } else continue; } else { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s references a missing serial object of type %s. " "Please completed the collection or specify an externalReferences collection containing the object.", s.getConcreteTypeName(), s0.getConcreteTypeName()); } subordinateCollection->release(); requiresCollection->release(); return false; } } cmRequiresCollection->mObjects.clear(); } requiresCollection->release(); PxU32 numOrphans = subordinateCollection->getNbObjects(); for(PxU32 j = 0; j < numOrphans; ++j) { PxBase& subordinate = subordinateCollection->getObject(j); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: An object of type %s is subordinate but not required " "by other objects in the collection (orphan). Please remove the object from the collection or add its owner.", subordinate.getConcreteTypeName()); } subordinateCollection->release(); if(numOrphans>0) return false; if(externalReferences) { PxCollection* oppositeRequiresCollection = PxCreateCollection(); PX_ASSERT(oppositeRequiresCollection); RequiresCallback requiresCallback(*oppositeRequiresCollection); for (PxU32 i = 0; i < externalReferences->getNbObjects(); ++i) { PxBase& s = externalReferences->getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback); Cm::Collection* cmCollection = static_cast<Cm::Collection*>(oppositeRequiresCollection); for(PxU32 j = 0; j < cmCollection->getNbObjects(); ++j) { PxBase& s0 = cmCollection->getObject(j); if(collection.contains(s0)) { oppositeRequiresCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s in externalReferences references an object " "of type %s in collection (circular dependency).", s.getConcreteTypeName(), s0.getConcreteTypeName()); return false; } } cmCollection->mObjects.clear(); } oppositeRequiresCollection->release(); } return true; }
bool PxSerialization::isSerializable(PxCollection& collection, PxSerializationRegistry& sr, const PxCollection* externalReferences) { bool bRet = true; PxCollection* subordinateCollection = PxCreateCollection(); PX_ASSERT(subordinateCollection); for(PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); if(serializer->isSubordinate()) subordinateCollection->add(s); if(externalReferences) { PxSerialObjectId id = collection.getId(s); if(id != PX_SERIAL_OBJECT_ID_INVALID) { PxBase* object = externalReferences->find(id); if(object && (object != &s)) { subordinateCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: object shares reference name with other object in externalReferences (reference clash)."); return false; } } } } PxCollection* requiresCollection = PxCreateCollection(); PX_ASSERT(requiresCollection); RequiresCallback requiresCallback0(*requiresCollection); for (PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback0); } for(PxU32 j = 0; j < subordinateCollection->getNbObjects(); ++j) { PxBase& subordinate = subordinateCollection->getObject(j); bRet = requiresCollection->contains(subordinate); if(!bRet) { requiresCollection->release(); subordinateCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: object is a subordinate and not required by other objects in the collection (orphan)."); return false; } } subordinateCollection->release(); for(PxU32 j = 0; j < requiresCollection->getNbObjects(); ++j) { PxBase& s0 = requiresCollection->getObject(j); bRet = collection.contains(s0); if(!bRet && externalReferences) { bRet = externalReferences->contains(s0) && externalReferences->getId(s0) != PX_SERIAL_OBJECT_ID_INVALID; } if(!bRet) { requiresCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: cannot find a required serial object (collection is not complete)."); return false; } } requiresCollection->release(); if(externalReferences) { PxCollection* oppsiteRequiresCollection = PxCreateCollection(); PX_ASSERT(oppsiteRequiresCollection); RequiresCallback requiresCallback(*oppsiteRequiresCollection); for (PxU32 i = 0; i < externalReferences->getNbObjects(); ++i) { PxBase& s = externalReferences->getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback); } for(PxU32 j = 0; j < oppsiteRequiresCollection->getNbObjects(); ++j) { PxBase& s0 = oppsiteRequiresCollection->getObject(j); if(collection.contains(s0)) { oppsiteRequiresCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: object in externalReferences requires an object in collection (circular dependency)."); return false; } } oppsiteRequiresCollection->release(); } return true; }
virtual bool SerializeActors(FName Format, const TArray<FBodyInstance*>& Bodies, const TArray<UBodySetup*>& BodySetups, const TArray<UPhysicalMaterial*>& PhysicalMaterials, TArray<uint8>& OutBuffer) const override { #if WITH_PHYSX PxSerializationRegistry* PRegistry = PxSerialization::createSerializationRegistry(*GPhysXSDK); PxCollection* PCollection = PxCreateCollection(); PxBase* PLastObject = nullptr; for(FBodyInstance* BodyInstance : Bodies) { if(BodyInstance->RigidActorSync) { PCollection->add(*BodyInstance->RigidActorSync, BodyInstance->RigidActorSyncId); PLastObject = BodyInstance->RigidActorSync; } if(BodyInstance->RigidActorAsync) { PCollection->add(*BodyInstance->RigidActorAsync, BodyInstance->RigidActorAsyncId); PLastObject = BodyInstance->RigidActorAsync; } } PxSerialization::createSerialObjectIds(*PCollection, PxSerialObjectId(1)); //we get physx to assign an id for each actor //Note that rigid bodies may have assigned ids. It's important to let them go first because we rely on that id for deserialization. //One this is done we must find out the next available ID, and use that for naming the shared resources. We have to save this for deserialization uint64 BaseId = PLastObject ? (PCollection->getId(*PLastObject) + 1) : 1; PxCollection* PExceptFor = MakePhysXCollection(PhysicalMaterials, BodySetups, BaseId); for (FBodyInstance* BodyInstance : Bodies) //and then we mark that id back into the bodyinstance so we can pair the two later { if (BodyInstance->RigidActorSync) { BodyInstance->RigidActorSyncId = PCollection->getId(*BodyInstance->RigidActorSync); } if (BodyInstance->RigidActorAsync) { BodyInstance->RigidActorAsyncId = PCollection->getId(*BodyInstance->RigidActorAsync); } } //We must store the BaseId for shared resources. FMemoryWriter Ar(OutBuffer); uint8 bIsLittleEndian = PLATFORM_LITTLE_ENDIAN; //TODO: We should pass the target platform into this function and write it. Then swap the endian on the writer so the reader doesn't have to do it at runtime Ar << bIsLittleEndian; Ar << BaseId; //Note that PhysX expects the binary data to be 128-byte aligned. Because of this we must pad int32 BytesToPad = PHYSX_SERIALIZATION_ALIGNMENT - (Ar.Tell() % PHYSX_SERIALIZATION_ALIGNMENT); OutBuffer.AddZeroed(BytesToPad); FPhysXOutputStream Buffer(&OutBuffer); PxSerialization::complete(*PCollection, *PRegistry, PExceptFor); PxSerialization::serializeCollectionToBinary(Buffer, *PCollection, *PRegistry, PExceptFor); #if PHYSX_MEMORY_VALIDATION GPhysXAllocator->ValidateHeaders(); #endif PCollection->release(); PExceptFor->release(); PRegistry->release(); #if PHYSX_MEMORY_VALIDATION GPhysXAllocator->ValidateHeaders(); #endif return true; #endif return false; }