Pārlūkot izejas kodu

Added serialization/reflection methods

Marko Pintera 13 gadi atpakaļ
vecāks
revīzija
4dc4b7d4e6

+ 1 - 0
CamelotRenderer/CamelotRenderer.vcxproj

@@ -157,6 +157,7 @@
     <ClCompile Include="Source\CmRenderTarget.cpp" />
     <ClCompile Include="Source\CmRenderTarget.cpp" />
     <ClCompile Include="Source\CmRenderTexture.cpp" />
     <ClCompile Include="Source\CmRenderTexture.cpp" />
     <ClCompile Include="Source\CmRenderWindow.cpp" />
     <ClCompile Include="Source\CmRenderWindow.cpp" />
+    <ClCompile Include="Source\CmResource.cpp" />
     <ClCompile Include="Source\CmResources.cpp" />
     <ClCompile Include="Source\CmResources.cpp" />
     <ClCompile Include="Source\CmTexture.cpp" />
     <ClCompile Include="Source\CmTexture.cpp" />
     <ClCompile Include="Source\CmTextureManager.cpp" />
     <ClCompile Include="Source\CmTextureManager.cpp" />

+ 3 - 0
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -256,5 +256,8 @@
     <ClCompile Include="Source\CmResources.cpp">
     <ClCompile Include="Source\CmResources.cpp">
       <Filter>Source Files\Resources</Filter>
       <Filter>Source Files\Resources</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmResource.cpp">
+      <Filter>Source Files\Resources</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 11 - 2
CamelotRenderer/Include/CmResource.h

@@ -11,12 +11,21 @@ namespace CamelotEngine
 	class CM_EXPORT Resource
 	class CM_EXPORT Resource
 	{
 	{
 	public:
 	public:
+		virtual ~Resource() {};
+
+	protected:
+		friend class Resources;
+
 		Resource(/*const UUID& sourceUUID*/) // TODO - Temporarily don't initialize UUID, because I want texture to inherit from resource and UUIDs arent set up yet
 		Resource(/*const UUID& sourceUUID*/) // TODO - Temporarily don't initialize UUID, because I want texture to inherit from resource and UUIDs arent set up yet
 			:mSize(0) /*mSourceUUID(sourceUUID),*/
 			:mSize(0) /*mSourceUUID(sourceUUID),*/
 		{}
 		{}
-		virtual ~Resource() {};
 
 
-	protected:
+		//virtual void load() = 0;
+		//virtual void unload() = 0;
+
+		//virtual void calculateSize() = 0;
+		//virtual void reload();
+
 		UUID mSourceUUID; 
 		UUID mSourceUUID; 
 		UINT32 mSize;
 		UINT32 mSize;
 	};
 	};

+ 48 - 0
CamelotRenderer/Source/CmResource.cpp

@@ -0,0 +1,48 @@
+#include "CmResource.h"
+
+namespace CamelotEngine
+{
+	//void Resource::unload() 
+	//{ 
+	//	// Early-out without lock (mitigate perf cost of ensuring unloaded)
+	//	LoadingState old = mLoadingState.get();
+	//	if (old!=LOADSTATE_LOADED && old!=LOADSTATE_PREPARED) return;
+
+
+	//	if (!mLoadingState.cas(old,LOADSTATE_UNLOADING)) return;
+
+	//	// Scope lock for actual unload
+	//	{
+	//		OGRE_LOCK_AUTO_MUTEX
+	//			if (old==LOADSTATE_PREPARED) {
+	//				unprepareImpl();
+	//			} else {
+	//				preUnloadImpl();
+	//				unloadImpl();
+	//				postUnloadImpl();
+	//			}
+	//	}
+
+	//	mLoadingState.set(LOADSTATE_UNLOADED);
+
+	//	// Notify manager
+	//	// Note if we have gone from PREPARED to UNLOADED, then we haven't actually
+	//	// unloaded, i.e. there is no memory freed on the GPU.
+	//	if(old==LOADSTATE_LOADED && mCreator)
+	//		mCreator->_notifyResourceUnloaded(this);
+
+	//	_fireUnloadingComplete();
+
+
+	//}
+	////-----------------------------------------------------------------------
+	//void Resource::reload() 
+	//{ 
+	//	OGRE_LOCK_AUTO_MUTEX
+	//		if (mLoadingState.get() == LOADSTATE_LOADED)
+	//		{
+	//			unload();
+	//			load();
+	//		}
+	//}
+}

+ 17 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -77,17 +77,28 @@
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemGroup>
   <ItemGroup>
+    <ClInclude Include="Include\CmBinarySerializer.h" />
     <ClInclude Include="Include\CmBitwise.h" />
     <ClInclude Include="Include\CmBitwise.h" />
     <ClInclude Include="Include\CmBox.h" />
     <ClInclude Include="Include\CmBox.h" />
     <ClInclude Include="Include\CmColor.h" />
     <ClInclude Include="Include\CmColor.h" />
     <ClInclude Include="Include\CmDebug.h" />
     <ClInclude Include="Include\CmDebug.h" />
     <ClInclude Include="Include\CmDynLibManager.h" />
     <ClInclude Include="Include\CmDynLibManager.h" />
     <ClInclude Include="Include\CmException.h" />
     <ClInclude Include="Include\CmException.h" />
+    <ClInclude Include="Include\CmFileSerializer.h" />
+    <ClInclude Include="Include\CmIReflectable.h" />
     <ClInclude Include="Include\CmLog.h" />
     <ClInclude Include="Include\CmLog.h" />
+    <ClInclude Include="Include\CmManagedDataBlock.h" />
     <ClInclude Include="Include\CmMathAsm.h" />
     <ClInclude Include="Include\CmMathAsm.h" />
     <ClInclude Include="Include\CmModule.h" />
     <ClInclude Include="Include\CmModule.h" />
     <ClInclude Include="Include\CmPath.h" />
     <ClInclude Include="Include\CmPath.h" />
     <ClInclude Include="Include\CmPixelUtil.h" />
     <ClInclude Include="Include\CmPixelUtil.h" />
+    <ClInclude Include="Include\CmRTTIField.h" />
+    <ClInclude Include="Include\CmRTTIManagedDataBlockField.h" />
+    <ClInclude Include="Include\CmRTTIPlainField.h" />
+    <ClInclude Include="Include\CmRTTIReflectableField.h" />
+    <ClInclude Include="Include\CmRTTIReflectablePtrField.h" />
+    <ClInclude Include="Include\CmRTTIType.h" />
+    <ClInclude Include="Include\CmSerializableType.h" />
     <ClInclude Include="Include\CmString.h" />
     <ClInclude Include="Include\CmString.h" />
     <ClInclude Include="Include\CmThreadDefines.h" />
     <ClInclude Include="Include\CmThreadDefines.h" />
     <ClInclude Include="Include\CmTypes.h" />
     <ClInclude Include="Include\CmTypes.h" />
@@ -110,9 +121,15 @@
     <ClInclude Include="Include\CmDynLib.h" />
     <ClInclude Include="Include\CmDynLib.h" />
     <ClInclude Include="Include\CmDataStream.h" />
     <ClInclude Include="Include\CmDataStream.h" />
     <ClInclude Include="Include\CmTextureData.h" />
     <ClInclude Include="Include\CmTextureData.h" />
+    <ClCompile Include="Source\CmBinarySerializer.cpp" />
+    <ClCompile Include="Source\CmFileSerializer.cpp" />
+    <ClCompile Include="Source\CmIReflectable.cpp" />
+    <ClCompile Include="Source\CmRTTIField.cpp" />
+    <ClCompile Include="Source\CmRTTIType.cpp" />
     <ClCompile Include="Source\CmTextureData.cpp">
     <ClCompile Include="Source\CmTextureData.cpp">
       <FileType>CppHeader</FileType>
       <FileType>CppHeader</FileType>
     </ClCompile>
     </ClCompile>
+    <ClInclude Include="Include\CmISerializable.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmAxisAlignedBox.cpp" />
     <ClCompile Include="Include\CmAxisAlignedBox.cpp" />

+ 63 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -25,6 +25,18 @@
     <Filter Include="Header Files\Threading">
     <Filter Include="Header Files\Threading">
       <UniqueIdentifier>{b65008fc-0109-4b6d-b82b-7c30abdbeacf}</UniqueIdentifier>
       <UniqueIdentifier>{b65008fc-0109-4b6d-b82b-7c30abdbeacf}</UniqueIdentifier>
     </Filter>
     </Filter>
