Преглед на файлове

Instantiate scene objects/components after prefab diff only after game object handles are resolved to avoid issue of broken handles

BearishSun преди 9 години
родител
ревизия
a29d10f79d

+ 4 - 0
Source/BansheeCore/Include/BsPrefabDiff.h

@@ -96,6 +96,10 @@ namespace BansheeEngine
 		/**
 		 * Applies the internal prefab diff to the provided object. The object should have similar hierarchy as the prefab
 		 * the diff was created for, otherwise the results are undefined.
+		 *
+		 * @note	Be aware that this method will not instantiate newly added components or scene objects. It's expected
+		 *			that this method will be called on a fresh copy of a scene object hierarchy, and everything to be
+		 *			instantiated at once after diff is applied.
 		 */
 		void apply(const HSceneObject& object);
 

+ 7 - 2
Source/BansheeCore/Include/BsSceneObject.h

@@ -98,8 +98,13 @@ namespace BansheeEngine
 		/** @copydoc GameObject::_setInstanceData */
 		void _setInstanceData(GameObjectInstanceDataPtr& other) override;
 
-		/** Register the scene object with the scene and activate all of its components. */
-		void _instantiate();
+		/** 
+		 * Register the scene object with the scene and activate all of its components. 
+		 *
+		 * @param[in]	prefabOnly	If true, only objects within the current prefab will be instantiated. If false all child
+		 *							objects and components will.
+		 */
+		void _instantiate(bool prefabOnly = false);
 
 		/**
 		 * Clears the internally stored prefab diff. If this object is updated from prefab its instance specific changes 

+ 0 - 4
Source/BansheeCore/Source/BsPrefabDiff.cpp

@@ -115,9 +115,6 @@ namespace BansheeEngine
 			SPtr<Component> component = std::static_pointer_cast<Component>(bs._decodeFromIntermediate(addedComponentData));
 
 			object->addComponentInternal(component);
-
-			if(object->isInstantiated())
-				component->_instantiate();
 		}
 
 		for (auto& addedChildData : diff->addedChildren)
@@ -125,7 +122,6 @@ namespace BansheeEngine
 			BinarySerializer bs;
 			SPtr<SceneObject> sceneObject = std::static_pointer_cast<SceneObject>(bs._decodeFromIntermediate(addedChildData));
 			sceneObject->setParent(object);
-			sceneObject->_instantiate();
 		}
 
 		for (auto& componentDiff : diff->componentDiffs)

+ 5 - 2
Source/BansheeCore/Source/BsPrefabUtility.cpp

@@ -110,7 +110,6 @@ namespace BansheeEngine
 
 				current->destroy(true);
 				HSceneObject newInstance = prefabLink->_clone();
-				newInstance->_instantiate();
 
 				// When restoring instance IDs it is important to make all the new handles point to the old GameObjectInstanceData.
 				// This is because old handles will have different GameObjectHandleData and we have no easy way of accessing it to
@@ -125,7 +124,7 @@ namespace BansheeEngine
 			}
 		}
 
-		// Once everything is instantiated, apply diffs, restore old parents & link IDs for root.
+		// Once everything is cloned, apply diffs, restore old parents & link IDs for root.
 		for (auto& entry : newPrefabInstanceData)
 		{
 			// Diffs must be applied after everything is instantiated and instance data restored since it may contain
@@ -139,6 +138,10 @@ namespace BansheeEngine
 			entry.newInstance->mLinkId = entry.originalLinkId;
 		}
 
+		// Finally, instantiate everything
+		for (auto& entry : newPrefabInstanceData)
+			entry.newInstance->_instantiate(true);
+
 		gResources().unloadAllUnused();
 	}
 

+ 9 - 3
Source/BansheeCore/Source/BsSceneObject.cpp

@@ -198,7 +198,7 @@ namespace BansheeEngine
 			child->unsetFlags(flags);
 	}
 
-	void SceneObject::_instantiate()
+	void SceneObject::_instantiate(bool prefabOnly)
 	{
 		std::function<void(SceneObject*)> instantiateRecursive = [&](SceneObject* obj)
 		{
@@ -211,7 +211,10 @@ namespace BansheeEngine
 				component->_instantiate();
 
 			for (auto& child : obj->mChildren)
-				instantiateRecursive(child.get());
+			{
+				if(!prefabOnly || child->getPrefabLink().empty())
+					instantiateRecursive(child.get());
+			}
 		};
 
 		std::function<void(SceneObject*)> triggerEventsRecursive = [&](SceneObject* obj)
@@ -225,7 +228,10 @@ namespace BansheeEngine
 			}
 
 			for (auto& child : obj->mChildren)
-				triggerEventsRecursive(child.get());
+			{
+				if (!prefabOnly || child->getPrefabLink().empty())
+					triggerEventsRecursive(child.get());
+			}
 		};
 
 		instantiateRecursive(this);

+ 1 - 1
Source/MBansheeEditor/General/EditorApplication.cs

@@ -514,7 +514,7 @@ namespace BansheeEditor
         /// </summary>
         /// <param name="path">Path relative to the resource folder. This can be the path to the existing scene
         ///                    prefab if it just needs updating. </param>
-        private static void SaveScene(string path)
+        internal static void SaveScene(string path)
         {
             Prefab scene = Internal_SaveScene(path);
             Scene.SetActive(scene);

+ 0 - 4
Source/SBansheeEngine/Source/BsScriptGameObjectManager.cpp

@@ -74,10 +74,6 @@ namespace BansheeEngine
 
 	ScriptComponent* ScriptGameObjectManager::createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component)
 	{
-		ScriptGameObjectBase* comp = getScriptComponent(component.getInstanceId());
-		if (comp != nullptr)
-			BS_EXCEPT(InvalidStateException, "Script object for this Component already exists.");
-
 		ScriptComponent* nativeInstance = new (bs_alloc<ScriptComponent>()) ScriptComponent(existingInstance);
 		nativeInstance->setNativeHandle(component);