Explorar o código

Nested prefab instances now have a link ID assigned by their parent
Clear obsolete prefab diffs when saving scene or breaking prefab
updateFromPrefab will now set parents only after everything is instantiated so that prefabs lower in the hierarchy wont get destroyed by their parents

BearishSun %!s(int64=10) %!d(string=hai) anos
pai
achega
24df064285

+ 3 - 3
BansheeCore/Include/BsGameObjectRTTI.h

@@ -40,18 +40,18 @@ namespace BansheeEngine
 			addPlainField("mLinkId", 2, &GameObjectRTTI::getLinkId, &GameObjectRTTI::setLinkId);
 			addPlainField("mLinkId", 2, &GameObjectRTTI::getLinkId, &GameObjectRTTI::setLinkId);
 		}
 		}
 
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 		{
 			static String name = "GameObject";
 			static String name = "GameObject";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_GameObject;
 			return TID_GameObject;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
 			BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class.");
 			BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class.");
 		}
 		}

+ 5 - 2
BansheeCore/Include/BsPrefabUtility.h

@@ -97,12 +97,15 @@ namespace BansheeEngine
 		 * @brief	Restores instance data in the provided hierarchy, using link ids to determine
 		 * @brief	Restores instance data in the provided hierarchy, using link ids to determine
 		 *			what data maps to which objects. 
 		 *			what data maps to which objects. 
 		 *
 		 *
-		 * @param[in]	so					Object to traverse and restore the instance data.
+		 * @param[in]	so		Object to traverse and restore the instance data.
+		 * @param[in]	proxy	Hierarchy containing instance data for all objects and components, returned by
+		 *						"recordInstanceData" method.				
 		 * @param[in]	linkedInstanceData	A map of link IDs to instance data, returned by "recordInstanceData" method.
 		 * @param[in]	linkedInstanceData	A map of link IDs to instance data, returned by "recordInstanceData" method.
 		 *
 		 *
 		 * @note	Does not recurse into child prefab instances.
 		 * @note	Does not recurse into child prefab instances.
 		 */
 		 */