+    <Filter Include="Header Files\RTTI">
+      <UniqueIdentifier>{ceeeab21-95fc-4e22-922c-7c91ecaba0df}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\RTTI">
+      <UniqueIdentifier>{11d535e6-1203-47ca-9062-8548e4d71027}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\Serialization">
+      <UniqueIdentifier>{4af02e17-2cf7-4e71-a749-58e0ba71625e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Serialization">
+      <UniqueIdentifier>{155906c8-9f79-4f86-835a-eb8f5c2f66bf}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\CmTypes.h">
     <ClInclude Include="Include\CmTypes.h">
@@ -126,6 +138,42 @@
     <ClInclude Include="Include\CmTextureData.h">
     <ClInclude Include="Include\CmTextureData.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmIReflectable.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRTTIField.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRTTIManagedDataBlockField.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRTTIPlainField.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRTTIReflectableField.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRTTIReflectablePtrField.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRTTIType.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmBinarySerializer.h">
+      <Filter>Header Files\Serialization</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmFileSerializer.h">
+      <Filter>Header Files\Serialization</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmManagedDataBlock.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmISerializable.h">
+      <Filter>Header Files\Serialization</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmSerializableType.h">
+      <Filter>Header Files\Serialization</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">
@@ -185,5 +233,20 @@
     <ClCompile Include="Source\CmTextureData.cpp">
     <ClCompile Include="Source\CmTextureData.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmRTTIField.cpp">
+      <Filter>Source Files\RTTI</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\CmRTTIType.cpp">
+      <Filter>Source Files\RTTI</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\CmBinarySerializer.cpp">
+      <Filter>Source Files\Serialization</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\CmFileSerializer.cpp">
+      <Filter>Source Files\Serialization</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\CmIReflectable.cpp">
+      <Filter>Source Files\RTTI</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 175 - 0
CamelotUtility/Include/CmBinarySerializer.h

@@ -0,0 +1,175 @@
+#pragma once
+
+#include <unordered_map>
+#include <boost/function.hpp>
+
+#include "CmPrerequisitesUtil.h"
+#include "CmRTTIField.h"
+
+namespace CamelotEngine
+{
+	class IReflectable;
+	struct RTTIReflectableFieldBase;
+	struct RTTIReflectablePtrFieldBase;
+
+	// TODO - Low priority. I will probably want to extract a generalized Serializer class so we can re-use the code
+	// in text or other serializers
+	// TODO - Low priority. Encode does a chunk-based encode so that we don't need to know the buffer size in advance,
+	// and don't have to use a lot of memory for the buffer. Consider doing something similar for decode.
+	// TODO - Low priority. Add a simple encode method that doesn't require a callback, instead it calls the callback internally
+	// and creates the buffer internally.
+	/**
+	 * @brief	Encodes all the fields of the provided object into a binary format. Fields are
+	 * 			encoded using their unique IDs. Encoded data will remain compatible for decoding even
+	 * 			if you modify the encoded class, as long as you assign new unique field IDs to
+	 * 			added/modified fields.
+	 * 			
+	 *			Like for any serializable class, fields are defined in RTTIType that each
+	 *			IReflectable class must be able to return.
+	 *
+	 * 			Any data the object or its children are pointing to will also be serialized (unless the pointer isn't
+	 * 			registered in RTTIType). Upon decoding the pointer addresses will be set
+	 * 			to proper values.
+	 */
+	class CM_UTILITY_EXPORT BinarySerializer
+	{
+	public:
+		BinarySerializer();
+
+		/**
+		 * @brief	Encodes all serializable fields provided by "object" into a binary format. Data is written in chunks.
+		 * 			Whenever a chunk is filled a callback is triggered that gives the user opportunity to expand or 
+		 * 			empty the buffer (for example write the chunk to disk)
+		 *
+		 * @param [in]	object				Object to encode into binary format.
+		 * @param [out]	buffer				Preallocated buffer where the data will be stored.
+		 * @param	bufferLength			Length of the buffer, in bytes.
+		 * @param [out]	bytesWritten		Length of the data that was actually written to the buffer,
+		 * 									in bytes.
+		 * @param	flushBufferCallback 	This callback will get called whenever the buffer gets full (Be careful to check the provided
+		 * 									"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.
+		 * 									If the returned buffer address is NULL, encoding is aborted.
+		 */
+		void encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, int* bytesWritten, 
+			boost::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+
+		/**
+		 * @brief	Decodes all of the fields of the provided object from a binary format.
+		 *
+		 * @param [in]	object	Object whos fields to decode.
+		 * @param [in]	data  	Binary data to decode.
+		 * @param	dataLength	Length of the data.
+		 */
+		void decode(IReflectable* object, UINT8* data, UINT32 dataLength);
+
+	private:
+		struct ObjectToEncode
+		{
+			ObjectToEncode(UINT32 _objectId, IReflectable* _object)
+				:objectId(_objectId), object(_object)
+			{ }
+
+			UINT32 objectId;
+			IReflectable* object;
+		};
+
+		/**
+		 * @brief	Pointer fields get resolved after everything is loaded. Store their
+		 * 			temporary data here until then.
+		 */
+		struct PtrToResolve
+		{
+			PtrToResolve()
+				:field(nullptr), object(nullptr), id(0)
+			{ }
+
+			PtrToResolve(RTTIReflectablePtrFieldBase* _field, IReflectable* _object, UINT32 _id)
+				:field(_field), object(_object), id(_id), arrIdx(0)
+			{ }
+
+			PtrToResolve(RTTIReflectablePtrFieldBase* _field, IReflectable* _object, UINT32 _id, UINT32 _arrIdx)
+				:field(_field), object(_object), id(_id), arrIdx(_arrIdx)
+			{ }
+
+			RTTIReflectablePtrFieldBase* field;
+			UINT32 arrIdx;
+			IReflectable* object;
+			UINT32 id;
+		};
+
+		std::unordered_map<UINT32, UINT32> mObjectAddrToId;
+		UINT32 mLastUsedObjectId;
+		std::vector<ObjectToEncode> mObjectsToEncode;
+		int mTotalBytesWritten;
+
+		std::vector<PtrToResolve> mPtrsToResolve;
+		std::unordered_map<UINT32, IReflectable*> mDecodedObjects;
+
+
+		UINT32 getObjectSize(IReflectable* object);
+
+		/**
+		 * @brief	Encodes a single IReflectable object. 
+		 */
+		UINT8* encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, int* bytesWritten, 
+			boost::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+
+		/**
+		 * @brief	Decodes a single IReflectable object.
+		 */
+		bool decodeInternal(IReflectable* object, UINT8* data, UINT32 dataLength, UINT32& bytesRead);
+
+		/**
+		* @brief	Encodes data required for representing a serialized field, into 4 bytes.
+		*/
+		UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type);
+
+		/**
+		* @brief	Decode meta field that was encoded using encodeFieldMetaData.
+		*/
+		void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, SerializableFieldType& type);
+
+		/**
+		* @brief	Encodes data required for representing an object identifier, into 4 bytes.
+		*
+		* @note		Id can be a maximum of 31 bits, as one bit is reserved.
+		*/
+		UINT32 encodeObjectMetaData(UINT32 objId);
+
+		/**
+		* @brief	Decode meta field that was encoded using encodeObjectMetaData.
+		* 			
+		* @note		Id can be a maximum of 31 bits, as one bit is reserved.
+		*/
+		void decodeObjectMetaData(UINT32 encodedData, UINT32& objId);
+
+		/**
+		 * @brief	Returns true if the provided encoded meta data represents object meta data.
+		 */
+		bool isObjectMetaData(UINT32 encodedData);
+
+		/**
+		 * @brief	Helper method for encoding a complex object and copying its data to a buffer.
+		 */
+		UINT8* complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, int* bytesWritten, 
+			boost::function<UINT8*(UINT8* buffer, int bytesWritten, UINT32& newBufferSize)> flushBufferCallback);
+
+		/**
+		 * @brief	Helper method for decoding a complex object from the provided data buffer.
+		 */
+		IReflectable* complexTypeFromBuffer(RTTIReflectableFieldBase* field, UINT8* data, int* complexTypeSize);
+
+		/**
+		 * @brief	Finds an existing, or creates a unique unique identifier for the specified object. 
+		 */
+		UINT32 findOrCreatePersistentId(IReflectable* object);
+
+		/**
+		 * @brief	Finds or creates an id for the provided object and returns it.
+		 * 			And it adds the object to a list of objects that need to be encoded,
+		 * 			if it's not already there.
+		 */
+		UINT32 registerObjectPtr(IReflectable* object);
+	};
+}

+ 32 - 0
CamelotUtility/Include/CmFileSerializer.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+
+namespace CamelotEngine
+{
+	// TODO - Low priority. Eventually I'll want to generalize BinarySerializer to Serializer class, then I can make this class accept
+	// a generic Serializer interface so it may write both binary, plain-text or some other form of data.
+	class CM_UTILITY_EXPORT FileSerializer
+	{
+	public:
+		FileSerializer();
+		~FileSerializer();
+
+		void encode(IReflectable* object, std::string fileLocation);
+		void decode(IReflectable* object, std::string fileLocation);
+
+	private:
+		std::ofstream mOutputStream;
+		UINT8* mWriteBuffer;
+
+		std::ifstream mInputStream;
+
+		UINT8* flushBuffer(UINT8* bufferStart, int bytesWritten, UINT32& newBufferSize);
+
+		/************************************************************************/
+		/* 								CONSTANTS	                     		*/
+		/************************************************************************/
+	private:
+		static const UINT32 WRITE_BUFFER_SIZE = 2048;
+	};
+}

+ 6 - 0
CamelotUtility/Include/CmFwdDeclUtil.h

@@ -25,6 +25,12 @@ namespace CamelotEngine {
 	class MemoryDataStream;
 	class MemoryDataStream;
 	class FileDataStream;
 	class FileDataStream;
 	class TextureData;
 	class TextureData;
+	// Reflection
+	class IReflectable;
+	class RTTITypeBase;
+	// Serialization
+	class ISerializable;
+	class SerializableType;
 
 
 	typedef std::shared_ptr<DataStream> DataStreamPtr;
 	typedef std::shared_ptr<DataStream> DataStreamPtr;
 	typedef std::shared_ptr<MemoryDataStream> MemoryDataStreamPtr;
 	typedef std::shared_ptr<MemoryDataStream> MemoryDataStreamPtr;

+ 29 - 0
CamelotUtility/Include/CmIReflectable.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+
+namespace CamelotEngine
+{
+	/**
+	 * @brief	Interface implemented by classes that provide run time type information.
+	 * 			It just provides a method that returns an interface to the class metadata.
+	 */
+	class CM_UTILITY_EXPORT IReflectable
+	{
+	public:
+		/**
+		 * @brief	Returns an interface you can use to access class Run Time Type Information.
+		 *
+		 * @note	It is suggested you derive your own version of RTTIType, in which you
+		 * 			may encapsulate all reflection specific operations. Although this is optional.
+		 */
+		virtual RTTITypeBase* getRTTI() const = 0;
+
+		/**
+		 * @brief	Creates an empty instance of a reflectable object. This is a bit of a hack, 
+		 * 			but EVERY class deriving from IReflectable needs to implement this method. 
+		 * 			You will get a compiler error otherwise.
+		 */
+		static IReflectable* newObject();
+	};
+}

+ 13 - 0
CamelotUtility/Include/CmISerializable.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "CmIReflectable.h"
+
+namespace CamelotEngine
+{
+	class CM_UTILITY_EXPORT ISerializable : IReflectable
+	{
+	public:
+		virtual SerializableType* getSerializable() = 0;
+	};
+}

+ 55 - 0
CamelotUtility/Include/CmManagedDataBlock.h

@@ -0,0 +1,55 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+
+namespace CamelotEngine
+{
+	/**
+	 * @brief	Data block holding an array of bytes, usually used in serialization.
+	 */
+	class ManagedDataBlock
+	{
+	public:
+		/**
+		 * @brief	Constructor
+		 *
+		 * @param [in]	data		Array of bytes to store. Direct pointer to the provided
+		 * 							array will be stored, no copying will be done. Data won't be modified
+		 * 							unless "managed" is true.
+		 * @param	size			Size of the array, in bytes.
+		 * @param	managed			If true then the provided data array will be deleted once
+		 * 							it is no longer being used. When serializing it is always faster to provide direct
+		 * 							pointer to the data, but sometimes you need to provide a copy of the data
+		 * 							instead (e.g. maybe it's needed in a different format). 
+		 * 							In that case set managed to true so it can be properly freed.
+		 */
+		ManagedDataBlock(UINT8* data, UINT32 size, bool managed)
+			:mData(data), mSize(size), mManaged(managed), mIsDataOwner(true)
+		{ }
+
+		ManagedDataBlock(const ManagedDataBlock& source)
+		{
+			mData = source.mData;
+			mSize = source.mSize;
+			mManaged = source.mManaged;
+
+			mIsDataOwner = true;
+			source.mIsDataOwner = false;
+		}
+
+		~ManagedDataBlock()
+		{
+			if(mManaged && mIsDataOwner)
+				delete[] mData;
+		}
+
+		UINT8* getData() { return mData; }
+		UINT32 getSize() { return mSize; }
+
+	private:
+		UINT8* mData;
+		UINT32 mSize;
+		bool mManaged;
+		mutable bool mIsDataOwner;
+	};
+}

+ 133 - 0
CamelotUtility/Include/CmRTTIField.h

@@ -0,0 +1,133 @@
+#pragma once
+
+#include <string>
+
+#include <boost/function.hpp>
+#include <boost/any.hpp>
+
+#include "CmPrerequisitesUtil.h"
+#include "CmIReflectable.h"
+#include "CmManagedDataBlock.h"
+
+namespace CamelotEngine
+{
+	class RTTITypeBase;
+	struct RTTIField;
+
+	template<class T>
+	struct SerializableSimpleType { enum { id = T::TYPE_ID }; enum { isNativeType = 0 }; };
+	
+#define SERIALIZABLE_SIMPLE_TYPE(type, type_id) \
+	template<> struct SerializableSimpleType<##type##> { enum { id=##type_id }; enum { isNativeType = 1 }; }; 
+
+	SERIALIZABLE_SIMPLE_TYPE(UINT8, 0);
+	SERIALIZABLE_SIMPLE_TYPE(UINT16, 1);
+	SERIALIZABLE_SIMPLE_TYPE(UINT32, 2);
+	SERIALIZABLE_SIMPLE_TYPE(UINT64, 3);
+	SERIALIZABLE_SIMPLE_TYPE(INT8, 4);
+	SERIALIZABLE_SIMPLE_TYPE(INT16, 5);
+	SERIALIZABLE_SIMPLE_TYPE(INT32, 6);
+	SERIALIZABLE_SIMPLE_TYPE(INT64, 7);
+	SERIALIZABLE_SIMPLE_TYPE(float, 8);
+	SERIALIZABLE_SIMPLE_TYPE(double, 9);
+	SERIALIZABLE_SIMPLE_TYPE(bool, 10);
+
+#undef SERIALIZABLE_SIMPLE_TYPE
+
+	/**
+	 * @brief	Types of fields we can serialize:
+	 * 			
+	 * - Simple - Native data types and POD (Plain old data) structures. POD structures  
+	 *			  need to define a static TYPE_ID field with a unique ID. (IDs 0-31 are reserved for native types)
+	 *			  
+	 * - DataBlock - Array of bytes of a certain size. When returning a data block you may specify if its managed or unmanaged.  
+	 *				 Managed data blocks have their buffers deleted after they go out of scope. This is useful if you need to return some
+	 *				 temporary data. On the other hand if the data in the block belongs to your class, and isn't temporary, keep the data unmanaged.
+	 *				 
+	 * - Complex - Field that is of IReflectable type. Cannot be a pointer to IReflectable and must be actual value type. 
+	 * 
+	 * - ComplexPtr - A pointer to IReflectable.
+	 */
+	enum SerializableFieldType
+	{
+		SerializableFT_Plain,
+		SerializableFT_DataBlock,
+		SerializableFT_Reflectable,
+		SerializableFT_ReflectablePtr
+	};
+
+	/**
+	 * @brief	Structure that keeps meta-data concerning a single class field. 
+	 */
+	struct CM_UTILITY_EXPORT RTTIField
+	{
+		boost::any valueGetter;
+		boost::any valueSetter;
+
+		boost::any arraySizeGetter;
+		boost::any arraySizeSetter;
+
+		std::string mName;
+		UINT16 mUniqueId;
+		bool mIsVectorType;
+		SerializableFieldType mType;
+
+		bool isSimpleType() { return mType == SerializableFT_Plain; }
+		bool isDataBlockType() { return mType == SerializableFT_DataBlock; }
+		bool isComplexType() { return mType == SerializableFT_Reflectable; }
+		bool isComplexPtrType() { return mType == SerializableFT_ReflectablePtr; }
+		
+		virtual UINT32 getArraySize(void* object) = 0;
+		virtual void setArraySize(void* object, UINT32 size) = 0;
+
+		virtual UINT32 getTypeSize() = 0;
+
+		/**
+		 * @brief	Throws an exception if this field doesn't contain a simple value.
+		 *
+		 * @param	array	If true then the field must support simple array types.
+		 */
+		void checkIsSimple(bool array);
+
+		/**
+		 * @brief	Throws an exception if this field doesn't contain a complex value.
+		 *
+		 * @param	array	If true then the field must support complex array types.
+		 */
+		void checkIsComplex(bool array);
+
+		/**
+		 * @brief	Throws an exception if this field doesn't contain a complex pointer value.
+		 *
+		 * @param	array	If true then the field must support complex array types.
+		 */
+		void checkIsComplexPtr(bool array);
+
+		/**
+		 * @brief	Throws an exception depending if the field is or isn't an array.
+		 *
+		 * @param	array	If true, then exception will be thrown if field is not an array.
+		 * 					If false, then it will be thrown if field is an array.
+		 */
+		void checkIsArray(bool array);
+
+		/**
+		 * @brief	Throws an exception if this field doesn't contain a data block value.
+		 */
+		void checkIsDataBlock();
+
+	protected:
+		void initAll(boost::any valueGetter, boost::any valueSetter, boost::any arraySizeGetter, boost::any arraySizeSetter,
+			std::string mName, UINT16 mUniqueId, bool mIsVectorType, SerializableFieldType type)
+		{
+			this->valueGetter = valueGetter;
+			this->valueSetter = valueSetter;
+			this->arraySizeGetter = arraySizeGetter;
+			this->arraySizeSetter = arraySizeSetter;
+			this->mName = mName;
+			this->mUniqueId = mUniqueId;
+			this->mIsVectorType = mIsVectorType;
+			this->mType = type;
+		}
+	};
+}

+ 65 - 0
CamelotUtility/Include/CmRTTIManagedDataBlockField.h

@@ -0,0 +1,65 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "CmRTTIField.h"
+#include "CmManagedDataBlock.h"
+
+namespace CamelotEngine
+{
+	struct RTTIManagedDataBlockFieldBase : public RTTIField
+	{
+		virtual ManagedDataBlock getValue(void* object) = 0;
+		virtual void setValue(void* object, ManagedDataBlock value) = 0;
+	};
+
+	template <class DataType, class ObjectType>
+	struct RTTIManagedDataBlockField : public RTTIManagedDataBlockFieldBase
+	{
+		/**
+		 * @brief	Initializes a field that returns a block of bytes. Can be used for serializing pretty much anything.
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: SerializableDataBlock(ObjectType*)
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, SerializableDataBlock)
+		 */
+		void initSingle(const std::string& name, UINT16 uniqueId, boost::any getter, boost::any setter)
+		{
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_DataBlock);
+		}
+
+		virtual UINT32 getTypeSize()
+		{
+			return 0; // Data block types don't store size the conventional way
+		}
+
+		virtual UINT32 getArraySize(void* object)
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Data block types don't support arrays.");
+		}
+
+		virtual void setArraySize(void* object, UINT32 size)
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Data block types don't support arrays.");
+		}
+
+		virtual ManagedDataBlock getValue(void* object)
+		{
+			ObjectType* castObj = static_cast<ObjectType*>(object);
+			boost::function<ManagedDataBlock(ObjectType*)> f = boost::any_cast<boost::function<ManagedDataBlock(ObjectType*)>>(valueGetter);
+			return f(castObj);
+		}
+
+		virtual void setValue(void* object, ManagedDataBlock value)
+		{
+			ObjectType* castObj = static_cast<ObjectType*>(object);
+			boost::function<void(ObjectType*, ManagedDataBlock)> f = boost::any_cast<boost::function<void(ObjectType*, ManagedDataBlock)>>(valueSetter);
+			f(castObj, value);
+		}
+	};
+}

