Просмотр исходного кода

Don't record an empty managed serializable diff if no changes are detected
When loading a resource directly from UUID handle the case when resource only exists in memory
Game object handles no longer hold a redundant instance ID field which was confusing the game object renaming process during prefab diff

BearishSun 10 лет назад
Родитель
Сommit
8042c0b9e3

+ 3 - 8
BansheeCore/Include/BsGameObjectHandle.h

@@ -13,20 +13,15 @@ namespace BansheeEngine
 	struct BS_CORE_EXPORT GameObjectHandleData
 	{
 		GameObjectHandleData()
-			:mPtr(nullptr), mInstanceId(0)
+			:mPtr(nullptr)
 		{ }
 
 		GameObjectHandleData(const std::shared_ptr<GameObjectInstanceData>& ptr)
 		{
 			mPtr = ptr;
-			if(ptr != nullptr)
-				mInstanceId = ptr->object->getInstanceId();
-			else
-				mInstanceId = 0;
 		}
 
 		std::shared_ptr<GameObjectInstanceData> mPtr;
-		UINT64 mInstanceId;
 	};
 
 	/**
@@ -58,7 +53,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns the instance ID of the object the handle is referencing.
 		 */
-		UINT64 getInstanceId() const { return mData->mInstanceId; }
+		UINT64 getInstanceId() const { return mData->mPtr != nullptr ? mData->mPtr->mInstanceId : 0; }
 
 		/**
 		 * @brief	Returns pointer to the referenced GameObject.
@@ -302,7 +297,7 @@ namespace BansheeEngine
 	bool operator==(const GameObjectHandle<_Ty1>& _Left, const GameObjectHandle<_Ty2>& _Right)
 	{	
 		return (_Left.mData == nullptr && _Right.mData == nullptr) || 
-			(_Left.mData != nullptr && _Right.mData != nullptr && _Left.mData->mInstanceId == _Right.mData->mInstanceId);
+			(_Left.mData != nullptr && _Right.mData != nullptr && _Left.getInstanceId() == _Right.getInstanceId());
 	}
 
 	/**

+ 14 - 3
BansheeCore/Include/BsGameObjectHandleRTTI.h

@@ -10,8 +10,17 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT GameObjectHandleRTTI : public RTTIType<GameObjectHandleBase, IReflectable, GameObjectHandleRTTI>
 	{
 	private:
-		UINT64& getInstanceId(GameObjectHandleBase* obj) { return obj->mData->mInstanceId; }
-		void setInstanceId(GameObjectHandleBase* obj, UINT64& value) { obj->mData->mInstanceId = value; } 
+		UINT64& getInstanceId(GameObjectHandleBase* obj)
+		{
+			static UINT64 invalidId = 0;
+
+			if (obj->mData->mPtr != nullptr)
+				return obj->mData->mPtr->mInstanceId;
+
+			return invalidId;
+		}
+
+		void setInstanceId(GameObjectHandleBase* obj, UINT64& value) { obj->mRTTIData = value; } 
 
 	public:
 		GameObjectHandleRTTI()
@@ -23,7 +32,9 @@ namespace BansheeEngine
 		{
 			GameObjectHandleBase* gameObjectHandle = static_cast<GameObjectHandleBase*>(obj);
 
-			GameObjectManager::instance().registerUnresolvedHandle(*gameObjectHandle);
+			UINT64 originalInstanceId = any_cast<UINT64>(gameObjectHandle->mRTTIData);
+			GameObjectManager::instance().registerUnresolvedHandle(originalInstanceId, *gameObjectHandle);
+			gameObjectHandle->mRTTIData = nullptr;
 		}
 
 		virtual const String& getRTTIName() override

+ 12 - 3
BansheeCore/Include/BsGameObjectManager.h

@@ -33,6 +33,15 @@ namespace BansheeEngine
 	 */
 	class BS_CORE_EXPORT GameObjectManager : public Module<GameObjectManager>
 	{
+		/**
+		 * @brief	Contains data for an yet unresolved game object handle.
+		 */
+		struct UnresolvedHandle
+		{
+			UINT64 originalInstanceId;
+			GameObjectHandleBase handle;
+		};
+
 	public:
 		GameObjectManager();
 		~GameObjectManager();
@@ -123,7 +132,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Queues the specified handle and resolves it when deserialization ends.
 		 */
-		void registerUnresolvedHandle(const GameObjectHandleBase& object);
+		void registerUnresolvedHandle(UINT64 originalId, const GameObjectHandleBase& object);
 
 		/**
 		 * @brief	Registers a callback that will be triggered when GameObject serialization ends.
@@ -142,7 +151,7 @@ namespace BansheeEngine
 		 *			the newly deserialized object and its new ID. Game object deserialization
 		 *			must be active.
 		 */
-		void resolveDeserializedHandle(GameObjectHandleBase& handle, UINT32 flags);
+		void resolveDeserializedHandle(UnresolvedHandle& data, UINT32 flags);
 
 		/**
 		 * @brief	Gets the currently active flags that control how are game object handles deserialized.
@@ -157,7 +166,7 @@ namespace BansheeEngine
 		GameObject* mActiveDeserializedObject;
 		bool mIsDeserializationActive;
 		Map<UINT64, UINT64> mIdMapping;
-		Vector<GameObjectHandleBase> mUnresolvedHandles;
+		Vector<UnresolvedHandle> mUnresolvedHandles;
 		Vector<std::function<void()>> mEndCallbacks;
 		UINT32 mGODeserializationMode;
 	};

+ 51 - 15
BansheeCore/Include/BsPrefabDiffRTTI.h

@@ -85,6 +85,15 @@ namespace BansheeEngine
 
 	class BS_CORE_EXPORT PrefabDiffRTTI : public RTTIType < PrefabDiff, IReflectable, PrefabDiffRTTI >
 	{
+		/**
+		 * @brief	Contains data about a game object handle serialized in a prefab diff. 
+		 */
+		struct SerializedHandle
+		{
+			SPtr<SerializedObject> object;
+			SPtr<GameObjectHandleBase> handle;
+		};
+
 	private:
 		BS_REFLPTR_MEMBER(mRoot);
 	public:
@@ -101,15 +110,19 @@ namespace BansheeEngine
 				GameObjectManager::instance().registerOnDeserializationEndCallback(std::bind(&PrefabDiffRTTI::delayedOnDeserializationEnded, prefabDiff));
 		}
 
