Przeglądaj źródła

Linked native and managed diff
Tested and fixed native diff

Marko Pintera 10 lat temu
rodzic
commit
9a0e9b0b78

+ 5 - 3
BansheeEditor/Source/BsEditorTestSuite.cpp

@@ -343,7 +343,7 @@ namespace BansheeEngine
 		newObj->objPtrB->strA = "kiwi";
 		newObj->objPtrB->strA = "kiwi";
 		newObj->objPtrC = nullptr;
 		newObj->objPtrC = nullptr;
 		newObj->objPtrD = bs_shared_ptr<TestObjectB>();
 		newObj->objPtrD = bs_shared_ptr<TestObjectB>();
-		newObj->arrObjB[1].strA = "starberry";
+		newObj->arrObjB[1].strA = "strawberry";
 		newObj->arrObjPtrB[0]->intA = 99100;
 		newObj->arrObjPtrB[0]->intA = 99100;
 
 
 		MemorySerializer ms;
 		MemorySerializer ms;
@@ -356,10 +356,12 @@ namespace BansheeEngine
 		UINT32 dummy = 0;
 		UINT32 dummy = 0;
 		BinarySerializer bs;
 		BinarySerializer bs;
 		SPtr<SerializedObject> orgSerialized = bs._decodeIntermediate(orgData, orgDataLength, dummy);
 		SPtr<SerializedObject> orgSerialized = bs._decodeIntermediate(orgData, orgDataLength, dummy);
+		dummy = 0;
 		SPtr<SerializedObject> newSerialized = bs._decodeIntermediate(newData, newDataLength, dummy);
 		SPtr<SerializedObject> newSerialized = bs._decodeIntermediate(newData, newDataLength, dummy);
 
 
-		SPtr<SerializedObject> objDiff = BinaryDiff::generateDiff(orgSerialized, newSerialized);
-		BinaryDiff::applyDiff(orgObj, objDiff);
+		IDiff& diffHandler = orgObj->getRTTI()->getDiffHandler();
+		SPtr<SerializedObject> objDiff = diffHandler.generateDiff(orgSerialized, newSerialized);
+		diffHandler.applyDiff(orgObj, objDiff);
 
 
 		bs_free(orgData);
 		bs_free(orgData);
 		bs_free(newData);
 		bs_free(newData);

+ 42 - 15
BansheeUtility/Include/BsBinaryDiff.h

@@ -1,22 +1,18 @@
 #pragma once
 #pragma once
 
 
 #include "BsPrerequisitesUtil.h"
 #include "BsPrerequisitesUtil.h"
-#include "BsSerializedObject.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	/**
 	/**
-	 * @brief	Generates and applies "diffs". Diffs contain per-field differences between
-	 *			an original and new object. These differences can be saved and then applied
-	 *			to an original object to transform it to the new version.
-	 *
-	 * @note	Objects must be in intermediate serialized format generated by BinarySerializer.
+	 * @brief	Represents an interface RTTI objects need to implement if they
+	 *			want to provide custom "diff" generation and applying.
 	 */
 	 */
-	class BS_UTILITY_EXPORT BinaryDiff
+	class BS_UTILITY_EXPORT IDiff
 	{
 	{
-		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<SerializedObject>> ObjectMap;
-		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<IReflectable>> DiffObjectMap;
 	public:
 	public:
+		virtual ~IDiff() { }
+
 		/**
 		/**
 		 * @brief	Generates per-field differences between the provided original and new object. Any field
 		 * @brief	Generates per-field differences between the provided original and new object. Any field
 		 *			or array entry that is different in the new object compared to the original will be output
 		 *			or array entry that is different in the new object compared to the original will be output
@@ -24,16 +20,19 @@ namespace BansheeEngine
 		 *
 		 *
 		 *			Will return null if there is no difference.
 		 *			Will return null if there is no difference.
 		 */
 		 */
-		static SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj);
+		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj);
 
 
 		/**
 		/**
 		 * @brief	Applies a previously generated per-field differences to the provided object. This will
 		 * @brief	Applies a previously generated per-field differences to the provided object. This will
 		 *			essentially transform the original object the differences were generated for into the modified
 		 *			essentially transform the original object the differences were generated for into the modified
 		 *			version.
 		 *			version.
 		 */
 		 */
-		static void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff);
+		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff);
+
+	protected:
+		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<SerializedObject>> ObjectMap;
+		typedef UnorderedMap<SPtr<SerializedObject>, SPtr<IReflectable>> DiffObjectMap;
 
 
-	private:
 		/**
 		/**
 		 * @brief	Types of commands that are used when applying difference field values.
 		 * @brief	Types of commands that are used when applying difference field values.
 		 */
 		 */
@@ -73,7 +72,7 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
 		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
 		 */
 		 */
-		static SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap);
+		virtual SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) = 0;
 
 
 		/**
 		/**
 		 * @brief	Generates a difference between data of a specific field type indiscriminately of the
 		 * @brief	Generates a difference between data of a specific field type indiscriminately of the
@@ -81,7 +80,7 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
 		 * @see		generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&)
 		 */
 		 */