+ 255 - 0
CamelotUtility/Include/CmRTTIPlainField.h

@@ -0,0 +1,255 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "CmRTTIField.h"
+
+namespace CamelotEngine
+{
+	struct RTTIPlainFieldBase : public RTTIField
+	{
+		/**
+		 * @brief	Throws an exception if the current field type and provided template types don't match.
+		 */
+		template<class DataType>
+		void checkType()
+		{
+			// TODO: Low priority. Because I wanted to get rid of SerializableType I have no way of checking the actual
+			// type of the field and the type provided to get/set methods matches
+
+			/*if(mType.id != SerializableType<DataType>().id)
+			{
+				CM_EXCEPT(InternalErrorException,
+					"Invalid field type.",
+					"SerializableSimpleTypeFieldBase::checkType()");
+			}*/
+		}
+
+		virtual UINT32 getTypeId()
+		{
+			return 0;
+		}
+
+		template<class ObjectType, class DataType>
+		void getValue(ObjectType* object, DataType& value)
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			boost::function<DataType(ObjectType*)> f = boost::any_cast<boost::function<DataType(ObjectType*)>>(valueGetter);
+			value = f(object);
+		}
+
+		template<class ObjectType, class DataType>
+		void getArrayValue(ObjectType* object, UINT32 index, DataType& value)
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			boost::function<DataType(ObjectType*, UINT32)> f = boost::any_cast<boost::function<DataType(ObjectType*, UINT32)>>(valueGetter);
+			value = f(object, index);
+		}
+
+		template<class ObjectType, class DataType>
+		void setValue(ObjectType* object, DataType& value)
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			if(valueSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException,
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			boost::function<void(ObjectType*, DataType)> f = boost::any_cast<boost::function<void(ObjectType*, DataType)>>(valueSetter);
+			f(object, value);
+		}
+
+		template<class ObjectType, class DataType>
+		void setArrayValue(ObjectType* object, UINT32 index, DataType& value)
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			if(valueSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			boost::function<void(ObjectType*, UINT32, DataType)> f = boost::any_cast<boost::function<void(ObjectType*, UINT32, DataType)>>(valueSetter);
+			f(object, index, value);
+		}
+
+		/**
+		 * @brief	Retrieves the value from the provided field of the provided object, and copies
+		 * 			it into the buffer. WARNING - It does not check if buffer is large enough.
+		 * 			
+		 * @note	Size of the data copied to buffer is mType.size
+		 */
+		virtual void toBuffer(void* object, void* buffer) = 0;
+
+		/**
+		 * @brief	Retrieves the value at the specified array index on the provided field of the
+		 * 			provided object, and copies it into the buffer. WARNING - It does not check if buffer
+		 * 			is large enough.
+		 * 			
+		 * @note	Size of the data copied to buffer is mType.size
+		 */
+		virtual void arrayElemToBuffer(void* object, int index, void* buffer) = 0;
+
+		/**
+		 * @brief	Sets the value on the provided field of the provided object. Value is copied from the buffer. 
+		 * 			WARNING - It does not check the value in the buffer in any way. You must make sure buffer points
+		 * 			to the proper location and contains the proper type.
+		 * 			
+		 * @note	Size of the data copied from buffer is mType.size
+		 */
+		virtual void fromBuffer(void* object, void* buffer) = 0;
+
+		/**
+		 * @brief	Sets the value at the specified array index on the provided field of the provided
+		 * 			object. Value is copied from the buffer. WARNING - It does not check the value in the
+		 * 			buffer in any way. You must make sure buffer points to the proper location and
+		 * 			contains the proper type.
+		 * 			
+		 * 	@note	Size of the data copied from buffer is mType.size.
+		 */
+		virtual void arrayElemFromBuffer(void* object, int index, void* buffer) = 0;
+	};
+
+	template <class DataType, class ObjectType>
+	struct RTTIPlainField : public RTTIPlainFieldBase
+	{
+		/**
+		 * @brief	Initializes a field with one of the built-in types. You may provide your own type ID,
+		 * 			just make sure it doesn't conflict with any standard types.
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: DataType(ObjectType*).
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, DataType)
+		 * 						
+		 * @note	IMPORTANT - Type returned/set by getter/setter must provide "public static int TYPE_ID" field, which can be used for identifying the
+		 * 			type. You can set the ID to anything you wish, as it is not used internally. However its possible that other engine modules do require
+		 * 			you to set this field to a unique value. Native types do not need (or can) set this field. 
+		 */
+		void initSingle(const std::string& name, UINT16 uniqueId, boost::any getter, boost::any setter)
+		{
+			int typeId = SerializableSimpleType<DataType>::id; // Just making sure provided type has a type ID
+
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_Plain);
+		}
+
+		/**
+		 * @brief	Initializes a VECTOR field with one of the built-in types. You may provide your own
+		 * 			type ID, just make sure it doesn't conflict with any standard types.
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: DataType(ObjectType*, UINT32)
+		 * @param	getSize 	Getter method that returns the size of an array. Cannot be null. Must be a specific signature: UINT32(ObjectType*)
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, UINT32, DataType)
+		 * @param	setSize 	Setter method that allows you to resize an array. Can be null. Must be a specific signature: void(ObjectType*, UINT32)
+		 * 						
+		 * @note	IMPORTANT - Type returned/set by getter/setter must provide "public static UINT32 TYPE_ID" field, which can be used for identifying the
+		 * 			type. You can set the ID to anything you wish, as it is not used internally. However its possible that other engine modules do require
+		 * 			you to set this field to a unique value. Native types do not need (or can) set this field.
+		 */
+		void initArray(const std::string& name, UINT16 uniqueId, boost::any getter, 
+			boost::any getSize, boost::any setter, boost::any setSize)
+		{
+			int typeId = SerializableSimpleType<DataType>::id; // Just making sure provided type has a type ID
+
+			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_Plain);
+		}
+
+		virtual UINT32 getTypeSize()
+		{
+			return sizeof(DataType);
+		}
+
+		virtual UINT32 getTypeId()
+		{
+			return SerializableSimpleType<DataType>::id;
+		}
+
+		virtual UINT32 getArraySize(void* object)
+		{
+			checkIsArray(true);
+
+			boost::function<UINT32(ObjectType*)> f = boost::any_cast<boost::function<UINT32(ObjectType*)>>(arraySizeGetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			return f(castObject);
+		}
+
+		virtual void setArraySize(void* object, UINT32 size)
+		{
+			checkIsArray(true);
+
+			if(arraySizeSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no array size setter.");
+			}
+
+			boost::function<void(ObjectType*, UINT32)> f = boost::any_cast<boost::function<void(ObjectType*, UINT32)>>(arraySizeSetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			f(castObject, size);
+		}
+
+		virtual void toBuffer(void* object, void* buffer)
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			DataType value;
+			getValue(castObject, value);
+			memcpy(buffer, &value, getTypeSize());
+		}
+
+		virtual void arrayElemToBuffer(void* object, int index, void* buffer)
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			DataType value;
+			getArrayValue(castObject, index, value);
+			memcpy(buffer, &value, getTypeSize());
+		}
+
+		virtual void fromBuffer(void* object, void* buffer)
+		{
+			checkIsArray(false);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			DataType value;
+			memcpy(&value, buffer, getTypeSize());
+			setValue(castObject, value);
+		}
+
+		virtual void arrayElemFromBuffer(void* object, int index, void* buffer)
+		{
+			checkIsArray(true);
+			checkType<DataType>();
+
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+
+			DataType value;
+			memcpy(&value, buffer, getTypeSize());
+			setArrayValue(castObject, index, value);
+		}
+	};
+}

+ 146 - 0
CamelotUtility/Include/CmRTTIReflectableField.h

