Explorar el Código

Modified managed components so their managed instances aren't created if the parent SO isn't being instantiated
Modified managed components so that they are registered with the script GO manager before attempting to deserialize handles to other components

Marko Pintera hace 10 años
padre
commit
809719519c

+ 7 - 0
BansheeCore/Include/BsComponent.h

@@ -46,6 +46,13 @@ namespace BansheeEngine
 		Component(const HSceneObject& parent);
 		virtual ~Component();
 
+		/**
+		 * @brief	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() {}
+
 		/**
 		 * @brief	Called when the component is ready to be initialized.
 		 */

+ 4 - 3
BansheeCore/Include/BsSceneObject.h

@@ -485,10 +485,11 @@ namespace BansheeEngine
 
 			if (isInstantiated())
 			{
-				if (getActive())
-					newComponent->onInitialized();
+				newComponent->instantiate();
+				newComponent->onInitialized();
 
-				newComponent->onEnabled();
+				if (getActive())
+					newComponent->onEnabled();
 			}
 
 			return newComponent;

+ 24 - 9
BansheeCore/Source/BsSceneObject.cpp

@@ -174,19 +174,34 @@ namespace BansheeEngine
 	{
 		mFlags &= ~SOF_DontInstantiate;
 
-		if (mParent == nullptr)
-			gCoreSceneManager().registerNewSO(mThisHandle);
+		std::function<void(SceneObject*)> instantiateRecursive = [&](SceneObject* obj)
+		{
+			if (obj->mParent == nullptr)
+				gCoreSceneManager().registerNewSO(obj->mThisHandle);
+
+			for (auto& component : obj->mComponents)
+				component->instantiate();
+
+			for (auto& child : obj->mChildren)
+				instantiateRecursive(child.get());
+		};
 
-		for (auto& component : mComponents)
+		std::function<void(SceneObject*)> triggerEventsRecursive = [&](SceneObject* obj)
 		{
-			component->onInitialized();
+			for (auto& component : obj->mComponents)
+			{
+				component->onInitialized();
 
-			if (getActive())
-				component->onEnabled();
-		}
+				if (obj->getActive())
+					component->onEnabled();
+			}
 
-		for (auto& child : mChildren)
-			child->instantiate();
+			for (auto& child : obj->mChildren)
+				triggerEventsRecursive(child.get());
+		};
+
+		instantiateRecursive(this);
+		triggerEventsRecursive(this);
 	}
 
 	/************************************************************************/

+ 1 - 0
BansheeEditor/Include/BsGUITreeView.h

@@ -56,6 +56,7 @@ namespace BansheeEngine
 			bool mIsHighlighted;
 			bool mIsVisible;
 			bool mIsGrayedOut;
+			Color mTint;
 
 			bool isParentRec(TreeElement* element) const;
 		};

+ 3 - 1
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -128,9 +128,10 @@ namespace BansheeEngine
 			for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
 			{
 				HSceneObject currentSOChild = currentSO->getChild(i);
+				bool isInternal = currentSOChild->hasFlag(SOF_Internal);
 
 #if BS_DEBUG_MODE == 0
-				if (currentSOChild->hasFlag(SOF_Internal))
+				if (isInternal)
 					continue;
 #endif
 
@@ -161,6 +162,7 @@ namespace BansheeEngine
 					newChild->mName = currentSOChild->getName();
 					newChild->mSortedIdx = (UINT32)newChildren.size();
 					newChild->mIsVisible = element->mIsVisible && element->mIsExpanded;
+					newChild->mTint = isInternal ? Color::Red : Color::White;
 
 					newChildren.push_back(newChild);
 

+ 9 - 1
BansheeEditor/Source/BsGUITreeView.cpp

@@ -786,7 +786,15 @@ namespace BansheeEngine
 				_registerChildElement(element->mElement);
 			}
 
