Browse Source

Better RTTI object cloning (untested)

Marko Pintera 10 năm trước cách đây
mục cha
commit
1ff5442ad7

+ 2 - 0
BansheeUtility/BansheeUtility.vcxproj

@@ -251,6 +251,7 @@
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemGroup>
   <ItemGroup>
+    <ClCompile Include="Source\BsBinaryCloner.cpp" />
     <ClCompile Include="Source\BsBounds.cpp" />
     <ClCompile Include="Source\BsBounds.cpp" />
     <ClCompile Include="Source\BsCapsule.cpp" />
     <ClCompile Include="Source\BsCapsule.cpp" />
     <ClCompile Include="Source\BsConvexVolume.cpp" />
     <ClCompile Include="Source\BsConvexVolume.cpp" />
@@ -288,6 +289,7 @@
     <ClCompile Include="Source\Win32\BsFileSystem.cpp" />
     <ClCompile Include="Source\Win32\BsFileSystem.cpp" />
     <ClCompile Include="Source\Win32\BsTimer.cpp" />
     <ClCompile Include="Source\Win32\BsTimer.cpp" />
     <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsAny.h" />
+    <ClInclude Include="Include\BsBinaryCloner.h" />
     <ClInclude Include="Include\BsBounds.h" />
     <ClInclude Include="Include\BsBounds.h" />
     <ClInclude Include="Include\BsCapsule.h" />
     <ClInclude Include="Include\BsCapsule.h" />
     <ClInclude Include="Include\BsConvexVolume.h" />
     <ClInclude Include="Include\BsConvexVolume.h" />

+ 6 - 0
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -302,6 +302,9 @@
     <ClInclude Include="Include\BsSerializedObjectRTTI.h">
     <ClInclude Include="Include\BsSerializedObjectRTTI.h">
       <Filter>Header Files\RTTI</Filter>
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsBinaryCloner.h">
+      <Filter>Header Files\Serialization</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsThreadPool.cpp">
     <ClCompile Include="Source\BsThreadPool.cpp">
@@ -481,5 +484,8 @@
     <ClCompile Include="Source\BsSerializedObject.cpp">
     <ClCompile Include="Source\BsSerializedObject.cpp">
       <Filter>Source Files\Serialization</Filter>
       <Filter>Source Files\Serialization</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsBinaryCloner.cpp">
+      <Filter>Source Files\Serialization</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 83 - 0
BansheeUtility/Include/BsBinaryCloner.h

@@ -0,0 +1,83 @@
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Helper class that performs cloning of an object that implements RTTI.
+	 */
+	class BS_UTILITY_EXPORT BinaryCloner
+	{
+	public:
+
+		/**
+		 * @brief	Returns a copy of the provided object with identical data.
+		 *
+		 * @param	object		Object to clone.
+		 * @param	shallow		If false then all referenced objects will be cloned
+		 *						as well, otherwise the references to the original
+		 *						objects will be kept.
+		 */
+		static SPtr<IReflectable> clone(IReflectable* object, bool shallow = false);
+
+	private:
+		struct ObjectReferenceData;
+
+		/**
+		 * @brief	Identifier representing a single field
+		 *			or an array entry in an object.
+		 */
+		struct FieldId
+		{
+			RTTIField* field;
+			INT32 arrayIdx;
+		};
+
+		/**
+		 * @brief	A saved reference to an object with a field
+		 *			identifier that owns it.
+		 */
+		struct ObjectReference
+		{
+			FieldId fieldId;
+			SPtr<IReflectable> object;
+		};
+
+		/**
+		 * @brief	Contains all object references in a portion of an
+		 *			object belonging to a specific class (base and derived 
+		 *			classes count as separate sub-objects).
+		 */
+		struct SubObjectReferenceData
+		{
+			RTTITypeBase* rtti;
+			Vector<ObjectReference> references;
+			Vector<ObjectReferenceData> children;
+		};
+
+		/**
+		 * @brief	Contains all object references in an entire object, as well
+		 *			as the identifier of the field owning this object.
+		 */
+		struct ObjectReferenceData
+		{
+			FieldId fieldId;
+			Vector<SubObjectReferenceData> subObjectData;
+		};
+
+		/**
+		 * @brief	Iterates over the provided object hierarchy and retrieves all object references
+		 *			which are returned in "referenceData" output parameter, also in a hierarchical
+		 *			format for easier parsing.
+		 */
+		static void gatherReferences(IReflectable* object, ObjectReferenceData& referenceData);
+
+		/**
+		 * @brief	Restores a set of references retrieved by "gatherReferences" and applies them to
+		 *			a specific object. Type of the object must be the same as the type that was used
+		 *			when calling "gatherReferences".
+		 */
+		static void restoreReferences(IReflectable* object, const ObjectReferenceData& referenceData);
+	};
+}