@@ -0,0 +1,146 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "CmRTTIField.h"
+#include "CmIReflectable.h"
+
+namespace CamelotEngine
+{
+	struct RTTIReflectableFieldBase : public RTTIField
+	{
+		virtual IReflectable& getValue(void* object) = 0;
+		virtual IReflectable& getArrayValue(void* object, UINT32 index) = 0;
+
+		virtual void setValue(void* object, IReflectable& value) = 0;
+		virtual void setArrayValue(void* object, UINT32 index, IReflectable& value) = 0;
+
+		virtual IReflectable* newObject() = 0;
+	};
+
+	template <class DataType, class ObjectType>
+	struct RTTIReflectableField : public RTTIReflectableFieldBase
+	{
+		/**
+		 * @brief	Initializes a field with a data type implementing IReflectable interface. 
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: DataType&(ObjectType*)
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, DataType)
+		 */
+		void initSingle(const std::string& name, UINT16 uniqueId, boost::any getter, boost::any setter)
+		{
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_Reflectable);
+		}
+
+		/**
+		 * @brief	Initializes a VECTOR field with data type implementing by IReflectable interface.
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: DataType&(ObjectType*, UINT32)
+		 * @param	getSize 	Getter method that returns the size of an array. Cannot be null. Must be a specific signature: UINT32(ObjectType*)
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, UINT32, DataType)
+		 * @param	setSize 	Setter method that allows you to resize an array. Can be null. Can be null. Must be a specific signature: void(ObjectType*, UINT32)
+		 */
+		void initArray(const std::string& name, UINT16 uniqueId, boost::any getter, 
+			boost::any getSize, boost::any setter, boost::any setSize)
+		{
+			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_Reflectable);
+		}
+
+		virtual UINT32 getTypeSize()
+		{
+			return 0; // Complex types don't store size the conventional way
+		}
+
+		virtual IReflectable& getValue(void* object)
+		{
+			checkIsArray(false);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			boost::function<DataType&(ObjectType*)> f = boost::any_cast<boost::function<DataType&(ObjectType*)>>(valueGetter);
+			IReflectable& castDataType = f(castObjType);
+
+			return castDataType;
+		}
+
+		virtual IReflectable& getArrayValue(void* object, UINT32 index)
+		{
+			checkIsArray(true);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			boost::function<DataType&(ObjectType*, UINT32)> f = boost::any_cast<boost::function<DataType&(ObjectType*, UINT32)>>(valueGetter);
+
+			IReflectable& castDataType = f(castObjType, index);
+			return castDataType;
+		}
+
+		virtual void setValue(void* object, IReflectable& value)
+		{
+			checkIsArray(false);
+
+			if(valueSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException,
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			DataType& castDataObj = static_cast<DataType&>(value);
+			boost::function<void(ObjectType*, DataType)> f = boost::any_cast<boost::function<void(ObjectType*, DataType)>>(valueSetter);
+			f(castObjType, castDataObj);
+		}
+
+		virtual void setArrayValue(void* object, UINT32 index, IReflectable& value)
+		{
+			checkIsArray(true);
+
+			if(valueSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			DataType& castDataObj = static_cast<DataType&>(value);
+			boost::function<void(ObjectType*, UINT32, DataType)> f = boost::any_cast<boost::function<void(ObjectType*, UINT32, DataType)>>(valueSetter);
+			f(castObjType, index, castDataObj);
+		}
+
+		virtual UINT32 getArraySize(void* object)
+		{
+			checkIsArray(true);
+
+			boost::function<UINT32(ObjectType*)> f = boost::any_cast<boost::function<UINT32(ObjectType*)>>(arraySizeGetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			return f(castObject);
+		}
+
+		virtual void setArraySize(void* object, UINT32 size)
+		{
+			checkIsArray(true);
+
+			if(arraySizeSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no array size setter.");
+			}
+
+			boost::function<void(ObjectType*, UINT32)> f = boost::any_cast<boost::function<void(ObjectType*, UINT32)>>(arraySizeSetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			f(castObject, size);
+		}
+
+		virtual IReflectable* newObject()
+		{
+			return DataType::newObject();
+		}
+	};
+}

+ 146 - 0
CamelotUtility/Include/CmRTTIReflectablePtrField.h

@@ -0,0 +1,146 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "CmRTTIField.h"
+#include "CmIReflectable.h"
+
+namespace CamelotEngine
+{
+	struct RTTIReflectablePtrFieldBase : public RTTIField
+	{
+		virtual IReflectable* getValue(void* object) = 0;
+		virtual IReflectable* getArrayValue(void* object, UINT32 index) = 0;
+
+		virtual void setValue(void* object, IReflectable* value) = 0;
+		virtual void setArrayValue(void* object, UINT32 index, IReflectable* value) = 0;
+
+		virtual IReflectable* newObject() = 0;
+	};
+
+	template <class DataType, class ObjectType>
+	struct RTTIReflectablePtrField : public RTTIReflectablePtrFieldBase
+	{
+		/**
+		 * @brief	Initializes a field pointing to a class implementing a IReflectable interface. 
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: DataType*(ObjectType*)
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, DataType*)
+		 */
+		void initSingle(const std::string& name, UINT16 uniqueId, boost::any getter, boost::any setter)
+		{
+			initAll(getter, setter, nullptr, nullptr, name, uniqueId, false, SerializableFT_ReflectablePtr);
+		}
+
+		/**
+		 * @brief	Initializes a VECTOR field with entries pointing to a class implementing IReflectable interface.
+		 *
+		 * @param	name		Name of the field.
+		 * @param	uniqueId	Unique identifier for this field. Although name is also a unique
+		 * 						identifier we want a small data type that can be used for efficiently
+		 * 						serializing data to disk and similar. It is primarily used for compatibility
+		 * 						between different versions of serialized data.
+		 * @param	getter  	The getter method for the field. Cannot be null. Must be a specific signature: DataType*(ObjectType*, UINT32)
+		 * @param	getSize 	Getter method that returns the size of an array. Cannot be null. Must be a specific signature: UINT32(ObjectType*)
+		 * @param	setter  	The setter method for the field. Can be null. Must be a specific signature: void(ObjectType*, UINT32, DataType*)
+		 * @param	setSize 	Setter method that allows you to resize an array. Can be null. Can be null. Must be a specific signature: void(ObjectType*, UINT32)
+		 */
+		void initArray(const std::string& name, UINT16 uniqueId, boost::any getter, 
+			boost::any getSize, boost::any setter, boost::any setSize)
+		{
+			initAll(getter, setter, getSize, setSize, name, uniqueId, true, SerializableFT_ReflectablePtr);
+		}
+
+		virtual UINT32 getTypeSize()
+		{
+			return 0; // Complex types don't store size the conventional way
+		}
+
+		virtual IReflectable* getValue(void* object)
+		{
+			checkIsArray(false);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			boost::function<DataType*(ObjectType*)> f = boost::any_cast<boost::function<DataType*(ObjectType*)>>(valueGetter);
+			IReflectable* castDataType = f(castObjType);
+
+			return castDataType;
+		}
+
+		virtual IReflectable* getArrayValue(void* object, UINT32 index)
+		{
+			checkIsArray(true);
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			boost::function<DataType*(ObjectType*, UINT32)> f = boost::any_cast<boost::function<DataType*(ObjectType*, UINT32)>>(valueGetter);
+
+			IReflectable* castDataType = f(castObjType, index);
+			return castDataType;
+		}
+
+		virtual void setValue(void* object, IReflectable* value)
+		{
+			checkIsArray(false);
+
+			if(valueSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException,
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			DataType* castDataObj = static_cast<DataType*>(value);
+			boost::function<void(ObjectType*, DataType*)> f = boost::any_cast<boost::function<void(ObjectType*, DataType*)>>(valueSetter);
+			f(castObjType, castDataObj);
+		}
+
+		virtual void setArrayValue(void* object, UINT32 index, IReflectable* value)
+		{
+			checkIsArray(true);
+
+			if(valueSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no setter.");
+			}
+
+			ObjectType* castObjType = static_cast<ObjectType*>(object);
+			DataType* castDataObj = static_cast<DataType*>(value);
+			boost::function<void(ObjectType*, UINT32, DataType*)> f = boost::any_cast<boost::function<void(ObjectType*, UINT32, DataType*)>>(valueSetter);
+			f(castObjType, index, castDataObj);
+		}
+
+		virtual UINT32 getArraySize(void* object)
+		{
+			checkIsArray(true);
+
+			boost::function<UINT32(ObjectType*)> f = boost::any_cast<boost::function<UINT32(ObjectType*)>>(arraySizeGetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			return f(castObject);
+		}
+
+		virtual void setArraySize(void* object, UINT32 size)
+		{
+			checkIsArray(true);
+
+			if(arraySizeSetter.empty())
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Specified field (" + mName + ") has no array size setter.");
+			}
+
+			boost::function<void(ObjectType*, UINT32)> f = boost::any_cast<boost::function<void(ObjectType*, UINT32)>>(arraySizeSetter);
+			ObjectType* castObject = static_cast<ObjectType*>(object);
+			f(castObject, size);
+		}
+
+		virtual IReflectable* newObject()
+		{
+			return DataType::newObject();
+		}
+	};
+}

+ 485 - 0
CamelotUtility/Include/CmRTTIType.h

@@ -0,0 +1,485 @@
+#pragma once
+
+#include <string>
+#include <algorithm>
+#include <unordered_map>
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/type_traits.hpp>
+#include <boost/static_assert.hpp>
+
+#include "CmPrerequisitesUtil.h"
+#include "CmManagedDataBlock.h"
+#include "CmRTTIField.h"
+#include "CmRTTIPlainField.h"
+#include "CmRTTIReflectableField.h"
+#include "CmRTTIReflectablePtrField.h"
+#include "CmRTTIManagedDataBlockField.h"
+#include "CmIReflectable.h"
+
+namespace CamelotEngine
+{
+	/**
+	 * @brief	Provides an interface for accessing fields of a certain class.
+	 * 			Data can be easily accessed by getter and setter methods.
+	 * 			
+	 *			Supported data types:
+	 *			 - Plain types - All types defined in CmRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte.  
+	 *			                 No pointers to plain types are supported. Data is passed around by value.
+	 *			 - Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its ReflectionInterface. Can be pointer or value type.
+	 *			 - Arrays of both plain and reflectable types are supported
+	 *			 - Data blocks - A managed or unmanaged block of data. See CmManagedDataBlock.h
+	 */
+	class CM_UTILITY_EXPORT RTTITypeBase
+	{
+	public:
+		RTTITypeBase();
+		virtual ~RTTITypeBase();
+
+		template <class ObjectType, class DataType>
+		void setPlainValue(ObjectType* object, const std::string& name, DataType& value)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsSimple(false);
+
+			RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
+			field->setValue(object, value);
+		}
+
+		template <class ObjectType, class DataType>
+		void setPlainArrayValue(ObjectType* object, const std::string& name, UINT32 index, DataType& value)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsSimple(true);
+
+			RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
+			field->setArrayValue(object, index, value);
+		}
+
+		template <class ObjectType, class DataType>
+		void setReflectableValue(ObjectType* object, const std::string& name, DataType& value)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplex(false);
+
+			RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
+			field->setValue(object, value);
+		}
+
+		template <class ObjectType, class DataType>
+		void setReflectableArrayValue(ObjectType* object, const std::string& name, UINT32 index, DataType& value)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplex(true);
+
+			RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
+			field->setArrayValue(object, index, value);
+		}
+
+		template <class ObjectType>
+		void setDataBlockValue(ObjectType* object, const std::string& name, ManagedDataBlock value)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsDataBlock();
+
+			RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(genericField);
+			field->setValue(object, value);
+		}
+
+
+		template <class ObjectType, class DataType>
+		void setReflectablePtrValue(ObjectType* object, const std::string& name, DataType* value)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplexPtr(false);
+
+			RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
+			field->setValue(object, value);
+		}
+
+		template <class ObjectType, class DataType>
+		void setReflectablePtrArrayValue(ObjectType* object, const std::string& name, UINT32 index, DataType* value)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplexPtr(true);
+
+			RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
+			field->setArrayValue(object, index, value);
+		}
+
+		template <class ObjectType, class DataType>
+		void getPlainValue(ObjectType* object, const std::string& name, DataType& value)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsSimple(false);
+
+			RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
+			field->getValue(object, value);
+		}
+
+		template <class ObjectType, class DataType>
+		void getPlainArrayValue(ObjectType* object, const std::string& name, UINT32 index, DataType& value)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsSimple(true);
+
+			RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
+			field->getArrayValue(object, index, value);
+		}	
+
+		template <class ObjectType>
+		IReflectable& getReflectableValue(ObjectType* object, const std::string& name)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplex(false);
+
+			RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
+			return field->getValue(object);
+		}
+
+		template <class ObjectType>
+		IReflectable& getReflectableArrayValue(ObjectType* object, const std::string& name, UINT32 index)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplex(true);
+
+			RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
+			return field->getArrayValue(object, index);
+		}
+
+		template <class ObjectType>
+		ManagedDataBlock getDataBlockValue(ObjectType* object, const std::string& name)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsDataBlock();
+
+			RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(genericField);
+			return field->getValue(object);
+		}
+
+		template <class ObjectType>
+		IReflectable* getReflectablePtrValue(ObjectType* object, const std::string& name)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplexPtr(false);
+
+			RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
+			return field->getValue(object);
+		}
+
+		template <class ObjectType>
+		IReflectable* getReflectablePtrArrayValue(ObjectType* object, const std::string& name, UINT32 index)
+		{
+			RTTIField* genericField = findField(name);
+			genericField->checkIsComplexPtr(true);
+
+			RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
+			return field->getArrayValue(object, index);
+		}
+
+		template <class ObjectType>
+		UINT32 getArraySize(ObjectType* object, const std::string& name)
+		{
+			RTTIField* field = findField(name);
+			return field->getArraySize(object);
+		}
+
+		template <class ObjectType>
+		void setArraySize(ObjectType* object, const std::string& name, UINT32 size)
+		{
+			RTTIField* field = findField(name);
+			field->setArraySize(object, size);
+		}	
+
+		UINT32 getNumFields() { return mFields.size(); }
+		RTTIField* getField(UINT32 idx) { return mFields.at(idx); }
+
+		/**
+		 * @brief	Tries to find a field with the specified name. Throws an exception if it can't.
+		 *
+		 * @param	name	The name of the field.
+		 */
+		RTTIField* findField(const std::string& name);
+
+		/**
+		 * @brief	Tries to find a field with the specified unique ID. Doesn't throw an exception
+		 * 			if it can't find the field (Unlike findField(name)). 
+		 *
+		 * @param	uniqueFieldId	Unique identifier for the field.
+		 *
+		 * @return	nullptr if it can't find the field.
+		 */
+		RTTIField* findField(int uniqueFieldId);
+
+	protected:
+		/**
+		 * @brief	Tries to add a new field to the fields array, and throws an exception
+		 * 			if a field with the same name or id already exists.
+		 *
+		 * @param [in]	field	Field, must be non-null.
+		 */
+		void addNewField(RTTIField* field);
+
+	private:
+		std::vector<RTTIField*> mFields;
+	};
+
+	/**
+	 * @brief	Pretty much just an extension of SerializationInterfaceBase. Feel free to derive from this class and return
+	 * 			the derived class from IReflectable::getSerializationInterface. This way you can separate serialization logic from
+	 * 			the actual class you're serializing.
+	 */
+	// TODO - Low priority. This class is separate from SerializationInterfaceBase because of obsolete reasons. It might be okay to merge them in the future, provided there will be
+	// no more changes to serialization.
+	class CM_UTILITY_EXPORT RTTIType : public RTTITypeBase
+	{
+	public:
+		RTTIType() {}
+		virtual ~RTTIType() {}
+
+		/************************************************************************/
+		/* 			FIELDS OPERATING DIRECTLY ON SERIALIZABLE OBJECT            */
+		/************************************************************************/
+		template<class ObjectType, class DataType>
+		void addPlainField(const std::string& name, UINT32 uniqueId, DataType (ObjectType::*getter)(), void (ObjectType::*setter)(DataType) = nullptr)
+		{
+			addPlainField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType(ObjectType*)>(getter), 
+				boost::function<void(ObjectType*, DataType)>(setter));
+		}
+
+		template<class ObjectType, class DataType>
+		void addReflectableField(const std::string& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(), void (ObjectType::*setter)(DataType) = nullptr)
+		{
+			addReflectableField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType&(ObjectType*)>(getter), 
+				boost::function<void(ObjectType*, DataType)>(setter));
+		}
+
+		template<class ObjectType, class DataType>
+		void addReflectablePtrField(const std::string& name, UINT32 uniqueId, DataType* (ObjectType::*getter)(), void (ObjectType::*setter)(DataType*) = nullptr)
+		{
+			addReflectablePtrField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType*(ObjectType*)>(getter), 
+				boost::function<void(ObjectType*, DataType*)>(setter));
+		}
+
+		template<class ObjectType, class DataType>
+		void addPlainArrayField(const std::string& name, UINT32 uniqueId, DataType (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), 
+			void (ObjectType::*setter)(UINT32, DataType) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr)
+		{
+			addPlainArrayField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType(ObjectType*, UINT32)>(getter), 
+				boost::function<UINT32(ObjectType*)>(getSize), 
+				boost::function<void(ObjectType*, UINT32, DataType)>(setter), 
+				boost::function<void(ObjectType*, UINT32)>(setSize));
+		}	
+
+		template<class ObjectType, class DataType>
+		void addReflectableArrayField(const std::string& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), 
+			void (ObjectType::*setter)(UINT32, DataType) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr)
+		{
+			addReflectableArrayField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType&(ObjectType*, UINT32)>(getter), 
+				boost::function<UINT32(ObjectType*)>(getSize), 
+				boost::function<void(ObjectType*, UINT32, DataType)>(setter), 
+				boost::function<void(ObjectType*, UINT32)>(setSize));
+		}
+
+		template<class ObjectType, class DataType>
+		void addReflectablePtrArrayField(const std::string& name, UINT32 uniqueId, DataType* (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), 
+			void (ObjectType::*setter)(UINT32, DataType*) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr)
+		{
+			addReflectablePtrArrayField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType*(ObjectType*, UINT32)>(getter), 
+				boost::function<UINT32(ObjectType*)>(getSize), 
+				boost::function<void(ObjectType*, UINT32, DataType*)>(setter), 
+				boost::function<void(ObjectType*, UINT32)>(setSize));
+		}
+
+		template<class ObjectType>
+		void addDataBlockField(const std::string& name, UINT32 uniqueId, ManagedDataBlock (ObjectType::*getter)(), 
+			void (ObjectType::*setter)(ManagedDataBlock) = nullptr)
+		{
+			addDataBlockField<ObjectType>(name, uniqueId, 
+				boost::function<ManagedDataBlock(ObjectType*)>(getter),  
+				boost::function<void(ObjectType*, ManagedDataBlock)>(setter));
+		}	
+
+	protected:
+		virtual void initSerializableFields() {}
+
+		/************************************************************************/
+		/* 		FIELDS OPERATING ON DERIVED SERIALIZATION INTERFACE				*/
+		/*		(Needs an extra pointer to the actual object)					*/
+		/************************************************************************/
+		template<class InterfaceType, class ObjectType, class DataType>
+		void addPlainField(const std::string& name, UINT32 uniqueId, 
+			DataType (InterfaceType::*getter)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, DataType) = nullptr)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::RTTIType, InterfaceType>::value), 
+				"Class with the get/set methods must derive from CamelotEngine::SerializationInterface.");
+
+			addPlainField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType(ObjectType*)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1)), 
+				boost::function<void(ObjectType*, DataType)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2)));
+		}
+
+		template<class InterfaceType, class ObjectType, class DataType>
+		void addReflectableField(const std::string& name, UINT32 uniqueId, 
+			DataType& (InterfaceType::*getter)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, DataType) = nullptr)
+		{
+			addReflectableField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType&(ObjectType*)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1)), 
+				boost::function<void(ObjectType*, DataType)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2)));
+		}
+
+		template<class InterfaceType, class ObjectType, class DataType>
+		void addReflectablePtrField(const std::string& name, UINT32 uniqueId, 
+			DataType* (InterfaceType::*getter)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, DataType*) = nullptr)
+		{
+			addReflectablePtrField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType*(ObjectType*)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1)), 
+				boost::function<void(ObjectType*, DataType*)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2)));
+		}
+
+		template<class InterfaceType, class ObjectType, class DataType>
+		void addPlainArrayField(const std::string& name, UINT32 uniqueId, 
+			DataType (InterfaceType::*getter)(ObjectType*, UINT32), 
+			UINT32 (InterfaceType::*getSize)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, UINT32, DataType) = nullptr, 
+			void(InterfaceType::*setSize)(ObjectType*, UINT32) = nullptr)
+		{
+			addPlainArrayField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType(ObjectType*, UINT32)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1, _2)), 
+				boost::function<UINT32(ObjectType*)>(boost::bind(getSize, static_cast<InterfaceType*>(this), _1)), 
+				boost::function<void(ObjectType*, UINT32, DataType)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2, _3)), 
+				boost::function<void(ObjectType*, UINT32)>(boost::bind(setSize, static_cast<InterfaceType*>(this), _1, _2)));
+		}	
+
+		template<class InterfaceType, class ObjectType, class DataType>
+		void addReflectableArrayField(const std::string& name, UINT32 uniqueId, 
+			DataType& (InterfaceType::*getter)(ObjectType*, UINT32), 
+			UINT32 (InterfaceType::*getSize)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, UINT32, DataType) = nullptr, 
+			void(InterfaceType::*setSize)(ObjectType*, UINT32) = nullptr)
+		{
+			addReflectableArrayField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType&(ObjectType*, UINT32)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1, _2)), 
+				boost::function<UINT32(ObjectType*)>(boost::bind(getSize, static_cast<InterfaceType*>(this), _1)), 
+				boost::function<void(ObjectType*, UINT32, DataType)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2, _3)), 
+				boost::function<void(ObjectType*, UINT32)>(boost::bind(setSize, static_cast<InterfaceType*>(this), _1, _2)));
+		}
+
+		template<class InterfaceType, class ObjectType, class DataType>
+		void addReflectablePtrArrayField(const std::string& name, UINT32 uniqueId, 
+			DataType* (InterfaceType::*getter)(ObjectType*, UINT32), 
+			UINT32 (InterfaceType::*getSize)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, UINT32, DataType*) = nullptr, 
+			void(InterfaceType::*setSize)(ObjectType*, UINT32) = nullptr)
+		{
+			addReflectablePtrArrayField<ObjectType, DataType>(name, uniqueId, 
+				boost::function<DataType*(ObjectType*, UINT32)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1, _2)), 
+				boost::function<UINT32(ObjectType*)>(boost::bind(getSize, static_cast<InterfaceType*>(this), _1)), 
+				boost::function<void(ObjectType*, UINT32, DataType*)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2, _3)), 
+				boost::function<void(ObjectType*, UINT32)>(boost::bind(setSize, static_cast<InterfaceType*>(this), _1, _2)));
+		}
+
+		template<class InterfaceType, class ObjectType>
+		void addDataBlockField(const std::string& name, UINT32 uniqueId, ManagedDataBlock (InterfaceType::*getter)(ObjectType*), 
+			void (InterfaceType::*setter)(ObjectType*, ManagedDataBlock) = nullptr)
+		{
+			addDataBlockField<ObjectType>(name, uniqueId, 
+				boost::function<ManagedDataBlock(ObjectType*)>(boost::bind(getter, static_cast<InterfaceType*>(this), _1)),  
+				boost::function<void(ObjectType*, ManagedDataBlock)>(boost::bind(setter, static_cast<InterfaceType*>(this), _1, _2)));
+		}	
+
+	private:
+		template<class ObjectType, class DataType>
+		void addPlainField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any setter = nullptr)
+		{
+			RTTIPlainField<DataType, ObjectType>* newField = new RTTIPlainField<DataType, ObjectType>();
+			newField->initSingle(name, uniqueId, getter, setter);
+			addNewField(newField);
+		}
+		
+		template<class ObjectType, class DataType>
+		void addReflectableField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any setter = nullptr)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIReflectableField<DataType, ObjectType>* newField = new RTTIReflectableField<DataType, ObjectType>();
+			newField->initSingle(name, uniqueId, getter, setter);
+			addNewField(newField);
+		}
+
+		template<class ObjectType, class DataType>
+		void addReflectablePtrField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any setter = nullptr)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIReflectablePtrField<DataType, ObjectType>* newField = new RTTIReflectablePtrField<DataType, ObjectType>();
+			newField->initSingle(name, uniqueId, getter, setter);
+			addNewField(newField);
+		}
+
+		template<class ObjectType, class DataType>
+		void addPlainArrayField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any getSize, 
+			boost::any setter = nullptr, boost::any setSize = nullptr)
+		{
+			RTTIPlainField<DataType, ObjectType>* newField = new RTTIPlainField<DataType, ObjectType>();
+			newField->initArray(name, uniqueId, getter, getSize, setter, setSize);
+			addNewField(newField);
+		}	
+
+		template<class ObjectType, class DataType>
+		void addReflectableArrayField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any getSize, 
+			boost::any setter = nullptr, boost::any setSize = nullptr)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIReflectableField<DataType, ObjectType>* newField = new RTTIReflectableField<DataType, ObjectType>();
+			newField->initArray(name, uniqueId, getter, getSize, setter, setSize);
+			addNewField(newField);
+		}
+
+		template<class ObjectType, class DataType>
+		void addReflectablePtrArrayField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any getSize, 
+			boost::any setter = nullptr, boost::any setSize = nullptr)
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::IReflectable, DataType>::value), 
+				"Invalid data type for complex field. It needs to derive from CamelotEngine::IReflectable.");
+
+			RTTIReflectablePtrField<DataType, ObjectType>* newField = new RTTIReflectablePtrField<DataType, ObjectType>();
+			newField->initArray(name, uniqueId, getter, getSize, setter, setSize);
+			addNewField(newField);
+		}
+
+		template<class ObjectType>
+		void addDataBlockField(const std::string& name, UINT32 uniqueId, boost::any getter, boost::any setter = nullptr)
+		{
+			RTTIManagedDataBlockField<ManagedDataBlock, ObjectType>* newField = new RTTIManagedDataBlockField<ManagedDataBlock, ObjectType>();
+			newField->initSingle(name, uniqueId, getter,  setter);
+			addNewField(newField);
+		}	
+	};
+}

