Explorar o código

In hierarchy and inspector don't report root scene objects as prefab instances

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

+ 6 - 0
BansheeCore/Include/BsSceneObject.h

@@ -78,6 +78,12 @@ namespace BansheeEngine
 		 */
 		String getPrefabLink() const;
 
+		/** 
+		 * Returns the root object of the prefab instance that this object belongs to, if any. Returns null if the object 
+		 * is not part of a prefab instance. 
+		 */
+		HSceneObject getPrefabParent() const;
+
 		/**
 		 * Breaks the link between this prefab instance and its prefab. Object will retain all current values but will no
 		 * longer be influenced by modifications to its parent prefab.

+ 18 - 0
BansheeCore/Source/BsSceneObject.cpp

@@ -132,6 +132,24 @@ namespace BansheeEngine
 		return "";
 	}
 
+	HSceneObject SceneObject::getPrefabParent() const
+	{
+		HSceneObject curObj = mThisHandle;
+
+		while (curObj != nullptr)
+		{
+			if (!curObj->mPrefabLinkUUID.empty())
+				return curObj;
+
+			if (curObj->mParent != nullptr)
+				curObj = curObj->mParent;
+			else
+				curObj = nullptr;
+		}
+
+		return curObj;
+	}
+
 	void SceneObject::breakPrefabLink()
 	{
 		SceneObject* rootObj = this;

+ 9 - 2
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -130,7 +130,11 @@ namespace BansheeEngine
 			{
 				HSceneObject currentSOChild = currentSO->getChild(i);
 				bool isInternal = currentSOChild->hasFlag(SOF_Internal);
-				bool isPrefabInstance = !currentSOChild->getPrefabLink().empty();
+
+				HSceneObject prefabParent = currentSOChild->getPrefabParent();
+
+				// Only count it as a prefab instance if its not scene root (otherwise every object would be colored as a prefab)
+				bool isPrefabInstance = prefabParent != nullptr && prefabParent->getParent() != nullptr;
 
 #if BS_DEBUG_MODE == 0
 				if (isInternal)
@@ -204,7 +208,10 @@ namespace BansheeEngine
 		}
 
 		// Check if prefab instance state needs updating
-		bool isPrefabInstance = !element->mSceneObject->getPrefabLink().empty();
+		HSceneObject prefabParent = element->mSceneObject->getPrefabParent();
+
+		// Only count it as a prefab instance if its not scene root (otherwise every object would be colored as a prefab)
+		bool isPrefabInstance = prefabParent != nullptr && prefabParent->getParent() != nullptr;
 		if (element->mIsPrefabInstance != isPrefabInstance)
 		{
 			element->mIsPrefabInstance = isPrefabInstance;

+ 4 - 1
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -353,7 +353,10 @@ namespace BansheeEditor
             soNameInput.Text = activeSO.Name;
             soActiveToggle.Value = activeSO.Active;
 
-            bool hasPrefab = PrefabUtility.IsPrefabInstance(activeSO);
+            SceneObject prefabParent = PrefabUtility.GetPrefabParent(activeSO);
+
+            // Ignore prefab parent if scene root, we only care for non-root prefab instances
+            bool hasPrefab = prefabParent != null && prefabParent.Parent != null;
             if (soHasPrefab != hasPrefab || forceUpdate)
             {
                 int numChildren = soPrefabLayout.ChildCount;

+ 102 - 85
MBansheeEditor/PrefabUtility.cs

@@ -1,85 +1,102 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Performs various prefab specific operations.
-    /// </summary>
-    public static class PrefabUtility
-    {
-        /// <summary>
-        /// Breaks the link between a prefab instance and its prefab. Object will retain all current values but will
-        /// no longer be influenced by modifications to its parent prefab.
-        /// </summary>
-        /// <param name="obj">Prefab instance whose link to break.</param>
-        public static void BreakPrefab(SceneObject obj)
-        {
-            if (obj == null)
-                return;
-
-            IntPtr objPtr = obj.GetCachedPtr();
-            Internal_BreakPrefab(objPtr);
-        }
-
-        /// <summary>
-        /// Updates the contents of the prefab with the contents of the provided prefab instance. If the provided object
-        /// is not a prefab instance nothing happens.
-        /// </summary>
-        /// <param name="obj">Prefab instance whose prefab to update.</param>
-        public static void ApplyPrefab(SceneObject obj)
-        {
-            if (obj == null)
-                return;
-
-            IntPtr objPtr = obj.GetCachedPtr();
-            Internal_ApplyPrefab(objPtr);
-        }
-
-        /// <summary>
-        /// Remove any instance specific changes to the object or its hierarchy from the provided prefab instance and 
-        /// restore it to the exact copy of the linked prefab.
-        /// </summary>
-        /// <param name="obj">Prefab instance to revert to original state.</param>
-        public static void RevertPrefab(SceneObject obj)
-        {
-            if (obj == null)
-                return;
-
-            IntPtr objPtr = obj.GetCachedPtr();
-            Internal_RevertPrefab(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.
-        /// </summary>
-        /// <param name="obj">Scene object to check if it has a prefab link.</param>
-        /// <returns>True if the object is a prefab instance (has a prefab link), false otherwise.</returns>
-        public static bool IsPrefabInstance(SceneObject obj)
-        {
-            if (obj == null)
-                return false;
-
-            IntPtr objPtr = obj.GetCachedPtr();
-            return Internal_HasPrefabLink(objPtr);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_BreakPrefab(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_ApplyPrefab(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_RevertPrefab(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_HasPrefabLink(IntPtr nativeInstance);
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Performs various prefab specific operations.
+    /// </summary>
+    public static class PrefabUtility
+    {
+        /// <summary>
+        /// Breaks the link between a prefab instance and its prefab. Object will retain all current values but will
+        /// no longer be influenced by modifications to its parent prefab.
+        /// </summary>
+        /// <param name="obj">Prefab instance whose link to break.</param>
+        public static void BreakPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_BreakPrefab(objPtr);
+        }
+
+        /// <summary>
+        /// Updates the contents of the prefab with the contents of the provided prefab instance. If the provided object
+        /// is not a prefab instance nothing happens.
+        /// </summary>
+        /// <param name="obj">Prefab instance whose prefab to update.</param>
+        public static void ApplyPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_ApplyPrefab(objPtr);
+        }
+
+        /// <summary>
+        /// Remove any instance specific changes to the object or its hierarchy from the provided prefab instance and 
+        /// restore it to the exact copy of the linked prefab.
+        /// </summary>
+        /// <param name="obj">Prefab instance to revert to original state.</param>
+        public static void RevertPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_RevertPrefab(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.
+        /// </summary>
+        /// <param name="obj">Scene object to check if it has a prefab link.</param>
+        /// <returns>True if the object is a prefab instance (has a prefab link), false otherwise.</returns>
+        public static bool IsPrefabInstance(SceneObject obj)
+        {
+            if (obj == null)
+                return false;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            return Internal_HasPrefabLink(objPtr);
+        }
+
+        /// <summary>
+        /// Returns the root object of the prefab instance that this object belongs to, if any. 
+        /// </summary>
+        /// <param name="obj">Scene object to retrieve the prefab parent for.</param>
+        /// <returns>Prefab parent of the provided object, or null if the object is not part of a prefab instance.</returns>
+        public static SceneObject GetPrefabParent(SceneObject obj)
+        {
+            if (obj == null)
+                return null;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            return Internal_GetPrefabParent(objPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_BreakPrefab(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_ApplyPrefab(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_RevertPrefab(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_HasPrefabLink(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SceneObject Internal_GetPrefabParent(IntPtr nativeInstance);
+    }
+}

+ 27 - 26
SBansheeEditor/Include/BsScriptPrefabUtility.h

@@ -1,27 +1,28 @@
-#pragma once
-
-#include "BsScriptEditorPrerequisites.h"
-#include "BsScriptObject.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Interop class between C++ & CLR for PrefabUtility.
-	 */
-	class BS_SCR_BED_EXPORT ScriptPrefabUtility : public ScriptObject <ScriptPrefabUtility>
-	{
-	public:
-		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "PrefabUtility")
-
-	private:
-		/************************************************************************/
-		/* 								CLR HOOKS						   		*/
-		/************************************************************************/
-		static void internal_breakPrefab(ScriptSceneObject* nativeInstance);
-		static void internal_applyPrefab(ScriptSceneObject* nativeInstance);
-		static void internal_revertPrefab(ScriptSceneObject* nativeInstance);
-		static bool internal_hasPrefabLink(ScriptSceneObject* nativeInstance);
-
-		ScriptPrefabUtility(MonoObject* instance);
-	};
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Interop class between C++ & CLR for PrefabUtility.
+	 */
+	class BS_SCR_BED_EXPORT ScriptPrefabUtility : public ScriptObject <ScriptPrefabUtility>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "PrefabUtility")
+
+	private:
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_breakPrefab(ScriptSceneObject* nativeInstance);
+		static void internal_applyPrefab(ScriptSceneObject* nativeInstance);
+		static void internal_revertPrefab(ScriptSceneObject* nativeInstance);
+		static bool internal_hasPrefabLink(ScriptSceneObject* nativeInstance);
+		static MonoObject* internal_getPrefabParent(ScriptSceneObject* nativeInstance);
+
+		ScriptPrefabUtility(MonoObject* instance);
+	};
 }