-		/**
-		 * @brief	Decodes GameObjectHandles from their binary format, because during deserialization GameObjectManager
-		 *			will update all object IDs and we want to keep the handles up to date.So we deserialize them
-		 *			and allow them to be updated before storing them back into binary format.
-		 */
-		static void delayedOnDeserializationEnded(PrefabDiff* prefabDiff)
+		virtual void onDeserializationEnded(IReflectable* obj) override
 		{
+			assert(GameObjectManager::instance().isGameObjectDeserializationActive());
+
+			// Make sure to deserialize all game object handles since their IDs need to be updated. Normally they are
+			// updated automatically upon deserialization but since we store them in intermediate form we need to manually
+			// deserialize and reserialize them in order to update their IDs.
+			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
+
 			Stack<SPtr<PrefabObjectDiff>> todo;
-			todo.push(prefabDiff->mRoot);
+
+			if (prefabDiff->mRoot != nullptr)
+				todo.push(prefabDiff->mRoot);
 
 			UnorderedSet<SPtr<SerializedObject>> handleObjects;
 
@@ -131,17 +144,40 @@ namespace BansheeEngine
 					todo.push(child);
 			}
 
+			Vector<SerializedHandle> handleData(handleObjects.size());
+
+			UINT32 idx = 0;
 			BinarySerializer bs;
