Просмотр исходного кода

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 10 лет назад
Родитель
Сommit
809719519c

+ 7 - 0
BansheeCore/Include/BsComponent.h

@@ -46,6 +46,13 @@ namespace BansheeEngine
 		Component(const HSceneObject& parent);
 		Component(const HSceneObject& parent);
 		virtual ~Component();
 		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.
 		 * @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 (isInstantiated())
 			{
 			{
-				if (getActive())
-					newComponent->onInitialized();
+				newComponent->instantiate();
+				newComponent->onInitialized();
 
 
-				newComponent->onEnabled();
+				if (getActive())
+					newComponent->onEnabled();
 			}
 			}
 
 
 			return newComponent;
 			return newComponent;

+ 24 - 9
BansheeCore/Source/BsSceneObject.cpp

@@ -174,19 +174,34 @@ namespace BansheeEngine
 	{
 	{
 		mFlags &= ~SOF_DontInstantiate;
 		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 mIsHighlighted;
 			bool mIsVisible;
 			bool mIsVisible;
 			bool mIsGrayedOut;
 			bool mIsGrayedOut;
+			Color mTint;
 
 
 			bool isParentRec(TreeElement* element) const;
 			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++)
 			for(UINT32 i = 0; i < currentSO->getNumChildren(); i++)
 			{
 			{
 				HSceneObject currentSOChild = currentSO->getChild(i);
 				HSceneObject currentSOChild = currentSO->getChild(i);
+				bool isInternal = currentSOChild->hasFlag(SOF_Internal);
 
 
 #if BS_DEBUG_MODE == 0
 #if BS_DEBUG_MODE == 0
-				if (currentSOChild->hasFlag(SOF_Internal))
+				if (isInternal)
 					continue;
 					continue;
 #endif
 #endif
 
 
@@ -161,6 +162,7 @@ namespace BansheeEngine
 					newChild->mName = currentSOChild->getName();
 					newChild->mName = currentSOChild->getName();
 					newChild->mSortedIdx = (UINT32)newChildren.size();
 					newChild->mSortedIdx = (UINT32)newChildren.size();
 					newChild->mIsVisible = element->mIsVisible && element->mIsExpanded;
 					newChild->mIsVisible = element->mIsVisible && element->mIsExpanded;
+					newChild->mTint = isInternal ? Color::Red : Color::White;
 
 
 					newChildren.push_back(newChild);
 					newChildren.push_back(newChild);
 
 

+ 9 - 1
BansheeEditor/Source/BsGUITreeView.cpp

@@ -786,7 +786,15 @@ namespace BansheeEngine
 				_registerChildElement(element->mElement);
 				_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)
 			if(element->mChildren.size() > 0)
 			{
 			{

+ 7 - 2
SBansheeEngine/Include/BsManagedComponent.h

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

+ 5 - 37
SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -41,7 +41,7 @@ namespace BansheeEngine
 
 
 		void setObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
 		void setObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
 		{
 		{
-			obj->mRTTIData = val;
+			obj->mSerializedObjectData = val;
 		}
 		}
 
 
 		bool& getMissingType(ManagedComponent* obj)
 		bool& getMissingType(ManagedComponent* obj)
@@ -54,16 +54,6 @@ namespace BansheeEngine
 			obj->mMissingType = val;
 			obj->mMissingType = val;
 		}
 		}
 
 
-		ManagedSerializableObjectPtr getMissingTypeObjectData(ManagedComponent* obj)
-		{
-			return obj->mMissingTypeObjectData;
-		}
-
-		void setMissingTypeObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
-		{
-			obj->mMissingTypeObjectData = val;
-		}
-
 	public:
 	public:
 		ManagedComponentRTTI()
 		ManagedComponentRTTI()
 		{
 		{
@@ -71,49 +61,27 @@ namespace BansheeEngine
 			addPlainField("mTypename", 1, &ManagedComponentRTTI::getTypename, &ManagedComponentRTTI::setTypename);
 			addPlainField("mTypename", 1, &ManagedComponentRTTI::getTypename, &ManagedComponentRTTI::setTypename);
 			addReflectablePtrField("mObjectData", 2, &ManagedComponentRTTI::getObjectData, &ManagedComponentRTTI::setObjectData);
 			addReflectablePtrField("mObjectData", 2, &ManagedComponentRTTI::getObjectData, &ManagedComponentRTTI::setObjectData);
 			addPlainField("mMissingType", 3, &ManagedComponentRTTI::getMissingType, &ManagedComponentRTTI::setMissingType);
 			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);
 			ManagedComponent* mc = static_cast<ManagedComponent*>(obj);
 
 
 			mc->mRTTIData = ManagedSerializableObject::createFromExisting(mc->getManagedInstance());
 			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";
 			static String name = "ManagedComponent";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_ManagedComponent;
 			return TID_ManagedComponent;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
 			return GameObjectRTTI::createGameObject<ManagedComponent>();
 			return GameObjectRTTI::createGameObject<ManagedComponent>();
 		}
 		}

+ 13 - 0
SBansheeEngine/Include/BsManagedSerializableObject.h

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

+ 13 - 8
SBansheeEngine/Source/BsManagedSerializableObject.cpp

@@ -112,18 +112,23 @@ namespace BansheeEngine
 
 
 	void ManagedSerializableObject::deserialize()
 	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();
 			mCachedData.clear();
 			return;
 			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();
 			mCachedData.clear();
 			return;
 			return;
@@ -147,7 +152,7 @@ namespace BansheeEngine
 
 
 					ManagedSerializableFieldKey key(typeID, fieldId);
 					ManagedSerializableFieldKey key(typeID, fieldId);
 
 
-					ManagedSerializableFieldInfoPtr matchingFieldInfo = currentObjInfo->findMatchingField(field.second, curType->mTypeInfo);
+					ManagedSerializableFieldInfoPtr matchingFieldInfo = objInfo->findMatchingField(field.second, curType->mTypeInfo);
 					if (matchingFieldInfo != nullptr)
 					if (matchingFieldInfo != nullptr)
 						setFieldData(matchingFieldInfo, mCachedData[key]);
 						setFieldData(matchingFieldInfo, mCachedData[key]);
 
 
@@ -158,7 +163,7 @@ namespace BansheeEngine
 			curType = curType->mBaseClass;
 			curType = curType->mBaseClass;
 		}
 		}
 
 
-		mObjInfo = currentObjInfo;
+		mObjInfo = objInfo;
 		mCachedData.clear();
 		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)
    - 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
    - Consider saving this information with the serialized object
  - Make sure to persist EditorSettings
  - Make sure to persist EditorSettings
+ - Doubleclick on a prefab in Project should open that level
  - Import option inspectors for Texture, Mesh, Font
  - 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)
  - 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
  - Add "focus on object" key (F) - animate it: rotate camera towards then speed towards while zooming in