Prechádzať zdrojové kódy

Modified serialization so it no longers need to calculate complex object size so prevent issues with objects that require pre- and post-serialization steps
Fixed GUIListBox so it properly handles non-multiselect values with index 0
Fixed dialog box so it doesn't create GUI twice

BearishSun 10 rokov pred
rodič
commit
f8912549b8

+ 5 - 0
BansheeEditor/Include/BsGUIListBoxField.h

@@ -175,6 +175,11 @@ namespace BansheeEngine
 		GUIListBoxField(const PrivatelyConstruct& dummy, const Vector<HString>& elements, bool multiselect, 
 		GUIListBoxField(const PrivatelyConstruct& dummy, const Vector<HString>& elements, bool multiselect, 
 			const GUIContent& labelContent, UINT32 labelWidth, const String& style, const GUIDimensions& dimensions, bool withLabel);
 			const GUIContent& labelContent, UINT32 labelWidth, const String& style, const GUIDimensions& dimensions, bool withLabel);
 
 
+		/**
+		 * @brief	Checks whether the listbox supports multiple selected elements at once.
+		 */
+		bool isMultiselect() const;
+
 		/**
 		/**
 		 * @brief	Changes the list box elements.
 		 * @brief	Changes the list box elements.
 		 */
 		 */

+ 5 - 0
BansheeEditor/Source/BsGUIListBoxField.cpp

@@ -146,6 +146,11 @@ namespace BansheeEngine
 			GUIDimensions::create(), false);
 			GUIDimensions::create(), false);
 	}
 	}
 
 
+	bool GUIListBoxField::isMultiselect() const
+	{
+		return mListBox->isMultiselect();
+	}
+
 	void GUIListBoxField::setElements(const Vector<HString>& elements)
 	void GUIListBoxField::setElements(const Vector<HString>& elements)
 	{
 	{
 		mListBox->setElements(elements);
 		mListBox->setElements(elements);

+ 5 - 0
BansheeEngine/Include/BsGUIListBox.h

@@ -59,6 +59,11 @@ namespace BansheeEngine
 		static GUIListBox* create(const Vector<HString>& elements, const GUIOptions& options, 
 		static GUIListBox* create(const Vector<HString>& elements, const GUIOptions& options, 
 			const String& styleName = StringUtil::BLANK);
 			const String& styleName = StringUtil::BLANK);
 
 
+		/**
+		 * @brief	Checks whether the listbox supports multiple selected elements at once.
+		 */
+		bool isMultiselect() const { return mIsMultiselect; }
+
 		/**
 		/**
 		 * @brief	Changes the list box elements.
 		 * @brief	Changes the list box elements.
 		 */
 		 */

+ 4 - 8
BansheeUtility/Include/BsBinarySerializer.h

@@ -129,12 +129,6 @@ namespace BansheeEngine
 			bool isDecoded;
 			bool isDecoded;
 		};
 		};
 
 
-		/**
-		 * @brief	Parses the entire object and calculates total size required for
-		 *			saving the object and all the objects it contains.
-		 */
-		UINT32 getObjectSize(IReflectable* object);
-
 		/**
 		/**
 		 * @brief	Encodes a single IReflectable object. 
 		 * @brief	Encodes a single IReflectable object. 
 		 */
 		 */
@@ -178,12 +172,14 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Encodes data required for representing a serialized field, into 4 bytes.
 		 * @brief	Encodes data required for representing a serialized field, into 4 bytes.
 		 */
 		 */
-		static UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type, bool hasDynamicSize);
+		static UINT32 encodeFieldMetaData(UINT16 id, UINT8 size, bool array, 
+			SerializableFieldType type, bool hasDynamicSize, bool terminator);
 
 
 		/**
 		/**
 		 * @brief	Decode meta field that was encoded using encodeFieldMetaData.
 		 * @brief	Decode meta field that was encoded using encodeFieldMetaData.
 		 */
 		 */