-		static SPtr<SerializedInstance> generateDiff(UINT32 fieldType, const SPtr<SerializedInstance>& orgData, 
+		SPtr<SerializedInstance> generateDiff(RTTITypeBase* rtti, UINT32 fieldType, const SPtr<SerializedInstance>& orgData,
 			const SPtr<SerializedInstance>& newData, ObjectMap& objectMap);
 			const SPtr<SerializedInstance>& newData, ObjectMap& objectMap);
 
 
 		/**
 		/**
@@ -91,6 +90,34 @@ 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);
+		virtual void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) = 0;
+
+		/**
+		 * @brief	Applies diff according to the diff handler retrieved from the provided RTTI object.
+		 *
+		 * @see		applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
+		 */
+		void applyDiff(RTTITypeBase* rtti, const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands);
+	};
+
+	/**
+	 * @brief	Generates and applies "diffs". Diffs contain per-field differences between
+	 *			an original and new object. These differences can be saved and then applied
+	 *			to an original object to transform it to the new version.
+	 *
+	 * @note	Objects must be in intermediate serialized format generated by BinarySerializer.
+	 */
+	class BS_UTILITY_EXPORT BinaryDiff : public IDiff
+	{
+	private:
+		/**
+		 * @copydoc	IDiff::generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&, ObjectMap&)
+		 */
+		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgObj, const SPtr<SerializedObject>& newObj, ObjectMap& objectMap) override;
+
+		/**
+		 * @copydoc	IDiff::applyDiff(const SPtr<IReflectable>&, const SPtr<SerializedObject>&, DiffObjectMap&, Vector<DiffCommand>&)
+		 */
+		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) override;
 	};
 	};
 }
 }

+ 8 - 11
BansheeUtility/Include/BsBinarySerializer.h

@@ -67,17 +67,7 @@ namespace BansheeEngine
 		 * @param 	data  	Binary data to decode.
 		 * @param 	data  	Binary data to decode.
 		 * @param	dataLength	Length of the data in bytes.
 		 * @param	dataLength	Length of the data in bytes.
 		 */
 		 */
-		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);
+		SPtr<IReflectable> decode(UINT8* data, UINT32 dataLength);
 
 
 		/**
 		/**
 		 * @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.
@@ -88,6 +78,13 @@ namespace BansheeEngine
 		 */
 		 */
 		SPtr<SerializedObject> _decodeIntermediate(UINT8* data, UINT32 dataLength, UINT32& bytesRead);
 		SPtr<SerializedObject> _decodeIntermediate(UINT8* data, UINT32 dataLength, UINT32& bytesRead);
 
 