+ 14 - 0
CamelotUtility/Include/CmSerializableType.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include "CmRTTIType.h"
+
+namespace CamelotEngine
+{
+	class CM_UTILITY_EXPORT SerializableType : public RTTITypeBase
+	{
+	public:
+		virtual void beginSerialization() {}
+		virtual void endSerialization() {}
+	};
+}

+ 863 - 0
CamelotUtility/Source/CmBinarySerializer.cpp

@@ -0,0 +1,863 @@
+#include "CmBinarySerializer.h"
+
+#include "CmException.h"
+#include "CmIReflectable.h"
+#include "CmRTTIType.h"
+#include "CmRTTIField.h"
+#include "CmRTTIPlainField.h"
+#include "CmRTTIReflectableField.h"
+#include "CmRTTIReflectablePtrField.h"
+#include "CmRTTIManagedDataBlockField.h"
+
+#include <unordered_set>
+
+/**
+ * @brief	A macro that represents a block of code that gets used a lot inside
+ * 			encodeInternal. It checks if the buffer has enough space, and if it does
+ * 			it copies the data from the specified location and increments the needed
+ * 			pointers and counters. If there is not enough space the buffer is flushed
+ * 			(hopefully to make some space). If there is still not enough space the entire
+ * 			encoding process ends.
+ *
+ * @param	dataPtr	Pointer to data which to copy.
+ * @param	size   	Size of the data to copy
+ */
+#define COPY_TO_BUFFER(dataPtr, size)									\
+if((*bytesWritten + size##) > bufferLength)								\
+{																		\
+	mTotalBytesWritten += *bytesWritten;								\
+	buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);	\
+	if(buffer == nullptr || bufferLength < size##) return nullptr;		\
+	*bytesWritten = 0;													\
+}																		\
+																		\
+memcpy(buffer, dataPtr##, size##);										\
+buffer += size##;														\
+*bytesWritten += size##;
+
+namespace CamelotEngine
+{
+	BinarySerializer::BinarySerializer()
+		:mLastUsedObjectId(1)
+	{
+	}
+
+	void BinarySerializer::encode(IReflectable* object, UINT8* buffer, UINT32 bufferLength, int* bytesWritten, boost::function<UINT8*(UINT8*, int, UINT32&)> flushBufferCallback)
+	{
+		mObjectsToEncode.clear();
+		mObjectAddrToId.clear();
+		mLastUsedObjectId = 1;
+		*bytesWritten = 0;
+		mTotalBytesWritten = 0;
+		UINT8* bufferStart = buffer;
+
+		UINT32 objectId = findOrCreatePersistentId(object);
+		
+		// Encode primary object and its value types
+		buffer = encodeInternal(object, objectId, buffer, bufferLength, bytesWritten, flushBufferCallback);
+		if(buffer == nullptr)
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Destination buffer is null or not large enough.");
+		}
+
+		// Encode pointed to objects and their value types
+		std::unordered_set<UINT32> serializedObjects;
+		while(true)
+		{
+			auto iter = mObjectsToEncode.begin();
+			bool foundObjectToProcess = false;
+			for(iter; iter != mObjectsToEncode.end(); ++iter)
+			{
+				auto foundExisting = serializedObjects.find(iter->objectId);
+				if(foundExisting != serializedObjects.end())
+					continue; // Already processed
+
+				IReflectable* curObject = iter->object;
+				buffer = encodeInternal(curObject, iter->objectId, buffer, bufferLength, bytesWritten, flushBufferCallback);
+				if(buffer == nullptr)
+				{
+					CM_EXCEPT(InternalErrorException, 
+						"Destination buffer is null or not large enough.");
+				}
+
+				serializedObjects.insert(iter->objectId);
+				mObjectsToEncode.erase(iter);
+				foundObjectToProcess = true;
+				break; // Need to start over as mObjectsToSerialize was possibly modified
+			}
+
+			if(!foundObjectToProcess) // We're done
+				break;
+		}
+
+		// Final flush
+		if(*bytesWritten > 0)
+		{
+			mTotalBytesWritten += *bytesWritten;
+			buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
+		}
+
+		*bytesWritten = mTotalBytesWritten;
+	}
+
+	void BinarySerializer::decode(IReflectable* object, UINT8* data, UINT32 dataLength)
+	{
+		mPtrsToResolve.clear();
+		mDecodedObjects.clear();
+
+		// Create initial object + all other objects that are being referenced.
+		// Use fields to find the type of referenced object.
+		UINT32 bytesRead = 0;
+		while(decodeInternal(object, data, dataLength, bytesRead))
+		{
+			data += bytesRead;
+
+			UINT8* localDataPtr = data;
+			UINT32 localBytesRead = bytesRead;
+
+			if((bytesRead + sizeof(UINT32)) > dataLength)
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Error decoding data.");
+			}
+
+			UINT32 objectMetaData = 0;
+			memcpy(&objectMetaData, localDataPtr, sizeof(UINT32));
+			localDataPtr += sizeof(UINT32);
+			localBytesRead += sizeof(UINT32);
+
+			UINT32 objectId = 0;
+			decodeObjectMetaData(objectMetaData, objectId);
+
+			object = nullptr;
+			if(objectId != 0)
+			{
+				auto iterFind = std::find_if(mPtrsToResolve.begin(), mPtrsToResolve.end(), [objectId](PtrToResolve x) { return x.id == objectId; });
+
+				if(iterFind != mPtrsToResolve.end())
+					object = iterFind->field->newObject();
+			}
+		}
+
+		for(auto iter = mPtrsToResolve.begin(); iter != mPtrsToResolve.end(); ++iter)
+		{
+			IReflectable* resolvedObject = nullptr;
+
+			PtrToResolve curPtr = *iter;
+			if(curPtr.id != 0)
+			{
+				auto iterFind = mDecodedObjects.find(curPtr.id);
+				if(iterFind != mDecodedObjects.end())
+					resolvedObject = iterFind->second;
+			}
+
+			if(curPtr.field->mIsVectorType)
+				curPtr.field->setArrayValue(curPtr.object, curPtr.arrIdx, resolvedObject);
+			else
+				curPtr.field->setValue(curPtr.object, resolvedObject);
+		}
+	}
+
+	UINT8* BinarySerializer::encodeInternal(IReflectable* object, UINT32 objectId, UINT8* buffer, UINT32& bufferLength, int* bytesWritten, boost::function<UINT8*(UINT8*, int, UINT32&)> flushBufferCallback)
+	{
+		static const UINT32 META_SIZE = 4; // Meta field size
+		static const UINT32 NUM_ELEM_FIELD_SIZE = 4; // Size of the field storing number of array elements
+		static const UINT32 COMPLEX_TYPE_SIZE = 4; // Size of the field storing the size of a child complex type
+
+		RTTITypeBase* si = object->getRTTI();
+
+		// Encode object ID if it has one
+		UINT32 objectMetaData = encodeObjectMetaData(objectId);
+		COPY_TO_BUFFER(&objectMetaData, sizeof(UINT32))
+
+		int numFields = si->getNumFields();
+		for(int i = 0; i < numFields; i++)
+		{
+			RTTIField* curGenericField = si->getField(i);
+
+			// Copy field ID & other meta-data like field size and type
+			int metaData = encodeFieldMetaData(curGenericField->mUniqueId, curGenericField->getTypeSize(), curGenericField->mIsVectorType, curGenericField->mType);
+			COPY_TO_BUFFER(&metaData, META_SIZE)
+
+			if(curGenericField->mIsVectorType)
+			{
+				UINT32 arrayNumElems = curGenericField->getArraySize(object);
+
+				// Copy num vector elements
+				COPY_TO_BUFFER(&arrayNumElems, NUM_ELEM_FIELD_SIZE)
+
+				switch(curGenericField->mType)
+				{
+				case SerializableFT_ReflectablePtr:
+					{
+						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+						for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+						{
+							IReflectable* childObject = curField->getArrayValue(object, arrIdx); 
+
+							UINT32 objId = registerObjectPtr(childObject);
+							COPY_TO_BUFFER(&objId, sizeof(UINT32))
+						}
+
+						break;
+					}
+				case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+						for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+						{
+							IReflectable& childObject = curField->getArrayValue(object, arrIdx);
+
+							buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, bytesWritten, flushBufferCallback);
+							if(buffer == nullptr)
+								return nullptr;
+						}
+
+						break;
+					}
+				case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+						UINT32 typeSize = curField->getTypeSize();
+						for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+						{
+							if((*bytesWritten + typeSize) > bufferLength)
+							{
+								mTotalBytesWritten += *bytesWritten;
+								buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
+								if(buffer == nullptr || bufferLength < typeSize) return nullptr;
+								*bytesWritten = 0;
+							}
+
+							curField->arrayElemToBuffer(object, arrIdx, buffer);
+							buffer += typeSize;
+							*bytesWritten += typeSize;
+						}
+
+						break;
+					}
+				default:
+					CM_EXCEPT(InternalErrorException, 
+						"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
+						", Is array: " + toString(curGenericField->mIsVectorType));
+				}
+			}
+			else
+			{
+				switch(curGenericField->mType)
+				{
+				case SerializableFT_ReflectablePtr:
+					{
+						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+						IReflectable* childObject = curField->getValue(object); 
+
+						UINT32 objId = registerObjectPtr(childObject);
+						COPY_TO_BUFFER(&objId, sizeof(UINT32))
+
+						break;
+					}
+				case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+						IReflectable& childObject = curField->getValue(object);
+
+						buffer = complexTypeToBuffer(&childObject, buffer, bufferLength, bytesWritten, flushBufferCallback);
+						if(buffer == nullptr)
+							return nullptr;
+
+						break;
+					}
+				case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+						UINT32 typeSize = curField->getTypeSize();
+
+						if((*bytesWritten + typeSize) > bufferLength)
+						{
+							mTotalBytesWritten += *bytesWritten;
+							buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
+							if(buffer == nullptr || bufferLength < typeSize) return nullptr;
+							*bytesWritten = 0;
+						}
+
+						curField->toBuffer(object, buffer);
+						buffer += typeSize;
+						*bytesWritten += typeSize;
+
+						break;
+					}
+				case SerializableFT_DataBlock:
+					{
+						RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
+						ManagedDataBlock value = curField->getValue(object);
+
+						// Data block size
+						UINT32 dataBlockSize = value.getSize();
+						COPY_TO_BUFFER(&dataBlockSize, sizeof(UINT32))
+
+						// Data block data
+						UINT8* dataToStore = value.getData();
+						UINT32 remainingSize = dataBlockSize;
+						while(remainingSize > 0)
+						{
+							UINT32 remainingSpaceInBuffer = bufferLength - *bytesWritten;
+
+							if(remainingSize <= remainingSpaceInBuffer)
+							{
+								COPY_TO_BUFFER(dataToStore, remainingSize);
+								remainingSize = 0;
+							}
+							else
+							{
+								memcpy(buffer, dataToStore, remainingSpaceInBuffer);
+								buffer += remainingSpaceInBuffer;
+								*bytesWritten += remainingSpaceInBuffer;
+								dataToStore += remainingSpaceInBuffer;
+								remainingSize -= remainingSpaceInBuffer;
+								
+								mTotalBytesWritten += *bytesWritten;
+								buffer = flushBufferCallback(buffer - *bytesWritten, *bytesWritten, bufferLength);
+								if(buffer == nullptr || bufferLength == 0) return nullptr;
+								*bytesWritten = 0;
+							}
+						}
+
+						break;
+					}
+				default:
+					CM_EXCEPT(InternalErrorException, 
+						"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
+						", Is array: " + toString(curGenericField->mIsVectorType));
+				}
+			}
+		}
+
+		return buffer;
+	}
+
+	bool BinarySerializer::decodeInternal(IReflectable* object, UINT8* data, UINT32 dataLength, UINT32& bytesRead)
+	{
+		static const int META_SIZE = 4; // Meta field size
+		static const int NUM_ELEM_FIELD_SIZE = 4; // Size of the field storing number of array elements
+		static const int COMPLEX_TYPE_FIELD_SIZE = 4; // Size of the field storing the size of a child complex type
+		static const int DATA_BLOCK_TYPE_FIELD_SIZE = 4;
+
+		RTTITypeBase* si = nullptr;
+		if(object != nullptr)
+			si = object->getRTTI();
+
+		if((bytesRead + sizeof(UINT32)) > dataLength)
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Error decoding data.");
+		}
+
+		UINT32 objectMetaData = 0;
+		memcpy(&objectMetaData, data, sizeof(UINT32));
+		data += sizeof(UINT32);
+		bytesRead += sizeof(UINT32);
+
+		UINT32 objectId = 0;
+		decodeObjectMetaData(objectMetaData, objectId);
+
+		if(object != nullptr && objectId != 0)
+			mDecodedObjects.insert(std::make_pair(objectId, object));
+		
+		while(bytesRead < dataLength)
+		{
+			int metaData = -1;
+
+			if((bytesRead + META_SIZE) > dataLength)
+			{
+				CM_EXCEPT(InternalErrorException, 
+					"Error decoding data.");
+			}
+
+			memcpy((void*)&metaData, data, META_SIZE);
+
+			if(isObjectMetaData(metaData)) // We've reached a new object
+			{
+				UINT32 objId = 0;
+				decodeObjectMetaData(metaData, objId);
+
+				if(objId != 0) // Objects with 0 ID represent complex types serialized by value, in which case we just decode them on the spot
+					return true;
+			}
+
+			data += META_SIZE;
+			bytesRead += META_SIZE;
+
+			bool isArray;
+			SerializableFieldType fieldType;
+			UINT16 fieldId;
+			UINT8 fieldSize;
+			decodeFieldMetaData(metaData, fieldId, fieldSize, isArray, fieldType);
+			
+			RTTIField* curGenericField = nullptr;
+			
+			if(si != nullptr)
+				curGenericField = si->findField(fieldId);
+
+			if(curGenericField != nullptr)
+			{
+				if(curGenericField->getTypeSize() != fieldSize)
+				{
+					CM_EXCEPT(InternalErrorException, 
+						"Data type mismatch. Type size stored in file and actual type size don't match. (" 
+						+ toString(curGenericField->getTypeSize()) + " vs. " + toString(fieldSize) + ")");
+				}
+
+				if(curGenericField->mIsVectorType != isArray)
+				{
+					CM_EXCEPT(InternalErrorException, 
+						"Data type mismatch. One is array, other is a single type.");
+				}
+
+				if(curGenericField->mType != fieldType) 
+				{
+					CM_EXCEPT(InternalErrorException, 
+						"Data type mismatch. Field types don't match. " + toString(UINT32(curGenericField->mType)) + " vs. " + toString(UINT32(fieldType)));
+				}
+			}
+
+			int arrayNumElems = 1;
+			if(isArray)
+			{
+				if((bytesRead + NUM_ELEM_FIELD_SIZE) > dataLength)
+				{
+					CM_EXCEPT(InternalErrorException, 
+						"Error decoding data.");
+				}
+
+				memcpy((void*)&arrayNumElems, data, NUM_ELEM_FIELD_SIZE);
+				data += NUM_ELEM_FIELD_SIZE;
+				bytesRead += NUM_ELEM_FIELD_SIZE;
+
+				if(curGenericField != nullptr)
+					curGenericField->setArraySize(object, arrayNumElems);
+
+				switch(fieldType)
+				{
+				case SerializableFT_ReflectablePtr:
+					{
+						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+						for(int i = 0; i < arrayNumElems; i++)
+						{
+							if((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
+							{
+								CM_EXCEPT(InternalErrorException, 
+									"Error decoding data.");
+							}
+
+							int objectId = 0;
+							memcpy(&objectId, data, COMPLEX_TYPE_FIELD_SIZE);
+							data += COMPLEX_TYPE_FIELD_SIZE;
+							bytesRead += COMPLEX_TYPE_FIELD_SIZE;
+
+							if(curField != nullptr)
+								mPtrsToResolve.push_back(PtrToResolve(curField, object, objectId, i));
+						}
+
+						break;
+					}
+				case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+						for(int i = 0; i < arrayNumElems; i++)
+						{
+							if((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
+							{
+								CM_EXCEPT(InternalErrorException, 
+									"Error decoding data.");
+							}
+
+							int complexTypeSize = COMPLEX_TYPE_FIELD_SIZE;
+							if(curField != nullptr)
+							{
+								IReflectable* complexType = complexTypeFromBuffer(curField, data, &complexTypeSize);
+								curField->setArrayValue(object, i, *complexType);
+								delete complexType;
+							}
+
+							data += complexTypeSize;
+							bytesRead += complexTypeSize;
+						}
+						break;
+					}
+				case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+						for(int i = 0; i < arrayNumElems; i++)
+						{
+							if(curField != nullptr)
+								curField->arrayElemFromBuffer(object, i, data);
+
+							data += fieldSize;
+							bytesRead += fieldSize;
+						}
+						break;
+					}
+				default:
+					CM_EXCEPT(InternalErrorException, 
+						"Error decoding data. Encountered a type I don't know how to decode. Type: " + toString(UINT32(fieldType)) + 
+						", Is array: " + toString(isArray));
+				}
+			}
+			else
+			{
+				switch(fieldType)
+				{
+				case SerializableFT_ReflectablePtr:
+					{
+						RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
+
+						if((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
+						{
+							CM_EXCEPT(InternalErrorException, 
+								"Error decoding data.");
+						}
+
+						int objectId = 0;
+						memcpy(&objectId, data, COMPLEX_TYPE_FIELD_SIZE);
+						data += COMPLEX_TYPE_FIELD_SIZE;
+						bytesRead += COMPLEX_TYPE_FIELD_SIZE;
+
+						if(curField != nullptr)
+							mPtrsToResolve.push_back(PtrToResolve(curField, object, objectId));
+
+						break;
+					}
+				case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+						if((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
+						{
+							CM_EXCEPT(InternalErrorException, 
+								"Error decoding data.");
+						}
+
+						int complexTypeSize = COMPLEX_TYPE_FIELD_SIZE;
+						if(curField != nullptr)
+						{
+							IReflectable* complexType = complexTypeFromBuffer(curField, data, &complexTypeSize);
+							curField->setValue(object, *complexType);
+							delete complexType;
+						}
+
+						data += complexTypeSize;
+						bytesRead += complexTypeSize;
+
+						break;
+					}
+				case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+
+						if(curField != nullptr)
+							curField->fromBuffer(object, data);
+
+						data += fieldSize;
+						bytesRead += fieldSize;
+						break;
+					}
+				case SerializableFT_DataBlock:
+					{
+						RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
+
+						if((bytesRead + DATA_BLOCK_TYPE_FIELD_SIZE) > dataLength)
+						{
+							CM_EXCEPT(InternalErrorException, 
+								"Error decoding data.");
+						}
+
+						// Data block size
+						UINT32 dataBlockSize = 0;
+						memcpy(&dataBlockSize, data, DATA_BLOCK_TYPE_FIELD_SIZE);
+						data += DATA_BLOCK_TYPE_FIELD_SIZE;
+						bytesRead += DATA_BLOCK_TYPE_FIELD_SIZE;
+
+						if((bytesRead + dataBlockSize) > dataLength)
+						{
+							CM_EXCEPT(InternalErrorException, 
+								"Error decoding data.");
+						}
+
+						// Data block data
+						if(curField != nullptr)
+						{
+							UINT8* dataCopy = new UINT8[dataBlockSize]; // TODO - Low priority. I need to read files better, so I
+							memcpy(dataCopy, data, dataBlockSize);		//    can just pass the buffer pointer directly without copying (possibly large amounts of data)
+
+							ManagedDataBlock value(dataCopy, dataBlockSize, false); // Not managed because I assume the owner class will decide whether to delete the data or keep it
+							curField->setValue(object, value);
+						}
+
+						data += dataBlockSize;
+						bytesRead += dataBlockSize;
+
+						break;
+					}
+				default:
+					CM_EXCEPT(InternalErrorException, 
+						"Error decoding data. Encountered a type I don't know how to decode. Type: " + toString(UINT32(fieldType)) + 
+						", Is array: " + toString(isArray));
+				}
+			}
+		}
+
+		return false;
+	}
+
+	UINT32 BinarySerializer::getObjectSize(IReflectable* object)
+	{
+		if(object == nullptr)
+			return 0;
+
+		UINT32 objectSize = 0;
+		RTTITypeBase* si = object->getRTTI();
+
+		// Object ID
+		objectSize += sizeof(UINT32);
+
+		int numFields = si->getNumFields();
+		for(int i = 0; i < numFields; i++)
+		{
+			RTTIField* curGenericField = si->getField(i);
+
+			// Field meta data
+			objectSize += sizeof(UINT32);
+
+			if(curGenericField->mIsVectorType)
+			{
+				UINT32 arrayNumElems = curGenericField->getArraySize(object);
+
+				// Num array elems
+				objectSize += sizeof(UINT32);
+
+				switch(curGenericField->mType)
+				{
+					case SerializableFT_ReflectablePtr:
+						{
+							objectSize += sizeof(UINT32) * arrayNumElems;
+							break;
+						}
+					case SerializableFT_Reflectable:
+						{
+							RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+
+							for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
+							{
+								IReflectable& childObject = curField->getArrayValue(object, arrIdx);
+								objectSize += getObjectSize(&childObject);
+							}
+
+							break;
+						}
+					case SerializableFT_Plain:
+						{
+							RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+							objectSize += arrayNumElems * curField->getTypeSize();
+
+							break;
+						}
+					default:
+						CM_EXCEPT(InternalErrorException, 
+							"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
+							", Is array: " + toString(curGenericField->mIsVectorType));
+				}
+			}
+			else
+			{
+				switch(curGenericField->mType)
+				{
+				case SerializableFT_ReflectablePtr:
+					{
+						objectSize += sizeof(UINT32);
+						break;
+					}
+				case SerializableFT_Reflectable:
+					{
+						RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
+						IReflectable& childObject = curField->getValue(object);
+						objectSize += getObjectSize(&childObject);
+
+						break;
+					}
+				case SerializableFT_Plain:
+					{
+						RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
+						objectSize += curField->getTypeSize();
+
+						break;
+					}
+				case SerializableFT_DataBlock:
+					{
+						RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
+						ManagedDataBlock value = curField->getValue(object);
+
+						// Data block size
+						UINT32 dataBlockSize = value.getSize();
+						objectSize += sizeof(UINT32) + dataBlockSize;
+
+						break;
+					}
+				default:
+					CM_EXCEPT(InternalErrorException, 
+						"Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) + 
+						", Is array: " + toString(curGenericField->mIsVectorType));
+				}
+			}
+		}
+
+		return objectSize;
+	}
+
+	UINT32 BinarySerializer::encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type)
+	{
+		// If O == 0 - Meta contains field information (Encoded using this method)
+		//// Encoding: IIII IIII IIII IIII SSSS SSSS xxxP DCAO
+		//// I - Id
+		//// S - Size
+		//// C - Complex
+		//// A - Array
+		//// D - Data block
+		//// P - Complex ptr
+		//// O - Object descriptor
+ 
+		return (id << 16 | size << 8 | 
+			(array ? 0x02 : 0) | 
+			((type == SerializableFT_DataBlock) ? 0x04 : 0) | 
+			((type == SerializableFT_Reflectable) ? 0x08 : 0) | 
+			((type == SerializableFT_ReflectablePtr) ? 0x10 : 0)); // TODO - Low priority. Technically I could encode this much more tightly, and use var-ints for ID
+	}
+
+	void BinarySerializer::decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, SerializableFieldType& type)
+	{
+		if(isObjectMetaData(encodedData))
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Meta data represents an object description but is trying to be decoded as a field descriptor.");
+		}
+
+		if((encodedData & 0x10) != 0)
+			type = SerializableFT_ReflectablePtr;
+		else if((encodedData & 0x08) != 0)
+			type = SerializableFT_Reflectable;
+		else if((encodedData & 0x04) != 0)
+			type = SerializableFT_DataBlock;
+		else
+			type = SerializableFT_Plain;
+
+		array = (encodedData & 0x02) != 0;
+		size = (UINT8)((encodedData >> 8) & 0xFF);
+		id = (UINT16)((encodedData >> 16) & 0xFFFF);
+	}
+
+	UINT32 BinarySerializer::encodeObjectMetaData(UINT32 objId)
+	{
+		// If O == 1 - Meta contains object instance information (Encoded using encodeObjectMetaData)
+		//// Encoding: SSSS SSSS SSSS SSSS xxxx xxxx xxxx xxxO
+		//// S - Size of the object identifier
+		//// O - Object descriptor
+
+		return (objId << 1) | 0x01;
+	}
+
+	void BinarySerializer::decodeObjectMetaData(UINT32 encodedData, UINT32& objId)
+	{
+		if(!isObjectMetaData(encodedData))
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Meta data represents a field description but is trying to be decoded as an object descriptor.");
+		}
+
+		objId = (encodedData >> 1) & 0x7FFFFFFF;
+	}
+
+	bool BinarySerializer::isObjectMetaData(UINT32 encodedData)
+	{
+		return ((encodedData & 0x01) != 0);
+	}
+
+	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, int* bytesWritten, boost::function<UINT8*(UINT8*, int, UINT32&)> flushBufferCallback)
+	{
+		static const UINT32 COMPLEX_TYPE_FIELD_SIZE = 4; // Size of the field storing the size of a child complex type
+
+		int complexTypeSize = 0;
+		if(object != nullptr)
+			complexTypeSize = getObjectSize(object);
+
+		COPY_TO_BUFFER(&complexTypeSize, COMPLEX_TYPE_FIELD_SIZE)
+
+		if(object != nullptr)
+			return encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback);
+
+		return buffer;
+	}
+
+	IReflectable* BinarySerializer::complexTypeFromBuffer(RTTIReflectableFieldBase* field, UINT8* data, int* complexTypeSize)
+	{
+		static const int COMPLEX_TYPE_FIELD_SIZE = 4; // Size of the field storing the size of a child complex type
+
+		memcpy(complexTypeSize, data, COMPLEX_TYPE_FIELD_SIZE);
+		data += COMPLEX_TYPE_FIELD_SIZE;
+
+		IReflectable* emptyObject = nullptr;
+		if(*complexTypeSize > 0)
+		{
+			emptyObject = field->newObject();
+			UINT32 dummy = 0;
+			decodeInternal(emptyObject, data, *complexTypeSize, dummy);
+		}
+
+		*complexTypeSize += COMPLEX_TYPE_FIELD_SIZE;
+
+		return emptyObject;
+	}
+
+	UINT32 BinarySerializer::findOrCreatePersistentId(IReflectable* object)
+	{
+		UINT32 ptrAddress = (UINT32)object;
+
+		auto findIter = mObjectAddrToId.find(ptrAddress);
+		if(findIter != mObjectAddrToId.end())
+			return findIter->second;
+
+		UINT32 objId = mLastUsedObjectId++;
+		mObjectAddrToId.insert(std::make_pair(ptrAddress, objId));
+
+		return objId;
+	}
+
+	UINT32 BinarySerializer::registerObjectPtr(IReflectable* object)
+	{
+		if(object == nullptr)
+			return 0;
+
+		UINT32 ptrAddress = (UINT32)object;
+
+		auto iterFind = mObjectAddrToId.find(ptrAddress);
+		if(iterFind == mObjectAddrToId.end())
+		{
+			UINT32 objId = findOrCreatePersistentId(object);
+
+			mObjectsToEncode.push_back(ObjectToEncode(objId, object));
+			mObjectAddrToId.insert(std::make_pair(ptrAddress, objId));
+
+			return objId;
+		}
+
+		return iterFind->second;
+	}
+}
+
+#undef COPY_TO_BUFFER