+ 0 - 5
BansheeUtility/Include/BsBinaryDiff.h

@@ -92,10 +92,5 @@ namespace BansheeEngine
 		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
 		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
 		 */
 		 */
 		static void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands);
 		static void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands);
-
-		/**
-		 * @brief	Helper method that clones any object with RTTI implemented.
-		 */
-		static SPtr<IReflectable> clone(IReflectable* object);
 	};
 	};
 }
 }

+ 18 - 4
BansheeUtility/Include/BsBinarySerializer.h

@@ -53,18 +53,32 @@ namespace BansheeEngine
 		 * 									"bytesRead" variable, as buffer might not be full completely). User must then
 		 * 									"bytesRead" variable, as buffer might not be full completely). User must then
 		 * 									either create a new buffer or empty the existing one, and then return it by the callback.
 		 * 									either create a new buffer or empty the existing one, and then return it by the callback.
 		 * 									If the returned buffer address is NULL, encoding is aborted.
 		 * 									If the returned buffer address is NULL, encoding is aborted.
+		 * @param	shallow					Determines how to handle referenced objects. If true then references will not be encoded
+		 *									and will be set to null. If false then references will be encoded as well and restored
+		 *									upon decoding.
 		 */
 		 */
 		void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, UINT32* bytesWritten,
 		void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback,
+			bool shallow = false);
 
 
 		/**
 		/**
 		 * @brief	Decodes an object from binary data.
 		 * @brief	Decodes an object from binary data.
 		 *
 		 *
 		 * @param 	data  	Binary data to decode.
 		 * @param 	data  	Binary data to decode.
-		 * @param	dataLength	Length of the data.
+		 * @param	dataLength	Length of the data in bytes.
 		 */
 		 */
 		std::shared_ptr<IReflectable> decode(UINT8* data, UINT32 dataLength);
 		std::shared_ptr<IReflectable> decode(UINT8* data, UINT32 dataLength);
 
 
+		/**
+		 * @brief	Returns a copy of the provided object with indentical data.
+		 *
+		 * @param	object		Object to clone
+		 * @param	shallow		If false then all referenced objects will be cloned
+		 *						as well, otherwise the references to the original
+		 *						objects will be kept.
+		 */
+		std::shared_ptr<IReflectable> clone(IReflectable* object, bool shallow = false);
+
 		/**
 		/**
 		 * @brief	Decodes an object in memory into an intermediate representation for easier parsing.
 		 * @brief	Decodes an object in memory into an intermediate representation for easier parsing.
 		 *			
 		 *			
@@ -112,7 +126,7 @@ namespace BansheeEngine
 		 * @brief	Encodes a single IReflectable object. 
 		 * @brief	Encodes a single IReflectable object. 
 		 */
 		 */
 		UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
 		UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
 
 
 		/**
 		/**
 		 * @brief	Decodes a single IReflectable object.
 		 * @brief	Decodes a single IReflectable object.
@@ -128,7 +142,7 @@ namespace BansheeEngine
 		 * @brief	Helper method for encoding a complex object and copying its data to a buffer.
 		 * @brief	Helper method for encoding a complex object and copying its data to a buffer.
 		 */
 		 */
 		UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
 		UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, UINT32* bytesWritten,