-			for (auto& serializedHandle : handleObjects)
+			for (auto& handleObject : handleObjects)
 			{
-				SPtr<GameObjectHandleBase> handle = std::static_pointer_cast<GameObjectHandleBase>(bs._decodeIntermediate(serializedHandle));
-				if (handle != nullptr)
-				{
-					UINT32 flags = GameObjectManager::instance().getDeserializationFlags();
-					GameObjectManager::instance().resolveDeserializedHandle(*handle, flags | GODM_KeepMissing);
-					*serializedHandle = *bs._encodeIntermediate(handle.get());
-				}
+				SerializedHandle& handle = handleData[idx];
+
+				handle.object = handleObject;
+				handle.handle = std::static_pointer_cast<GameObjectHandleBase>(bs._decodeIntermediate(handleObject));
+
+				idx++;
 			}
+
+			prefabDiff->mRTTIData = handleData;
+		}
+
+		/**
+		 * @brief	Decodes GameObjectHandles from their binary format, because during deserialization GameObjectManager
+		 *			will update all object IDs and we want to keep the handles up to date.So we deserialize them
+		 *			and allow them to be updated before storing them back into binary format.
+		 */
+		static void delayedOnDeserializationEnded(PrefabDiff* prefabDiff)
+		{
+			Vector<SerializedHandle>& handleData = any_cast_ref<Vector<SerializedHandle>>(prefabDiff->mRTTIData);
+
+			BinarySerializer bs;
+			for (auto& serializedHandle : handleData)
+			{
+				if (serializedHandle.handle != nullptr)
+					*serializedHandle.object = *bs._encodeIntermediate(serializedHandle.handle.get());
+			}
+
+			prefabDiff->mRTTIData = nullptr;
 		}
 
 		/**

+ 0 - 2
BansheeCore/Source/BsGameObjectHandle.cpp

@@ -29,13 +29,11 @@ namespace BansheeEngine
 	void GameObjectHandleBase::_resolve(const GameObjectHandleBase& object) 
 	{ 
 		mData->mPtr = object.mData->mPtr;
-		mData->mInstanceId = object.mData->mInstanceId;
 	}
 
 	void GameObjectHandleBase::_setHandleData(const GameObjectPtr& object)
 	{
 		mData->mPtr = object->mInstanceData;
-		mData->mInstanceId = object->mInstanceData->mInstanceId;
 	}
 
 	void GameObjectHandleBase::throwIfDestroyed() const

+ 7 - 7
BansheeCore/Source/BsGameObjectManager.cpp

@@ -112,11 +112,11 @@ namespace BansheeEngine
 		mEndCallbacks.clear();
 	}
 
-	void GameObjectManager::resolveDeserializedHandle(GameObjectHandleBase& handle, UINT32 flags)
+	void GameObjectManager::resolveDeserializedHandle(UnresolvedHandle& data, UINT32 flags)
 	{
 		assert(mIsDeserializationActive);
 
-		UINT64 instanceId = handle.getInstanceId();
+		UINT64 instanceId = data.originalInstanceId;
 
 		bool isInternalReference = false;
 
@@ -134,17 +134,17 @@ namespace BansheeEngine
 			auto findIterObj = mObjects.find(instanceId);
 
 			if (findIterObj != mObjects.end())
-				handle._resolve(findIterObj->second);
+				data.handle._resolve(findIterObj->second);
 			else
 			{
 				if ((flags & GODM_KeepMissing) == 0)
-					handle._resolve(nullptr);
+					data.handle._resolve(nullptr);
 			}
 		}
 		else
 		{
 			if ((flags & GODM_KeepMissing) == 0)
-				handle._resolve(nullptr);
+				data.handle._resolve(nullptr);
 		}
 	}
 
@@ -160,7 +160,7 @@ namespace BansheeEngine
 		mIdMapping[serializedId] = actualId;
 	}
 
-	void GameObjectManager::registerUnresolvedHandle(const GameObjectHandleBase& object)
+	void GameObjectManager::registerUnresolvedHandle(UINT64 originalId, const GameObjectHandleBase& object)
 	{
 #if BS_DEBUG_MODE
 		if(!mIsDeserializationActive)
@@ -169,7 +169,7 @@ namespace BansheeEngine
 		}
 #endif
 
-		mUnresolvedHandles.push_back(object);
+		mUnresolvedHandles.push_back({ originalId, object });
 	}
 
 	void GameObjectManager::registerOnDeserializationEndCallback(std::function<void()> callback)

+ 3 - 0
BansheeCore/Source/BsPrefabDiff.cpp

@@ -189,6 +189,9 @@ namespace BansheeEngine
 		{
 			HSceneObject instanceChild = instance->getChild(i);
 
+			if (instanceChild->hasFlag(SOF_DontSave))
+				continue;
+
 			bool foundMatching = false;
 			if (instanceChild->getLinkId() != -1)
 			{

+ 14 - 16
BansheeCore/Source/BsResources.cpp

@@ -58,27 +58,13 @@ namespace BansheeEngine
 	HResource Resources::loadFromUUID(const String& uuid, bool async, bool loadDependencies)
 	{
 		Path filePath;
-		bool foundPath = false;
 
 		// Default manifest is at 0th index but all other take priority since Default manifest could
 		// contain obsolete data. 
 		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
 		{
 			if((*iter)->uuidToFilePath(uuid, filePath))
-			{
-				foundPath = true;
 				break;
-			}
-		}
-
-		if (!foundPath)
-		{
-			gDebug().logWarning("Cannot load resource. Resource with UUID '" + uuid + "' doesn't exist.");
-
-			HResource outputResource(uuid);
-			loadComplete(outputResource);
-
-			return outputResource;
 		}
 
 		return loadInternal(uuid, filePath, !async, loadDependencies);
@@ -128,9 +114,21 @@ namespace BansheeEngine
 
 		// We have nowhere to load from, warn and complete load if a file path was provided,
 		// otherwise pass through as we might just want to load from memory. 
-		if (!filePath.isEmpty() && !FileSystem::isFile(filePath))
+		if (filePath.isEmpty())
+		{
+			if (!alreadyLoading)
+			{
+				gDebug().logWarning("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist.");
+
+				// Complete the load as that the depedency counter is properly reduced, in case this 
+				// is a dependency of some other resource.
+				loadComplete(outputResource);
+				return outputResource;
+			}
+		}
+		else if (!FileSystem::isFile(filePath))
 		{
-			LOGWRN("Specified file: " + filePath.toString() + " doesn't exist.");
+			LOGWRN("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
 
 			// Complete the load as that the depedency counter is properly reduced, in case this 
 			// is a dependency of some other resource.

+ 27 - 27
SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h

@@ -47,18 +47,18 @@ namespace BansheeEngine
 				&ManagedSerializableAssemblyInfoRTTI::setSerializableObjectInfoArraySize);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableAssemblyInfo";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableAssemblyInfo;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableAssemblyInfo>();
 		}
@@ -116,18 +116,18 @@ namespace BansheeEngine
 				&ManagedSerializableObjectInfoRTTI::setSerializableFieldInfoArraySize);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableObjectInfo";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableObjectInfo;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableObjectInfo>();
 		}
@@ -196,18 +196,18 @@ namespace BansheeEngine
 			addPlainField("mParentTypeId", 4, &ManagedSerializableFieldInfoRTTI::getParentTypeId, &ManagedSerializableFieldInfoRTTI::setParentTypeId);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableFieldInfo";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableFieldInfo;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableFieldInfo>();
 		}
@@ -223,18 +223,18 @@ namespace BansheeEngine
 
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableTypeInfo";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableTypeInfo;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			BS_EXCEPT(InvalidStateException, "Cannot instantiate an abstract class");
 		}
@@ -259,18 +259,18 @@ namespace BansheeEngine
 			addPlainField("mType", 0, &ManagedSerializableTypeInfoPrimitiveRTTI::getType, &ManagedSerializableTypeInfoPrimitiveRTTI::setType);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableTypeInfoPrimitive";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableTypeInfoPrimitive;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableTypeInfoPrimitive>();
 		}
@@ -328,18 +328,18 @@ namespace BansheeEngine
 			addPlainField("mTypeId", 3, &ManagedSerializableTypeInfoObjectRTTI::getIsValueType, &ManagedSerializableTypeInfoObjectRTTI::setIsValueType);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableTypeInfoObject";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableTypeInfoObject;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableTypeInfoObject>();
 		}
@@ -375,18 +375,18 @@ namespace BansheeEngine
 			addPlainField("mRank", 1, &ManagedSerializableTypeInfoArrayRTTI::getRank, &ManagedSerializableTypeInfoArrayRTTI::setRank);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableTypeInfoArray";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableTypeInfoArray;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableTypeInfoArray>();
 		}
@@ -411,18 +411,18 @@ namespace BansheeEngine
 			addReflectablePtrField("mElementType", 0, &ManagedSerializableTypeInfoListRTTI::getElementType, &ManagedSerializableTypeInfoListRTTI::setElementType);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableTypeInfoList";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableTypeInfoList;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableTypeInfoList>();
 		}
@@ -458,18 +458,18 @@ namespace BansheeEngine
 			addReflectablePtrField("mValueType", 1, &ManagedSerializableTypeInfoDictionaryRTTI::getValueType, &ManagedSerializableTypeInfoDictionaryRTTI::setValueType);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableTypeInfoDictionary";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_SerializableTypeInfoDictionary;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<ManagedSerializableTypeInfoDictionary>();
 		}

+ 9 - 3
SBansheeEngine/Source/BsManagedDiff.cpp

@@ -54,9 +54,15 @@ namespace BansheeEngine
 		SPtr<SerializedField> field = std::static_pointer_cast<SerializedField>(serzDiff->subObjects[0].entries[0].serialized);
 
 		MemorySerializer ms;
-		ManagedSerializableDiffPtr diff = std::static_pointer_cast<ManagedSerializableDiff>(ms.decode(field->value, field->size));
+		ManagedSerializableDiffPtr diff;
+		
+		if (field->size > 0)
+			diff = std::static_pointer_cast<ManagedSerializableDiff>(ms.decode(field->value, field->size));
 
-		SPtr<ManagedSerializableObject> managedObj = std::static_pointer_cast<ManagedSerializableObject>(object);
-		diff->apply(managedObj);
+		if (diff != nullptr)
+		{
+			SPtr<ManagedSerializableObject> managedObj = std::static_pointer_cast<ManagedSerializableObject>(object);
+			diff->apply(managedObj);
+		}
 	}
 }

+ 7 - 4
SBansheeEngine/Source/BsManagedSerializableDiff.cpp

@@ -157,16 +157,19 @@ namespace BansheeEngine
 		ManagedSerializableObjectInfoPtr oldObjInfo = oldObj->getObjectInfo();
 		ManagedSerializableObjectInfoPtr newObjInfo = newObj->getObjectInfo();
 
-		ManagedSerializableDiffPtr output = bs_shared_ptr_new<ManagedSerializableDiff>();
 		if (!oldObjInfo->mTypeInfo->matches(newObjInfo->mTypeInfo))
-			return output;
+			return nullptr;
 
+		ManagedSerializableDiffPtr output = bs_shared_ptr_new<ManagedSerializableDiff>();
 		SPtr<ModifiedObject> modifications = output->generateDiff(oldObj, newObj);
 
 		if (modifications != nullptr)
+		{
 			output->mModificationRoot->entries = modifications->entries;
-
-		return output;
+			return output;
+		}
+		
+		return nullptr;
 	}
 
 	SPtr<ManagedSerializableDiff::ModifiedObject> ManagedSerializableDiff::generateDiff