+ 65 - 0
CamelotUtility/Source/CmFileSerializer.cpp

@@ -0,0 +1,65 @@
+#include "CmFileSerializer.h"
+
+#include "CmException.h"
+#include "CmIReflectable.h"
+#include "CmBinarySerializer.h"
+
+#include <numeric>
+#include <boost/bind.hpp>
+
+namespace CamelotEngine
+{
+	FileSerializer::FileSerializer()
+	{
+		mWriteBuffer = new UINT8[WRITE_BUFFER_SIZE];
+	}
+
+	FileSerializer::~FileSerializer()
+	{
+		delete[] mWriteBuffer;
+	}
+
+	void FileSerializer::encode(IReflectable* object, std::string fileLocation)
+	{
+		mOutputStream.open(fileLocation.c_str(), std::ios::out | std::ios::binary);
+
+		BinarySerializer bs;
+		int totalBytesWritten = 0;
+		bs.encode(object, mWriteBuffer, WRITE_BUFFER_SIZE, &totalBytesWritten, boost::bind(&FileSerializer::flushBuffer, this, _1, _2, _3));
+
+		mOutputStream.close();
+		mOutputStream.clear();
+	}
+
+	void FileSerializer::decode(IReflectable* object, std::string fileLocation)
+	{
+		mInputStream.open(fileLocation.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
+		
+		std::streamoff fileSize = mInputStream.tellg();
+		if(fileSize > std::numeric_limits<UINT32>::max())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"File size is larger that UINT32 can hold. Ask a programmer to use a bigger data type.");
+		}
+
+		UINT8* readBuffer = new UINT8[(UINT32)fileSize]; // TODO - Low priority. Consider upgrading BinarySerializer so we don't have to read everything at once
+
+		mInputStream.seekg(0, std::ios::beg);
+		mInputStream.read((char*)readBuffer, fileSize);
+
+		BinarySerializer bs;
+		bs.decode(object, readBuffer, (UINT32)fileSize);
+
+		mInputStream.close();
+		mInputStream.clear();
+
+		delete[] readBuffer;
+	}
+
+	UINT8* FileSerializer::flushBuffer(UINT8* bufferStart, int bytesWritten, UINT32& newBufferSize)
+	{
+		mOutputStream.write((const char*)bufferStart, bytesWritten);
+
+		return bufferStart;
+	}
+}

