Browse Source

Prefab diff now properly handles the case when a component added by the diff already exists
Scene objects no longer allow for more than one type of component

BearishSun 10 years ago
parent
commit
95cea2ed0b

+ 8 - 0
BansheeCore/Include/BsComponent.h

@@ -29,6 +29,14 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual void update() { }
 		virtual void update() { }
 
 
+		/**
+		 * @brief	Checks if this and the provided component represent the same type.
+		 * 			
+		 * @note	RTTI type cannot be checked directly since components can be further specialized internally 
+		 * 			for scripting purposes.
+		 */
+		virtual bool typeEquals(const Component& other);
+
 		/**
 		/**
 		 * @brief	Removes the component from parent SceneObject and deletes it. All
 		 * @brief	Removes the component from parent SceneObject and deletes it. All
 		 * 			the references to this component will be marked as destroyed and you
 		 * 			the references to this component will be marked as destroyed and you

+ 6 - 0
BansheeCore/Include/BsSceneObject.h

@@ -521,6 +521,12 @@ namespace BansheeEngine
 				std::forward<Args>(args)...),
 				std::forward<Args>(args)...),
 				&bs_delete<T>, StdAlloc<T>());
 				&bs_delete<T>, StdAlloc<T>());
 
 
+			for (auto& component : mComponents)
+			{
+				if (component->typeEquals(*gameObject))
+					return component; // Component of this type already exists
+			}
+
 			GameObjectHandle<T> newComponent =
 			GameObjectHandle<T> newComponent =
 				GameObjectManager::instance().registerObject(gameObject);
 				GameObjectManager::instance().registerObject(gameObject);
 
 

+ 5 - 0
BansheeCore/Source/BsComponent.cpp

@@ -15,6 +15,11 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	bool Component::typeEquals(const Component& other)
+	{
+		return getRTTI()->getRTTIId() == other.getRTTI()->getRTTIId();
+	}
+
 	void Component::destroy(bool immediate)
 	void Component::destroy(bool immediate)
 	{
 	{
 		SO()->destroyComponent(this, immediate);
 		SO()->destroyComponent(this, immediate);

+ 32 - 1
BansheeCore/Source/BsPrefabDiff.cpp

@@ -111,7 +111,38 @@ namespace BansheeEngine
 		{
 		{
 			BinarySerializer bs;
 			BinarySerializer bs;
 			SPtr<Component> component = std::static_pointer_cast<Component>(bs._decodeIntermediate(addedComponentData));
 			SPtr<Component> component = std::static_pointer_cast<Component>(bs._decodeIntermediate(addedComponentData));
-			object->addComponentInternal(component);
+
+			// It's possible the prefab added the same component that is in the diff, in which case we replace the existing
+			// component with the new one
+			bool foundExisting = false;
+			for (auto& entry : components)
+			{
+				if (entry->typeEquals(*component))
+				{
+					GameObjectInstanceDataPtr instanceData = entry->_getInstanceData();
+					entry->destroy(true);
+
+					component->_setInstanceData(instanceData);
+					object->addComponentInternal(component);
+
+					/*
+					SPtr<SerializedObject> encodedPrefab = bs._encodeIntermediate(entry.get());
+					SPtr<SerializedObject> encodedInstance = bs._encodeIntermediate(component.get());
+
+					IDiff& diffHandler = entry->getRTTI()->getDiffHandler();
+					SPtr<SerializedObject> componentDiff = diffHandler.generateDiff(encodedPrefab, encodedInstance);
+					
+					diffHandler.applyDiff(entry.getInternalPtr(), componentDiff);*/
+
+					foundExisting = true;
+					break;
+				}
+			}
+
+			if (!foundExisting)
+			{
+				object->addComponentInternal(component);
+			}			
 		}
 		}
 
 
 		for (auto& addedChildData : diff->addedChildren)
 		for (auto& addedChildData : diff->addedChildren)

+ 5 - 0
SBansheeEngine/Include/BsManagedComponent.h

@@ -152,6 +152,11 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual void update() override;
 		virtual void update() override;
 
 
+		/**
+		 * @copydoc	Component::typeEquals
+		 */
+		virtual bool typeEquals(const Component& other) override;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		/************************************************************************/

+ 13 - 0
SBansheeEngine/Source/BsManagedComponent.cpp

@@ -167,6 +167,19 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	bool ManagedComponent::typeEquals(const Component& other)
+	{
+		if(Component::typeEquals(other))
+		{
+			const ManagedComponent& otherMC = static_cast<const ManagedComponent&>(other);
+
+			// Not comparing MonoReflectionType directly because this needs to be able to work before instantiation
+			return mNamespace == otherMC.getManagedNamespace() && mTypeName == otherMC.getManagedTypeName();
+		}
+
+		return false;
+	}
+
 	void ManagedComponent::update()
 	void ManagedComponent::update()
 	{
 	{
 		assert(mManagedInstance != nullptr);
 		assert(mManagedInstance != nullptr);

+ 14 - 0
SBansheeEngine/Source/BsScriptComponent.cpp

@@ -40,6 +40,20 @@ namespace BansheeEngine
 		if (checkIfDestroyed(so))
 		if (checkIfDestroyed(so))
 			return nullptr;
 			return nullptr;
 
 
+		const Vector<HComponent>& mComponents = so->getComponents();
+		for (auto& component : mComponents)
+		{
+			if (component->getTypeId() == TID_ManagedComponent)
+			{
+				GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
+
+				if (managedComponent->getRuntimeType() == type)
+				{
+					return managedComponent->getManagedInstance();
+				}
+			}
+		}
+
 		GameObjectHandle<ManagedComponent> mc = so->addComponent<ManagedComponent>(type);
 		GameObjectHandle<ManagedComponent> mc = so->addComponent<ManagedComponent>(type);
 
 
 		return mc->getManagedInstance();
 		return mc->getManagedInstance();