-			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+			std::function<UINT8*(UINT8* buffer, UINT32 bytesWritten, UINT32& newBufferSize)> flushBufferCallback, bool shallow);
 
 
 		/**
 		/**
 		 * @brief	Helper method for encoding a data block to a buffer.
 		 * @brief	Helper method for encoding a data block to a buffer.

+ 1 - 0
BansheeUtility/Include/BsFwdDeclUtil.h

@@ -57,6 +57,7 @@ namespace BansheeEngine
 	class TestOutput;
 	class TestOutput;
 	class AsyncOpSyncData;
 	class AsyncOpSyncData;
 	struct RTTIField;
 	struct RTTIField;
+	struct RTTIReflectablePtrFieldBase;
 	// Reflection
 	// Reflection
 	class IReflectable;
 	class IReflectable;
 	class RTTITypeBase;
 	class RTTITypeBase;

+ 11 - 3
BansheeUtility/Include/BsMemorySerializer.h

@@ -23,10 +23,18 @@ namespace BansheeEngine
 		 * @brief	Parses the provided object, serializes all of its data as specified by its
 		 * @brief	Parses the provided object, serializes all of its data as specified by its
 		 *			RTTIType and returns the data in the form of raw memory.
 		 *			RTTIType and returns the data in the form of raw memory.
 		 *
 		 *
-		 *			All memory is allocated using the provided "allocator". If not specified the default
-		 *			allocator is used.
+		 * @param	object			Object to encode.
+		 * @param	bytesWritten	Output value containing the total number of bytes it took to encode the object.
+		 * @param	allocator		Determines how is memory allocated. If not specified the default allocator is used.
+		 * @param	shallow			Determines how to handle referenced objects. If true then references will not be encoded
+		 *							and will be set to null. If false then references will be encoded as well and restored
+		 *							upon decoding.
+		 *
+		 * @return	A buffer containing the encoded object. It is up to the user to release the buffer memory when
+		 *			no longer needed.
 		 */
 		 */
