Bläddra i källkod

Prefab fixes:
- When applying prefab changes update all instances of the prefab in the current scene
- Updating from prefab will now properly instantiate the components on the new instance
- Applying a prefab diff will now properly instantiate the components
- Instantiating a prefab will no longer attempt to instantiate the game objects twice

BearishSun 9 år sedan
förälder
incheckning
10e057da7b

+ 11 - 6
Source/BansheeCore/Include/BsComponent.h

@@ -58,6 +58,17 @@ namespace BansheeEngine
 		 */
 		void destroy(bool immediate = false);
 
+		/** @name Internal 
+		 *  @{
+		 */
+
+		/**
+		 * Construct any resources the component needs before use. Called when the parent scene object is instantiated. 
+		 * A non-instantiated component shouldn't be used for any other purpose than serialization.
+		 */
+		virtual void _instantiate() {}
+
+		/** @} */
 	protected:
 		friend class SceneObject;
 		friend class SceneObjectRTTI;
@@ -65,12 +76,6 @@ namespace BansheeEngine
 		Component(const HSceneObject& parent);
 		virtual ~Component();
 
-		/**
-		 * Construct any resources the component needs before use. Called when the parent scene object is instantiated. 
-		 * A non-instantiated component shouldn't be used for any other purpose than serialization.
-		 */
-		virtual void instantiate() {}
-
 		/**	Called when the component is ready to be initialized. */
 		virtual void onInitialized() {}
 

+ 1 - 1
Source/BansheeCore/Include/BsSceneObject.h

@@ -512,7 +512,7 @@ namespace BansheeEngine
 
 			if (isInstantiated())
 			{
-				newComponent->instantiate();
+				newComponent->_instantiate();
 				newComponent->onInitialized();
 
 				if (getActive())

+ 2 - 2
Source/BansheeCore/Source/BsPrefab.cpp

@@ -10,7 +10,7 @@
 namespace BansheeEngine
 {
 	Prefab::Prefab()
-		:Resource(false), mHash(0), mNextLinkId(0), mIsScene(false)
+		:Resource(false), mHash(0), mNextLinkId(0), mIsScene(true)
 	{
 		
 	}
@@ -157,7 +157,7 @@ namespace BansheeEngine
 			return HSceneObject();
 
 		mRoot->mPrefabHash = mHash;
-		return mRoot->clone();
+		return mRoot->clone(false);
 	}
 
 	RTTITypeBase* Prefab::getRTTIStatic()

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

@@ -115,6 +115,9 @@ 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)

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

@@ -110,11 +110,12 @@ 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
 				// change to which GameObjectInstanceData it points. But the GameObjectManager ensures that all handles deserialized
-				// at once (i.e. during the ::instantiate() call above) will share GameObjectHandleData so we can simply replace
+				// at once (i.e. during the ::_clone() call above) will share GameObjectHandleData so we can simply replace
 				// to what they point to, affecting all of the handles to that object. (In another words, we can modify the
 				// new handles at this point, but old ones must keep referencing what they already were.)
 				restoreLinkedInstanceData(newInstance, soProxy, linkedInstanceData);

+ 5 - 1
Source/BansheeCore/Source/BsSceneObject.cpp

@@ -207,7 +207,7 @@ namespace BansheeEngine
 				gCoreSceneManager().registerNewSO(obj->mThisHandle);
 
 			for (auto& component : obj->mComponents)
-				component->instantiate();
+				component->_instantiate();
 
 			for (auto& child : obj->mChildren)
 				instantiateRecursive(child.get());
@@ -685,6 +685,8 @@ namespace BansheeEngine
 	{
 		if (!instantiate)
 			setFlags(SOF_DontInstantiate);
+		else
+			unsetFlags(SOF_DontInstantiate);
 
 		UINT32 bufferSize = 0;
 
@@ -697,6 +699,8 @@ namespace BansheeEngine
 
 		if (!instantiate)
 			unsetFlags(SOF_DontInstantiate);
+		else
+			setFlags(SOF_DontInstantiate);
 
 		return cloneObj->mThisHandle;
 	}

+ 17 - 0
Source/MBansheeEditor/Utility/PrefabUtility.cs

@@ -57,6 +57,20 @@ namespace BansheeEditor
             Internal_RevertPrefab(objPtr);
         }
 