+		/**
+		 * @brief	Decodes an intermediate representation of a serialized object into the actual object.
+		 *			
+		 * @note	Internal method.
+		 */
+		SPtr<IReflectable> _decodeIntermediate(const SPtr<SerializedObject>& serializedObject);
+
 	private:
 	private:
 		struct ObjectMetaData
 		struct ObjectMetaData
 		{
 		{

+ 2 - 0
BansheeUtility/Include/BsFwdDeclUtil.h

@@ -58,6 +58,8 @@ namespace BansheeEngine
 	class AsyncOpSyncData;
 	class AsyncOpSyncData;
 	struct RTTIField;
 	struct RTTIField;
 	struct RTTIReflectablePtrFieldBase;
 	struct RTTIReflectablePtrFieldBase;
+	struct SerializedObject;
+	struct SerializedInstance;
 	// Reflection
 	// Reflection
 	class IReflectable;
 	class IReflectable;
 	class RTTITypeBase;
 	class RTTITypeBase;

+ 12 - 0
BansheeUtility/Include/BsRTTIType.h

@@ -12,6 +12,7 @@
 #include "BsRTTIReflectablePtrField.h"
 #include "BsRTTIReflectablePtrField.h"
 #include "BsRTTIManagedDataBlockField.h"
 #include "BsRTTIManagedDataBlockField.h"
 #include "BsIReflectable.h"
 #include "BsIReflectable.h"
+#include "BsBinaryDiff.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -152,6 +153,17 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual void onDeserializationEnded(IReflectable* obj) {}
 		virtual void onDeserializationEnded(IReflectable* obj) {}
 
 
+		/**
+		 * @brief	Returns a handler that determines how are "diffs" generated and applied when it
+		 *			comes to objects of this RTTI type. A "diff" is a list of differences between two
+		 *			objects that may be saved, viewed or applied to another object to transform it.
+		 */
+		virtual IDiff& getDiffHandler() const
+		{
+			static BinaryDiff diffHandler;
+			return diffHandler;
+		}
+
 		/**
 		/**
 		 * @brief	Allows you to assign a value to a plain field with the specified name on 
 		 * @brief	Allows you to assign a value to a plain field with the specified name on 
 		 *			the provided instance.
 		 *			the provided instance.

+ 196 - 167
BansheeUtility/Source/BsBinaryDiff.cpp

@@ -1,161 +1,19 @@
 #include "BsBinaryDiff.h"
 #include "BsBinaryDiff.h"
+#include "BsSerializedObject.h"
 #include "BsBinarySerializer.h"
 #include "BsBinarySerializer.h"
 #include "BsBinaryCloner.h"
 #include "BsBinaryCloner.h"
 #include "BsRTTIType.h"
 #include "BsRTTIType.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	SPtr<SerializedObject> BinaryDiff::generateDiff(const SPtr<SerializedObject>& orgObj,
+	SPtr<SerializedObject> IDiff::generateDiff(const SPtr<SerializedObject>& orgObj,
 		const SPtr<SerializedObject>& newObj)
 		const SPtr<SerializedObject>& newObj)
 	{
 	{
 		ObjectMap objectMap;
 		ObjectMap objectMap;
 		return generateDiff(orgObj, newObj, objectMap);
 		return generateDiff(orgObj, newObj, objectMap);
 	}
 	}
 
 
-	SPtr<SerializedObject> BinaryDiff::generateDiff(const SPtr<SerializedObject>& orgObj, 
-		const SPtr<SerializedObject>& newObj, ObjectMap& objectMap)
-	{
-		if (orgObj == nullptr || newObj == nullptr || orgObj->getRootTypeId() != newObj->getRootTypeId())
-			return nullptr;
-
-		RTTITypeBase* rootRtti = IReflectable::_getRTTIfromTypeId(newObj->getRootTypeId());
-		if (rootRtti == nullptr)
-			return nullptr;
-
-		SPtr<SerializedObject> output;
-		for (auto& subObject : newObj->subObjects)
-		{
-			RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
-			if (rtti == nullptr)
-				continue;
-
-			SerializedSubObject* orgSubObject = nullptr;
-			for (auto& curSubObject : orgObj->subObjects)
-			{
-				if (curSubObject.typeId == subObject.typeId)
-				{
-					orgSubObject = &curSubObject;
-					break;
-				}
-			}
-			
-			SerializedSubObject* diffSubObject = nullptr;
-			for (auto& newEntry : subObject.entries)
-			{
-				RTTIField* genericField = rtti->findField(newEntry.first);
-				if (genericField == nullptr)
-					continue;
-
-				SPtr<SerializedInstance> newEntryData = newEntry.second.serialized;
-				SPtr<SerializedInstance> orgEntryData;
-
-				if (orgSubObject != nullptr)
-				{
-					auto orgEntryFind = orgSubObject->entries.find(newEntry.first);
-					if (orgEntryFind != orgSubObject->entries.end())
-						orgEntryData = newEntry.second.serialized;
-				}
-
-				SPtr<SerializedInstance> modification;
-				bool hasModification = false;
-				if (genericField->isArray())
-				{
-					SPtr<SerializedArray> orgArrayData = std::static_pointer_cast<SerializedArray>(orgEntryData);
-					SPtr<SerializedArray> newArrayData = std::static_pointer_cast<SerializedArray>(newEntryData);
-
-					SPtr<SerializedArray> serializedArray;
-
-					if (newEntryData != nullptr && orgEntryData != nullptr)
-					{
-						for (auto& arrayEntryPair : newArrayData->entries)
-						{
-							SPtr<SerializedInstance> arrayModification;
-
-							auto iterFind = orgArrayData->entries.find(arrayEntryPair.first);
-							if (iterFind == orgArrayData->entries.end())
-								arrayModification = arrayEntryPair.second.serialized->clone();
-							else
-							{
-								arrayModification = generateDiff(genericField->mType, iterFind->second.serialized,
-									arrayEntryPair.second.serialized, objectMap);
-							}
-
-							if (arrayModification != nullptr)
-							{
-								if (serializedArray == nullptr)
-								{
-									serializedArray = bs_shared_ptr<SerializedArray>();
-									serializedArray->numElements = newArrayData->numElements;
-								}
-
-								SerializedArrayEntry arrayEntry;
-								arrayEntry.index = arrayEntryPair.first;
-								arrayEntry.serialized = arrayModification;
-								serializedArray->entries[arrayEntryPair.first] = arrayEntry;
-							}
-						}
-					}
-					else if (newEntryData == nullptr)
-					{
-						serializedArray = bs_shared_ptr<SerializedArray>();
-					}
-					else if (orgEntryData == nullptr)
-					{
-						serializedArray = std::static_pointer_cast<SerializedArray>(newArrayData->clone());
-					}
-
-					modification = serializedArray;
-					hasModification = modification != nullptr;
-				}
-				else
-				{
-					if (newEntryData != nullptr && orgEntryData != nullptr)
-					{
-						modification = generateDiff(genericField->mType, orgEntryData, newEntryData, objectMap);
-						hasModification = modification != nullptr;
-					}
-					else if (newEntryData == nullptr)
-					{
-						switch (genericField->mType)
-						{
-						case SerializableFT_Plain:
-						case SerializableFT_DataBlock:
-							modification = bs_shared_ptr<SerializedField>();
-							break;
-						}
-
-						hasModification = true;
-					}
-					else if (orgEntryData == nullptr)
-					{
-						modification = newEntryData->clone();
-						hasModification = modification != nullptr;
-					}
-				}
-
-				if (hasModification)
-				{
-					if (output == nullptr)
-						output = bs_shared_ptr<SerializedObject>();
-
-					if (diffSubObject == nullptr)
-					{
-						output->subObjects.push_back(SerializedSubObject());
-						diffSubObject = &output->subObjects.back();
-					}
-
-					SerializedEntry modificationEntry;
-					modificationEntry.fieldId = genericField->mUniqueId;
-					modificationEntry.serialized = modification;
-					diffSubObject->entries[genericField->mUniqueId] = modificationEntry;
-				}
-			}
-		}
-
-		return output;
-	}
-
-	SPtr<SerializedInstance> BinaryDiff::generateDiff(UINT32 fieldType, const SPtr<SerializedInstance>& orgData, 
+	SPtr<SerializedInstance> IDiff::generateDiff(RTTITypeBase* rtti, UINT32 fieldType, const SPtr<SerializedInstance>& orgData,
 		const SPtr<SerializedInstance>& newData, ObjectMap& objectMap)
 		const SPtr<SerializedInstance>& newData, ObjectMap& objectMap)
 	{
 	{
 		SPtr<SerializedInstance> modification;
 		SPtr<SerializedInstance> modification;
@@ -172,7 +30,17 @@ namespace BansheeEngine
 				modification = iterFind->second;
 				modification = iterFind->second;
 			else
 			else
 			{
 			{
-				SPtr<SerializedObject> objectDiff = generateDiff(orgObjData, newObjData);
+				RTTITypeBase* childRtti = nullptr;
+				if (orgObjData->getRootTypeId() == newObjData->getRootTypeId())
+					childRtti = IReflectable::_getRTTIfromTypeId(newObjData->getRootTypeId());
+
+				SPtr<SerializedObject> objectDiff;
+				if (childRtti != nullptr)
+				{
+					IDiff& handler = childRtti->getDiffHandler();
+					objectDiff = handler.generateDiff(orgObjData, newObjData, objectMap);
+				}
+
 				if (objectDiff != nullptr)
 				if (objectDiff != nullptr)
 					objectMap[newObjData] = objectDiff;
 					objectMap[newObjData] = objectDiff;
 
 
@@ -188,7 +56,7 @@ namespace BansheeEngine
 
 
 			bool isModified = orgFieldData->size != newFieldData->size;
 			bool isModified = orgFieldData->size != newFieldData->size;
 			if (!isModified)
 			if (!isModified)
-				isModified = memcmp(orgFieldData->value, newFieldData->value, newFieldData->size) == 0;
+				isModified = memcmp(orgFieldData->value, newFieldData->value, newFieldData->size) != 0;
 
 
 			if (isModified)
 			if (isModified)
 				modification = newFieldData->clone();
 				modification = newFieldData->clone();
@@ -199,26 +67,31 @@ namespace BansheeEngine
 		return modification;
 		return modification;
 	}
 	}
 
 
-	void BinaryDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
+	void IDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff)
 	{
 	{
 		Vector<DiffCommand> commands;
 		Vector<DiffCommand> commands;
 
 
 		DiffObjectMap objectMap;
 		DiffObjectMap objectMap;
 		applyDiff(object, diff, objectMap, commands);
 		applyDiff(object, diff, objectMap, commands);
 
 
+		IReflectable* destObject = nullptr;
+		Stack<IReflectable*> objectStack;
+
 		for (auto& command : commands)
 		for (auto& command : commands)
 		{
 		{
 			bool isArray = (command.type & Diff_ArrayFlag) != 0;
 			bool isArray = (command.type & Diff_ArrayFlag) != 0;
-			DiffCommandType type = (DiffCommandType)(command.type & 0xFF);
-			IReflectable* destObject = command.object.get();
+			DiffCommandType type = (DiffCommandType)(command.type & 0xF);
 
 
 			switch (type)
 			switch (type)
 			{
 			{
-			case Diff_ArraySize: 
-				command.field->setArraySize(destObject, command.size);
+			case Diff_ArraySize:
+				command.field->setArraySize(destObject, command.arraySize);
 				break;
 				break;
 			case Diff_ObjectStart:
 			case Diff_ObjectStart:
 			{
 			{
+				destObject = command.object.get();
+				objectStack.push(destObject);
+
 				RTTITypeBase* curRtti = destObject->getRTTI();
 				RTTITypeBase* curRtti = destObject->getRTTI();
 				while (curRtti != nullptr)
 				while (curRtti != nullptr)
 				{
 				{
@@ -227,7 +100,7 @@ namespace BansheeEngine
 				}
 				}
 			}
 			}
 				break;
 				break;
-			case Diff_ObjectEnd: 
+			case Diff_ObjectEnd:
 			{
 			{
 				Stack<RTTITypeBase*> rttiTypes;
 				Stack<RTTITypeBase*> rttiTypes;
 				RTTITypeBase* curRtti = destObject->getRTTI();
 				RTTITypeBase* curRtti = destObject->getRTTI();
@@ -242,6 +115,13 @@ namespace BansheeEngine
 					rttiTypes.top()->onDeserializationEnded(destObject);
 					rttiTypes.top()->onDeserializationEnded(destObject);
 					rttiTypes.pop();
 					rttiTypes.pop();
 				}
 				}
+
+				objectStack.pop();
+
+				if (!objectStack.empty())
+					destObject = objectStack.top();
+				else
+					destObject = nullptr;
 			}
 			}
 				break;
 				break;
 			}
 			}
@@ -256,13 +136,13 @@ namespace BansheeEngine
 					field->setArrayValue(destObject, command.arrayIdx, command.object);
 					field->setArrayValue(destObject, command.arrayIdx, command.object);
 				}
 				}
 					break;
 					break;
-				case Diff_Reflectable: 
+				case Diff_Reflectable:
 				{
 				{
 					RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(command.field);
 					RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(command.field);
-					field->setArrayValue(object.get(), command.arrayIdx, *command.object);
+					field->setArrayValue(destObject, command.arrayIdx, *command.object);
 				}
 				}
 					break;
 					break;
-				case Diff_Plain: 
+				case Diff_Plain:
 				{
 				{
 					RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(command.field);
 					RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(command.field);
 					field->arrayElemFromBuffer(destObject, command.arrayIdx, command.value);
 					field->arrayElemFromBuffer(destObject, command.arrayIdx, command.value);
@@ -283,7 +163,7 @@ namespace BansheeEngine
 				case Diff_Reflectable:
 				case Diff_Reflectable:
 				{
 				{
 					RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(command.field);
 					RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(command.field);
-					field->setValue(object.get(), *command.object);
+					field->setValue(destObject, *command.object);
 				}
 				}
 					break;
 					break;
 				case Diff_Plain:
 				case Diff_Plain:
@@ -292,7 +172,7 @@ namespace BansheeEngine
 					field->fromBuffer(destObject, command.value);
 					field->fromBuffer(destObject, command.value);
 				}
 				}
 					break;
 					break;
-				case Diff_DataBlock: 
+				case Diff_DataBlock:
 				{
 				{
 					RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(command.field);
 					RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(command.field);
 					UINT8* dataCopy = field->allocate(destObject, command.size);
 					UINT8* dataCopy = field->allocate(destObject, command.size);
@@ -307,6 +187,150 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	void IDiff::applyDiff(RTTITypeBase* rtti, const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff, 
+		DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands)
+	{
+		IDiff& diffHandler = rtti->getDiffHandler();
+		diffHandler.applyDiff(object, diff, objectMap, diffCommands);
+	}
+
+	SPtr<SerializedObject> BinaryDiff::generateDiff(const SPtr<SerializedObject>& orgObj, 
+		const SPtr<SerializedObject>& newObj, ObjectMap& objectMap)
+	{
+		SPtr<SerializedObject> output;
+		for (auto& subObject : newObj->subObjects)
+		{
+			RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
+			if (rtti == nullptr)
+				continue;
+
+			SerializedSubObject* orgSubObject = nullptr;
+			for (auto& curSubObject : orgObj->subObjects)
+			{
+				if (curSubObject.typeId == subObject.typeId)
+				{
+					orgSubObject = &curSubObject;
+					break;
+				}
+			}
+			
+			SerializedSubObject* diffSubObject = nullptr;
+			for (auto& newEntry : subObject.entries)
+			{
+				RTTIField* genericField = rtti->findField(newEntry.first);
+				if (genericField == nullptr)
+					continue;
+
+				SPtr<SerializedInstance> newEntryData = newEntry.second.serialized;
+				SPtr<SerializedInstance> orgEntryData;
+
+				if (orgSubObject != nullptr)
+				{
+					auto orgEntryFind = orgSubObject->entries.find(newEntry.first);
+					if (orgEntryFind != orgSubObject->entries.end())
+						orgEntryData = orgEntryFind->second.serialized;
+				}
+
+				SPtr<SerializedInstance> modification;
+				bool hasModification = false;
+				if (genericField->isArray())
+				{
+					SPtr<SerializedArray> orgArrayData = std::static_pointer_cast<SerializedArray>(orgEntryData);
+					SPtr<SerializedArray> newArrayData = std::static_pointer_cast<SerializedArray>(newEntryData);
+
+					SPtr<SerializedArray> serializedArray;
+
+					if (newEntryData != nullptr && orgEntryData != nullptr)
+					{
+						for (auto& arrayEntryPair : newArrayData->entries)
+						{
+							SPtr<SerializedInstance> arrayModification;
+
+							auto iterFind = orgArrayData->entries.find(arrayEntryPair.first);
+							if (iterFind == orgArrayData->entries.end())
+								arrayModification = arrayEntryPair.second.serialized->clone();
+							else
+							{
+								arrayModification = IDiff::generateDiff(rtti, genericField->mType, iterFind->second.serialized,
+									arrayEntryPair.second.serialized, objectMap);
+							}
+
+							if (arrayModification != nullptr)
+							{
+								if (serializedArray == nullptr)
+								{
+									serializedArray = bs_shared_ptr<SerializedArray>();
+									serializedArray->numElements = newArrayData->numElements;
+								}
+
+								SerializedArrayEntry arrayEntry;
+								arrayEntry.index = arrayEntryPair.first;
+								arrayEntry.serialized = arrayModification;
+								serializedArray->entries[arrayEntryPair.first] = arrayEntry;
+							}
+						}
+					}
+					else if (newEntryData == nullptr)
+					{
+						serializedArray = bs_shared_ptr<SerializedArray>();
+					}
+					else if (orgEntryData == nullptr)
+					{
+						serializedArray = std::static_pointer_cast<SerializedArray>(newArrayData->clone());
+					}
+
+					modification = serializedArray;
+					hasModification = modification != nullptr;
+				}
+				else
+				{
+					if (newEntryData != nullptr && orgEntryData != nullptr)
+					{
+						modification = IDiff::generateDiff(rtti, genericField->mType, orgEntryData, newEntryData, objectMap);
+						hasModification = modification != nullptr;
+					}
+					else if (newEntryData == nullptr)
+					{
+						switch (genericField->mType)
+						{
+						case SerializableFT_Plain:
+						case SerializableFT_DataBlock:
+							modification = bs_shared_ptr<SerializedField>();
+							break;
+						}
+
+						hasModification = true;
+					}
+					else if (orgEntryData == nullptr)
+					{
+						modification = newEntryData->clone();
+						hasModification = modification != nullptr;
+					}
+				}
+
+				if (hasModification)
+				{
+					if (output == nullptr)
+						output = bs_shared_ptr<SerializedObject>();
+
+					if (diffSubObject == nullptr)
+					{
+						output->subObjects.push_back(SerializedSubObject());
+						diffSubObject = &output->subObjects.back();
+						diffSubObject->typeId = rtti->getRTTIId();
+					}
+
+					SerializedEntry modificationEntry;
+					modificationEntry.fieldId = genericField->mUniqueId;
+					modificationEntry.serialized = modification;
+					diffSubObject->entries[genericField->mUniqueId] = modificationEntry;
+				}
+			}
+		}
+
+		return output;
+	}
+
 	void BinaryDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff,
 	void BinaryDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& diff,
 		DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands)
 		DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands)
 	{
 	{
@@ -363,7 +387,7 @@ namespace BansheeEngine
 						UINT32 orgArraySize = genericField->getArraySize(object.get());
 						UINT32 orgArraySize = genericField->getArraySize(object.get());
 						for (auto& arrayElem : diffArray->entries)
 						for (auto& arrayElem : diffArray->entries)
 						{
 						{
-							SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(diffData);
+							SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
 
 
 							DiffCommand command;
 							DiffCommand command;
 							command.field = genericField;
 							command.field = genericField;
@@ -383,7 +407,10 @@ namespace BansheeEngine
 								{
 								{
 									SPtr<IReflectable> childObj = field->getArrayValue(object.get(), arrayElem.first);
 									SPtr<IReflectable> childObj = field->getArrayValue(object.get(), arrayElem.first);
 									if (childObj != nullptr)
 									if (childObj != nullptr)
-										applyDiff(childObj, arrayElemData);
+									{
+										IDiff::applyDiff(childObj->getRTTI(), childObj, arrayElemData, objectMap, diffCommands);
+										command.object = childObj;
+									}
 									else
 									else
 										needsNewObject = true;
 										needsNewObject = true;
 								}
 								}
@@ -400,7 +427,7 @@ namespace BansheeEngine
 											findObj = objectMap.insert(std::make_pair(arrayElemData, newObject)).first;
 											findObj = objectMap.insert(std::make_pair(arrayElemData, newObject)).first;
 										}
 										}
 
 
-										applyDiff(findObj->second, arrayElemData);
+										IDiff::applyDiff(childRtti, findObj->second, arrayElemData, objectMap, diffCommands);
 										command.object = findObj->second;
 										command.object = findObj->second;
 										diffCommands.push_back(command);
 										diffCommands.push_back(command);
 									}
 									}
@@ -434,7 +461,8 @@ namespace BansheeEngine
 
 
 							if (arrayElem.first < orgArraySize)
 							if (arrayElem.first < orgArraySize)
 							{
 							{
-								applyDiff(newArrayElements[arrayElem.first], arrayElemData);
+								SPtr<IReflectable> childObj = newArrayElements[arrayElem.first];
+								IDiff::applyDiff(childObj->getRTTI(), childObj, arrayElemData, objectMap, diffCommands);
 							}
 							}
 							else
 							else
 							{
 							{
@@ -442,7 +470,7 @@ namespace BansheeEngine
 								if (childRtti != nullptr)
 								if (childRtti != nullptr)
 								{
 								{
 									SPtr<IReflectable> newObject = childRtti->newRTTIObject();
 									SPtr<IReflectable> newObject = childRtti->newRTTIObject();
-									applyDiff(newObject, arrayElemData);
+									IDiff::applyDiff(childRtti, newObject, arrayElemData, objectMap, diffCommands);
 
 
 									newArrayElements[arrayElem.first] = newObject;
 									newArrayElements[arrayElem.first] = newObject;
 								}
 								}
@@ -470,7 +498,7 @@ namespace BansheeEngine
 							{
 							{
 								DiffCommand command;
 								DiffCommand command;
 								command.field = genericField;
 								command.field = genericField;
-								command.type = Diff_DataBlock | Diff_ArrayFlag;
+								command.type = Diff_Plain | Diff_ArrayFlag;
 								command.value = fieldData->value;
 								command.value = fieldData->value;
 								command.size = fieldData->size;
 								command.size = fieldData->size;
 								command.arrayIdx = arrayElem.first;
 								command.arrayIdx = arrayElem.first;
@@ -512,7 +540,7 @@ namespace BansheeEngine
 										findObj = objectMap.insert(std::make_pair(fieldObjectData, newObject)).first;
 										findObj = objectMap.insert(std::make_pair(fieldObjectData, newObject)).first;
 									}
 									}
 
 
-									applyDiff(findObj->second, fieldObjectData);
+									IDiff::applyDiff(childRtti, findObj->second, fieldObjectData, objectMap, diffCommands);
 									command.object = findObj->second;
 									command.object = findObj->second;
 								}
 								}
 								else
 								else
@@ -522,7 +550,8 @@ namespace BansheeEngine
 							}
 							}
 							else
 							else
 							{
 							{
-								applyDiff(childObj, fieldObjectData);
+								IDiff::applyDiff(childObj->getRTTI(), childObj, fieldObjectData, objectMap, diffCommands);
+								command.object = childObj;
 							}
 							}
 						}
 						}
 
 
@@ -537,7 +566,7 @@ namespace BansheeEngine
 						IReflectable& childObj = field->getValue(object.get());
 						IReflectable& childObj = field->getValue(object.get());
 						std::shared_ptr<IReflectable> clonedObj = BinaryCloner::clone(&childObj, true);
 						std::shared_ptr<IReflectable> clonedObj = BinaryCloner::clone(&childObj, true);
 
 
-						applyDiff(clonedObj, fieldObjectData);
+						IDiff::applyDiff(clonedObj->getRTTI(), clonedObj, fieldObjectData, objectMap, diffCommands);
 
 
 						DiffCommand command;
 						DiffCommand command;
 						command.field = genericField;
 						command.field = genericField;

+ 21 - 11
BansheeUtility/Source/BsBinarySerializer.cpp

@@ -120,30 +120,34 @@ namespace BansheeEngine
 
 
 	std::shared_ptr<IReflectable> BinarySerializer::decode(UINT8* data, UINT32 dataLength)
 	std::shared_ptr<IReflectable> BinarySerializer::decode(UINT8* data, UINT32 dataLength)
 	{
 	{
-		mObjectMap.clear();
-
 		UINT32 dummy = 0;
 		UINT32 dummy = 0;
 		SPtr<SerializedObject> intermediateObject = _decodeIntermediate(data, dataLength, dummy);
 		SPtr<SerializedObject> intermediateObject = _decodeIntermediate(data, dataLength, dummy);
 		if (intermediateObject == nullptr)
 		if (intermediateObject == nullptr)
 			return nullptr;
 			return nullptr;
 
 
-		SPtr<IReflectable> rootObject;
+		return _decodeIntermediate(intermediateObject);
+	}
+
+	SPtr<IReflectable> BinarySerializer::_decodeIntermediate(const SPtr<SerializedObject>& serializedObject)
+	{
+		mObjectMap.clear();
 
 
-		RTTITypeBase* type = IReflectable::_getRTTIfromTypeId(intermediateObject->getRootTypeId());
+		SPtr<IReflectable> output;
+		RTTITypeBase* type = IReflectable::_getRTTIfromTypeId(serializedObject->getRootTypeId());
 		if (type != nullptr)
 		if (type != nullptr)
 		{
 		{
-			rootObject = type->newRTTIObject();
-			auto iterNewObj = mObjectMap.insert(std::make_pair(intermediateObject, ObjectToDecode(rootObject, intermediateObject)));
-			decodeInternal(rootObject, intermediateObject);
+			output = type->newRTTIObject();
+			auto iterNewObj = mObjectMap.insert(std::make_pair(serializedObject, ObjectToDecode(output, serializedObject)));
+			decodeInternal(output, serializedObject);
 			iterNewObj.first->second.isDecoded = true;
 			iterNewObj.first->second.isDecoded = true;
 		}
 		}
 
 
 		// Go through the remaining objects (should be only ones with weak refs)
 		// Go through the remaining objects (should be only ones with weak refs)
-		for(auto iter = mObjectMap.begin(); iter != mObjectMap.end(); ++iter)
+		for (auto iter = mObjectMap.begin(); iter != mObjectMap.end(); ++iter)
 		{
 		{
 			ObjectToDecode& objToDecode = iter->second;
 			ObjectToDecode& objToDecode = iter->second;
 
 
-			if(objToDecode.isDecoded)
+			if (objToDecode.isDecoded)
 				continue;
 				continue;
 
 
 			decodeInternal(objToDecode.object, objToDecode.serializedObject);
 			decodeInternal(objToDecode.object, objToDecode.serializedObject);
@@ -151,7 +155,7 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mObjectMap.clear();
 		mObjectMap.clear();
-		return rootObject;
+		return output;
 	}
 	}
 
 
 	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, 
 	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, 
@@ -543,6 +547,7 @@ namespace BansheeEngine
 			}
 			}
 
 
 			SPtr<SerializedInstance> serializedEntry;
 			SPtr<SerializedInstance> serializedEntry;
+			bool hasModification = false;
 
 
 			int arrayNumElems = 1;
 			int arrayNumElems = 1;
 			if (isArray)
 			if (isArray)
@@ -564,6 +569,7 @@ namespace BansheeEngine
 					serializedArray->numElements = arrayNumElems;
 					serializedArray->numElements = arrayNumElems;
 
 
 					serializedEntry = serializedArray;
 					serializedEntry = serializedArray;
+					hasModification = true;
 				}
 				}
 
 
 				switch (fieldType)
 				switch (fieldType)
@@ -716,6 +722,7 @@ namespace BansheeEngine
 						}
 						}
 
 
 						serializedEntry = serializedField;
 						serializedEntry = serializedField;
+						hasModification = true;
 					}
 					}
 
 
 					break;
 					break;
@@ -743,6 +750,7 @@ namespace BansheeEngine
 						decodeIntermediateInternal(data, complexTypeSize, dummy, serializedChildObj);
 						decodeIntermediateInternal(data, complexTypeSize, dummy, serializedChildObj);
 
 
 						serializedEntry = serializedChildObj;
 						serializedEntry = serializedChildObj;
+						hasModification = true;
 					}
 					}
 
 
 					data += complexTypeSize;
 					data += complexTypeSize;
@@ -765,6 +773,7 @@ namespace BansheeEngine
 						serializedField->size = typeSize;
 						serializedField->size = typeSize;
 
 
 						serializedEntry = serializedField;
 						serializedEntry = serializedField;
+						hasModification = true;
 					}
 					}
 
 
 					data += typeSize;
 					data += typeSize;
@@ -801,6 +810,7 @@ namespace BansheeEngine
 						serializedField->size = dataBlockSize;
 						serializedField->size = dataBlockSize;
 
 
 						serializedEntry = serializedField;
 						serializedEntry = serializedField;
+						hasModification = true;
 					}
 					}
 
 
 					data += dataBlockSize;
 					data += dataBlockSize;
@@ -815,7 +825,7 @@ namespace BansheeEngine
 				}
 				}
 			}
 			}
 
 
-			if (serializedEntry != nullptr)
+			if (hasModification)
 			{
 			{
 				SerializedEntry entry;
 				SerializedEntry entry;
 				entry.fieldId = curGenericField->mUniqueId;
 				entry.fieldId = curGenericField->mUniqueId;

+ 28 - 0
SBansheeEngine/Include/BsManagedDiff.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsBinaryDiff.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Diff handler that performs RTTI object diff for
+	 *			managed objects. Managed objects require special diff
+	 *			handling since their serialization works differently.
+	 */
+	class BS_SCR_BE_EXPORT ManagedDiff : public IDiff
+	{
+	protected:
+		/**
+		 * @copydoc	IDiff::generateDiff(const SPtr<SerializedObject>&, const SPtr<SerializedObject>&, ObjectMap&)
+		 */
+		SPtr<SerializedObject> generateDiff(const SPtr<SerializedObject>& orgSerzObj,
+			const SPtr<SerializedObject>& newSerzObj, ObjectMap& objectMap) override;
+
+		/**
+		 * @copydoc	IDiff::applyDiff(const SPtr<IReflectable>&, const SPtr<SerializedObject>&, DiffObjectMap&, Vector<DiffCommand>&)
+		 */
+		void applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serzDiff,
+			DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands) override;
+	};
+}