-			element->mElement->setTint(element->mIsGrayedOut ? GRAYED_OUT_COLOR : Color::White);
+			if (element->mIsGrayedOut)
+			{
+				Color grayedOutTint = element->mTint;
+				grayedOutTint.a = GRAYED_OUT_COLOR.a;
+
+				element->mElement->setTint(grayedOutTint);
+			}
+			else
+				element->mElement->setTint(element->mTint);
 
 			if(element->mChildren.size() > 0)
 			{

+ 7 - 2
SBansheeEngine/Include/BsManagedComponent.h

@@ -100,9 +100,9 @@ namespace BansheeEngine
 		String mFullTypeName;
 		bool mRequiresReset;
 
-		// We store data of a missing component type in hope it will be restored later
 		bool mMissingType;
-		ManagedSerializableObjectPtr mMissingTypeObjectData;
+		ManagedSerializableObjectPtr mSerializedObjectData;
+		ManagedSerializableObjectInfoPtr mObjInfo; // Transient
 
 		OnInitializedThunkDef mOnInitializedThunk;
 		UpdateThunkDef mUpdateThunk;
@@ -121,6 +121,11 @@ namespace BansheeEngine
 
 		ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType);
 
+		/**
+		 * @copydoc	Component::instantiate
+		 */
+		void instantiate() override;
+
 		/**
 		 * @copydoc	Component::onInitialized
 		 */

+ 5 - 37
SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -41,7 +41,7 @@ namespace BansheeEngine
 
 		void setObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
 		{
-			obj->mRTTIData = val;
+			obj->mSerializedObjectData = val;
 		}
 
 		bool& getMissingType(ManagedComponent* obj)
@@ -54,16 +54,6 @@ namespace BansheeEngine
 			obj->mMissingType = val;
 		}
 
-		ManagedSerializableObjectPtr getMissingTypeObjectData(ManagedComponent* obj)
-		{
-			return obj->mMissingTypeObjectData;
-		}
-
-		void setMissingTypeObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
-		{
-			obj->mMissingTypeObjectData = val;
-		}
-
 	public:
 		ManagedComponentRTTI()
 		{
@@ -71,49 +61,27 @@ namespace BansheeEngine
 			addPlainField("mTypename", 1, &ManagedComponentRTTI::getTypename, &ManagedComponentRTTI::setTypename);
 			addReflectablePtrField("mObjectData", 2, &ManagedComponentRTTI::getObjectData, &ManagedComponentRTTI::setObjectData);
 			addPlainField("mMissingType", 3, &ManagedComponentRTTI::getMissingType, &ManagedComponentRTTI::setMissingType);
-			addReflectablePtrField("mMissingTypeObjectData", 5, &ManagedComponentRTTI::getMissingTypeObjectData, &ManagedComponentRTTI::setMissingTypeObjectData);
 		}
 
-		void onSerializationStarted(IReflectable* obj)
+		void onSerializationStarted(IReflectable* obj) override
 		{
 			ManagedComponent* mc = static_cast<ManagedComponent*>(obj);
 
 			mc->mRTTIData = ManagedSerializableObject::createFromExisting(mc->getManagedInstance());
 		}
 
-		virtual void onDeserializationStarted(IReflectable* obj)
-		{
-			ManagedComponent* mc = static_cast<ManagedComponent*>(obj);
-
-			GameObjectManager::instance().registerOnDeserializationEndCallback(std::bind(&ManagedComponentRTTI::finalizeDeserialization, mc));
-		}
-
-		static void finalizeDeserialization(ManagedComponent* mc)
-		{
-			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
-			serializableObject->deserialize();
-			MonoObject* managedInstance = serializableObject->getManagedInstance();
-
-			// Note: This callback must be triggered before any child ManagedSerializable* object's callbacks.
-			// This is because their callbacks will try to resolve native GameObject handles to managed objects
-			// but the managed ScriptComponent will only be created in the code below.
-			// I'm noting this specially as it's somewhat of a hidden requirement.
-			mc->initialize(managedInstance);
-			mc->mRTTIData = nullptr;
-		}
-
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ManagedComponent";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_ManagedComponent;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return GameObjectRTTI::createGameObject<ManagedComponent>();
 		}

+ 13 - 0
SBansheeEngine/Include/BsManagedSerializableObject.h

@@ -99,6 +99,19 @@ namespace BansheeEngine
 		 */
 		void deserialize();
 