-		UINT8* encode(IReflectable* object, UINT32& bytesWritten, std::function<void*(UINT32)> allocator = nullptr);
+		UINT8* encode(IReflectable* object, UINT32& bytesWritten, std::function<void*(UINT32)> allocator = nullptr, 
+			bool shallow = false);
 
 
 		/**
 		/**
 		 * @brief	Deserializes an IReflectable object by reading the binary data from the provided
 		 * @brief	Deserializes an IReflectable object by reading the binary data from the provided

+ 202 - 0
BansheeUtility/Source/BsBinaryCloner.cpp

@@ -0,0 +1,202 @@
+#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<IReflectable> BinaryCloner::clone(IReflectable* object, bool shallow)
+	{
+		if (object == nullptr)
+			return nullptr;
+
+		ObjectReferenceData referenceData;
+		if (shallow)
+			gatherReferences(object, referenceData);
+
+		MemorySerializer ms;
+		UINT32 dataSize = 0;
+		UINT8* data = ms.encode(object, dataSize, &bs_alloc, shallow);
+		SPtr<IReflectable> 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;
+
+		Stack<IReflectable*> todo;
+
+		RTTITypeBase* rtti = object->getRTTI();
+		Stack<RTTITypeBase*> 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<RTTIReflectablePtrFieldBase*>(field);
+							SPtr<IReflectable> childObj = curField->getArrayValue(object, j);
+
+							if (childObj != nullptr)
+							{
+								if (subObjectData == nullptr)
+								{
+									referenceData.subObjectData.push_back(SubObjectReferenceData());
+									subObjectData = &referenceData.subObjectData.back();
+									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<RTTIReflectableFieldBase*>(field);
+							IReflectable* childObj = &curField->getArrayValue(object, j);
+							
+							if (subObjectData == nullptr)
+							{
+								referenceData.subObjectData.push_back(SubObjectReferenceData());
+								subObjectData = &referenceData.subObjectData.back();
+								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<RTTIReflectablePtrFieldBase*>(field);
+						SPtr<IReflectable> childObj = curField->getValue(object);
+
+						if (childObj != nullptr)
+						{
+							if (subObjectData == nullptr)
+							{
+								referenceData.subObjectData.push_back(SubObjectReferenceData());
+								subObjectData = &referenceData.subObjectData.back();
+								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<RTTIReflectableFieldBase*>(field);
+						IReflectable* childObj = &curField->getValue(object);
+
+						if (subObjectData == nullptr)
+						{
+							referenceData.subObjectData.push_back(SubObjectReferenceData());
+							subObjectData = &referenceData.subObjectData.back();
+							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<RTTIReflectablePtrFieldBase*>(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<RTTIReflectableFieldBase*>(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);
+			}
+		}
+	}
+}

+ 3 - 14
BansheeUtility/Source/BsBinaryDiff.cpp

@@ -1,6 +1,6 @@
 #include "BsBinaryDiff.h"
 #include "BsBinaryDiff.h"
 #include "BsBinarySerializer.h"
 #include "BsBinarySerializer.h"
-#include "BsMemorySerializer.h"
+#include "BsBinaryCloner.h"
 #include "BsRTTIType.h"
 #include "BsRTTIType.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -425,7 +425,7 @@ namespace BansheeEngine
 						for (UINT32 i = 0; i < minArrayLength; i++)
 						for (UINT32 i = 0; i < minArrayLength; i++)
 						{
 						{
 							IReflectable& childObj = field->getArrayValue(object.get(), i);
 							IReflectable& childObj = field->getArrayValue(object.get(), i);
-							newArrayElements[i] = clone(&childObj);
+							newArrayElements[i] = BinaryCloner::clone(&childObj, true);
 						}
 						}
 
 
 						for (auto& arrayElem : diffArray->entries)
 						for (auto& arrayElem : diffArray->entries)
@@ -535,7 +535,7 @@ namespace BansheeEngine
 						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(diffData);
 						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(diffData);
 
 
 						IReflectable& childObj = field->getValue(object.get());
 						IReflectable& childObj = field->getValue(object.get());
-						std::shared_ptr<IReflectable> clonedObj = clone(&childObj);
+						std::shared_ptr<IReflectable> clonedObj = BinaryCloner::clone(&childObj, true);
 
 
 						applyDiff(clonedObj, fieldObjectData);
 						applyDiff(clonedObj, fieldObjectData);
 
 
@@ -594,15 +594,4 @@ namespace BansheeEngine
 			rttiTypes.pop();
 			rttiTypes.pop();
 		}
 		}
 	}
 	}
-
-	SPtr<IReflectable> BinaryDiff::clone(IReflectable* object)
-	{
-		UINT32 bufferSize = 0;
-		MemorySerializer serializer;
-		UINT8* buffer = serializer.encode(object, bufferSize, &bs_alloc);
-		std::shared_ptr<IReflectable> clonedObj = serializer.decode(buffer, bufferSize);
-		bs_free(buffer);
-
-		return clonedObj;
-	}
 }
 }

+ 20 - 10
BansheeUtility/Source/BsBinarySerializer.cpp

@@ -43,7 +43,8 @@ namespace BansheeEngine
 	{
 	{
 	}
 	}
 
 
-	void BinarySerializer::encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback)
+	void BinarySerializer::encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, 
+		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
 	{
 	{
 		mObjectsToEncode.clear();
 		mObjectsToEncode.clear();
 		mObjectAddrToId.clear();
 		mObjectAddrToId.clear();
@@ -56,7 +57,7 @@ namespace BansheeEngine
 		UINT32 objectId = findOrCreatePersistentId(object);
 		UINT32 objectId = findOrCreatePersistentId(object);
 		
 		
 		// Encode primary object and its value types
 		// Encode primary object and its value types
-		buffer = encodeInternal(object, objectId, buffer, bufferLength, bytesWritten, flushBufferCallback);
+		buffer = encodeInternal(object, objectId, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
 		if(buffer == nullptr)
 		if(buffer == nullptr)
 		{
 		{
 			BS_EXCEPT(InternalErrorException, 
 			BS_EXCEPT(InternalErrorException, 
@@ -80,7 +81,8 @@ namespace BansheeEngine
 				serializedObjects.insert(curObjectid);
 				serializedObjects.insert(curObjectid);
 				mObjectsToEncode.erase(iter);
 				mObjectsToEncode.erase(iter);
 
 
-				buffer = encodeInternal(curObject.get(), curObjectid, buffer, bufferLength, bytesWritten, flushBufferCallback);
+				buffer = encodeInternal(curObject.get(), curObjectid, buffer, 
+					bufferLength, bytesWritten, flushBufferCallback, shallow);
 				if(buffer == nullptr)
 				if(buffer == nullptr)
 				{
 				{
 					BS_EXCEPT(InternalErrorException, 
 					BS_EXCEPT(InternalErrorException, 
@@ -153,7 +155,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, 
 	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, 
-		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback)
+		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
 	{
 	{
 		RTTITypeBase* si = object->getRTTI();
 		RTTITypeBase* si = object->getRTTI();
 		bool isBaseClass = false;
 		bool isBaseClass = false;
@@ -192,7 +194,10 @@ namespace BansheeEngine
 
 
 							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
 							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
 							{
 							{
-								std::shared_ptr<IReflectable> childObject = curField->getArrayValue(object, arrIdx); 
+								std::shared_ptr<IReflectable> childObject;
+								
+								if (!shallow)
+									childObject = curField->getArrayValue(object, arrIdx);
 
 
 								UINT32 objId = registerObjectPtr(childObject);
 								UINT32 objId = registerObjectPtr(childObject);
 								COPY_TO_BUFFER(&objId, sizeof(UINT32))
 								COPY_TO_BUFFER(&objId, sizeof(UINT32))
@@ -208,7 +213,8 @@ namespace BansheeEngine
 							{
 							{
 								IReflectable& childObject = curField->getArrayValue(object, arrIdx);
 								IReflectable& childObject = curField->getArrayValue(object, arrIdx);
 
 
-								buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, bytesWritten, flushBufferCallback);
+								buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, 
+									bytesWritten, flushBufferCallback, shallow);
 								if(buffer == nullptr)
 								if(buffer == nullptr)
 								{
 								{
 									si->onSerializationEnded(object);
 									si->onSerializationEnded(object);
@@ -268,7 +274,10 @@ namespace BansheeEngine
 					case SerializableFT_ReflectablePtr:
 					case SerializableFT_ReflectablePtr:
 						{
 						{
 							RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
 							RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
-							std::shared_ptr<IReflectable> childObject = curField->getValue(object); 
+							std::shared_ptr<IReflectable> childObject;
+							
+							if (!shallow)
+								childObject = curField->getValue(object);
 
 
 							UINT32 objId = registerObjectPtr(childObject);
 							UINT32 objId = registerObjectPtr(childObject);
 							COPY_TO_BUFFER(&objId, sizeof(UINT32))
 							COPY_TO_BUFFER(&objId, sizeof(UINT32))
@@ -280,7 +289,8 @@ namespace BansheeEngine
 							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
 							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
 							IReflectable& childObject = curField->getValue(object);
 							IReflectable& childObject = curField->getValue(object);
 
 
-							buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, bytesWritten, flushBufferCallback);
+							buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, 
+								bytesWritten, flushBufferCallback, shallow);
 							if(buffer == nullptr)
 							if(buffer == nullptr)
 							{
 							{
 								si->onSerializationEnded(object);
 								si->onSerializationEnded(object);
@@ -1238,7 +1248,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, 
 	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, 
-		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback)
+		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
 	{
 	{
 		int complexTypeSize = 0;
 		int complexTypeSize = 0;
 		if(object != nullptr)
 		if(object != nullptr)
@@ -1247,7 +1257,7 @@ namespace BansheeEngine
 		COPY_TO_BUFFER(&complexTypeSize, COMPLEX_TYPE_FIELD_SIZE)
 		COPY_TO_BUFFER(&complexTypeSize, COMPLEX_TYPE_FIELD_SIZE)
 
 
 		if(object != nullptr)
 		if(object != nullptr)
-			return encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback);
+			return encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
 
 
 		return buffer;
 		return buffer;
 	}
 	}

+ 4 - 2
BansheeUtility/Source/BsMemorySerializer.cpp

@@ -14,7 +14,8 @@ namespace BansheeEngine
 	MemorySerializer::~MemorySerializer()
 	MemorySerializer::~MemorySerializer()
 	{ }
 	{ }
 
 
-	UINT8* MemorySerializer::encode(IReflectable* object, UINT32& bytesWritten, std::function<void*(UINT32)> allocator)
+	UINT8* MemorySerializer::encode(IReflectable* object, UINT32& bytesWritten, 
+		std::function<void*(UINT32)> allocator, bool shallow)
 	{
 	{
 		using namespace std::placeholders;
 		using namespace std::placeholders;
 
 
@@ -26,7 +27,8 @@ namespace BansheeEngine
 
 
 		mBufferPieces.push_back(piece);
 		mBufferPieces.push_back(piece);
 
 
-		bs.encode(object, piece.buffer, WRITE_BUFFER_SIZE, &bytesWritten, std::bind(&MemorySerializer::flushBuffer, this, _1, _2, _3));
+		bs.encode(object, piece.buffer, WRITE_BUFFER_SIZE, &bytesWritten, 
+			std::bind(&MemorySerializer::flushBuffer, this, _1, _2, _3), shallow);
 
 
 		UINT8* resultBuffer;
 		UINT8* resultBuffer;
 		if(allocator != nullptr)
 		if(allocator != nullptr)

+ 0 - 3
TODO.txt

@@ -32,9 +32,6 @@ IMMEDIATE:
  - Create a native only unit test for binary diff
  - Create a native only unit test for binary diff
  - Test and debug native diff
  - Test and debug native diff
 
 
-Is cloning broken?
- - What if I clone a Reflectable that references a Reflectable by pointer? Then that will be cloned as well but it shouldn't be
-
 See "Prefabs" gdoc for later goals
 See "Prefabs" gdoc for later goals
 See "Brainstorm" gdoc for ideas about how to solve the ID issue (and see below)
 See "Brainstorm" gdoc for ideas about how to solve the ID issue (and see below)