PxCollection* MakePhysXCollection(const TArray<UPhysicalMaterial*>& PhysicalMaterials, const TArray<UBodySetup*>& BodySetups, uint64 BaseId)
{
	QUICK_SCOPE_CYCLE_COUNTER(STAT_CreateSharedData);
	PxCollection* PCollection = PxCreateCollection();
	for (UPhysicalMaterial* PhysicalMaterial : PhysicalMaterials)
	{
		if (PhysicalMaterial)
		{
			PCollection->add(*PhysicalMaterial->GetPhysXMaterial());
		}
	}

	for (UBodySetup* BodySetup : BodySetups)
	{
		for(PxTriangleMesh* TriMesh : BodySetup->TriMeshes)
		{
			AddToCollection(PCollection, TriMesh);
		}

		for (const FKConvexElem& ConvexElem : BodySetup->AggGeom.ConvexElems)
		{
			AddToCollection(PCollection, ConvexElem.ConvexMesh);
			AddToCollection(PCollection, ConvexElem.ConvexMeshNegX);
		}
	}

	PxSerialization::createSerialObjectIds(*PCollection, PxSerialObjectId(BaseId));

	return PCollection;
}
	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;
	}