+		/**
+		 * @brief	Deserializes a set of cached data into an existing managed object. Caller must ensure the provided object
+		 *			is of proper type.
+		 *
+		 *			This action transfers the object into linked mode. All further operations will operate directly on the managed instance
+		 *			and the cached data will be cleared. If you call this method on an already linked object the old object will be
+		 *			replaced and initialized with empty data (since cached data does not exist).
+		 *
+		 * @param	instance	Existing managed instance of the same type this serializable object represents.
+		 * @param	objInfo		Serializable object info for the managed object type.
+		 */
+		void deserialize(MonoObject* instance, const ManagedSerializableObjectInfoPtr& objInfo);
+
 		/**
 		 * @brief	Creates a managed serializable object that references an existing managed object. Created object will be in linked mode.
 		 *

+ 45 - 23
SBansheeEngine/Source/BsManagedComponent.cpp

@@ -7,6 +7,7 @@
 #include "BsMemorySerializer.h"
 #include "BsManagedSerializableObject.h"
 #include "BsScriptGameObjectManager.h"
+#include "BsScriptAssemblyManager.h"
 #include "BsDebug.h"
 
 namespace BansheeEngine
@@ -25,17 +26,7 @@ namespace BansheeEngine
 		::MonoClass* monoClass = mono_type_get_class(monoType);
 
 		MonoUtil::getClassName(monoClass, mNamespace, mTypeName);
-
-		MonoClass* managedClass = MonoManager::instance().findClass(mNamespace, mTypeName);
-		if(managedClass == nullptr)
-		{
-			LOGWRN("Cannot create managed component: " + mNamespace + "." + mTypeName + " because that type doesn't exist.");
-			return;
-		}
-
 		setName(mTypeName);
-
-		initialize(managedClass->createInstance());
 	}
 
 	ManagedComponent::~ManagedComponent()
@@ -75,8 +66,8 @@ namespace BansheeEngine
 
 			backupData.size = 0;
 
-			if (mMissingTypeObjectData != nullptr)
-				backupData.data = ms.encode(mMissingTypeObjectData.get(), backupData.size);
+			if (mSerializedObjectData != nullptr)
+				backupData.data = ms.encode(mSerializedObjectData.get(), backupData.size);
 			else
 				backupData.data = nullptr;
 		}
@@ -104,6 +95,7 @@ namespace BansheeEngine
 	void ManagedComponent::restore(MonoObject* instance, const ComponentBackupData& data, bool missingType)
 	{
 		initialize(instance);
+		mObjInfo = nullptr;
 
 		if (instance != nullptr && data.data != nullptr)
 		{
@@ -114,13 +106,17 @@ namespace BansheeEngine
 			GameObjectManager::instance().endDeserialization();
 
 			if (!missingType)
-				serializableObject->deserialize();
+			{
+				ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo);
+
+				serializableObject->deserialize(instance, mObjInfo);
+			}
 			else
-				mMissingTypeObjectData = serializableObject;
+				mSerializedObjectData = serializableObject;
 		}
 
 		if (!missingType)
-			mMissingTypeObjectData = nullptr;
+			mSerializedObjectData = nullptr;
 
 		mMissingType = missingType;
 		mRequiresReset = true;
@@ -173,7 +169,9 @@ namespace BansheeEngine
 
 	void ManagedComponent::update()
 	{
-		if (mUpdateThunk != nullptr && mManagedInstance != nullptr)
+		assert(mManagedInstance != nullptr);
+
+		if (mUpdateThunk != nullptr)
 		{
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
@@ -183,7 +181,9 @@ namespace BansheeEngine
 
 	void ManagedComponent::triggerOnReset()
 	{
-		if (mRequiresReset && mOnResetThunk != nullptr && mManagedInstance != nullptr)
+		assert(mManagedInstance != nullptr);
+
+		if (mRequiresReset && mOnResetThunk != nullptr)
 		{
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
@@ -193,8 +193,22 @@ namespace BansheeEngine
 		mRequiresReset = false;
 	}
 
-	void ManagedComponent::onInitialized()
+	void ManagedComponent::instantiate()
 	{
+		mObjInfo = nullptr;
+		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo))
+		{
+			MonoObject* instance = ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
+
+			initialize(instance);
+			mMissingType = true;
+		}
+		else
+		{
+			initialize(mObjInfo->mMonoClass->createInstance());
+			mMissingType = false;
+		}
+
 		assert(mManagedInstance != nullptr);
 
 		// Find handle to self
@@ -214,6 +228,17 @@ namespace BansheeEngine
 
 		assert(componentHandle != nullptr);
 		ScriptComponent* nativeInstance = ScriptGameObjectManager::instance().createScriptComponent(mManagedInstance, componentHandle);
+	}
+
+	void ManagedComponent::onInitialized()
+	{
+		assert(mManagedInstance != nullptr);
+
+		if (mSerializedObjectData != nullptr && !mMissingType)
+		{
+			mSerializedObjectData->deserialize(mManagedInstance, mObjInfo);
+			mSerializedObjectData = nullptr;
+		}
 
 		if (mOnInitializedThunk != nullptr)
 		{
@@ -236,11 +261,8 @@ namespace BansheeEngine
 			MonoUtil::invokeThunk(mOnDestroyThunk, mManagedInstance);
 		}
 
-		if (mManagedInstance != nullptr)
-		{
-			mManagedInstance = nullptr;
-			mono_gchandle_free(mManagedHandle);
-		}
+		mManagedInstance = nullptr;
+		mono_gchandle_free(mManagedHandle);
 	}
 
 	void ManagedComponent::onEnabled()

+ 13 - 8
SBansheeEngine/Source/BsManagedSerializableObject.cpp

@@ -112,18 +112,23 @@ namespace BansheeEngine
 
 	void ManagedSerializableObject::deserialize()
 	{
-		mManagedInstance = createManagedInstance(mObjInfo->mTypeInfo);
-
-		if (mManagedInstance == nullptr)
+		// See if this type even still exists
+		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
+		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mObjInfo->mTypeInfo->mTypeNamespace, mObjInfo->mTypeInfo->mTypeName, currentObjInfo))
 		{
+			mManagedInstance = nullptr;
 			mCachedData.clear();
 			return;
 		}
 
-		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
+		deserialize(createManagedInstance(currentObjInfo->mTypeInfo), currentObjInfo);
+	}
 
-		// See if this type even still exists
-		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mObjInfo->mTypeInfo->mTypeNamespace, mObjInfo->mTypeInfo->mTypeName, currentObjInfo))
+	void ManagedSerializableObject::deserialize(MonoObject* instance, const ManagedSerializableObjectInfoPtr& objInfo)
+	{
+		mManagedInstance = instance;
+
+		if (mManagedInstance == nullptr)
 		{
 			mCachedData.clear();
 			return;
@@ -147,7 +152,7 @@ namespace BansheeEngine
 
 					ManagedSerializableFieldKey key(typeID, fieldId);
 
-					ManagedSerializableFieldInfoPtr matchingFieldInfo = currentObjInfo->findMatchingField(field.second, curType->mTypeInfo);
+					ManagedSerializableFieldInfoPtr matchingFieldInfo = objInfo->findMatchingField(field.second, curType->mTypeInfo);
 					if (matchingFieldInfo != nullptr)
 						setFieldData(matchingFieldInfo, mCachedData[key]);
 
@@ -158,7 +163,7 @@ namespace BansheeEngine
 			curType = curType->mBaseClass;
 		}
 
-		mObjInfo = currentObjInfo;
+		mObjInfo = objInfo;
 		mCachedData.clear();
 	}
 

+ 1 - 0
TODO.txt

@@ -90,6 +90,7 @@ Other polish:
    - This has to work not only when I come back to the object, but whenever inspector rebuilds (e.g. after removing element from array)
    - Consider saving this information with the serialized object
  - Make sure to persist EditorSettings
+ - Doubleclick on a prefab in Project should open that level
  - Import option inspectors for Texture, Mesh, Font
  - Update GUISlider so it works with the new style (and to have min/max limits, plus step size)
  - Add "focus on object" key (F) - animate it: rotate camera towards then speed towards while zooming in