+ 7 - 0
SBansheeEngine/Include/BsManagedSerializableObjectRTTI.h

@@ -5,6 +5,7 @@
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableField.h"
 #include "BsManagedSerializableField.h"
+#include "BsManagedDiff.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -86,6 +87,12 @@ namespace BansheeEngine
 			castObj->mRTTIData = nullptr;
 			castObj->mRTTIData = nullptr;
 		}
 		}
 
 
+		virtual IDiff& getDiffHandler() const override
+		{
+			static ManagedDiff managedDiffHandler;
+			return managedDiffHandler;
+		}
+
 		virtual const String& getRTTIName() override
 		virtual const String& getRTTIName() override
 		{
 		{
 			static String name = "ScriptSerializableObject";
 			static String name = "ScriptSerializableObject";

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -234,6 +234,7 @@
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsManagedComponent.h" />
     <ClInclude Include="Include\BsManagedComponent.h" />
     <ClInclude Include="Include\BsManagedComponentRTTI.h" />
     <ClInclude Include="Include\BsManagedComponentRTTI.h" />
+    <ClInclude Include="Include\BsManagedDiff.h" />
     <ClInclude Include="Include\BsManagedResource.h" />
     <ClInclude Include="Include\BsManagedResource.h" />
     <ClInclude Include="Include\BsManagedResourceManager.h" />
     <ClInclude Include="Include\BsManagedResourceManager.h" />
     <ClInclude Include="Include\BsManagedResourceMetaData.h" />
     <ClInclude Include="Include\BsManagedResourceMetaData.h" />
@@ -329,6 +330,7 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsManagedComponent.cpp" />
     <ClCompile Include="Source\BsManagedComponent.cpp" />
+    <ClCompile Include="Source\BsManagedDiff.cpp" />
     <ClCompile Include="Source\BsManagedResource.cpp" />
     <ClCompile Include="Source\BsManagedResource.cpp" />
     <ClCompile Include="Source\BsManagedResourceManager.cpp" />
     <ClCompile Include="Source\BsManagedResourceManager.cpp" />
     <ClCompile Include="Source\BsManagedResourceMetaData.cpp" />
     <ClCompile Include="Source\BsManagedResourceMetaData.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -315,6 +315,9 @@
     <ClInclude Include="Include\BsManagedSerializableDiffRTTI.h">
     <ClInclude Include="Include\BsManagedSerializableDiffRTTI.h">
       <Filter>Header Files\Serialization\RTTI</Filter>
       <Filter>Header Files\Serialization\RTTI</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsManagedDiff.h">
+      <Filter>Header Files\Serialization</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -566,5 +569,8 @@
     <ClCompile Include="Source\BsManagedSerializableDiff.cpp">
     <ClCompile Include="Source\BsManagedSerializableDiff.cpp">
       <Filter>Source Files\Serialization</Filter>
       <Filter>Source Files\Serialization</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsManagedDiff.cpp">
+      <Filter>Source Files\Serialization</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 58 - 0
SBansheeEngine/Source/BsManagedDiff.cpp

@@ -0,0 +1,58 @@
+#include "BsManagedDiff.h"
+#include "BsManagedSerializableDiff.h"
+#include "BsBinarySerializer.h"
+#include "BsMemorySerializer.h"
+#include "BsManagedSerializableObject.h"
+#include "BsRTTIType.h"
+
+namespace BansheeEngine
+{
+	SPtr<SerializedObject> ManagedDiff::generateDiff(const SPtr<SerializedObject>& orgSerzObj,
+		const SPtr<SerializedObject>& newSerzObj, ObjectMap& objectMap)
+	{
+		BinarySerializer bs;
+
+		SPtr<ManagedSerializableObject> orgObj = std::static_pointer_cast<ManagedSerializableObject>(bs._decodeIntermediate(orgSerzObj));
+		SPtr<ManagedSerializableObject> newObj = std::static_pointer_cast<ManagedSerializableObject>(bs._decodeIntermediate(newSerzObj));
+
+		ManagedSerializableDiffPtr diff = ManagedSerializableDiff::create(orgObj, newObj);
+		if (diff == nullptr)
+			return nullptr;
+
+		MemorySerializer ms;
+
+		UINT32 dataLength = 0;
+		UINT8* diffData = ms.encode(diff.get(), dataLength, &bs_alloc);
+
+		SPtr<SerializedObject> output = bs_shared_ptr<SerializedObject>();
+		output->subObjects.push_back(SerializedSubObject());
+
+		SerializedSubObject& subObject = output->subObjects.back();
+		subObject.typeId = ManagedSerializableObject::getRTTIStatic()->getRTTIId();
+
+		SPtr<SerializedField> field = bs_shared_ptr<SerializedField>();
+		field->value = diffData;
+		field->size = dataLength;
+		field->ownsMemory = true;
+
+		SerializedEntry entry;
+		entry.fieldId = 0;
+		entry.serialized = field;
+
+		subObject.entries[0] = entry;
+
+		return output;
+	}
+
+	void ManagedDiff::applyDiff(const SPtr<IReflectable>& object, const SPtr<SerializedObject>& serzDiff,
+		DiffObjectMap& objectMap, Vector<DiffCommand>& diffCommands)
+	{
+		SPtr<SerializedField> field = std::static_pointer_cast<SerializedField>(serzDiff->subObjects[0].entries[0].serialized);
+
+		MemorySerializer ms;
+		ManagedSerializableDiffPtr diff = std::static_pointer_cast<ManagedSerializableDiff>(ms.decode(field->value, field->size));
+
+		SPtr<ManagedSerializableObject> managedObj = std::static_pointer_cast<ManagedSerializableObject>(object);
+		diff->apply(managedObj);
+	}
+}

+ 4 - 1
TODO.txt

@@ -29,9 +29,12 @@ Prefab diff
 
 
 IMMEDIATE:
 IMMEDIATE:
  - Integrated native diff and managed diff
  - Integrated native diff and managed diff
- - Create a native only unit test for binary diff
  - Test and debug native diff
  - Test and debug native diff
 
 
+Later: Native+Managed diff is not tested (only the link needs to be tested, I have a separate managed and native tests)
+
+Make RTTIType return an interface for creating and applying diffs, rather than dealing with overriding individual methods.
+
 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)