+ 13 - 0
CamelotUtility/Source/CmIReflectable.cpp

@@ -0,0 +1,13 @@
+#include "CmIReflectable.h"
+#include "CmException.h"
+
+namespace CamelotEngine
+{
+	IReflectable* IReflectable::newObject() 
+	{ 
+		CM_EXCEPT(InternalErrorException, 
+			"Cannot create an instance of an abstract class.");
+
+		return nullptr; 
+	} 
+}

+ 66 - 0
CamelotUtility/Source/CmRTTIField.cpp

@@ -0,0 +1,66 @@
+#include "CmRTTIField.h"
+#include "CmException.h"
+
+namespace CamelotEngine
+{
+	void RTTIField::checkIsSimple(bool array)
+	{
+		if(!isSimpleType())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Invalid field type. Needed: Simple type. Got: " + toString(mIsVectorType) + ", " + 
+				toString(isSimpleType()) + ", " + toString(isComplexType()) + ", " + toString(isDataBlockType()) + ", " + toString(isComplexPtrType()));
+		}
+
+		checkIsArray(array);
+	}
+
+	void RTTIField::checkIsDataBlock()
+	{
+		if(!isDataBlockType())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Invalid field type. Needed: Data block. Got: " + toString(mIsVectorType) + ", " + 
+				toString(isSimpleType()) + ", " + toString(isComplexType()) + ", " + toString(isDataBlockType()) + ", " + toString(isComplexPtrType()));
+		}
+	}
+
+	void RTTIField::checkIsComplex(bool array)
+	{
+		if(!isComplexType())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Invalid field type. Needed: Complex type. Got: " + toString(mIsVectorType) + ", " + 
+				toString(isSimpleType()) + ", " + toString(isComplexType()) + ", " + toString(isDataBlockType()) + ", " + toString(isComplexPtrType()));
+		}
+
+		checkIsArray(array);
+	}
+
+	void RTTIField::checkIsComplexPtr(bool array)
+	{
+		if(!isComplexPtrType())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Invalid field type. Needed: Complex ptr type. Got: " + toString(mIsVectorType) + ", " + 
+				toString(isSimpleType()) + ", " + toString(isComplexType()) + ", " + toString(isDataBlockType()) + ", " + toString(isComplexPtrType()));
+		}
+
+		checkIsArray(array);
+	}
+
+	void RTTIField::checkIsArray(bool array)
+	{
+		if(array && !mIsVectorType)
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Invalid field type. Needed an array type but got a single type.");
+		}
+
+		if(!array && mIsVectorType)
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Invalid field type. Needed a single type but got an array type.");
+		}
+	}
+}