-		static void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, SerializableFieldType& type, bool& hasDynamicSize);
+		static void decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, bool& array, 
+			SerializableFieldType& type, bool& hasDynamicSize, bool& terminator);
 
 
 		/**
 		/**
 		 * @brief	Encodes data required for representing an object identifier, into 8 bytes.
 		 * @brief	Encodes data required for representing an object identifier, into 8 bytes.

+ 44 - 185
BansheeUtility/Source/BsBinarySerializer.cpp

@@ -183,7 +183,7 @@ namespace BansheeEngine
 
 
 				// Copy field ID & other meta-data like field size and type
 				// Copy field ID & other meta-data like field size and type
 				int metaData = encodeFieldMetaData(curGenericField->mUniqueId, curGenericField->getTypeSize(), 
 				int metaData = encodeFieldMetaData(curGenericField->mUniqueId, curGenericField->getTypeSize(), 
-					curGenericField->mIsVectorType, curGenericField->mType, curGenericField->hasDynamicSize());
+					curGenericField->mIsVectorType, curGenericField->mType, curGenericField->hasDynamicSize(), false);
 				COPY_TO_BUFFER(&metaData, META_SIZE)
 				COPY_TO_BUFFER(&metaData, META_SIZE)
 
 
 				if(curGenericField->mIsVectorType)
 				if(curGenericField->mIsVectorType)
@@ -478,7 +478,7 @@ namespace BansheeEngine
 
 
 			memcpy((void*)&metaData, data, META_SIZE);
 			memcpy((void*)&metaData, data, META_SIZE);
 
 
-			if (isObjectMetaData(metaData)) // We've reached a new object
+			if (isObjectMetaData(metaData)) // We've reached a new object or a base class of the current one
 			{
 			{
 				if ((bytesRead + sizeof(ObjectMetaData)) > dataLength)
 				if ((bytesRead + sizeof(ObjectMetaData)) > dataLength)
 				{
 				{
@@ -522,12 +522,8 @@ namespace BansheeEngine
 				}
 				}
 				else
 				else
 				{
 				{
-					if (objId != 0)
-						return true;
-
-					// Objects with ID == 0 represent complex types serialized by value, but they should only get serialized
-					// if we encounter a field with one, not by just iterating through the file.
-					BS_EXCEPT(InternalErrorException, "Object with ID 0 encountered. Cannot proceed with serialization.");
+					// Found new object, we're done
+					return true;
 				}
 				}
 			}
 			}
 
 
@@ -539,7 +535,16 @@ namespace BansheeEngine
 			UINT16 fieldId;
 			UINT16 fieldId;
 			UINT8 fieldSize;
 			UINT8 fieldSize;
 			bool hasDynamicSize;
 			bool hasDynamicSize;
-			decodeFieldMetaData(metaData, fieldId, fieldSize, isArray, fieldType, hasDynamicSize);
+			bool terminator;
+			decodeFieldMetaData(metaData, fieldId, fieldSize, isArray, fieldType, hasDynamicSize, terminator);
+
+			if (terminator)
+			{
+				// We've processed the last field in this object, so return. Although we return false we don't actually know
+				// if there is an object following this one. However it doesn't matter since terminator fields are only used 
+				// for embedded objects that are all processed within this method so we can compensate.
+				return false;
+			}
 
 
 			RTTIField* curGenericField = nullptr;
 			RTTIField* curGenericField = nullptr;
 
 
@@ -645,32 +650,21 @@ namespace BansheeEngine
 
 
 					for (int i = 0; i < arrayNumElems; i++)
 					for (int i = 0; i < arrayNumElems; i++)
 					{
 					{
-						if ((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
-						{
-							BS_EXCEPT(InternalErrorException,
-								"Error decoding data.");
-						}
-
-						UINT32 complexTypeSize = 0;
-						memcpy(&complexTypeSize, data, COMPLEX_TYPE_FIELD_SIZE);
-						data += COMPLEX_TYPE_FIELD_SIZE;
-						bytesRead += COMPLEX_TYPE_FIELD_SIZE;
-
-						if (curField != nullptr && complexTypeSize > 0)
+						if (curField != nullptr)
 						{
 						{
-							UINT32 dummy = 0;
+							UINT32 bytesReadStart = bytesRead;
 							SPtr<SerializedObject> serializedArrayEntry;
 							SPtr<SerializedObject> serializedArrayEntry;
-							decodeIntermediateInternal(data, complexTypeSize, dummy, serializedArrayEntry, copyData);
+							decodeIntermediateInternal(data, dataLength, bytesRead, serializedArrayEntry, copyData);
 
 
 							SerializedArrayEntry arrayEntry;
 							SerializedArrayEntry arrayEntry;
 							arrayEntry.serialized = serializedArrayEntry;
 							arrayEntry.serialized = serializedArrayEntry;
 							arrayEntry.index = i;
 							arrayEntry.index = i;
 
 
 							serializedArray->entries[i] = arrayEntry;
 							serializedArray->entries[i] = arrayEntry;
-						}
 
 
-						data += complexTypeSize;
-						bytesRead += complexTypeSize;
+							UINT32 complexTypeSize = bytesRead - bytesReadStart;
+							data += complexTypeSize;
+						}
 					}
 					}
 					break;
 					break;
 				}
 				}
@@ -762,30 +756,18 @@ namespace BansheeEngine
 				{
 				{
 					RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
 					RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
 
 
-					if ((bytesRead + COMPLEX_TYPE_FIELD_SIZE) > dataLength)
-					{
-						BS_EXCEPT(InternalErrorException,
-							"Error decoding data.");
-					}
-
-					UINT32 complexTypeSize = 0;
-					memcpy(&complexTypeSize, data, COMPLEX_TYPE_FIELD_SIZE);
-					data += COMPLEX_TYPE_FIELD_SIZE;
-					bytesRead += COMPLEX_TYPE_FIELD_SIZE;
-
-					if (curField != nullptr && complexTypeSize > 0)
+					if (curField != nullptr)
 					{
 					{
-						UINT32 dummy = 0;
-
+						UINT32 bytesReadStart = bytesRead;
 						SPtr<SerializedObject> serializedChildObj;
 						SPtr<SerializedObject> serializedChildObj;
-						decodeIntermediateInternal(data, complexTypeSize, dummy, serializedChildObj, copyData);
+						decodeIntermediateInternal(data, dataLength, bytesRead, serializedChildObj, copyData);
 
 
 						serializedEntry = serializedChildObj;
 						serializedEntry = serializedChildObj;
 						hasModification = true;
 						hasModification = true;
-					}
 
 
-					data += complexTypeSize;
-					bytesRead += complexTypeSize;
+						UINT32 complexTypeSize = bytesRead - bytesReadStart;
+						data += complexTypeSize;
+					}
 
 
 					break;
 					break;
 				}
 				}
@@ -1094,140 +1076,11 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	// TODO - This needs serious fixing, it doesn't account for all properties
-	UINT32 BinarySerializer::getObjectSize(IReflectable* object)
-	{
-		if(object == nullptr)
-			return 0;
-
-		UINT32 objectSize = 0;
-		RTTITypeBase* si = object->getRTTI();
-
-		do 
-		{
-			// Object ID + type data
-			objectSize += sizeof(ObjectMetaData);
-
-			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 += sizeof(UINT32); // Complex type size
-									objectSize += getObjectSize(&childObject);
-								}
-
-								break;
-							}
-						case SerializableFT_Plain:
-							{
-								RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-								for(UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
-								{
-									UINT32 typeSize = 0;
-									if(curField->hasDynamicSize())
-										typeSize = curField->getArrayElemDynamicSize(object, arrIdx);
-									else
-										typeSize = curField->getTypeSize();
-
-									objectSize += typeSize;
-								}
-
-								break;
-							}
-						default:
-							BS_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 += sizeof(UINT32); // Complex type size
-							objectSize += getObjectSize(&childObject);
-
-							break;
-						}
-					case SerializableFT_Plain:
-						{
-							RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
-
-							UINT32 typeSize = 0;
-							if(curField->hasDynamicSize())
-								typeSize = curField->getDynamicSize(object);
-							else
-								typeSize = curField->getTypeSize();
-
-							objectSize += typeSize;
-
-							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:
-						BS_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));
-					}
-				}
-			}
-
-			si = si->getBaseClass();
-
-		} while (si != nullptr);
-
-		return objectSize;
-	}
-
-	UINT32 BinarySerializer::encodeFieldMetaData(UINT16 id, UINT8 size, bool array, SerializableFieldType type, bool hasDynamicSize)
+	UINT32 BinarySerializer::encodeFieldMetaData(UINT16 id, UINT8 size, bool array, 
+		SerializableFieldType type, bool hasDynamicSize, bool terminator)
 	{
 	{
 		// If O == 0 - Meta contains field information (Encoded using this method)
 		// If O == 0 - Meta contains field information (Encoded using this method)
-		//// Encoding: IIII IIII IIII IIII SSSS SSSS xxYP DCAO
+		//// Encoding: IIII IIII IIII IIII SSSS SSSS xTYP DCAO
 		//// I - Id
 		//// I - Id
 		//// S - Size
 		//// S - Size
 		//// C - Complex
 		//// C - Complex
@@ -1236,16 +1089,19 @@ namespace BansheeEngine
 		//// P - Complex ptr
 		//// P - Complex ptr
 		//// O - Object descriptor
 		//// O - Object descriptor
 		//// Y - Plain field has dynamic size
 		//// Y - Plain field has dynamic size
+		//// T - Terminator (last field in an object)
 
 
 		return (id << 16 | size << 8 | 
 		return (id << 16 | size << 8 | 
 			(array ? 0x02 : 0) | 
 			(array ? 0x02 : 0) | 
 			((type == SerializableFT_DataBlock) ? 0x04 : 0) | 
 			((type == SerializableFT_DataBlock) ? 0x04 : 0) | 
 			((type == SerializableFT_Reflectable) ? 0x08 : 0) | 
 			((type == SerializableFT_Reflectable) ? 0x08 : 0) | 
 			((type == SerializableFT_ReflectablePtr) ? 0x10 : 0) | 
 			((type == SerializableFT_ReflectablePtr) ? 0x10 : 0) | 
-			(hasDynamicSize ? 0x20 : 0)); // TODO - Low priority. Technically I could encode this much more tightly, and use var-ints for ID
+			(hasDynamicSize ? 0x20 : 0) |
+			(terminator ? 0x40 : 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, bool& hasDynamicSize)
+	void BinarySerializer::decodeFieldMetaData(UINT32 encodedData, UINT16& id, UINT8& size, 
+		bool& array, SerializableFieldType& type, bool& hasDynamicSize, bool& terminator)
 	{
 	{
 		if(isObjectMetaData(encodedData))
 		if(isObjectMetaData(encodedData))
 		{
 		{
@@ -1253,6 +1109,7 @@ namespace BansheeEngine
 				"Meta data represents an object description but is trying to be decoded as a field descriptor.");
 				"Meta data represents an object description but is trying to be decoded as a field descriptor.");
 		}
 		}
 
 
+		terminator = (encodedData & 0x40) != 0;
 		hasDynamicSize = (encodedData & 0x20) != 0;
 		hasDynamicSize = (encodedData & 0x20) != 0;
 
 
 		if((encodedData & 0x10) != 0)
 		if((encodedData & 0x10) != 0)
@@ -1309,14 +1166,16 @@ namespace BansheeEngine
 	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, 
 	UINT8* BinarySerializer::complexTypeToBuffer(IReflectable* object, UINT8* buffer, UINT32& bufferLength, 
 		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
 		UINT32* bytesWritten, std::function<UINT8*(UINT8*, UINT32, UINT32&)> flushBufferCallback, bool shallow)
 	{
 	{
-		int complexTypeSize = 0;
-		if(object != nullptr)
-			complexTypeSize = getObjectSize(object);
-
-		COPY_TO_BUFFER(&complexTypeSize, COMPLEX_TYPE_FIELD_SIZE)
+		if (object != nullptr)
+		{
+			buffer = encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
 
 
-		if(object != nullptr)
-			return encodeInternal(object, 0, buffer, bufferLength, bytesWritten, flushBufferCallback, shallow);
+			// Encode terminator field
+			// Complex types require terminator fields because they can be embedded within other complex types and we need
+			// to know when their fields end and parent's resume
+			int metaData = encodeFieldMetaData(0, 0, false, SerializableFT_Plain, false, true);
+			COPY_TO_BUFFER(&metaData, META_SIZE)
+		}
 
 
 		return buffer;
 		return buffer;
 	}
 	}

+ 0 - 8
MBansheeEditor/DialogBox.cs

@@ -45,7 +45,6 @@ namespace BansheeEditor
 
 
         private GUILabel messageLabel;
         private GUILabel messageLabel;
         private ResultType result = ResultType.None;
         private ResultType result = ResultType.None;
-        private bool constructed;
 
 
         /// <summary>
         /// <summary>
         /// Button that was pressed when the dialog box was closed. Only valid after the user closes the dialog box.
         /// Button that was pressed when the dialog box was closed. Only valid after the user closes the dialog box.
@@ -81,7 +80,6 @@ namespace BansheeEditor
             this.resultCallback = resultCallback;
             this.resultCallback = resultCallback;
             this.type = type;
             this.type = type;
 
 
-            constructed = true;
             SetupGUI();
             SetupGUI();
 
 
             Title = title;
             Title = title;
@@ -91,12 +89,6 @@ namespace BansheeEditor
             Height = messageLabel.Bounds.height + 60;
             Height = messageLabel.Bounds.height + 60;
         }
         }
 
 
-        private void OnInitialize()
-        {
-            if (constructed)
-                SetupGUI();
-        }
-
         private void OnEditorUpdate()
         private void OnEditorUpdate()
         {
         {
             if (Input.IsButtonDown(ButtonCode.Return))
             if (Input.IsButtonDown(ButtonCode.Return))

+ 11 - 2
SBansheeEditor/Source/BsScriptGUIEnumField.cpp

@@ -131,8 +131,17 @@ namespace BansheeEngine
 
 
 		const Vector<UINT64>& values = nativeInstance->mValues;
 		const Vector<UINT64>& values = nativeInstance->mValues;
 		Vector<bool> states = field->getElementStates();
 		Vector<bool> states = field->getElementStates();
-		for (UINT32 i = 0; i < (UINT32)values.size(); i++)
-			states[i] = (values[i] & value) == values[i];
+
+		if (field->isMultiselect())
+		{
+			for (UINT32 i = 0; i < (UINT32)values.size(); i++)
+				states[i] = (values[i] & value) == values[i];
+		}
+		else
+		{
+			for (UINT32 i = 0; i < (UINT32)values.size(); i++)
+				states[i] = values[i] == value;
+		}
 
 
 		field->setElementStates(states);
 		field->setElementStates(states);
 	}
 	}