-		static void restoreLinkedInstanceData(const HSceneObject& so, UnorderedMap<UINT32, GameObjectInstanceDataPtr>& linkedInstanceData);
+		static void restoreLinkedInstanceData(const HSceneObject& so, SceneObjectProxy& proxy, 
+			UnorderedMap<UINT32, GameObjectInstanceDataPtr>& linkedInstanceData);
 
 
 		/**
 		/**
 		 * @brief	Restores instance data in the provided hierarchy, but only for objects without a link id.
 		 * @brief	Restores instance data in the provided hierarchy, but only for objects without a link id.

+ 76 - 38
BansheeCore/Source/BsPrefabDiff.cpp

@@ -29,9 +29,12 @@ namespace BansheeEngine
 
 
 	SPtr<PrefabDiff> PrefabDiff::create(const HSceneObject& prefab, const HSceneObject& instance)
 	SPtr<PrefabDiff> PrefabDiff::create(const HSceneObject& prefab, const HSceneObject& instance)
 	{
 	{
-		if (prefab->mPrefabLinkUUID != instance->mPrefabLinkUUID || prefab->getLinkId() != instance->getLinkId())
+		if (prefab->mPrefabLinkUUID != instance->mPrefabLinkUUID)
 			return nullptr;
 			return nullptr;
 
 
+		// Note: If this method is called multiple times in a row then renaming all objects every time is redundant, it
+		// would be more efficient to do it once outside of this method. I'm keeping it this way for simplicity for now.
+
 		Vector<RenamedGameObject> renamedObjects;
 		Vector<RenamedGameObject> renamedObjects;
 		renameInstanceIds(prefab, instance, renamedObjects);
 		renameInstanceIds(prefab, instance, renamedObjects);
 
 
@@ -55,9 +58,6 @@ namespace BansheeEngine
 
 
 	void PrefabDiff::applyDiff(const SPtr<PrefabObjectDiff>& diff, const HSceneObject& object)
 	void PrefabDiff::applyDiff(const SPtr<PrefabObjectDiff>& diff, const HSceneObject& object)
 	{
 	{
-		if (diff->id != object->getLinkId())
-			return;
-
 		object->setName(diff->name);
 		object->setName(diff->name);
 
 
 		// Note: It is important to remove objects and components first, before adding them.
 		// Note: It is important to remove objects and components first, before adding them.
@@ -159,7 +159,9 @@ namespace BansheeEngine
 
 
 				if (prefabChild->getLinkId() == instanceChild->getLinkId())
 				if (prefabChild->getLinkId() == instanceChild->getLinkId())
 				{
 				{
-					childDiff = generateDiff(prefabChild, instanceChild);
+					if (instanceChild->mPrefabLinkUUID.empty())
+						childDiff = generateDiff(prefabChild, instanceChild);
+
 					foundMatching = true;
 					foundMatching = true;
 					break;
 					break;
 				}
 				}
@@ -319,73 +321,109 @@ namespace BansheeEngine
 
 
 	void PrefabDiff::renameInstanceIds(const HSceneObject& prefab, const HSceneObject& instance, Vector<RenamedGameObject>& output)
 	void PrefabDiff::renameInstanceIds(const HSceneObject& prefab, const HSceneObject& instance, Vector<RenamedGameObject>& output)
 	{
 	{
-		UnorderedMap<UINT32, UINT64> linkToInstanceId;
+		UnorderedMap<String, UnorderedMap<UINT32, UINT64>> linkToInstanceId;
+
+		struct StackEntry
+		{
+			HSceneObject so;
+			String uuid;
+		};
+
+		Stack<StackEntry> todo;
+		todo.push({ prefab, "root" });
 
 
-		Stack<HSceneObject> todo;
-		todo.push(prefab);
 		while (!todo.empty())
 		while (!todo.empty())
 		{
 		{
-			HSceneObject current = todo.top();
+			StackEntry current = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			linkToInstanceId[current->getLinkId()] = current->getInstanceId();
+			UnorderedMap<UINT32, UINT64>& parentIdMap = linkToInstanceId[current.uuid];
+			parentIdMap[current.so->getLinkId()] = current.so->getInstanceId();
+
+			// SceneObject's link ID belongs to the parent prefab, but components belong to current one
+			UnorderedMap<UINT32, UINT64>* idMap = &parentIdMap;
+			if (!current.so->mPrefabLinkUUID.empty())
+				idMap = &linkToInstanceId[current.so->mPrefabLinkUUID];
 
 
-			const Vector<HComponent>& components = current->getComponents();
+			const Vector<HComponent>& components = current.so->getComponents();
 			for (auto& component : components)
 			for (auto& component : components)
-				linkToInstanceId[component->getLinkId()] = component->getInstanceId();
+				(*idMap)[component->getLinkId()] = component->getInstanceId();
 
 
-			UINT32 numChildren = current->getNumChildren();
+			UINT32 numChildren = current.so->getNumChildren();
 			for (UINT32 i = 0; i < numChildren; i++)
 			for (UINT32 i = 0; i < numChildren; i++)
 			{
 			{
-				HSceneObject child = current->getChild(i);
+				HSceneObject child = current.so->getChild(i);
 
 
-				if (child->mPrefabLinkUUID.empty())
-					todo.push(child);
+				if (current.so->mPrefabLinkUUID.empty())
+					todo.push({ child, current.uuid });
+				else
+					todo.push({ child, current.so->mPrefabLinkUUID });
 			}
 			}
 		}
 		}
 
 
-		todo.push(instance);
+		todo.push({ instance, "root" });
 		while (!todo.empty())
 		while (!todo.empty())
 		{
 		{
-			HSceneObject current = todo.top();
+			StackEntry current = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			if (current->getLinkId() != -1)
+			auto iterFind = linkToInstanceId.find(current.uuid);
+			UnorderedMap<UINT32, UINT64>* idMap = nullptr;
+			if (iterFind != linkToInstanceId.end())
 			{
 			{
-				auto iterFind = linkToInstanceId.find(current->getLinkId());
-				if (iterFind != linkToInstanceId.end())
+				UnorderedMap<UINT32, UINT64>& parentIdMap = iterFind->second;
+
+				if (current.so->getLinkId() != -1)
 				{
 				{
-					output.push_back(RenamedGameObject());
-					RenamedGameObject& renamedGO = output.back();
-					renamedGO.instanceData = current->mInstanceData;
-					renamedGO.originalId = current->getInstanceId();
+					auto iterFind2 = parentIdMap.find(current.so->getLinkId());
+					if (iterFind2 != parentIdMap.end())
+					{
+						output.push_back(RenamedGameObject());
+						RenamedGameObject& renamedGO = output.back();
+						renamedGO.instanceData = current.so->mInstanceData;
+						renamedGO.originalId = current.so->getInstanceId();
 
 
-					current->mInstanceData->mInstanceId = iterFind->second;
+						current.so->mInstanceData->mInstanceId = iterFind2->second;
+					}
 				}
 				}
+
+				if (current.so->mPrefabLinkUUID.empty())
+					idMap = &parentIdMap;
 			}
 			}
 
 
-			const Vector<HComponent>& components = current->getComponents();
-			for (auto& component : components)
+			if (idMap == nullptr && !current.so->mPrefabLinkUUID.empty())
 			{
 			{
-				auto iterFind = linkToInstanceId.find(component->getLinkId());
-				if (iterFind != linkToInstanceId.end())
+				auto iterFind3 = linkToInstanceId.find(current.so->mPrefabLinkUUID);
+				idMap = &iterFind3->second;
+			}
+
+			if (idMap != nullptr)
+			{
+				const Vector<HComponent>& components = current.so->getComponents();
+				for (auto& component : components)
 				{
 				{
-					output.push_back(RenamedGameObject());
-					RenamedGameObject& renamedGO = output.back();
-					renamedGO.instanceData = component->mInstanceData;
-					renamedGO.originalId = component->getInstanceId();
+					auto iterFind2 = idMap->find(component->getLinkId());
+					if (iterFind2 != idMap->end())
+					{
+						output.push_back(RenamedGameObject());
+						RenamedGameObject& renamedGO = output.back();
+						renamedGO.instanceData = component->mInstanceData;
+						renamedGO.originalId = component->getInstanceId();
 
 
-					component->mInstanceData->mInstanceId = iterFind->second;
+						component->mInstanceData->mInstanceId = iterFind2->second;
+					}
 				}
 				}
 			}
 			}
 
 
-			UINT32 numChildren = current->getNumChildren();
+			UINT32 numChildren = current.so->getNumChildren();
 			for (UINT32 i = 0; i < numChildren; i++)
 			for (UINT32 i = 0; i < numChildren; i++)
 			{
 			{
-				HSceneObject child = current->getChild(i);
+				HSceneObject child = current.so->getChild(i);
 
 
 				if (child->mPrefabLinkUUID.empty())
 				if (child->mPrefabLinkUUID.empty())
-					todo.push(child);
+					todo.push({ child, current.uuid });
+				else
+					todo.push({ child, child->mPrefabLinkUUID });
 			}
 			}
 		}
 		}
 	}
 	}

+ 58 - 49
BansheeCore/Source/BsPrefabUtility.cpp

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		HSceneObject newInstance = prefabLink->instantiate();
 		HSceneObject newInstance = prefabLink->instantiate();
 		newInstance->mParent = parent;
 		newInstance->mParent = parent;
 
 
-		restoreLinkedInstanceData(newInstance, linkedInstanceData);
+		restoreLinkedInstanceData(newInstance, soProxy, linkedInstanceData);
 	}
 	}
 
 
 	void PrefabUtility::updateFromPrefab(const HSceneObject& so)
 	void PrefabUtility::updateFromPrefab(const HSceneObject& so)
@@ -67,6 +67,8 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
+		Vector<std::pair<HSceneObject, HSceneObject>> newPrefabInstances;
+
 		// Need to do this bottom up to ensure I don't destroy the parents before children
 		// Need to do this bottom up to ensure I don't destroy the parents before children
 		for (auto iter = prefabInstanceRoots.rbegin(); iter != prefabInstanceRoots.rend(); ++iter)
 		for (auto iter = prefabInstanceRoots.rbegin(); iter != prefabInstanceRoots.rend(); ++iter)
 		{
 		{
@@ -83,20 +85,25 @@ namespace BansheeEngine
 				PrefabDiffPtr prefabDiff = current->mPrefabDiff;
 				PrefabDiffPtr prefabDiff = current->mPrefabDiff;
 				HSceneObject parent = current->getParent();
 				HSceneObject parent = current->getParent();
 
 
-				// This will destroy the object but keep it in the parent's child list
-				current->destroyInternal(current, true);
-
+				current->destroy(true);
 				HSceneObject newInstance = prefabLink->instantiate();
 				HSceneObject newInstance = prefabLink->instantiate();
-				newInstance->mParent = parent;
 
 
 				if (prefabDiff != nullptr)
 				if (prefabDiff != nullptr)
 					prefabDiff->apply(newInstance);
 					prefabDiff->apply(newInstance);
 
 
-				restoreLinkedInstanceData(newInstance, linkedInstanceData);
+				restoreLinkedInstanceData(newInstance, soProxy, linkedInstanceData);
 				restoreUnlinkedInstanceData(newInstance, soProxy);
 				restoreUnlinkedInstanceData(newInstance, soProxy);
+
+				newPrefabInstances.push_back({ newInstance, parent });
 			}
 			}
 		}
 		}
 
 
+		// Once everything is instantiated, restore old parents
+		for (auto& newInstanceData : newPrefabInstances)
+		{
+			newInstanceData.first->mParent = newInstanceData.second;
+		}
+
 		gResources().unloadAllUnused();
 		gResources().unloadAllUnused();
 	}
 	}
 
 
@@ -113,17 +120,12 @@ namespace BansheeEngine
 			HSceneObject currentSO = todo.top();
 			HSceneObject currentSO = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			if (currentSO->mLinkId == -1)
-				objectsToId.push_back(currentSO);
-			else
-				existingIds.insert(currentSO->mLinkId);
-
 			for (auto& component : currentSO->mComponents)
 			for (auto& component : currentSO->mComponents)
 			{
 			{
-				if (component->mLinkId == -1)
+				if (component->getLinkId() == -1)
 					objectsToId.push_back(component);
 					objectsToId.push_back(component);
 				else
 				else
-					existingIds.insert(component->mLinkId);
+					existingIds.insert(component->getLinkId());
 			}
 			}
 
 
 			UINT32 numChildren = (UINT32)currentSO->getNumChildren();
 			UINT32 numChildren = (UINT32)currentSO->getNumChildren();
@@ -131,8 +133,16 @@ namespace BansheeEngine
 			{
 			{
 				HSceneObject child = currentSO->getChild(i);
 				HSceneObject child = currentSO->getChild(i);
 
 
-				if (!child->hasFlag(SOF_DontSave) && child->mPrefabLinkUUID.empty())
-					todo.push(currentSO->getChild(i));
+				if (!child->hasFlag(SOF_DontSave))
+				{
+					if (child->getLinkId() == -1)
+						objectsToId.push_back(child);
+					else
+						existingIds.insert(child->getLinkId());
+
+					if(child->mPrefabLinkUUID.empty())
+						todo.push(currentSO->getChild(i));
+				}
 			}
 			}
 		}
 		}
 
 
@@ -169,7 +179,6 @@ namespace BansheeEngine
 			HSceneObject currentSO = todo.top();
 			HSceneObject currentSO = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			currentSO->mLinkId = -1;
 			for (auto& component : currentSO->mComponents)
 			for (auto& component : currentSO->mComponents)
 				component->mLinkId = -1;
 				component->mLinkId = -1;
 
 
@@ -179,6 +188,7 @@ namespace BansheeEngine
 				for (UINT32 i = 0; i < numChildren; i++)
 				for (UINT32 i = 0; i < numChildren; i++)
 				{
 				{
 					HSceneObject child = currentSO->getChild(i);
 					HSceneObject child = currentSO->getChild(i);
+					child->mLinkId = -1;
 
 
 					if (child->mPrefabLinkUUID.empty())
 					if (child->mPrefabLinkUUID.empty())
 						todo.push(child);
 						todo.push(child);
@@ -242,16 +252,14 @@ namespace BansheeEngine
 		Stack<StackData> todo;
 		Stack<StackData> todo;
 		todo.push({so, &output});
 		todo.push({so, &output});
 
 
+		output.instanceData = so->_getInstanceData();
+		output.linkId = -1;
+
 		while (!todo.empty())
 		while (!todo.empty())
 		{
 		{
 			StackData curData = todo.top();
 			StackData curData = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			curData.proxy->instanceData = curData.so->_getInstanceData();
-			curData.proxy->linkId = curData.so->getLinkId();
-
-			linkedInstanceData[curData.proxy->linkId] = curData.proxy->instanceData;
-
 			const Vector<HComponent>& components = curData.so->getComponents();
 			const Vector<HComponent>& components = curData.so->getComponents();
 			for (auto& component : components)
 			for (auto& component : components)
 			{
 			{
@@ -265,48 +273,41 @@ namespace BansheeEngine
 			}
 			}
 
 
 			UINT32 numChildren = curData.so->getNumChildren();
 			UINT32 numChildren = curData.so->getNumChildren();
-			UINT32 numProxyChildren = 0;
+			curData.proxy->children.resize(numChildren);
+
 			for (UINT32 i = 0; i < numChildren; i++)
 			for (UINT32 i = 0; i < numChildren; i++)
 			{
 			{
 				HSceneObject child = curData.so->getChild(i);
 				HSceneObject child = curData.so->getChild(i);
 
 
-				if (child->mPrefabLinkUUID.empty())
-					numProxyChildren++;
-			}
+				SceneObjectProxy& childProxy = curData.proxy->children[i];
 
 
-			curData.proxy->children.resize(numProxyChildren);
+				childProxy.instanceData = child->_getInstanceData();
+				childProxy.linkId = child->getLinkId();
 
 
-			UINT32 proxyIdx = 0;
-			for (UINT32 i = 0; i < numChildren; i++)
-			{
-				HSceneObject child = curData.so->getChild(i);
+				linkedInstanceData[childProxy.linkId] = childProxy.instanceData;
 
 
 				if (child->mPrefabLinkUUID.empty())
 				if (child->mPrefabLinkUUID.empty())
 				{
 				{
-					todo.push({ child, &curData.proxy->children[proxyIdx] });
-					proxyIdx++;
+					todo.push({ child, &curData.proxy->children[i] });
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	void PrefabUtility::restoreLinkedInstanceData(const HSceneObject& so, UnorderedMap<UINT32, GameObjectInstanceDataPtr>& linkedInstanceData)
+	void PrefabUtility::restoreLinkedInstanceData(const HSceneObject& so, SceneObjectProxy& proxy, 
+		UnorderedMap<UINT32, GameObjectInstanceDataPtr>& linkedInstanceData)
 	{
 	{
 		Stack<HSceneObject> todo;
 		Stack<HSceneObject> todo;
 		todo.push(so);
 		todo.push(so);
 
 
+		// Root is not in the instance data map because its link ID belongs to the parent prefab, if any
+		so->_setInstanceData(proxy.instanceData);
+
 		while (!todo.empty())
 		while (!todo.empty())
 		{
 		{
 			HSceneObject current = todo.top();
 			HSceneObject current = todo.top();
 			todo.pop();
 			todo.pop();
 
 
-			if (current->getLinkId() != -1)
-			{
-				auto iterFind = linkedInstanceData.find(current->getLinkId());
-				if (iterFind != linkedInstanceData.end())
-					current->_setInstanceData(iterFind->second);
-			}
-
 			const Vector<HComponent>& components = current->getComponents();
 			const Vector<HComponent>& components = current->getComponents();
 			for (auto& component : components)
 			for (auto& component : components)
 			{
 			{
@@ -323,6 +324,13 @@ namespace BansheeEngine
 			{
 			{
 				HSceneObject child = current->getChild(i);
 				HSceneObject child = current->getChild(i);
 
 
+				if (child->getLinkId() != -1)
+				{
+					auto iterFind = linkedInstanceData.find(child->getLinkId());
+					if (iterFind != linkedInstanceData.end())
+						child->_setInstanceData(iterFind->second);
+				}
+
 				if (child->mPrefabLinkUUID.empty())
 				if (child->mPrefabLinkUUID.empty())
 					todo.push(child);
 					todo.push(child);
 			}
 			}
@@ -340,8 +348,6 @@ namespace BansheeEngine
 		Stack<StackEntry> todo;
 		Stack<StackEntry> todo;
 		todo.push(StackEntry());
 		todo.push(StackEntry());
 
 
-		assert(so->getLinkId() == proxy.linkId);
-		
 		StackEntry& topEntry = todo.top();
 		StackEntry& topEntry = todo.top();
 		topEntry.so = so;
 		topEntry.so = so;
 		topEntry.proxy = &proxy;
 		topEntry.proxy = &proxy;
@@ -383,9 +389,6 @@ namespace BansheeEngine
 			{
 			{
 				HSceneObject child = current.so->getChild(i);
 				HSceneObject child = current.so->getChild(i);
 
 
-				if (!child->mPrefabLinkUUID.empty())
-					continue;
-
 				if (child->getLinkId() == -1)
 				if (child->getLinkId() == -1)
 				{
 				{
 					bool foundInstanceData = false;
 					bool foundInstanceData = false;
@@ -397,11 +400,14 @@ namespace BansheeEngine
 						assert(current.proxy->children[childProxyIdx].linkId == -1);
 						assert(current.proxy->children[childProxyIdx].linkId == -1);
 						child->_setInstanceData(current.proxy->children[childProxyIdx].instanceData);
 						child->_setInstanceData(current.proxy->children[childProxyIdx].instanceData);
 
 
-						todo.push(StackEntry());
+						if (child->mPrefabLinkUUID.empty())
+						{
+							todo.push(StackEntry());
 
 
-						StackEntry& newEntry = todo.top();
-						newEntry.so = child;
-						newEntry.proxy = &current.proxy->children[childProxyIdx];
+							StackEntry& newEntry = todo.top();
+							newEntry.so = child;
+							newEntry.proxy = &current.proxy->children[childProxyIdx];
+						}
 
 
 						foundInstanceData = true;
 						foundInstanceData = true;
 						break;
 						break;
@@ -411,6 +417,9 @@ namespace BansheeEngine
 				}
 				}
 				else
 				else
 				{
 				{
+					if (!child->mPrefabLinkUUID.empty())
+						continue;
+
 					for (UINT32 j = 0; j < numChildProxies; j++)
 					for (UINT32 j = 0; j < numChildProxies; j++)
 					{
 					{
 						if (child->getLinkId() == current.proxy->children[j].linkId)
 						if (child->getLinkId() == current.proxy->children[j].linkId)

+ 29 - 12
BansheeCore/Source/BsSceneObject.cpp

@@ -127,23 +127,40 @@ namespace BansheeEngine
 
 
 	void SceneObject::breakPrefabLink()
 	void SceneObject::breakPrefabLink()
 	{
 	{
-		SceneObject* curObj = this;
+		SceneObject* rootObj = this;
 
 
-		while (curObj == nullptr)
+		while (rootObj == nullptr)
 		{
 		{
-			if (!curObj->mPrefabLinkUUID.empty())
+			if (!rootObj->mPrefabLinkUUID.empty())
+				return;
+
+			if (rootObj->mParent != nullptr)
+				rootObj = rootObj->mParent.get();
+			else
+				rootObj = nullptr;
+		}
+
+		if (rootObj != nullptr)
+		{
+			rootObj->mPrefabLinkUUID = "";
+			PrefabUtility::clearPrefabIds(rootObj->getHandle());
+
+			Stack<SceneObject*> todo;
+			todo.push(rootObj);
+
+			while (!todo.empty())
 			{
 			{
-				curObj->mPrefabLinkUUID = "";
+				SceneObject* curObj = todo.top();
+				todo.pop();
+
 				curObj->mPrefabDiff = nullptr;
 				curObj->mPrefabDiff = nullptr;
-				PrefabUtility::clearPrefabIds(curObj->getHandle());
 
 
-				return;
+				for (auto& child : curObj->mChildren)
+				{
+					if (child->mPrefabLinkUUID.empty())
+						todo.push(child.get());
+				}
 			}
 			}
-
-			if (curObj->mParent != nullptr)
-				curObj = curObj->mParent.get();
-			else
-				curObj = nullptr;
 		}
 		}
 	}
 	}
 
 
@@ -499,7 +516,7 @@ namespace BansheeEngine
 #if BS_EDITOR_BUILD
 #if BS_EDITOR_BUILD
 			String newPrefab = getPrefabLink();
 			String newPrefab = getPrefabLink();
 			if (originalPrefab != newPrefab)
 			if (originalPrefab != newPrefab)
-				PrefabUtility::clearPrefabIds(mThisHandle, false);
+				PrefabUtility::clearPrefabIds(mThisHandle);
 #endif
 #endif
 
 
 			setWorldPosition(worldPos);
 			setWorldPosition(worldPos);