+        /// <summary>
+        /// Updates all of the objects belonging to the same prefab instance as the provided object (if any). The update
+        /// will apply any changes from the linked prefab to the hierarchy(if any).
+        /// </summary>
+        /// <param name="obj"></param>
+        public static void UpdateFromPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_UpdateFromPrefab(objPtr);
+        }
+
         /// <summary>
         /// Checks if a scene object has a prefab link. Scene objects with a prefab link will be automatically updated
         /// when their prefab changes in order to reflect its changes.
@@ -112,6 +126,9 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern bool Internal_HasPrefabLink(IntPtr nativeInstance);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UpdateFromPrefab(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SceneObject Internal_GetPrefabParent(IntPtr nativeInstance);
 

+ 3 - 0
Source/MBansheeEditor/Window/MenuItems.cs

@@ -607,6 +607,9 @@ namespace BansheeEditor
                 return;
 
             PrefabUtility.ApplyPrefab(so);
+
+            // Refresh any prefab instances in the scene
+            PrefabUtility.UpdateFromPrefab(Scene.Root);
         }
 
         /// <summary>

+ 7 - 1
Source/MBansheeEditor/Windows/Inspector/InspectorWindow.cs

@@ -378,7 +378,13 @@ namespace BansheeEditor
                     GUIButton btnRevertPrefab = new GUIButton(new LocEdString("Revert"), GUIOption.FixedWidth(60));
                     GUIButton btnBreakPrefab = new GUIButton(new LocEdString("Break"), GUIOption.FixedWidth(60));
 
-                    btnApplyPrefab.OnClick += () => PrefabUtility.ApplyPrefab(activeSO);
+                    btnApplyPrefab.OnClick += () =>
+                    {
+                        PrefabUtility.ApplyPrefab(activeSO);
+
+                        // Refresh any prefab instances in the scene
+                        PrefabUtility.UpdateFromPrefab(Scene.Root);
+                    };
                     btnRevertPrefab.OnClick += () =>
                     {
                         UndoRedo.RecordSO(activeSO, true, "Reverting \"" + activeSO.Name + "\" to prefab.");

+ 1 - 0
Source/SBansheeEditor/Include/BsScriptPrefabUtility.h

@@ -27,6 +27,7 @@ namespace BansheeEngine
 		static bool internal_hasPrefabLink(ScriptSceneObject* nativeInstance);
 		static MonoObject* internal_getPrefabParent(ScriptSceneObject* nativeInstance);
 		static MonoString* internal_GetPrefabUUID(ScriptSceneObject* nativeInstance);
+		static void internal_UpdateFromPrefab(ScriptSceneObject* nativeInstance);
 
 		ScriptPrefabUtility(MonoObject* instance);
 	};

+ 10 - 0
Source/SBansheeEditor/Source/BsScriptPrefabUtility.cpp

@@ -25,6 +25,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_HasPrefabLink", &ScriptPrefabUtility::internal_hasPrefabLink);
 		metaData.scriptClass->addInternalCall("Internal_GetPrefabParent", &ScriptPrefabUtility::internal_getPrefabParent);
 		metaData.scriptClass->addInternalCall("Internal_GetPrefabUUID", &ScriptPrefabUtility::internal_GetPrefabUUID);
+		metaData.scriptClass->addInternalCall("Internal_UpdateFromPrefab", &ScriptPrefabUtility::internal_UpdateFromPrefab);
 	}
 
 	void ScriptPrefabUtility::internal_breakPrefab(ScriptSceneObject* nativeInstance)
@@ -97,4 +98,13 @@ namespace BansheeEngine
 
 		return MonoUtil::stringToMono(prefabUUID);
 	}
+
+	void ScriptPrefabUtility::internal_UpdateFromPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		HSceneObject so = nativeInstance->getNativeSceneObject();
+		PrefabUtility::updateFromPrefab(so);
+	}
 }

+ 2 - 2
Source/SBansheeEngine/Include/BsManagedComponent.h

@@ -122,8 +122,8 @@ namespace BansheeEngine
 
 		ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType);
 
-		/** @copydoc Component::instantiate */
-		void instantiate() override;
+		/** @copydoc Component::_instantiate */
+		void _instantiate() override;
 
 		/** @copydoc Component::onInitialized */
 		void onInitialized() override;

+ 1 - 1
Source/SBansheeEngine/Source/BsManagedComponent.cpp

@@ -323,7 +323,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void ManagedComponent::instantiate()
+	void ManagedComponent::_instantiate()
 	{
 		mObjInfo = nullptr;
 		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo))