#include "BsBinaryCloner.h" #include "BsIReflectable.h" #include "BsRTTIType.h" #include "BsRTTIField.h" #include "BsRTTIPlainField.h" #include "BsRTTIReflectableField.h" #include "BsRTTIReflectablePtrField.h" #include "BsRTTIManagedDataBlockField.h" #include "BsMemorySerializer.h" namespace BansheeEngine { SPtr BinaryCloner::clone(IReflectable* object, bool shallow) { if (object == nullptr) return nullptr; ObjectReferenceData referenceData; if (shallow) gatherReferences(object, referenceData); std::function allocator = &MemoryAllocator::allocate; MemorySerializer ms; UINT32 dataSize = 0; UINT8* data = ms.encode(object, dataSize, allocator, shallow); SPtr clonedObj = ms.decode(data, dataSize); if (shallow) restoreReferences(clonedObj.get(), referenceData); bs_free(data); return clonedObj; } void BinaryCloner::gatherReferences(IReflectable* object, ObjectReferenceData& referenceData) { if (object == nullptr) return; RTTITypeBase* rtti = object->getRTTI(); Stack rttiTypes; while (rtti != nullptr) { rtti->onSerializationStarted(object); SubObjectReferenceData* subObjectData = nullptr; UINT32 numFields = rtti->getNumFields(); for (UINT32 i = 0; i < numFields; i++) { RTTIField* field = rtti->getField(i); FieldId fieldId; fieldId.field = field; fieldId.arrayIdx = -1; if (field->isArray()) { UINT32 numElements = field->getArraySize(object); for (UINT32 j = 0; j < numElements; j++) { fieldId.arrayIdx = j; if (field->mType == SerializableFT_ReflectablePtr) { RTTIReflectablePtrFieldBase* curField = static_cast(field); SPtr childObj = curField->getArrayValue(object, j); if (childObj != nullptr) { if (subObjectData == nullptr) { referenceData.subObjectData.push_back(SubObjectReferenceData()); subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; subObjectData->rtti = rtti; } subObjectData->references.push_back(ObjectReference()); ObjectReference& reference = subObjectData->references.back(); reference.fieldId = fieldId; reference.object = childObj; } } else if (field->mType == SerializableFT_Reflectable) { RTTIReflectableFieldBase* curField = static_cast(field); IReflectable* childObj = &curField->getArrayValue(object, j); if (subObjectData == nullptr) { referenceData.subObjectData.push_back(SubObjectReferenceData()); subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; subObjectData->rtti = rtti; } subObjectData->children.push_back(ObjectReferenceData()); ObjectReferenceData& childData = subObjectData->children.back(); childData.fieldId = fieldId; gatherReferences(childObj, childData); } } } else { if (field->mType == SerializableFT_ReflectablePtr) { RTTIReflectablePtrFieldBase* curField = static_cast(field); SPtr childObj = curField->getValue(object); if (childObj != nullptr) { if (subObjectData == nullptr) { referenceData.subObjectData.push_back(SubObjectReferenceData()); subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; subObjectData->rtti = rtti; } subObjectData->references.push_back(ObjectReference()); ObjectReference& reference = subObjectData->references.back(); reference.fieldId = fieldId; reference.object = childObj; } } else if (field->mType == SerializableFT_Reflectable) { RTTIReflectableFieldBase* curField = static_cast(field); IReflectable* childObj = &curField->getValue(object); if (subObjectData == nullptr) { referenceData.subObjectData.push_back(SubObjectReferenceData()); subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; subObjectData->rtti = rtti; } subObjectData->children.push_back(ObjectReferenceData()); ObjectReferenceData& childData = subObjectData->children.back(); childData.fieldId = fieldId; gatherReferences(childObj, childData); } } } rttiTypes.push(rtti); rtti = rtti->getBaseClass(); } while (!rttiTypes.empty()) { rtti = rttiTypes.top(); rttiTypes.pop(); rtti->onSerializationEnded(object); } } void BinaryCloner::restoreReferences(IReflectable* object, const ObjectReferenceData& referenceData) { for (auto& subObject : referenceData.subObjectData) { if (subObject.references.size() > 0) { subObject.rtti->onDeserializationStarted(object); for (auto& reference : subObject.references) { RTTIReflectablePtrFieldBase* curField = static_cast(reference.fieldId.field); if (curField->isArray()) curField->setArrayValue(object, reference.fieldId.arrayIdx, reference.object); else curField->setValue(object, reference.object); } subObject.rtti->onDeserializationEnded(object); } if (subObject.children.size() > 0) { subObject.rtti->onSerializationStarted(object); for (auto& childObjectData : subObject.children) { RTTIReflectableFieldBase* curField = static_cast(childObjectData.fieldId.field); IReflectable* childObj = nullptr; if (curField->isArray()) childObj = &curField->getArrayValue(object, childObjectData.fieldId.arrayIdx); else childObj = &curField->getValue(object); restoreReferences(childObj, childObjectData); } subObject.rtti->onSerializationEnded(object); } } } }