+ 68 - 0
CamelotUtility/Source/CmRTTIType.cpp

@@ -0,0 +1,68 @@
+#include "CmRTTIType.h"
+#include "CmException.h"
+
+namespace CamelotEngine
+{
+	RTTITypeBase::RTTITypeBase()
+	{ }
+
+	RTTITypeBase::~RTTITypeBase() 
+	{
+		for(auto iter = mFields.begin(); iter != mFields.end(); ++iter)
+			delete *iter;
+
+		mFields.clear();
+	}
+
+	RTTIField* RTTITypeBase::findField(const std::string& name)
+	{
+		auto foundElement = std::find_if(mFields.begin(), mFields.end(), [&name](RTTIField* x) { return x->mName == name; });
+
+		if(foundElement == mFields.end())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Cannot find a field with the specified name: " + name);
+		}
+
+		return *foundElement;
+	}
+
+	RTTIField* RTTITypeBase::findField(int uniqueFieldId)
+	{
+		auto foundElement = std::find_if(mFields.begin(), mFields.end(), [&uniqueFieldId](RTTIField* x) { return x->mUniqueId == uniqueFieldId; });
+
+		if(foundElement == mFields.end())
+			return nullptr;
+
+		return *foundElement;
+	}
+
+	void RTTITypeBase::addNewField(RTTIField* field)
+	{
+		if(field == nullptr)
+		{
+			CM_EXCEPT(InvalidParametersException, 
+				"Field argument can't be null.");
+		}
+
+		int uniqueId = field->mUniqueId;
+		auto foundElementById = std::find_if(mFields.begin(), mFields.end(), [uniqueId](RTTIField* x) { return x->mUniqueId == uniqueId; });
+
+		if(foundElementById != mFields.end())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Field with the same ID already exists.");
+		}
+
+		std::string& name = field->mName;
+		auto foundElementByName = std::find_if(mFields.begin(), mFields.end(), [&name](RTTIField* x) { return x->mName == name; });
+
+		if(foundElementByName != mFields.end())
+		{
+			CM_EXCEPT(InternalErrorException, 
+				"Field with the same name already exists.");
+		}
+
+		mFields.push_back(field);
+	}
+}