+ 79 - 62
SBansheeEditor/Source/BsScriptPrefabUtility.cpp

@@ -1,63 +1,80 @@
-#include "BsScriptPrefabUtility.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
-#include "BsMonoMethod.h"
-#include "BsMonoUtil.h"
-#include "BsPrefabUtility.h"
-#include "BsScriptSceneObject.h"
-#include "BsSceneObject.h"
-#include "BsPrefab.h"
-#include "BsResources.h"
-
-namespace BansheeEngine
-{
-	ScriptPrefabUtility::ScriptPrefabUtility(MonoObject* instance)
-		:ScriptObject(instance)
-	{ }
-
-	void ScriptPrefabUtility::initRuntimeData()
-	{
-		metaData.scriptClass->addInternalCall("Internal_BreakPrefab", &ScriptPrefabUtility::internal_breakPrefab);
-		metaData.scriptClass->addInternalCall("Internal_ApplyPrefab", &ScriptPrefabUtility::internal_applyPrefab);
-		metaData.scriptClass->addInternalCall("Internal_RevertPrefab", &ScriptPrefabUtility::internal_revertPrefab);
-		metaData.scriptClass->addInternalCall("Internal_HasPrefabLink", &ScriptPrefabUtility::internal_hasPrefabLink);
-	}
-
-	void ScriptPrefabUtility::internal_breakPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
-			return;
-
-		nativeInstance->getNativeSceneObject()->breakPrefabLink();
-	}
-
-	void ScriptPrefabUtility::internal_applyPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
-			return;
-
-		String prefabLinkUUID = nativeInstance->getNativeSceneObject()->getPrefabLink();
-		HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(prefabLinkUUID, false, false));
-
-		if (prefab != nullptr)
-			prefab->update(nativeInstance->getNativeSceneObject());
-
-		gResources().save(prefab);
-	}
-
-	void ScriptPrefabUtility::internal_revertPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
-			return;
-
-		PrefabUtility::revertToPrefab(nativeInstance->getNativeSceneObject());
-	}
-
-	bool ScriptPrefabUtility::internal_hasPrefabLink(ScriptSceneObject* nativeInstance)
-	{
-		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
-			return false;
-
-		return !nativeInstance->getNativeSceneObject()->getPrefabLink().empty();
-	}
+#include "BsScriptPrefabUtility.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsPrefabUtility.h"
+#include "BsScriptSceneObject.h"
+#include "BsSceneObject.h"
+#include "BsPrefab.h"
+#include "BsResources.h"
+#include "BsScriptGameObjectManager.h"
+
+namespace BansheeEngine
+{
+	ScriptPrefabUtility::ScriptPrefabUtility(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptPrefabUtility::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_BreakPrefab", &ScriptPrefabUtility::internal_breakPrefab);
+		metaData.scriptClass->addInternalCall("Internal_ApplyPrefab", &ScriptPrefabUtility::internal_applyPrefab);
+		metaData.scriptClass->addInternalCall("Internal_RevertPrefab", &ScriptPrefabUtility::internal_revertPrefab);
+		metaData.scriptClass->addInternalCall("Internal_HasPrefabLink", &ScriptPrefabUtility::internal_hasPrefabLink);
+		metaData.scriptClass->addInternalCall("Internal_GetPrefabParent", &ScriptPrefabUtility::internal_getPrefabParent);
+	}
+
+	void ScriptPrefabUtility::internal_breakPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		nativeInstance->getNativeSceneObject()->breakPrefabLink();
+	}
+
+	void ScriptPrefabUtility::internal_applyPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		String prefabLinkUUID = nativeInstance->getNativeSceneObject()->getPrefabLink();
+		HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(prefabLinkUUID, false, false));
+
+		if (prefab != nullptr)
+			prefab->update(nativeInstance->getNativeSceneObject());
+
+		gResources().save(prefab);
+	}
+
+	void ScriptPrefabUtility::internal_revertPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		PrefabUtility::revertToPrefab(nativeInstance->getNativeSceneObject());
+	}
+
+	bool ScriptPrefabUtility::internal_hasPrefabLink(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return false;
+
+		return !nativeInstance->getNativeSceneObject()->getPrefabLink().empty();
+	}
+
+	MonoObject* ScriptPrefabUtility::internal_getPrefabParent(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return nullptr;
+
+		HSceneObject so = nativeInstance->getNativeSceneObject();
+		HSceneObject parent = so->getPrefabParent();
+
+		if(parent != nullptr)
+		{
+			ScriptSceneObject* scriptParent = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(parent);
+			return scriptParent->getManagedInstance();
+		}
+
+		return nullptr;
+	}
 }

+ 7 - 2
SBansheeEngine/Source/BsScriptSceneObject.cpp

@@ -120,9 +120,14 @@ namespace BansheeEngine
 			return nullptr;
 
 		HSceneObject parent = nativeInstance->mSceneObject->getParent();
-		ScriptSceneObject* parentScriptSO = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(parent);
+		if (parent != nullptr)
+		{
+			ScriptSceneObject* parentScriptSO = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(parent);
+
+			return parentScriptSO->getManagedInstance();
+		}
 
-		return parentScriptSO->getManagedInstance();
+		return nullptr;
 	}
 
 	void ScriptSceneObject::internal_getNumChildren(ScriptSceneObject* nativeInstance, UINT32* value)