Explorar o código

Added Rigidbody C++ component
SceneObjects can now contain more than one component of the same type
Retrieving components from SceneObjects can now be done by using base type instead of exact type

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

+ 18 - 3
BansheeCore/Include/BsCCollider.h

@@ -61,15 +61,21 @@ namespace BansheeEngine
 		/** @copydoc Collider::getRigidbody */
 		/** @copydoc Collider::getRigidbody */
 		HRigidbody getRigidbody() const { return mParent; }
 		HRigidbody getRigidbody() const { return mParent; }
 
 
-		/** @copydoc Collider::setIsTrigger */
+		/** @copydoc Collider::onCollisionBegin */
 		Event<void(const CollisionData&)> onCollisionBegin;
 		Event<void(const CollisionData&)> onCollisionBegin;
 
 
-		/** @copydoc Collider::setIsTrigger */
+		/** @copydoc Collider::onCollisionStay */
 		Event<void(const CollisionData&)> onCollisionStay;
 		Event<void(const CollisionData&)> onCollisionStay;
 
 
-		/** @copydoc Collider::setIsTrigger */
+		/** @copydoc Collider::onCollisionEnd */
 		Event<void(const CollisionData&)> onCollisionEnd;
 		Event<void(const CollisionData&)> onCollisionEnd;
 
 
+		/** @cond INTERNAL */
+
+		/** Changes the rigidbody parent of the collider. Meant to be called from the Rigidbody itself. */
+		void _setRigidbody(const HRigidbody& rigidbody);
+
+		/** @endcond */
 		/************************************************************************/
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -106,6 +112,15 @@ namespace BansheeEngine
 		/** Searches the parent scene object hierarchy to find a parent Rigidbody component. */
 		/** Searches the parent scene object hierarchy to find a parent Rigidbody component. */
 		void updateParentRigidbody();
 		void updateParentRigidbody();
 
 
+		/** Triggered when the internal collider begins touching another object. */
+		void triggerOnCollisionBegin(const CollisionData& data);
+
+		/** Triggered when the internal collider continues touching another object. */
+		void triggerOnCollisionStay(const CollisionData& data);
+
+		/** Triggered when the internal collider ends touching another object. */
+		void triggerOnCollisionEnd(const CollisionData& data);
+
 		SPtr<Collider> mInternal;
 		SPtr<Collider> mInternal;
 
 
 		UINT64 mLayer = 1;
 		UINT64 mLayer = 1;

+ 185 - 3
BansheeCore/Include/BsCRigidbody.h

@@ -5,6 +5,8 @@
 #include "BsCorePrerequisites.h"
 #include "BsCorePrerequisites.h"
 #include "BsRigidbody.h"
 #include "BsRigidbody.h"
 #include "BsComponent.h"
 #include "BsComponent.h"
+#include "BsVector3.h"
+#include "BsQuaternion.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -22,11 +24,160 @@ namespace BansheeEngine
 	public:
 	public:
 		CRigidbody(const HSceneObject& parent);
 		CRigidbody(const HSceneObject& parent);
 
 
-		// TODO
+		/** @copydoc Rigidbody::move */
+		inline void move(const Vector3& position);
+
+		/** @copydoc Rigidbody::rotate */
+		inline void rotate(const Quaternion& rotation);
+
+		/** @copydoc Rigidbody::setMass */
+		inline void setMass(float mass);
+
+		/** @copydoc Rigidbody::getMass */
+		float getMass() const { return mMass; };
+
+		/** @copydoc Rigidbody::setIsKinematic */
+		inline void setIsKinematic(bool kinematic);
+
+		/** @copydoc Rigidbody::getIsKinematic */
+		bool getIsKinematic() const { return mIsKinematic; }
+
+		/** @copydoc Rigidbody::isSleeping */
+		inline bool isSleeping() const;
+
+		/** @copydoc Rigidbody::sleep */
+		inline void sleep();
+
+		/** @copydoc Rigidbody::wakeUp */
+		inline void wakeUp();
+
+		/** @copydoc Rigidbody::setSleepThreshold */
+		inline void setSleepThreshold(float threshold);
+
+		/** @copydoc Rigidbody::getSleepThreshold */
+		float getSleepThreshold() const { return mSleepThreshold; }
+
+		/** @copydoc Rigidbody::setUseGravity */
+		inline void setUseGravity(bool gravity);
+
+		/** @copydoc Rigidbody::getUseGravity */
+		bool getUseGravity() const { return mUseGravity; }
+
+		/** @copydoc Rigidbody::setVelocity */
+		inline void setVelocity(const Vector3& velocity);
+
+		/** @copydoc Rigidbody::getVelocity */
+		inline Vector3 getVelocity() const;
+
+		/** @copydoc Rigidbody::setAngularVelocity */
+		inline void setAngularVelocity(const Vector3& velocity);
+
+		/** @copydoc Rigidbody::getAngularVelocity */
+		inline Vector3 getAngularVelocity() const;
+
+		/** @copydoc Rigidbody::setDrag */
+		inline void setDrag(float drag);
+
+		/** @copydoc Rigidbody::getDrag */
+		float getDrag() const { return mLinearDrag; }
+
+		/** @copydoc Rigidbody::setAngularDrag */
+		inline void setAngularDrag(float drag);
+
+		/** @copydoc Rigidbody::getAngularDrag */
+		float getAngularDrag() const { return mAngularDrag; }
+
+		/** @copydoc Rigidbody::setInertiaTensor */
+		inline void setInertiaTensor(const Vector3& tensor);
+
+		/** @copydoc Rigidbody::getInertiaTensor */
+		inline Vector3 getInertiaTensor() const;
+
+		/** @copydoc Rigidbody::setMaxAngularVelocity */
+		inline void setMaxAngularVelocity(float maxVelocity);
+
+		/** @copydoc Rigidbody::getMaxAngularVelocity */
+		float getMaxAngularVelocity() const { return mMaxAngularVelocity; }
+
+		/** @copydoc Rigidbody::setCenterOfMass */
+		inline void setCenterOfMass(const Vector3& position, const Quaternion& rotation);
+
+		/** @copydoc Rigidbody::getCenterOfMassPosition */
+		inline  Vector3 getCenterOfMassPosition() const;
+
+		/** @copydoc Rigidbody::getCenterOfMassRotation */
+		inline Quaternion getCenterOfMassRotation() const;
+
+		/** @copydoc Rigidbody::setPositionSolverCount */
+		inline void setPositionSolverCount(UINT32 count);
+
+		/** @copydoc Rigidbody::getPositionSolverCount */
+		UINT32 getPositionSolverCount() const { return mPositionSolverCount; }
+
+		/** @copydoc Rigidbody::setVelocitySolverCount */
+		inline void setVelocitySolverCount(UINT32 count);
+
+		/** @copydoc Rigidbody::getVelocitySolverCount */
+		UINT32 getVelocitySolverCount() const { return mVelocitySolverCount; }
+
+		/** @copydoc Rigidbody::setFlags */
+		inline void setFlags(Rigidbody::Flag flags);
+
+		/** @copydoc Rigidbody::getFlags */
+		Rigidbody::Flag getFlags() const { return mFlags; }
+
+		/** @copydoc Rigidbody::addForce */
+		inline void addForce(const Vector3& force, ForceMode mode = ForceMode::Force);
+
+		/** @copydoc Rigidbody::addTorque */
+		inline void addTorque(const Vector3& torque, ForceMode mode = ForceMode::Force);
+
+		/** @copydoc Rigidbody::addForceAtPoint */
+		inline void addForceAtPoint(const Vector3& force, const Vector3& position,
+			PointForceMode mode = PointForceMode::Force);
+
+		/** @copydoc Rigidbody::getVelocityAtPoint */
+		inline Vector3 getVelocityAtPoint(const Vector3& point) const;
+
+		/** @copydoc Rigidbody::onCollisionBegin */
+		Event<void(const CollisionData&)> onCollisionBegin;
+
+		/** @copydoc Rigidbody::onCollisionStay */
+		Event<void(const CollisionData&)> onCollisionStay;
+
+		/** @copydoc Rigidbody::onCollisionEnd */
+		Event<void(const CollisionData&)> onCollisionEnd;
+
+		/** @cond INTERNAL */
+
+		/** Returns the Rigidbody implementation wrapped by this component. */
 		SPtr<Rigidbody> _getInternal() const { return mInternal; }
 		SPtr<Rigidbody> _getInternal() const { return mInternal; }
-		void _updateMassDistribution() { }
+
+		/** @copydoc Rigidbody::_updateMassDistribution */
+		inline void _updateMassDistribution();
+
+		/** @endcond */
 	protected:
 	protected:
-		SPtr<Rigidbody> mInternal;
+		/** 
+		 * Searches child scene objects for Collider components and attaches them to the rigidbody. Make sure to call
+		 * clearChildColliders() if you need to clear old colliders first. 
+		 */
+		void updateChildColliders();
+
+		/** Unregisters all child colliders from the Rigidbody. */
+		void clearChildColliders();
+
+		/** Checks if the rigidbody is nested under another rigidbody, and throws out a warning if so. */
+		void checkForNestedRigibody();
+
+		/** Triggered when the internal rigidbody begins touching another object. */
+		void triggerOnCollisionBegin(const CollisionData& data);
+
+		/** Triggered when the internal rigidbody continues touching another object. */
+		void triggerOnCollisionStay(const CollisionData& data);
+
+		/** Triggered when the internal rigidbody ends touching another object. */
+		void triggerOnCollisionEnd(const CollisionData& data);
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/* 						COMPONENT OVERRIDES                      		*/
@@ -34,6 +185,37 @@ namespace BansheeEngine
 	protected:
 	protected:
 		friend class SceneObject;
 		friend class SceneObject;
 
 
+		/** @copydoc Component::onInitialized() */
+		void onInitialized() override;
+
+		/** @copydoc Component::onDestroyed() */
+		void onDestroyed() override;
+
+		/** @copydoc Component::onDisabled() */
+		void onDisabled() override;
+
+		/** @copydoc Component::onEnabled() */
+		void onEnabled() override;
+
+		/** @copydoc Component::onTransformChanged() */
+		void onTransformChanged(TransformChangedFlags flags) override;
+
+		SPtr<Rigidbody> mInternal;
+
+		UINT32 mPositionSolverCount = 4;
+		UINT32 mVelocitySolverCount = 1;
+		Rigidbody::Flag mFlags = (Rigidbody::Flag)((UINT32)Rigidbody::Flag::AutoTensors | (UINT32)Rigidbody::Flag::AutoMass);
+		Vector3 mCMassPosition;
+		Quaternion mCMassRotation;
+		Vector3 mIntertiaTensor;
+		float mMass = 0.0f;
+		float mMaxAngularVelocity = 1.0f;
+		float mLinearDrag = 0.0f;
+		float mAngularDrag = 0.0f;
+		float mSleepThreshold = 0.0f;
+		bool mUseGravity = true;
+		bool mIsKinematic = false;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		/************************************************************************/

+ 26 - 2
BansheeCore/Include/BsCRigidbodyRTTI.h

@@ -17,11 +17,35 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT CRigidbodyRTTI : public RTTIType<CRigidbody, Component, CRigidbodyRTTI>
 	class BS_CORE_EXPORT CRigidbodyRTTI : public RTTIType<CRigidbody, Component, CRigidbodyRTTI>
 	{
 	{
 	private:
 	private:
-
+		BS_PLAIN_MEMBER(mPositionSolverCount);
+		BS_PLAIN_MEMBER(mVelocitySolverCount);
+		BS_PLAIN_MEMBER(mFlags);
+		BS_PLAIN_MEMBER(mCMassPosition);
+		BS_PLAIN_MEMBER(mCMassRotation);
+		BS_PLAIN_MEMBER(mIntertiaTensor);
+		BS_PLAIN_MEMBER(mMass);
+		BS_PLAIN_MEMBER(mMaxAngularVelocity);
+		BS_PLAIN_MEMBER(mLinearDrag);
+		BS_PLAIN_MEMBER(mAngularDrag);
+		BS_PLAIN_MEMBER(mSleepThreshold);
+		BS_PLAIN_MEMBER(mUseGravity);
+		BS_PLAIN_MEMBER(mIsKinematic);
 	public:
 	public:
 		CRigidbodyRTTI()
 		CRigidbodyRTTI()
 		{
 		{
-
+			BS_ADD_PLAIN_FIELD(mPositionSolverCount, 0);
+			BS_ADD_PLAIN_FIELD(mVelocitySolverCount, 1);
+			BS_ADD_PLAIN_FIELD(mFlags, 2);
+			BS_ADD_PLAIN_FIELD(mCMassPosition, 3);
+			BS_ADD_PLAIN_FIELD(mCMassRotation, 4);
+			BS_ADD_PLAIN_FIELD(mIntertiaTensor, 5);
+			BS_ADD_PLAIN_FIELD(mMass, 6);
+			BS_ADD_PLAIN_FIELD(mMaxAngularVelocity, 7);
+			BS_ADD_PLAIN_FIELD(mLinearDrag, 8);
+			BS_ADD_PLAIN_FIELD(mAngularDrag, 9);
+			BS_ADD_PLAIN_FIELD(mSleepThreshold, 10);
+			BS_ADD_PLAIN_FIELD(mUseGravity, 11);
+			BS_ADD_PLAIN_FIELD(mIsKinematic, 12);
 		}
 		}
 
 
 		const String& getRTTIName() override
 		const String& getRTTIName() override

+ 0 - 3
BansheeCore/Include/BsCollider.h

@@ -30,9 +30,6 @@ namespace BansheeEngine
 		inline void setMaterial(const HPhysicsMaterial& material);
 		inline void setMaterial(const HPhysicsMaterial& material);
 		inline HPhysicsMaterial getMaterial() const;
 		inline HPhysicsMaterial getMaterial() const;
 
 
-		inline void setIsActive(bool value);
-		inline bool getIsActive() const;
-
 		inline void setContactOffset(float value);
 		inline void setContactOffset(float value);
 		inline float getContactOffset();
 		inline float getContactOffset();
 
 

+ 1 - 0
BansheeCore/Include/BsComponent.h

@@ -101,6 +101,7 @@ namespace BansheeEngine
 
 
 	protected:
 	protected:
 		HSceneObject mParent;
 		HSceneObject mParent;
+		HComponent mThisHandle;
 		TransformChangedFlags mNotifyFlags;
 		TransformChangedFlags mNotifyFlags;
 
 
 		/************************************************************************/
 		/************************************************************************/

+ 0 - 4
BansheeCore/Include/BsFCollider.h

@@ -30,9 +30,6 @@ namespace BansheeEngine
 		virtual void setMaterial(const HPhysicsMaterial& material);
 		virtual void setMaterial(const HPhysicsMaterial& material);
 		virtual HPhysicsMaterial getMaterial() const { return mMaterial; }
 		virtual HPhysicsMaterial getMaterial() const { return mMaterial; }
 
 
-		virtual void setIsActive(bool value);
-		virtual bool getIsActive() const { return mIsActive; }
-
 		virtual void setContactOffset(float value) = 0;
 		virtual void setContactOffset(float value) = 0;
 		virtual float getContactOffset() const = 0;
 		virtual float getContactOffset() const = 0;
 
 
@@ -42,7 +39,6 @@ namespace BansheeEngine
 		virtual void setLayer(UINT64 layer);
 		virtual void setLayer(UINT64 layer);
 		virtual UINT64 getLayer() const { return mLayer; }
 		virtual UINT64 getLayer() const { return mLayer; }
 	protected:
 	protected:
-		bool mIsActive = true;
 		UINT64 mLayer = 1;
 		UINT64 mLayer = 1;
 		float mMass = 1.0f;
 		float mMass = 1.0f;
 
 

+ 2 - 5
BansheeCore/Include/BsRigidbody.h

@@ -79,7 +79,7 @@ namespace BansheeEngine
 
 
 		virtual void setCenterOfMass(const Vector3& position, const Quaternion& rotation) = 0;
 		virtual void setCenterOfMass(const Vector3& position, const Quaternion& rotation) = 0;
 		virtual Vector3 getCenterOfMassPosition() const = 0;
 		virtual Vector3 getCenterOfMassPosition() const = 0;
-		virtual Quaternion getCenterOfMassRotatation() const = 0;
+		virtual Quaternion getCenterOfMassRotation() const = 0;
 
 
 		virtual void setPositionSolverCount(UINT32 count) = 0;
 		virtual void setPositionSolverCount(UINT32 count) = 0;
 		virtual UINT32 getPositionSolverCount() const = 0;
 		virtual UINT32 getPositionSolverCount() const = 0;
@@ -87,9 +87,6 @@ namespace BansheeEngine
 		virtual void setVelocitySolverCount(UINT32 count) = 0;
 		virtual void setVelocitySolverCount(UINT32 count) = 0;
 		virtual UINT32 getVelocitySolverCount() const = 0;
 		virtual UINT32 getVelocitySolverCount() const = 0;
 
 
-		virtual void setIsActive(bool value);
-		virtual bool getIsActive() const { return mIsActive; }
-
 		virtual void setFlags(Flag flags);
 		virtual void setFlags(Flag flags);
 		virtual Flag getFlags() const { return mFlags; }
 		virtual Flag getFlags() const { return mFlags; }
 
 
@@ -111,13 +108,13 @@ namespace BansheeEngine
 		void _setPriority(UINT32 priority);
 		void _setPriority(UINT32 priority);
 		void _setPhysicsId(UINT32 id) { mPhysicsId = id; }
 		void _setPhysicsId(UINT32 id) { mPhysicsId = id; }
 		void _setTransform(const Vector3& position, const Quaternion& rotation);
 		void _setTransform(const Vector3& position, const Quaternion& rotation);
+		void _detachColliders();
 	protected:
 	protected:
 		friend class FCollider;
 		friend class FCollider;
 
 
 		virtual void addCollider(FCollider* collider);
 		virtual void addCollider(FCollider* collider);
 		virtual void removeCollider(FCollider* collider);
 		virtual void removeCollider(FCollider* collider);
 
 
-		bool mIsActive = true;
 		Flag mFlags = Flag::None;
 		Flag mFlags = Flag::None;
 		UINT32 mPriority = 0;
 		UINT32 mPriority = 0;
 		UINT32 mPhysicsId = 0;
 		UINT32 mPhysicsId = 0;

+ 39 - 15
BansheeCore/Include/BsSceneObject.h

@@ -497,15 +497,10 @@ 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);
 
 
+			newComponent->mThisHandle = newComponent;
 			mComponents.push_back(newComponent);
 			mComponents.push_back(newComponent);
 
 
 			if (isInstantiated())
 			if (isInstantiated())
@@ -521,7 +516,8 @@ namespace BansheeEngine
 		}
 		}
 
 
 		/**
 		/**
-		 * Searches for a component with the specific type and returns the first one it finds. 
+		 * Searches for a component with the specific type and returns the first one it finds. Will also return components
+		 * derived from the type.
 		 * 			
 		 * 			
 		 * @tparam	typename T	Type of the component.
 		 * @tparam	typename T	Type of the component.
 		 * @return				Component if found, nullptr otherwise.
 		 * @return				Component if found, nullptr otherwise.
@@ -536,11 +532,38 @@ namespace BansheeEngine
 			static_assert((std::is_base_of<BansheeEngine::Component, T>::value), 
 			static_assert((std::is_base_of<BansheeEngine::Component, T>::value), 
 				"Specified type is not a valid Component.");
 				"Specified type is not a valid Component.");
 
 
-			return static_object_cast<T>(getComponent(T::getRTTIStatic()->getRTTIId()));
+			return static_object_cast<T>(getComponent(T::getRTTIStatic()));
 		}
 		}
 
 
 		/**
 		/**
-		 * Checks if the current object contains the specified component
+		 * Returns all components with the specific type. Will also return components derived from the type.
+		 * 			
+		 * @tparam	typename T	Type of the component.
+		 * @return				Array of found components.
+		 *
+		 * @note	
+		 * Don't call this too often as it is relatively slow. It is more efficient to call it once and store the result 
+		 * for further use.
+		 */
+		template <typename T>
+		Vector<GameObjectHandle<T>> getComponents()
+		{
+			static_assert((std::is_base_of<BansheeEngine::Component, T>::value), 
+				"Specified type is not a valid Component.");
+
+			Vector<GameObjectHandle<T>> output;
+
+			for (auto entry : mComponents)
+			{
+				if (entry->getRTTI()->isDerivedFrom(T::getRTTIStatic()))
+					output.push_back(entry);
+			}
+
+			return output;
+		}
+
+		/**
+		 * Checks if the current object contains the specified component or components derived from the provided type.
 		 * 			 			
 		 * 			 			
 		 * @tparam	typename T	Type of the component.
 		 * @tparam	typename T	Type of the component.
 		 * @return				True if component exists on the object.
 		 * @return				True if component exists on the object.
@@ -553,9 +576,9 @@ namespace BansheeEngine
 			static_assert((std::is_base_of<BansheeEngine::Component, T>::value), 
 			static_assert((std::is_base_of<BansheeEngine::Component, T>::value), 
 				"Specified type is not a valid Component.");
 				"Specified type is not a valid Component.");
 
 
-			for (auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
+			for (auto entry : mComponents)
 			{
 			{
-				if ((*iter)->getRTTI()->getRTTIId() == T::getRTTIStatic()->getRTTIId())
+				if (entry->getRTTI()->isDerivedFrom(T::getRTTIStatic()))
 					return true;
 					return true;
 			}
 			}
 
 
@@ -563,19 +586,20 @@ namespace BansheeEngine
 		}
 		}
 
 
 		/**
 		/**
-		 * Searches for a component with the specified type id and returns the first one it finds.
+		 * Searches for a component with the specified type and returns the first one it finds. Will also return components
+		 * derived from the type.
 		 * 			
 		 * 			
-		 * @param[in]	typeId	Identifier for the type.
+		 * @param[in]	type	RTTI information for the type.
 		 * @return				Component if found, nullptr otherwise.
 		 * @return				Component if found, nullptr otherwise.
 		 *
 		 *
 		 * @note	
 		 * @note	
 		 * Don't call this too often as it is relatively slow. It is more efficient to call it once and store the result
 		 * Don't call this too often as it is relatively slow. It is more efficient to call it once and store the result
 		 * for further use.
 		 * for further use.
 		 */
 		 */
-		HComponent getComponent(UINT32 typeId) const;
+		HComponent getComponent(RTTITypeBase* type) const;
 
 
 		/**
 		/**
-		 * Removes the component from this object, and deallocates it.
+		 * Removes the component from this object, and deallocates it. 
 		 *
 		 *
 		 * @param[in]	component	The component to destroy.
 		 * @param[in]	component	The component to destroy.
 		 * @param[in]	immediate	If true, the component will be deallocated and become unusable right away. Otherwise 
 		 * @param[in]	immediate	If true, the component will be deallocated and become unusable right away. Otherwise 

+ 39 - 1
BansheeCore/Source/BsCCollider.cpp

@@ -6,6 +6,8 @@
 #include "BsPhysics.h"
 #include "BsPhysics.h"
 #include "BsCColliderRTTI.h"
 #include "BsCColliderRTTI.h"
 
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	CCollider::CCollider(const HSceneObject& parent)
 	CCollider::CCollider(const HSceneObject& parent)
@@ -121,11 +123,32 @@ namespace BansheeEngine
 			updateTransform();
 			updateTransform();
 	}
 	}
 
 
+	void CCollider::_setRigidbody(const HRigidbody& rigidbody)
+	{
+		SPtr<Rigidbody> rigidBodyPtr;
+
+		if (rigidbody != nullptr)
+			rigidBodyPtr = rigidbody->_getInternal();
+
+		if (mInternal == nullptr)
+		{
+			mInternal->setRigidbody(rigidBodyPtr);
+			mParent = rigidbody;
+		}
+	}
+
 	void CCollider::restoreInternal()
 	void CCollider::restoreInternal()
 	{
 	{
-		if(mInternal == nullptr)
+		if (mInternal == nullptr)
+		{
 			mInternal = createInternal();
 			mInternal = createInternal();
 
 
+			mInternal->onCollisionBegin.connect(std::bind(&CCollider::triggerOnCollisionBegin, this, _1));
+			mInternal->onCollisionStay.connect(std::bind(&CCollider::triggerOnCollisionStay, this, _1));
+			mInternal->onCollisionEnd.connect(std::bind(&CCollider::triggerOnCollisionEnd, this, _1));
+		}
+
+		// Note: Merge into one call to avoid many virtual function calls
 		mInternal->setIsTrigger(mIsTrigger);
 		mInternal->setIsTrigger(mIsTrigger);
 		mInternal->setMass(mMass);
 		mInternal->setMass(mMass);
 		mInternal->setMaterial(mMaterial);
 		mInternal->setMaterial(mMaterial);
@@ -197,6 +220,21 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	void CCollider::triggerOnCollisionBegin(const CollisionData& data)
+	{
+		onCollisionBegin(data);
+	}
+
+	void CCollider::triggerOnCollisionStay(const CollisionData& data)
+	{
+		onCollisionStay(data);
+	}
+
+	void CCollider::triggerOnCollisionEnd(const CollisionData& data)
+	{
+		onCollisionEnd(data);
+	}
+
 	RTTITypeBase* CCollider::getRTTIStatic()
 	RTTITypeBase* CCollider::getRTTIStatic()
 	{
 	{
 		return CColliderRTTI::instance();
 		return CColliderRTTI::instance();

+ 366 - 0
BansheeCore/Source/BsCRigidbody.cpp

@@ -2,8 +2,11 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsCRigidbody.h"
 #include "BsCRigidbody.h"
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
+#include "BsCCollider.h"
 #include "BsCRigidbodyRTTI.h"
 #include "BsCRigidbodyRTTI.h"
 
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	CRigidbody::CRigidbody(const HSceneObject& parent)
 	CRigidbody::CRigidbody(const HSceneObject& parent)
@@ -12,6 +15,369 @@ namespace BansheeEngine
 		setName("Rigidbody");
 		setName("Rigidbody");
 	}
 	}
 
 
+	void CRigidbody::move(const Vector3& position)
+	{
+		if (mInternal != nullptr)
+			mInternal->move(position);
+	}
+
+	void CRigidbody::rotate(const Quaternion& rotation)
+	{
+		if (mInternal != nullptr)
+			mInternal->rotate(rotation);
+	}
+
+	void CRigidbody::setMass(float mass)
+	{
+		mMass = mass;
+
+		if(mInternal != nullptr)
+			mInternal->setMass(mass);
+	}
+
+	void CRigidbody::setIsKinematic(bool kinematic)
+	{
+		mIsKinematic = kinematic;
+		
+		if (mInternal != nullptr)
+			mInternal->setIsKinematic(kinematic);
+	}
+
+	bool CRigidbody::isSleeping() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->isSleeping();
+
+		return true;
+	}
+
+	void CRigidbody::sleep()
+	{
+		if (mInternal != nullptr)
+			return mInternal->sleep();
+	}
+
+	void CRigidbody::wakeUp()
+	{
+		if (mInternal != nullptr)
+			return mInternal->wakeUp();
+	}
+
+	void CRigidbody::setSleepThreshold(float threshold)
+	{
+		mSleepThreshold = threshold;
+
+		if (mInternal != nullptr)
+			mInternal->setSleepThreshold(threshold);
+	}
+
+	void CRigidbody::setUseGravity(bool gravity)
+	{
+		mUseGravity = gravity;
+
+		if (mInternal != nullptr)
+			mInternal->setUseGravity(gravity);
+	}
+
+	void CRigidbody::setVelocity(const Vector3& velocity)
+	{
+		if (mInternal != nullptr)
+			mInternal->setVelocity(velocity);
+	}
+
+	Vector3 CRigidbody::getVelocity() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getVelocity();
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::setAngularVelocity(const Vector3& velocity)
+	{
+		if (mInternal != nullptr)
+			mInternal->setAngularVelocity(velocity);
+	}
+
+	inline Vector3 CRigidbody::getAngularVelocity() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getAngularVelocity();
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::setDrag(float drag)
+	{
+		mLinearDrag = drag;
+
+		if (mInternal != nullptr)
+			mInternal->setDrag(drag);
+	}
+
+	void CRigidbody::setAngularDrag(float drag)
+	{
+		mAngularDrag = drag;
+
+		if (mInternal != nullptr)
+			mInternal->setAngularDrag(drag);
+	}
+
+	void CRigidbody::setInertiaTensor(const Vector3& tensor)
+	{
+		mIntertiaTensor = tensor;
+
+		if (mInternal != nullptr)
+			mInternal->setInertiaTensor(tensor);
+	}
+
+	Vector3 CRigidbody::getInertiaTensor() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getInertiaTensor();
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::setMaxAngularVelocity(float maxVelocity)
+	{
+		mMaxAngularVelocity = maxVelocity;
+
+		if (mInternal != nullptr)
+			mInternal->setMaxAngularVelocity(maxVelocity);
+	}
+
+	void CRigidbody::setCenterOfMass(const Vector3& position, const Quaternion& rotation)
+	{
+		mCMassPosition = position;
+		mCMassRotation = rotation;
+
+		if (mInternal != nullptr)
+			mInternal->setCenterOfMass(position, rotation);
+	}
+
+	Vector3 CRigidbody::getCenterOfMassPosition() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getCenterOfMassPosition();
+
+		return Vector3::ZERO;
+	}
+
+	Quaternion CRigidbody::getCenterOfMassRotation() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getCenterOfMassRotation();
+
+		return Quaternion::IDENTITY;
+	}
+
+	void CRigidbody::setPositionSolverCount(UINT32 count)
+	{
+		mPositionSolverCount = count;
+
+		if (mInternal != nullptr)
+			mInternal->setPositionSolverCount(count);
+	}
+
+	void CRigidbody::setVelocitySolverCount(UINT32 count)
+	{
+		mVelocitySolverCount = count;
+
+		if (mInternal != nullptr)
+			mInternal->setVelocitySolverCount(count);
+	}
+
+	void CRigidbody::setFlags(Rigidbody::Flag flags)
+	{
+		mFlags = flags;
+
+		if (mInternal != nullptr)
+			mInternal->setFlags(flags);
+	}
+
+	void CRigidbody::addForce(const Vector3& force, ForceMode mode)
+	{
+		if (mInternal != nullptr)
+			mInternal->addForce(force, mode);
+	}
+
+	void CRigidbody::addTorque(const Vector3& torque, ForceMode mode)
+	{
+		if (mInternal != nullptr)
+			mInternal->addTorque(torque, mode);
+	}
+
+	void CRigidbody::addForceAtPoint(const Vector3& force, const Vector3& position, PointForceMode mode)
+	{
+		if (mInternal != nullptr)
+			mInternal->addForceAtPoint(force, position, mode);
+	}
+
+	Vector3 CRigidbody::getVelocityAtPoint(const Vector3& point) const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getVelocityAtPoint(point);
+
+		return Vector3::ZERO;
+	}
+
+	void CRigidbody::_updateMassDistribution()
+	{
+		if (mInternal != nullptr)
+			return mInternal->_updateMassDistribution();
+	}
+
+	void CRigidbody::updateChildColliders()
+	{
+		Stack<HSceneObject> todo;
+		todo.push(SO());
+
+		while(!todo.empty())
+		{
+			HSceneObject currentSO = todo.top();
+			todo.pop();
+
+			if(currentSO->hasComponent<CCollider>())
+			{
+				Vector<HCollider> colliders = currentSO->getComponents<CCollider>();
+				
+				for (auto& entry : colliders)
+					entry->_setRigidbody(mThisHandle);
+			}
+
+			UINT32 childCount = currentSO->getNumChildren();
+			for (UINT32 i = 0; i < childCount; i++)
+			{
+				HSceneObject child = currentSO->getChild(i);
+
+				if (child->hasComponent<CRigidbody>())
+					continue;
+
+				todo.push(child);
+			}
+		}
+	}
+
+	void CRigidbody::clearChildColliders()
+	{
+		if (mInternal == nullptr)
+			return;
+
+		mInternal->_detachColliders();
+	}
+
+	void CRigidbody::checkForNestedRigibody()
+	{
+		HSceneObject currentSO = SO()->getParent();
+
+		while(currentSO != nullptr)
+		{
+			if(currentSO->hasComponent<CRigidbody>())
+			{
+				LOGWRN("Nested Rigidbodies detected. This will result in inconsistent transformations. To parent one " \
+					"Rigidbody to another move its colliders to the new parent, but remove the Rigidbody component.");
+				return;
+			}
+
+			currentSO = currentSO->getParent();
+		}
+	}
+
+	void CRigidbody::triggerOnCollisionBegin(const CollisionData& data)
+	{
+		onCollisionBegin(data);
+	}
+
+	void CRigidbody::triggerOnCollisionStay(const CollisionData& data)
+	{
+		onCollisionStay(data);
+	}
+
+	void CRigidbody::triggerOnCollisionEnd(const CollisionData& data)
+	{
+		onCollisionEnd(data);
+	}
+
+	void CRigidbody::onInitialized()
+	{
+
+	}
+
+	void CRigidbody::onDestroyed()
+	{
+		clearChildColliders();
+		mInternal = nullptr;
+	}
+
+	void CRigidbody::onDisabled()
+	{
+		clearChildColliders();
+		mInternal = nullptr;
+	}
+
+	void CRigidbody::onEnabled()
+	{
+		mInternal = Rigidbody::create(SO());
+
+		updateChildColliders();
+
+#if BS_DEBUG_MODE
+		checkForNestedRigibody();
+#endif
+
+		mInternal->onCollisionBegin.connect(std::bind(&CRigidbody::triggerOnCollisionBegin, this, _1));
+		mInternal->onCollisionStay.connect(std::bind(&CRigidbody::triggerOnCollisionStay, this, _1));
+		mInternal->onCollisionEnd.connect(std::bind(&CRigidbody::triggerOnCollisionEnd, this, _1));
+
+		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
+
+		// Note: Merge into one call to avoid many virtual function calls
+		mInternal->setPositionSolverCount(mPositionSolverCount);
+		mInternal->setVelocitySolverCount(mVelocitySolverCount);
+		mInternal->setMaxAngularVelocity(mMaxAngularVelocity);
+		mInternal->setDrag(mLinearDrag);
+		mInternal->setAngularDrag(mAngularDrag);
+		mInternal->setSleepThreshold(mSleepThreshold);
+		mInternal->setUseGravity(mUseGravity);
+		mInternal->setIsKinematic(mIsKinematic);
+
+		if(((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) == 0)
+		{
+			mInternal->setCenterOfMass(mCMassPosition, mCMassRotation);
+			mInternal->setInertiaTensor(mIntertiaTensor);
+			mInternal->setMass(mMass);
+		}
+		else
+		{
+			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoMass) == 0)
+				mInternal->setMass(mMass);
+
+			mInternal->_updateMassDistribution();
+		}
+	}
+
+	void CRigidbody::onTransformChanged(TransformChangedFlags flags)
+	{
+		if (!SO()->getActive())
+			return;
+
+		if((flags & TCF_Parent) != 0)
+		{
+			clearChildColliders();
+			updateChildColliders();
+
+			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) != 0)
+				mInternal->_updateMassDistribution();
+
+#if BS_DEBUG_MODE
+			checkForNestedRigibody();
+#endif
+		}
+
+		mInternal->setTransform(SO()->getWorldPosition(), SO()->getWorldRotation());
+	}
+
 	RTTITypeBase* CRigidbody::getRTTIStatic()
 	RTTITypeBase* CRigidbody::getRTTIStatic()
 	{
 	{
 		return CRigidbodyRTTI::instance();
 		return CRigidbodyRTTI::instance();

+ 0 - 10
BansheeCore/Source/BsCollider.cpp

@@ -58,16 +58,6 @@ namespace BansheeEngine
 		return mInternal->getMaterial();
 		return mInternal->getMaterial();
 	}
 	}
 
 
-	void Collider::setIsActive(bool value)
-	{
-		mInternal->setIsActive(value);
-	}
-
-	bool Collider::getIsActive() const
-	{
-		return mInternal->getIsActive();
-	}
-
 	void Collider::setContactOffset(float value)
 	void Collider::setContactOffset(float value)
 	{
 	{
 		mInternal->setContactOffset(value);
 		mInternal->setContactOffset(value);

+ 0 - 5
BansheeCore/Source/BsFCollider.cpp

@@ -28,11 +28,6 @@ namespace BansheeEngine
 		mMaterial = material;
 		mMaterial = material;
 	}
 	}
 
 
-	void FCollider::setIsActive(bool value)
-	{
-		mIsActive = value;
-	}
-
 	void FCollider::setLayer(UINT64 layer)
 	void FCollider::setLayer(UINT64 layer)
 	{
 	{
 		mLayer = layer;
 		mLayer = layer;

+ 510 - 531
BansheeCore/Source/BsPrefabDiff.cpp

@@ -1,534 +1,513 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPrefabDiff.h"
-#include "BsPrefabDiffRTTI.h"
-#include "BsSceneObject.h"
-#include "BsMemorySerializer.h"
-#include "BsBinarySerializer.h"
-#include "BsBinaryDiff.h"
-
-namespace BansheeEngine
-{
-	RTTITypeBase* PrefabComponentDiff::getRTTIStatic()
-	{
-		return PrefabComponentDiffRTTI::instance();
-	}
-
-	RTTITypeBase* PrefabComponentDiff::getRTTI() const
-	{
-		return PrefabComponentDiff::getRTTIStatic();
-	}
-
-	RTTITypeBase* PrefabObjectDiff::getRTTIStatic()
-	{
-		return PrefabObjectDiffRTTI::instance();
-	}
-
-	RTTITypeBase* PrefabObjectDiff::getRTTI() const
-	{
-		return PrefabObjectDiff::getRTTIStatic();
-	}
-
-	SPtr<PrefabDiff> PrefabDiff::create(const HSceneObject& prefab, const HSceneObject& instance)
-	{
-		if (prefab->mPrefabLinkUUID != instance->mPrefabLinkUUID)
-			return nullptr;
-
-		// Note: If this method is called multiple times in a row then renaming all objects every time is redundant, it
-		// would be more efficient to do it once outside of this method. I'm keeping it this way for simplicity for now.
-
-		// Rename instance objects so they share the same IDs as the prefab objects (if they link IDs match). This allows
-		// game object handle diff to work properly, because otherwise handles that point to same objects would be 
-		// marked as different because the instance IDs of the two objects don't match (since one is in prefab and one
-		// in instance).
-		Vector<RenamedGameObject> renamedObjects;
-		renameInstanceIds(prefab, instance, renamedObjects);
-
-		SPtr<PrefabDiff> output = bs_shared_ptr_new<PrefabDiff>();
-		output->mRoot = generateDiff(prefab, instance);
-
-		restoreInstanceIds(renamedObjects);
-
-		return output;
-	}
-
-	void PrefabDiff::apply(const HSceneObject& object)
-	{
-		if (mRoot == nullptr)
-			return;
-
-		GameObjectManager::instance().startDeserialization();
-		applyDiff(mRoot, object);
-		GameObjectManager::instance().endDeserialization();
-	}
-
-	void PrefabDiff::applyDiff(const SPtr<PrefabObjectDiff>& diff, const HSceneObject& object)
-	{
-		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Name) != 0)
-			object->setName(diff->name);
-
-		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Position) != 0)
-			object->setPosition(diff->position);
-
-		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Rotation) != 0)
-			object->setRotation(diff->rotation);
-
-		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Scale) != 0)
-			object->setScale(diff->scale);
-
-		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Active) != 0)
-			object->setActive(diff->isActive);
-
-		// Note: It is important to remove objects and components first, before adding them.
-		//		 Some systems rely on the fact that applyDiff added components/objects are 
-		//       always at the end.
-		const Vector<HComponent>& components = object->getComponents();
-		for (auto& removedId : diff->removedComponents)
-		{
-			for (auto component : components)
-			{
-				if (removedId == component->getLinkId())
-				{
-					component->destroy();
-					break;
-				}
-			}
-		}
-
-		for (auto& removedId : diff->removedChildren)
-		{
-			UINT32 childCount = object->getNumChildren();
-			for (UINT32 i = 0; i < childCount; i++)
-			{
-				HSceneObject child = object->getChild(i);
-				if (removedId == child->getLinkId())
-				{
-					child->destroy();
-					break;
-				}
-			}
-		}
-
-		for (auto& addedComponentData : diff->addedComponents)
-		{
-			BinarySerializer bs;
-			SPtr<Component> component = std::static_pointer_cast<Component>(bs._decodeIntermediate(addedComponentData));
-
-			// 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);
-
-					foundExisting = true;
-					break;
-				}
-			}
-
-			if (!foundExisting)
-			{
-				object->addComponentInternal(component);
-			}			
-		}
-
-		for (auto& addedChildData : diff->addedChildren)
-		{
-			BinarySerializer bs;
-			SPtr<SceneObject> sceneObject = std::static_pointer_cast<SceneObject>(bs._decodeIntermediate(addedChildData));
-			sceneObject->setParent(object);
-			sceneObject->_instantiate();
-		}
-
-		for (auto& componentDiff : diff->componentDiffs)
-		{
-			for (auto& component : components)
-			{
-				if (componentDiff->id == component->getLinkId())
-				{
-					IDiff& diffHandler = component->getRTTI()->getDiffHandler();
-					diffHandler.applyDiff(component.getInternalPtr(), componentDiff->data);
-					break;
-				}
-			}
-		}
-
-		for (auto& childDiff : diff->childDiffs)
-		{
-			UINT32 childCount = object->getNumChildren();
-			for (UINT32 i = 0; i < childCount; i++)
-			{
-				HSceneObject child = object->getChild(i);
-				if (childDiff->id == child->getLinkId())
-				{
-					applyDiff(childDiff, child);
-					break;
-				}
-			}
-		}
-	}
-
-	SPtr<PrefabObjectDiff> PrefabDiff::generateDiff(const HSceneObject& prefab, const HSceneObject& instance)
-	{
-		SPtr<PrefabObjectDiff> output;
-
-		if (prefab->getName() != instance->getName())
-		{
-			if (output == nullptr)
-				output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-			output->name = instance->getName();
-			output->soFlags |= (UINT32)SceneObjectDiffFlags::Name;
-		}
-
-		if (prefab->getPosition() != instance->getPosition())
-		{
-			if (output == nullptr)
-				output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-			output->position = instance->getPosition();
-			output->soFlags |= (UINT32)SceneObjectDiffFlags::Position;
-		}
-
-		if (prefab->getRotation() != instance->getRotation())
-		{
-			if (output == nullptr)
-				output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-			output->rotation = instance->getRotation();
-			output->soFlags |= (UINT32)SceneObjectDiffFlags::Rotation;
-		}
-
-		if (prefab->getScale() != instance->getScale())
-		{
-			if (output == nullptr)
-				output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-			output->scale = instance->getScale();
-			output->soFlags |= (UINT32)SceneObjectDiffFlags::Scale;
-		}
-
-		if (prefab->getActive() != instance->getActive())
-		{
-			if (output == nullptr)
-				output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-			output->isActive = instance->getActive();
-			output->soFlags |= (UINT32)SceneObjectDiffFlags::Active;
-		}
-
-		UINT32 prefabChildCount = prefab->getNumChildren();
-		UINT32 instanceChildCount = instance->getNumChildren();
-
-		// Find modified and removed children
-		for (UINT32 i = 0; i < prefabChildCount; i++)
-		{
-			HSceneObject prefabChild = prefab->getChild(i);
-
-			SPtr<PrefabObjectDiff> childDiff;
-			bool foundMatching = false;
-			for (UINT32 j = 0; j < instanceChildCount; j++)
-			{
-				HSceneObject instanceChild = instance->getChild(j);
-
-				if (prefabChild->getLinkId() == instanceChild->getLinkId())
-				{
-					if (instanceChild->mPrefabLinkUUID.empty())
-						childDiff = generateDiff(prefabChild, instanceChild);
-
-					foundMatching = true;
-					break;
-				}
-			}
-
-			if (foundMatching)
-			{
-				if (childDiff != nullptr)
-				{
-					if (output == nullptr)
-						output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-					output->childDiffs.push_back(childDiff);
-				}
-			}
-			else
-			{
-				if (output == nullptr)
-					output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-				output->removedChildren.push_back(prefabChild->getLinkId());
-			}	
-		}
-
-		// Find added children
-		for (UINT32 i = 0; i < instanceChildCount; i++)
-		{
-			HSceneObject instanceChild = instance->getChild(i);
-
-			if (instanceChild->hasFlag(SOF_DontSave))
-				continue;
-
-			bool foundMatching = false;
-			if (instanceChild->getLinkId() != -1)
-			{
-				for (UINT32 j = 0; j < prefabChildCount; j++)
-				{
-					HSceneObject prefabChild = prefab->getChild(j);
-
-					if (prefabChild->getLinkId() == instanceChild->getLinkId())
-					{
-						foundMatching = true;
-						break;
-					}
-				}
-			}
-
-			if (!foundMatching)
-			{
-				BinarySerializer bs;
-				SPtr<SerializedObject> obj = bs._encodeIntermediate(instanceChild.get());
-
-				if (output == nullptr)
-					output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-				output->addedChildren.push_back(obj);
-			}
-		}
-
-		const Vector<HComponent>& prefabComponents = prefab->getComponents();
-		const Vector<HComponent>& instanceComponents = instance->getComponents();
-
-		UINT32 prefabComponentCount = (UINT32)prefabComponents.size();
-		UINT32 instanceComponentCount = (UINT32)instanceComponents.size();
-
-		// Find modified and removed components
-		for (UINT32 i = 0; i < prefabComponentCount; i++)
-		{
-			HComponent prefabComponent = prefabComponents[i];
-
-			SPtr<PrefabComponentDiff> childDiff;
-			bool foundMatching = false;
-			for (UINT32 j = 0; j < instanceComponentCount; j++)
-			{
-				HComponent instanceComponent = instanceComponents[j];
-
-				if (prefabComponent->getLinkId() == instanceComponent->getLinkId())
-				{
-					BinarySerializer bs;
-					SPtr<SerializedObject> encodedPrefab = bs._encodeIntermediate(prefabComponent.get());
-					SPtr<SerializedObject> encodedInstance = bs._encodeIntermediate(instanceComponent.get());
-
-					IDiff& diffHandler = prefabComponent->getRTTI()->getDiffHandler();
-					SPtr<SerializedObject> diff = diffHandler.generateDiff(encodedPrefab, encodedInstance);
-
-					if (diff != nullptr)
-					{
-						childDiff = bs_shared_ptr_new<PrefabComponentDiff>();
-						childDiff->id = prefabComponent->getLinkId();
-						childDiff->data = diff;
-					}
-
-					foundMatching = true;
-					break;
-				}
-			}
-
-			if (foundMatching)
-			{
-				if (childDiff != nullptr)
-				{
-					if (output == nullptr)
-						output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-					output->componentDiffs.push_back(childDiff);
-				}
-			}
-			else
-			{
-				if (output == nullptr)
-					output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-				output->removedComponents.push_back(prefabComponent->getLinkId());
-			}
-		}
-
-		// Find added components
-		for (UINT32 i = 0; i < instanceComponentCount; i++)
-		{
-			HComponent instanceComponent = instanceComponents[i];
-
-			bool foundMatching = false;
-			if (instanceComponent->getLinkId() != -1)
-			{
-				for (UINT32 j = 0; j < prefabComponentCount; j++)
-				{
-					HComponent prefabComponent = prefabComponents[j];
-
-					if (prefabComponent->getLinkId() == instanceComponent->getLinkId())
-					{
-						foundMatching = true;
-						break;
-					}
-				}
-			}
-
-			if (!foundMatching)
-			{
-				BinarySerializer bs;
-				SPtr<SerializedObject> obj = bs._encodeIntermediate(instanceComponent.get());
-
-				if (output == nullptr)
-					output = bs_shared_ptr_new<PrefabObjectDiff>();
-
-				output->addedComponents.push_back(obj);
-			}
-		}
-
-		if (output != nullptr)
-			output->id = instance->getLinkId();
-
-		return output;
-	}
-
-	void PrefabDiff::renameInstanceIds(const HSceneObject& prefab, const HSceneObject& instance, Vector<RenamedGameObject>& output)
-	{
-		UnorderedMap<String, UnorderedMap<UINT32, UINT64>> linkToInstanceId;
-
-		struct StackEntry
-		{
-			HSceneObject so;
-			String uuid;
-		};
-
-		// When renaming it is important to rename the prefab and not the instance, since the diff will otherwise
-		// contain prefab's IDs, but will be used for the instance.
-
-		Stack<StackEntry> todo;
-		todo.push({ instance, "root" });
-
-		while (!todo.empty())
-		{
-			StackEntry current = todo.top();
-			todo.pop();
-
-			String childParentUUID;
-			if (current.so->mPrefabLinkUUID.empty())
-				childParentUUID = current.uuid;
-			else
-				childParentUUID = current.so->mPrefabLinkUUID;
-
-			UnorderedMap<UINT32, UINT64>& idMap = linkToInstanceId[childParentUUID];
-
-			const Vector<HComponent>& components = current.so->getComponents();
-			for (auto& component : components)
-			{
-				if (component->getLinkId() != (UINT32)-1)
-					idMap[component->getLinkId()] = component->getInstanceId();
-			}
-
-			UINT32 numChildren = current.so->getNumChildren();
-			for (UINT32 i = 0; i < numChildren; i++)
-			{
-				HSceneObject child = current.so->getChild(i);
-
-				if (child->getLinkId() != (UINT32)-1)
-					idMap[child->getLinkId()] = child->getInstanceId();
-
-				todo.push({ child, childParentUUID });
-			}
-		}
-
-		// Root has link ID from its parent so we handle it separately
-		{
-			output.push_back(RenamedGameObject());
-			RenamedGameObject& renamedGO = output.back();
-			renamedGO.instanceData = instance->mInstanceData;
-			renamedGO.originalId = instance->getInstanceId();
-
-			prefab->mInstanceData->mInstanceId = instance->getInstanceId();
-		}
-
-		todo.push({ prefab, "root" });
-		while (!todo.empty())
-		{
-			StackEntry current = todo.top();
-			todo.pop();
-
-			String childParentUUID;
-			if (current.so->mPrefabLinkUUID.empty())
-				childParentUUID = current.uuid;
-			else
-				childParentUUID = current.so->mPrefabLinkUUID;
-
-			auto iterFind = linkToInstanceId.find(childParentUUID);
-			if (iterFind != linkToInstanceId.end())
-			{
-				UnorderedMap<UINT32, UINT64>& idMap = iterFind->second;
-
-				const Vector<HComponent>& components = current.so->getComponents();
-				for (auto& component : components)
-				{
-					auto iterFind2 = idMap.find(component->getLinkId());
-					if (iterFind2 != idMap.end())
-					{
-						output.push_back(RenamedGameObject());
-						RenamedGameObject& renamedGO = output.back();
-						renamedGO.instanceData = component->mInstanceData;
-						renamedGO.originalId = component->getInstanceId();
-
-						component->mInstanceData->mInstanceId = iterFind2->second;
-					}
-				}
-			}
-
-			UINT32 numChildren = current.so->getNumChildren();
-			for (UINT32 i = 0; i < numChildren; i++)
-			{
-				HSceneObject child = current.so->getChild(i);
-
-				if (iterFind != linkToInstanceId.end())
-				{
-					if (child->getLinkId() != -1)
-					{
-						UnorderedMap<UINT32, UINT64>& idMap = iterFind->second;
-
-						auto iterFind2 = idMap.find(child->getLinkId());
-						if (iterFind2 != idMap.end())
-						{
-							output.push_back(RenamedGameObject());
-							RenamedGameObject& renamedGO = output.back();
-							renamedGO.instanceData = child->mInstanceData;
-							renamedGO.originalId = child->getInstanceId();
-
-							child->mInstanceData->mInstanceId = iterFind2->second;
-						}
-					}
-				}
-
-				todo.push({ child, childParentUUID });
-			}
-		}
-	}
-
-	void PrefabDiff::restoreInstanceIds(const Vector<RenamedGameObject>& renamedObjects)
-	{
-		for (auto& renamedGO : renamedObjects)
-			renamedGO.instanceData->mInstanceId = renamedGO.originalId;
-	}
-
-	RTTITypeBase* PrefabDiff::getRTTIStatic()
-	{
-		return PrefabDiffRTTI::instance();
-	}
-
-	RTTITypeBase* PrefabDiff::getRTTI() const
-	{
-		return PrefabDiff::getRTTIStatic();
-	}
+#include "BsPrefabDiff.h"
+#include "BsPrefabDiffRTTI.h"
+#include "BsSceneObject.h"
+#include "BsMemorySerializer.h"
+#include "BsBinarySerializer.h"
+#include "BsBinaryDiff.h"
+
+namespace BansheeEngine
+{
+	RTTITypeBase* PrefabComponentDiff::getRTTIStatic()
+	{
+		return PrefabComponentDiffRTTI::instance();
+	}
+
+	RTTITypeBase* PrefabComponentDiff::getRTTI() const
+	{
+		return PrefabComponentDiff::getRTTIStatic();
+	}
+
+	RTTITypeBase* PrefabObjectDiff::getRTTIStatic()
+	{
+		return PrefabObjectDiffRTTI::instance();
+	}
+
+	RTTITypeBase* PrefabObjectDiff::getRTTI() const
+	{
+		return PrefabObjectDiff::getRTTIStatic();
+	}
+
+	SPtr<PrefabDiff> PrefabDiff::create(const HSceneObject& prefab, const HSceneObject& instance)
+	{
+		if (prefab->mPrefabLinkUUID != instance->mPrefabLinkUUID)
+			return nullptr;
+
+		// Note: If this method is called multiple times in a row then renaming all objects every time is redundant, it
+		// would be more efficient to do it once outside of this method. I'm keeping it this way for simplicity for now.
+
+		// Rename instance objects so they share the same IDs as the prefab objects (if they link IDs match). This allows
+		// game object handle diff to work properly, because otherwise handles that point to same objects would be 
+		// marked as different because the instance IDs of the two objects don't match (since one is in prefab and one
+		// in instance).
+		Vector<RenamedGameObject> renamedObjects;
+		renameInstanceIds(prefab, instance, renamedObjects);
+
+		SPtr<PrefabDiff> output = bs_shared_ptr_new<PrefabDiff>();
+		output->mRoot = generateDiff(prefab, instance);
+
+		restoreInstanceIds(renamedObjects);
+
+		return output;
+	}
+
+	void PrefabDiff::apply(const HSceneObject& object)
+	{
+		if (mRoot == nullptr)
+			return;
+
+		GameObjectManager::instance().startDeserialization();
+		applyDiff(mRoot, object);
+		GameObjectManager::instance().endDeserialization();
+	}
+
+	void PrefabDiff::applyDiff(const SPtr<PrefabObjectDiff>& diff, const HSceneObject& object)
+	{
+		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Name) != 0)
+			object->setName(diff->name);
+
+		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Position) != 0)
+			object->setPosition(diff->position);
+
+		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Rotation) != 0)
+			object->setRotation(diff->rotation);
+
+		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Scale) != 0)
+			object->setScale(diff->scale);
+
+		if ((diff->soFlags & (UINT32)SceneObjectDiffFlags::Active) != 0)
+			object->setActive(diff->isActive);
+
+		// Note: It is important to remove objects and components first, before adding them.
+		//		 Some systems rely on the fact that applyDiff added components/objects are 
+		//       always at the end.
+		const Vector<HComponent>& components = object->getComponents();
+		for (auto& removedId : diff->removedComponents)
+		{
+			for (auto component : components)
+			{
+				if (removedId == component->getLinkId())
+				{
+					component->destroy();
+					break;
+				}
+			}
+		}
+
+		for (auto& removedId : diff->removedChildren)
+		{
+			UINT32 childCount = object->getNumChildren();
+			for (UINT32 i = 0; i < childCount; i++)
+			{
+				HSceneObject child = object->getChild(i);
+				if (removedId == child->getLinkId())
+				{
+					child->destroy();
+					break;
+				}
+			}
+		}
+
+		for (auto& addedComponentData : diff->addedComponents)
+		{
+			BinarySerializer bs;
+			SPtr<Component> component = std::static_pointer_cast<Component>(bs._decodeIntermediate(addedComponentData));
+
+			object->addComponentInternal(component);
+		}
+
+		for (auto& addedChildData : diff->addedChildren)
+		{
+			BinarySerializer bs;
+			SPtr<SceneObject> sceneObject = std::static_pointer_cast<SceneObject>(bs._decodeIntermediate(addedChildData));
+			sceneObject->setParent(object);
+			sceneObject->_instantiate();
+		}
+
+		for (auto& componentDiff : diff->componentDiffs)
+		{
+			for (auto& component : components)
+			{
+				if (componentDiff->id == component->getLinkId())
+				{
+					IDiff& diffHandler = component->getRTTI()->getDiffHandler();
+					diffHandler.applyDiff(component.getInternalPtr(), componentDiff->data);
+					break;
+				}
+			}
+		}
+
+		for (auto& childDiff : diff->childDiffs)
+		{
+			UINT32 childCount = object->getNumChildren();
+			for (UINT32 i = 0; i < childCount; i++)
+			{
+				HSceneObject child = object->getChild(i);
+				if (childDiff->id == child->getLinkId())
+				{
+					applyDiff(childDiff, child);
+					break;
+				}
+			}
+		}
+	}
+
+	SPtr<PrefabObjectDiff> PrefabDiff::generateDiff(const HSceneObject& prefab, const HSceneObject& instance)
+	{
+		SPtr<PrefabObjectDiff> output;
+
+		if (prefab->getName() != instance->getName())
+		{
+			if (output == nullptr)
+				output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+			output->name = instance->getName();
+			output->soFlags |= (UINT32)SceneObjectDiffFlags::Name;
+		}
+
+		if (prefab->getPosition() != instance->getPosition())
+		{
+			if (output == nullptr)
+				output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+			output->position = instance->getPosition();
+			output->soFlags |= (UINT32)SceneObjectDiffFlags::Position;
+		}
+
+		if (prefab->getRotation() != instance->getRotation())
+		{
+			if (output == nullptr)
+				output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+			output->rotation = instance->getRotation();
+			output->soFlags |= (UINT32)SceneObjectDiffFlags::Rotation;
+		}
+
+		if (prefab->getScale() != instance->getScale())
+		{
+			if (output == nullptr)
+				output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+			output->scale = instance->getScale();
+			output->soFlags |= (UINT32)SceneObjectDiffFlags::Scale;
+		}
+
+		if (prefab->getActive() != instance->getActive())
+		{
+			if (output == nullptr)
+				output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+			output->isActive = instance->getActive();
+			output->soFlags |= (UINT32)SceneObjectDiffFlags::Active;
+		}
+
+		UINT32 prefabChildCount = prefab->getNumChildren();
+		UINT32 instanceChildCount = instance->getNumChildren();
+
+		// Find modified and removed children
+		for (UINT32 i = 0; i < prefabChildCount; i++)
+		{
+			HSceneObject prefabChild = prefab->getChild(i);
+
+			SPtr<PrefabObjectDiff> childDiff;
+			bool foundMatching = false;
+			for (UINT32 j = 0; j < instanceChildCount; j++)
+			{
+				HSceneObject instanceChild = instance->getChild(j);
+
+				if (prefabChild->getLinkId() == instanceChild->getLinkId())
+				{
+					if (instanceChild->mPrefabLinkUUID.empty())
+						childDiff = generateDiff(prefabChild, instanceChild);
+
+					foundMatching = true;
+					break;
+				}
+			}
+
+			if (foundMatching)
+			{
+				if (childDiff != nullptr)
+				{
+					if (output == nullptr)
+						output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+					output->childDiffs.push_back(childDiff);
+				}
+			}
+			else
+			{
+				if (output == nullptr)
+					output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+				output->removedChildren.push_back(prefabChild->getLinkId());
+			}	
+		}
+
+		// Find added children
+		for (UINT32 i = 0; i < instanceChildCount; i++)
+		{
+			HSceneObject instanceChild = instance->getChild(i);
+
+			if (instanceChild->hasFlag(SOF_DontSave))
+				continue;
+
+			bool foundMatching = false;
+			if (instanceChild->getLinkId() != -1)
+			{
+				for (UINT32 j = 0; j < prefabChildCount; j++)
+				{
+					HSceneObject prefabChild = prefab->getChild(j);
+
+					if (prefabChild->getLinkId() == instanceChild->getLinkId())
+					{
+						foundMatching = true;
+						break;
+					}
+				}
+			}
+
+			if (!foundMatching)
+			{
+				BinarySerializer bs;
+				SPtr<SerializedObject> obj = bs._encodeIntermediate(instanceChild.get());
+
+				if (output == nullptr)
+					output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+				output->addedChildren.push_back(obj);
+			}
+		}
+
+		const Vector<HComponent>& prefabComponents = prefab->getComponents();
+		const Vector<HComponent>& instanceComponents = instance->getComponents();
+
+		UINT32 prefabComponentCount = (UINT32)prefabComponents.size();
+		UINT32 instanceComponentCount = (UINT32)instanceComponents.size();
+
+		// Find modified and removed components
+		for (UINT32 i = 0; i < prefabComponentCount; i++)
+		{
+			HComponent prefabComponent = prefabComponents[i];
+
+			SPtr<PrefabComponentDiff> childDiff;
+			bool foundMatching = false;
+			for (UINT32 j = 0; j < instanceComponentCount; j++)
+			{
+				HComponent instanceComponent = instanceComponents[j];
+
+				if (prefabComponent->getLinkId() == instanceComponent->getLinkId())
+				{
+					BinarySerializer bs;
+					SPtr<SerializedObject> encodedPrefab = bs._encodeIntermediate(prefabComponent.get());
+					SPtr<SerializedObject> encodedInstance = bs._encodeIntermediate(instanceComponent.get());
+
+					IDiff& diffHandler = prefabComponent->getRTTI()->getDiffHandler();
+					SPtr<SerializedObject> diff = diffHandler.generateDiff(encodedPrefab, encodedInstance);
+
+					if (diff != nullptr)
+					{
+						childDiff = bs_shared_ptr_new<PrefabComponentDiff>();
+						childDiff->id = prefabComponent->getLinkId();
+						childDiff->data = diff;
+					}
+
+					foundMatching = true;
+					break;
+				}
+			}
+
+			if (foundMatching)
+			{
+				if (childDiff != nullptr)
+				{
+					if (output == nullptr)
+						output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+					output->componentDiffs.push_back(childDiff);
+				}
+			}
+			else
+			{
+				if (output == nullptr)
+					output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+				output->removedComponents.push_back(prefabComponent->getLinkId());
+			}
+		}
+
+		// Find added components
+		for (UINT32 i = 0; i < instanceComponentCount; i++)
+		{
+			HComponent instanceComponent = instanceComponents[i];
+
+			bool foundMatching = false;
+			if (instanceComponent->getLinkId() != -1)
+			{
+				for (UINT32 j = 0; j < prefabComponentCount; j++)
+				{
+					HComponent prefabComponent = prefabComponents[j];
+
+					if (prefabComponent->getLinkId() == instanceComponent->getLinkId())
+					{
+						foundMatching = true;
+						break;
+					}
+				}
+			}
+
+			if (!foundMatching)
+			{
+				BinarySerializer bs;
+				SPtr<SerializedObject> obj = bs._encodeIntermediate(instanceComponent.get());
+
+				if (output == nullptr)
+					output = bs_shared_ptr_new<PrefabObjectDiff>();
+
+				output->addedComponents.push_back(obj);
+			}
+		}
+
+		if (output != nullptr)
+			output->id = instance->getLinkId();
+
+		return output;
+	}
+
+	void PrefabDiff::renameInstanceIds(const HSceneObject& prefab, const HSceneObject& instance, Vector<RenamedGameObject>& output)
+	{
+		UnorderedMap<String, UnorderedMap<UINT32, UINT64>> linkToInstanceId;
+
+		struct StackEntry
+		{
+			HSceneObject so;
+			String uuid;
+		};
+
+		// When renaming it is important to rename the prefab and not the instance, since the diff will otherwise
+		// contain prefab's IDs, but will be used for the instance.
+
+		Stack<StackEntry> todo;
+		todo.push({ instance, "root" });
+
+		while (!todo.empty())
+		{
+			StackEntry current = todo.top();
+			todo.pop();
+
+			String childParentUUID;
+			if (current.so->mPrefabLinkUUID.empty())
+				childParentUUID = current.uuid;
+			else
+				childParentUUID = current.so->mPrefabLinkUUID;
+
+			UnorderedMap<UINT32, UINT64>& idMap = linkToInstanceId[childParentUUID];
+
+			const Vector<HComponent>& components = current.so->getComponents();
+			for (auto& component : components)
+			{
+				if (component->getLinkId() != (UINT32)-1)
+					idMap[component->getLinkId()] = component->getInstanceId();
+			}
+
+			UINT32 numChildren = current.so->getNumChildren();
+			for (UINT32 i = 0; i < numChildren; i++)
+			{
+				HSceneObject child = current.so->getChild(i);
+
+				if (child->getLinkId() != (UINT32)-1)
+					idMap[child->getLinkId()] = child->getInstanceId();
+
+				todo.push({ child, childParentUUID });
+			}
+		}
+
+		// Root has link ID from its parent so we handle it separately
+		{
+			output.push_back(RenamedGameObject());
+			RenamedGameObject& renamedGO = output.back();
+			renamedGO.instanceData = instance->mInstanceData;
+			renamedGO.originalId = instance->getInstanceId();
+
+			prefab->mInstanceData->mInstanceId = instance->getInstanceId();
+		}
+
+		todo.push({ prefab, "root" });
+		while (!todo.empty())
+		{
+			StackEntry current = todo.top();
+			todo.pop();
+
+			String childParentUUID;
+			if (current.so->mPrefabLinkUUID.empty())
+				childParentUUID = current.uuid;
+			else
+				childParentUUID = current.so->mPrefabLinkUUID;
+
+			auto iterFind = linkToInstanceId.find(childParentUUID);
+			if (iterFind != linkToInstanceId.end())
+			{
+				UnorderedMap<UINT32, UINT64>& idMap = iterFind->second;
+
+				const Vector<HComponent>& components = current.so->getComponents();
+				for (auto& component : components)
+				{
+					auto iterFind2 = idMap.find(component->getLinkId());
+					if (iterFind2 != idMap.end())
+					{
+						output.push_back(RenamedGameObject());
+						RenamedGameObject& renamedGO = output.back();
+						renamedGO.instanceData = component->mInstanceData;
+						renamedGO.originalId = component->getInstanceId();
+
+						component->mInstanceData->mInstanceId = iterFind2->second;
+					}
+				}
+			}
+
+			UINT32 numChildren = current.so->getNumChildren();
+			for (UINT32 i = 0; i < numChildren; i++)
+			{
+				HSceneObject child = current.so->getChild(i);
+
+				if (iterFind != linkToInstanceId.end())
+				{
+					if (child->getLinkId() != -1)
+					{
+						UnorderedMap<UINT32, UINT64>& idMap = iterFind->second;
+
+						auto iterFind2 = idMap.find(child->getLinkId());
+						if (iterFind2 != idMap.end())
+						{
+							output.push_back(RenamedGameObject());
+							RenamedGameObject& renamedGO = output.back();
+							renamedGO.instanceData = child->mInstanceData;
+							renamedGO.originalId = child->getInstanceId();
+
+							child->mInstanceData->mInstanceId = iterFind2->second;
+						}
+					}
+				}
+
+				todo.push({ child, childParentUUID });
+			}
+		}
+	}
+
+	void PrefabDiff::restoreInstanceIds(const Vector<RenamedGameObject>& renamedObjects)
+	{
+		for (auto& renamedGO : renamedObjects)
+			renamedGO.instanceData->mInstanceId = renamedGO.originalId;
+	}
+
+	RTTITypeBase* PrefabDiff::getRTTIStatic()
+	{
+		return PrefabDiffRTTI::instance();
+	}
+
+	RTTITypeBase* PrefabDiff::getRTTI() const
+	{
+		return PrefabDiff::getRTTIStatic();
+	}
 }
 }

+ 4 - 2
BansheeCore/Source/BsRigidbody.cpp

@@ -1,5 +1,6 @@
 #include "BsRigidbody.h"
 #include "BsRigidbody.h"
 #include "BsPhysics.h"
 #include "BsPhysics.h"
+#include "BsFCollider.h"
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsUtility.h"
 #include "BsUtility.h"
 
 
@@ -30,9 +31,10 @@ namespace BansheeEngine
 			mColliders.erase(iterFind);
 			mColliders.erase(iterFind);
 	}
 	}
 
 
-	void Rigidbody::setIsActive(bool value)
+	void Rigidbody::_detachColliders()
 	{
 	{
-		mIsActive = value;
+		while (mColliders.size() > 0)
+			mColliders[0]->setRigidbody(nullptr);
 	}
 	}
 
 
 	void Rigidbody::setFlags(Flag flags)
 	void Rigidbody::setFlags(Flag flags)

+ 6 - 4
BansheeCore/Source/BsSceneObject.cpp

@@ -689,12 +689,12 @@ namespace BansheeEngine
 		return cloneObj->mThisHandle;
 		return cloneObj->mThisHandle;
 	}
 	}
 
 
-	HComponent SceneObject::getComponent(UINT32 typeId) const
+	HComponent SceneObject::getComponent(RTTITypeBase* type) const
 	{
 	{
-		for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
+		for(auto& entry : mComponents)
 		{
 		{
-			if((*iter)->getRTTI()->getRTTIId() == typeId)
-				return *iter;
+			if(entry->getRTTI()->isDerivedFrom(type))
+				return entry;
 		}
 		}
 
 
 		return HComponent();
 		return HComponent();
@@ -750,6 +750,8 @@ namespace BansheeEngine
 	{
 	{
 		GameObjectHandle<Component> newComponent = GameObjectManager::instance().getObject(component->getInstanceId());
 		GameObjectHandle<Component> newComponent = GameObjectManager::instance().getObject(component->getInstanceId());
 		newComponent->mParent = mThisHandle;
 		newComponent->mParent = mThisHandle;
+		newComponent->mThisHandle = newComponent;
+
 		mComponents.push_back(newComponent);
 		mComponents.push_back(newComponent);
 	}
 	}
 
 

+ 0 - 1
BansheePhysX/Include/BsFPhysXCollider.h

@@ -48,7 +48,6 @@ namespace BansheeEngine
 
 
 		void setRigidbody(const SPtr<Rigidbody>& rigidbody) override;
 		void setRigidbody(const SPtr<Rigidbody>& rigidbody) override;
 		void setMaterial(const HPhysicsMaterial& material) override;
 		void setMaterial(const HPhysicsMaterial& material) override;
-		void setIsActive(bool value) override;
 		void setLayer(UINT64 layer) override;
 		void setLayer(UINT64 layer) override;
 
 
 		physx::PxShape* _getShape() const { return mShape; }
 		physx::PxShape* _getShape() const { return mShape; }

+ 1 - 3
BansheePhysX/Include/BsPhysXRigidbody.h

@@ -59,7 +59,7 @@ namespace BansheeEngine
 
 
 		void setCenterOfMass(const Vector3& position, const Quaternion& rotation) override;
 		void setCenterOfMass(const Vector3& position, const Quaternion& rotation) override;
 		Vector3 getCenterOfMassPosition() const override;
 		Vector3 getCenterOfMassPosition() const override;
-		Quaternion getCenterOfMassRotatation() const override;
+		Quaternion getCenterOfMassRotation() const override;
 
 
 		void setPositionSolverCount(UINT32 count) override;
 		void setPositionSolverCount(UINT32 count) override;
 		UINT32 getPositionSolverCount() const override;
 		UINT32 getPositionSolverCount() const override;
@@ -67,8 +67,6 @@ namespace BansheeEngine
 		void setVelocitySolverCount(UINT32 count) override;
 		void setVelocitySolverCount(UINT32 count) override;
 		UINT32 getVelocitySolverCount() const override;
 		UINT32 getVelocitySolverCount() const override;
 
 
-		void setIsActive(bool value) override;
-
 		void addForce(const Vector3& force, ForceMode mode = ForceMode::Force) override;
 		void addForce(const Vector3& force, ForceMode mode = ForceMode::Force) override;
 		void addTorque(const Vector3& torque, ForceMode mode = ForceMode::Force) override;
 		void addTorque(const Vector3& torque, ForceMode mode = ForceMode::Force) override;
 		void addForceAtPoint(const Vector3& force, const Vector3& position,
 		void addForceAtPoint(const Vector3& force, const Vector3& position,

+ 0 - 16
BansheePhysX/Source/BsFPhysXCollider.cpp

@@ -135,22 +135,6 @@ namespace BansheeEngine
 		mShape->setMaterials(materials, sizeof(materials));
 		mShape->setMaterials(materials, sizeof(materials));
 	}
 	}
 
 
-	void FPhysXCollider::setIsActive(bool value)
-	{
-		// Note: A different option might be just to fully destroy the shape & actor when disabled (might result in better
-		//       performance if a lot of disabled actors in scene).
-
-		if (!value)
-			mShape->setFlags((PxShapeFlags)0);
-		else
-		{
-			mShape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true);
-			setIsTrigger(mIsTrigger);
-		}
-
-		FCollider::setIsActive(value);
-	}
-
 	void FPhysXCollider::setLayer(UINT64 layer)
 	void FPhysXCollider::setLayer(UINT64 layer)
 	{
 	{
 		PxFilterData data;
 		PxFilterData data;

+ 1 - 6
BansheePhysX/Source/BsPhysXRigidbody.cpp

@@ -235,7 +235,7 @@ namespace BansheeEngine
 		return fromPxVector(cMassTfrm.p);
 		return fromPxVector(cMassTfrm.p);
 	}
 	}
 
 
-	Quaternion PhysXRigidbody::getCenterOfMassRotatation() const
+	Quaternion PhysXRigidbody::getCenterOfMassRotation() const
 	{
 	{
 		PxTransform cMassTfrm = mInternal->getCMassLocalPose();
 		PxTransform cMassTfrm = mInternal->getCMassLocalPose();
 		return fromPxQuaternion(cMassTfrm.q);
 		return fromPxQuaternion(cMassTfrm.q);
@@ -269,11 +269,6 @@ namespace BansheeEngine
 		return velCount;
 		return velCount;
 	}
 	}
 
 
-	void PhysXRigidbody::setIsActive(bool value)
-	{
-		// TODO
-	}
-
 	void PhysXRigidbody::addForce(const Vector3& force, ForceMode mode)
 	void PhysXRigidbody::addForce(const Vector3& force, ForceMode mode)
 	{
 	{
 		mInternal->addForce(toPxVector(force), toPxForceMode(mode));
 		mInternal->addForce(toPxVector(force), toPxForceMode(mode));

+ 1 - 1
MBansheeEditor/EditorApplication.cs

@@ -589,7 +589,7 @@ namespace BansheeEditor
             sceneDirty = dirty;
             sceneDirty = dirty;
             SetStatusScene(Scene.ActiveSceneName, dirty);
             SetStatusScene(Scene.ActiveSceneName, dirty);
 
 
-            if (!dirty)
+            if (!dirty && Scene.ActiveSceneUUID != null)
                 persistentData.dirtyResources.Remove(Scene.ActiveSceneUUID);
                 persistentData.dirtyResources.Remove(Scene.ActiveSceneUUID);
         }
         }
 
 

+ 794 - 797
MBansheeEditor/UnitTests.cs

@@ -1,799 +1,796 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
-using BansheeEngine;
-using DebugUnit = System.Diagnostics.Debug;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Contains various managed unit tests.
-    /// </summary>
-    class UnitTests
-    {
-        /// <summary>
-        /// Triggers an exception when a unit test condition fails.
-        /// </summary>
-        /// <param name="success">True if the unit test condition succeeded, false otherwise.</param>
-        static void Assert(bool success)
-        {
-            if (!success)
-                throw new InvalidOperationException("Unit test failed.");
-        }
-
-        /// <summary>
-        /// Tests managed object serialization and deserialization.
-        /// </summary>
-        static void UnitTest1_ManagedSerialization()
-        {
-            SceneObject otherSO = new SceneObject("OtherSO");
-            UT1_Component2 dbgComponent2 = otherSO.AddComponent<UT1_Component2>();
-            dbgComponent2.a2 = 33;
-
-            SceneObject so = new SceneObject("TestSO");
-            UT1_Component1 dbgComponent = so.AddComponent<UT1_Component1>();
-
-            dbgComponent.a = 5;
-            dbgComponent.b = "SomeTestVal";
-            dbgComponent.complex.someValue = 19;
-            dbgComponent.complex.anotherValue = "AnotherValue";
-            dbgComponent.complex2.someValue2 = 21;
-            dbgComponent.complex2.anotherValue2 = "AnotherValue2";
-
-            dbgComponent.arrA = new int[5];
-            dbgComponent.arrA[4] = 5;
-            dbgComponent.arrB = new string[5];
-            dbgComponent.arrB[4] = "ArrAnotherValue";
-            dbgComponent.arrComplex = new UT1_SerzObj[5];
-            dbgComponent.arrComplex[4].someValue = 99;
-            dbgComponent.arrComplex[4].anotherValue = "ArrComplexAnotherValue";
-            dbgComponent.arrComplex2 = new UT1_SerzCls[5];
-            dbgComponent.arrComplex2[4] = new UT1_SerzCls();
-            dbgComponent.arrComplex2[4].someValue2 = 101;
-            dbgComponent.arrComplex2[4].anotherValue2 = "ArrComplex2AnotherValue";
-
-            dbgComponent.listA = new List<int>();
-            dbgComponent.listA.Add(5);
-            dbgComponent.listB = new List<string>();
-            dbgComponent.listB.Add("ListAnotherValue");
-            dbgComponent.listB.Add(null);
-            dbgComponent.listComplex = new List<UT1_SerzObj>();
-            dbgComponent.listComplex.Add(new UT1_SerzObj());
-            dbgComponent.listComplex.Add(new UT1_SerzObj(99, "ListComplexAnotherValue"));
-            dbgComponent.listComplex2 = new List<UT1_SerzCls>();
-            dbgComponent.listComplex2.Add(new UT1_SerzCls());
-            dbgComponent.listComplex2[0].someValue2 = 101;
-            dbgComponent.listComplex2[0].anotherValue2 = "ListComplexAnotherValue";
-            dbgComponent.listComplex2.Add(null);
-
-            dbgComponent.dictA = new Dictionary<int, string>();
-            dbgComponent.dictA[5] = "value";
-            dbgComponent.dictA[10] = "anotherValue";
-
-            dbgComponent.dictB = new Dictionary<string, UT1_SerzObj>();
-            dbgComponent.dictB["key1"] = new UT1_SerzObj(99, "DictComplexValue");
-
-            dbgComponent.otherComponent = dbgComponent2;
-            dbgComponent.otherSO = otherSO;
-
-            Internal_UT1_GameObjectClone(so);
-
-            System.Diagnostics.Debug.Assert(so.GetNumChildren() == 1);
-
-            for (int i = 0; i < so.GetNumChildren(); i++)
-            {
-                SceneObject childSO = so.GetChild(i);
-
-                UT1_Component1 otherComponent = childSO.GetComponent<UT1_Component1>();
-                DebugUnit.Assert(otherComponent.a == 5);
-                DebugUnit.Assert(otherComponent.b == "SomeTestVal");
-                DebugUnit.Assert(otherComponent.complex.someValue == 19);
-                DebugUnit.Assert(otherComponent.complex2.anotherValue2 == "AnotherValue2");
-
-                DebugUnit.Assert(otherComponent.arrA[4] == 5);
-                DebugUnit.Assert(otherComponent.arrB[4] == "ArrAnotherValue");
-                DebugUnit.Assert(otherComponent.arrComplex[4].someValue == 99);
-                DebugUnit.Assert(otherComponent.arrComplex2[4].anotherValue2 == "ArrComplex2AnotherValue");
-
-                DebugUnit.Assert(otherComponent.listA[0] == 5);
-                DebugUnit.Assert(otherComponent.listB[0] == "ListAnotherValue");
-                DebugUnit.Assert(otherComponent.listComplex[1].someValue == 99);
-                DebugUnit.Assert(otherComponent.listComplex2[0].anotherValue2 == "ListComplexAnotherValue");
-            }
-
-            so.Destroy();
-            otherSO.Destroy();
-        }
-
-        /// <summary>
-        /// Tests serializable properties used for inspection.
-        /// </summary>
-        static void UnitTest2_SerializableProperties()
-        {
-            SerializableObject obj = new SerializableObject(typeof(UT1_SerzCls), new UT1_SerzCls());
-
-            SerializableProperty prop = obj.Fields[0].GetProperty();
-            prop.SetValue(33);
-            DebugUnit.Assert(prop.GetValue<int>() == 33);
-
-            SerializableProperty prop2 = obj.Fields[2].GetProperty();
-
-            UT1_SerzCls child = new UT1_SerzCls();
-            child.anotherValue2 = "potato";
-            prop2.SetValue<UT1_SerzCls>(child);
-
-            DebugUnit.Assert(prop2.GetValue<UT1_SerzCls>() != null);
-            DebugUnit.Assert(prop2.GetValue<UT1_SerzCls>().anotherValue2 == "potato");
-        }
-
-        /// <summary>
-        /// Tests managed diff creation used by prefabs.
-        /// </summary>
-        static void UnitTest3_ManagedDiff()
-        {
-            UT_DiffObj original = new UT_DiffObj();
-            UT_DiffObj modified = new UT_DiffObj();
-
-            modified.plain2 = "banana";
-            modified.complex = new UT_DiffChildObj();
-            modified.complex2 = null;
-            modified.complex3.plain2 = "tomato";
-
-            modified.arrPlain1 = new[] {-1, -2, -3, -4};
-            modified.arrPlain2[2] = "cherry";
-            modified.arrComplex = new UT_DiffChildObj[3];
-            modified.arrComplex2[0].plain1 = -10;
-
-            modified.listPlain1[0] = -20;
-            modified.listPlain2 = new List<string>();
-            modified.listComplex = new List<UT_DiffChildObj>();
-            modified.listComplex.Add(new UT_DiffChildObj());
-            modified.listComplex2[1].plain2 = "orange";
-
-            modified.dictPlain1.Remove(20);
-            modified.dictPlain1[-30] = -30;
-            modified.dictComplex = new Dictionary<int, UT_DiffChildObj>();
-            modified.dictComplex[-40] = new UT_DiffChildObj();
-            modified.dictComplex2[31].plain1 = -50;
-
-            Internal_UT3_GenerateDiff(original, modified);
-            Internal_UT3_ApplyDiff(original);
-
-            DebugUnit.Assert(original.plain1 == modified.plain1);
-            DebugUnit.Assert(original.plain2 == modified.plain2);
-            DebugUnit.Assert(original.complex.plain2 == modified.complex.plain2);
-            DebugUnit.Assert(original.complex2 == modified.complex2);
-            DebugUnit.Assert(original.complex3.plain2 == modified.complex3.plain2);
-
-            DebugUnit.Assert(original.arrPlain1.Length == modified.arrPlain1.Length);
-            for (int i = 0; i < original.arrPlain1.Length; i++)
-                DebugUnit.Assert(original.arrPlain1[i] == modified.arrPlain1[i]);
-
-            for (int i = 0; i < original.arrPlain2.Length; i++)
-                DebugUnit.Assert(original.arrPlain2[i] == modified.arrPlain2[i]);
-
-            for (int i = 0; i < original.arrComplex.Length; i++)
-                DebugUnit.Assert(original.arrComplex[i] == modified.arrComplex[i]);
-
-            DebugUnit.Assert(original.arrComplex2[0].plain1 == modified.arrComplex2[0].plain1);
-
-            for (int i = 0; i < original.listPlain1.Count; i++)
-                DebugUnit.Assert(original.listPlain1[i] == modified.listPlain1[i]);
-
-            DebugUnit.Assert(original.listPlain2.Count == modified.listPlain2.Count);
-
-            for (int i = 0; i < original.listComplex.Count; i++)
-                DebugUnit.Assert(original.listComplex[i].plain1 == modified.listComplex[i].plain1);
-
-            DebugUnit.Assert(original.listComplex2[1].plain2 == modified.listComplex2[1].plain2);
-
-            foreach (var entry in modified.dictPlain1)
-            {
-                if (!original.dictPlain1.ContainsKey(entry.Key))
-                    DebugUnit.Assert(false);
-
-                DebugUnit.Assert(entry.Value == original.dictPlain1[entry.Key]);
-            }
-
-            foreach (var entry in modified.dictPlain2)
-            {
-                if (!original.dictPlain2.ContainsKey(entry.Key))
-                    DebugUnit.Assert(false);
-
-                DebugUnit.Assert(entry.Value == original.dictPlain2[entry.Key]);
-            }
-
-            foreach (var entry in modified.dictComplex)
-            {
-                if (!original.dictComplex.ContainsKey(entry.Key))
-                    DebugUnit.Assert(false);
-
-                DebugUnit.Assert(entry.Value.plain1 == original.dictComplex[entry.Key].plain1);
-            }
-
-            foreach (var entry in modified.dictComplex2)
-            {
-                if (!original.dictComplex2.ContainsKey(entry.Key))
-                    DebugUnit.Assert(false);
-
-                DebugUnit.Assert(entry.Value.plain1 == original.dictComplex2[entry.Key].plain1);
-            }
-        }
-
-        /// <summary>
-        /// Tests saving, loading and updating of prefabs.
-        /// </summary>
-        private static void UnitTest4_Prefabs()
-        {
-            if (!EditorApplication.IsProjectLoaded)
-            {
-                Debug.LogWarning("Skipping unit test as no project is loaded.");
-                return;
-            }
-
-            if (EditorApplication.IsSceneModified())
-            {
-                Debug.LogWarning("Cannot perform unit test as the current scene is modified.");
-                return;
-            }
-
-            Action PrintSceneState = () =>
-            {
-                SceneObject root = Scene.Root;
-
-                Stack<SceneObject> todo = new Stack<SceneObject>();
-                todo.Push(root);
-
-                StringBuilder output = new StringBuilder();
-                while (todo.Count > 0)
-                {
-                    SceneObject so = todo.Pop();
-
-                    int numChildren = so.GetNumChildren();
-                    for (int i = numChildren - 1; i >= 0; i--)
-                    {
-                        SceneObject child = so.GetChild(i);
-
-                        output.AppendLine(child.Name);
-                        todo.Push(child);
-                    }  
-                }
-
-                Debug.Log(output);
-            };
-
-            // Disabled because it's a slow test, enable only when relevant (or when a build machine is set up)
-            return;
-
-            string oldScene = Scene.ActiveSceneUUID;
-            Scene.Clear();
-
-            try
-            {
-                // Simple scene save & load
-                {
-                    {
-                        // unitTest4Scene_0.prefab:
-                        // so0 (Comp1)
-                        //  - so0_0
-                        //  - so0_1 (Comp1)
-                        //    - so0_1_0 (Comp1)
-                        // so1 (Comp2)
-                        //  - so1_0
-
-                        SceneObject so0 = new SceneObject("so0");
-                        SceneObject so1 = new SceneObject("so1");
-                        SceneObject so0_0 = new SceneObject("so0_0");
-                        SceneObject so0_1 = new SceneObject("so0_1");
-                        SceneObject so1_0 = new SceneObject("so1_0");
-                        SceneObject so0_1_0 = new SceneObject("so0_1_0");
-
-                        so0_0.Parent = so0;
-                        so0_1.Parent = so0;
-                        so1_0.Parent = so1;
-                        so0_1_0.Parent = so0_1;
-
-                        so0_1_0.LocalPosition = new Vector3(10.0f, 15.0f, 20.0f);
-                        so0_1.LocalPosition = new Vector3(1.0f, 2.0f, 3.0f);
-                        so1_0.LocalPosition = new Vector3(0, 123.0f, 0.0f);
-
-                        UT1_Component1 comp0 = so0.AddComponent<UT1_Component1>();
-                        UT1_Component2 comp1 = so1.AddComponent<UT1_Component2>();
-                        UT1_Component1 comp1_1 = so0_1.AddComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.AddComponent<UT1_Component1>();
-
-                        comp0.otherSO = so0_1_0;
-                        comp0.otherComponent = comp1;
-
-                        comp1_1.b = "originalValue2";
-
-                        comp0_1_0.b = "testValue";
-                        comp0_1_0.otherSO = so0;
-                        comp0_1_0.otherComponent2 = comp0;
-
-                        EditorApplication.SaveScene("unitTest4Scene_0.prefab");
-                    }
-                    {
-                        EditorApplication.LoadScene("unitTest4Scene_0.prefab");
-
-                        SceneObject sceneRoot = Scene.Root;
-                        SceneObject so0 = sceneRoot.FindChild("so0", false);
-                        SceneObject so1 = sceneRoot.FindChild("so1", false);
-                        SceneObject so0_0 = so0.FindChild("so0_0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        Assert(so0_0 != null);
-                        Assert(so0_1 != null);
-                        Assert(so0_1_0 != null);
-
-                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
-                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-
-                        Assert(comp0 != null);
-                        Assert(comp1 != null);
-                        Assert(comp0_1_0 != null);
-                        Assert(comp0_1_0.b == "testValue");
-                        Assert(comp0.otherSO == so0_1_0);
-                        Assert(comp0.otherComponent == comp1);
-                        Assert(comp0_1_0.otherSO == so0);
-                        Assert(comp0_1_0.otherComponent2 == comp0);
-                    }
-                }
-
-                Debug.Log("Passed stage 1");
-
-                // Load & save a scene that contains a prefab and references its objects
-                {
-                    {
-                        // unitTest4Scene_1.prefab:
-                        // parentSO0
-                        //  - [unitTest4Scene_0.prefab]
-                        // parentSO1
-                        //  - parentSO1_0 (Comp1)
-
-                        Scene.Clear();
-
-                        SceneObject parentSO0 = new SceneObject("parentSO0", false);
-                        SceneObject parentSO1 = new SceneObject("parentSO1", false);
-                        SceneObject parentSO1_0 = new SceneObject("parentSO1_0", false);
-
-                        parentSO1_0.Parent = parentSO1;
-                        parentSO0.LocalPosition = new Vector3(50.0f, 50.0f, 50.0f);
-
-                        UT1_Component1 parentComp1_0 = parentSO1_0.AddComponent<UT1_Component1>();
-
-                        Prefab scene0Prefab = ProjectLibrary.Load<Prefab>("unitTest4Scene_0.prefab");
-                        SceneObject prefabInstance = scene0Prefab.Instantiate();
-                        prefabInstance.Parent = parentSO0;
-                        prefabInstance.LocalPosition = Vector3.Zero;
-
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-
-                        parentComp1_0.otherSO = so1_0;
-                        parentComp1_0.otherComponent2 = comp0_1_0;
-
-                        EditorApplication.SaveScene("unitTest4Scene_1.prefab");
-                    }
-                    {
-                        EditorApplication.LoadScene("unitTest4Scene_1.prefab");
-
-                        SceneObject parentSO0 = Scene.Root.FindChild("parentSO0", false);
-                        SceneObject parentSO1 = Scene.Root.FindChild("parentSO1", false);
-                        SceneObject parentSO1_0 = parentSO1.FindChild("parentSO1_0", false);
-
-                        UT1_Component1 parentComp1_0 = parentSO1_0.GetComponent<UT1_Component1>();
-
-                        SceneObject prefabInstance = parentSO0.GetChild(0);
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-
-                        Assert(parentComp1_0.otherSO == so1_0);
-                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
-                    }
-                }
-
-                Debug.Log("Passed stage 2");
-
-                // Modify prefab, reload the scene and ensure it is updated with modified prefab
-                {
-                    {
-                        // unitTest4Scene_0.prefab:
-                        // so0
-                        //  - so0_1 (Comp1)
-                        //    - so0_1_0 (Comp1)
-                        // so1 (Comp1, Comp2)
-                        //  - so1_0
-                        //  - so1_1
-
-                        Scene.Load("unitTest4Scene_0.prefab");
-
-                        SceneObject sceneRoot = Scene.Root;
-                        SceneObject so0 = sceneRoot.FindChild("so0", false);
-                        SceneObject so0_0 = so0.FindChild("so0_0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1 = sceneRoot.FindChild("so1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        SceneObject so1_1 = new SceneObject("so1_1");
-                        so1_1.Parent = so1;
-
-                        so0.RemoveComponent<UT1_Component1>();
-                        UT1_Component1 comp1 = so1.AddComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-
-                        so0_0.Destroy();
-
-                        comp1.otherSO = so1_0;
-                        comp1.otherComponent2 = comp0_1_0;
-
-                        comp0_1_0.otherSO = so1_1;
-                        comp0_1_0.otherComponent2 = comp1;
-                        comp0_1_0.a = 123;
-                        comp0_1_0.b = "modifiedValue";
-
-                        so1.Name = "so1_modified";
-                        so1.LocalPosition = new Vector3(0, 999.0f, 0.0f);
-
-                        EditorApplication.SaveScene("unitTest4Scene_0.prefab");
-                    }
-
-                    {
-                        EditorApplication.LoadScene("unitTest4Scene_1.prefab");
-
-                        SceneObject parentSO0 = Scene.Root.FindChild("parentSO0", false);
-                        SceneObject parentSO1 = Scene.Root.FindChild("parentSO1", false);
-                        SceneObject parentSO1_0 = parentSO1.FindChild("parentSO1_0", false);
-
-                        UT1_Component1 parentComp1_0 = parentSO1_0.GetComponent<UT1_Component1>();
-
-                        SceneObject prefabInstance = parentSO0.GetChild(0);
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
-                        SceneObject so0_0 = so0.FindChild("so0_0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-                        SceneObject so1_1 = so1.FindChild("so1_1", false);
-
-                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp1 = so1.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-
-                        Assert(parentComp1_0.otherSO == so1_0);
-                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
-                        Assert(so1_1 != null);
-                        Assert(so0_0 == null);
-                        Assert(comp0 == null);
-                        Assert(comp0_1_0.otherSO == so1_1);
-                        Assert(comp0_1_0.otherComponent2 == comp1);
-                        Assert(comp0_1_0.a == 123);
-                        Assert(comp0_1_0.b == "modifiedValue");
-                        Assert(comp1.otherSO == so1_0);
-                        Assert(comp1.otherComponent2 == comp0_1_0);
-                        Assert(MathEx.ApproxEquals(so1.LocalPosition.y, 999.0f));
-                    }
-                }
-
-                Debug.Log("Passed stage 3");
-
-                // Make instance specific changes to the prefab, modify the prefab itself and ensure
-                // both changes persist
-                {
-                    // Create new scene referencing the prefab and make instance modifications
-                    {
-                        // unitTest4Scene_2.prefab:
-                        // parent2SO0
-                        //  - [unitTest4Scene_0.prefab]
-                        // parent2SO1
-                        //  - parent2SO1_0 (Comp1)
-
-                        // unitTest4Scene_0.prefab (unitTest4Scene_2.prefab instance):
-                        // so0 (Comp1(INSTANCE))
-                        //  - so0_0 (INSTANCE)
-                        //  - so0_1 (Comp1)
-                        //    - so0_1_0 (Comp1)
-                        // so1 (Comp2)
-                        //  - so1_0
-
-                        Scene.Clear();
-
-                        SceneObject parent2SO0 = new SceneObject("parent2SO0");
-                        SceneObject parent2SO1 = new SceneObject("parent2SO1");
-                        SceneObject parent2SO1_0 = new SceneObject("parent2SO1_0");
-
-                        parent2SO1_0.Parent = parent2SO1;
-
-                        UT1_Component1 parentComp1_0 = parent2SO1_0.AddComponent<UT1_Component1>();
-
-                        Prefab scene0Prefab = ProjectLibrary.Load<Prefab>("unitTest4Scene_0.prefab");
-                        SceneObject prefabInstance = scene0Prefab.Instantiate();
-                        prefabInstance.Parent = parent2SO0;
-
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
-
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so1_1 = so1.FindChild("so1_1", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1 = so0_1.GetComponent<UT1_Component1>();
-
-                        SceneObject so0_0 = new SceneObject("so0_0");
-                        so0_0.Parent = so0;
-                        UT1_Component1 comp0 = so0.AddComponent<UT1_Component1>();
-
-                        so1.RemoveComponent<UT1_Component1>();
-                        so1_1.Destroy();
-
-                        comp0.otherSO = so0_1_0;
-                        comp0.otherComponent = comp1;
-
-                        parentComp1_0.otherSO = so1_0;
-                        parentComp1_0.otherComponent2 = comp0_1_0;
-
-                        comp0_1_0.otherSO = parent2SO1_0;
-                        comp0_1_0.otherComponent2 = parentComp1_0;
-                        comp0_1_0.b = "instanceValue";
-
-                        comp0_1.b = "instanceValue2";
-
-                        EditorApplication.SaveScene("unitTest4Scene_2.prefab");
-                    }
-
-                    Debug.Log("Passed stage 4.1");
-
-                    // Reload the scene and ensure instance modifications remain
-                    {
-                        EditorApplication.LoadScene("unitTest4Scene_2.prefab");
-
-                        SceneObject root = Scene.Root;
-                        SceneObject parent2SO0 = root.FindChild("parent2SO0", false);
-                        SceneObject parent2SO1 = root.FindChild("parent2SO1", false);
-                        SceneObject parent2SO1_0 = parent2SO1.FindChild("parent2SO1_0", false);
-
-                        SceneObject prefabInstance = parent2SO0.GetChild(0);
-
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
-                        SceneObject so0_0 = so0.FindChild("so0_0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so1_1 = so1.FindChild("so1_1", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        UT1_Component1 parentComp1_0 = parent2SO1_0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
-                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
-                        UT1_Component1 comp11 = so1.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1 = so0_1.GetComponent<UT1_Component1>();
-
-                        Assert(so0_0 != null);
-                        Assert(comp0 != null);
-                        Assert(so1_1 == null);
-                        Assert(comp11 == null);
-
-                        Assert(comp0.otherSO == so0_1_0);
-                        Assert(comp0.otherComponent == comp1);
-
-                        Assert(parentComp1_0.otherSO == so1_0);
-                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
-
-                        Debug.Log(comp0_1_0.otherSO == null);
-                        if (comp0_1_0.otherSO != null)
-                            Debug.Log(comp0_1_0.otherSO.InstanceId + " - " + parent2SO1_0.InstanceId);
-
-                        Assert(comp0_1_0.otherSO == parent2SO1_0);
-                        Assert(comp0_1_0.otherComponent2 == parentComp1_0);
-                        Assert(comp0_1_0.b == "instanceValue");
-
-                        Assert(comp0_1.b == "instanceValue2");
-                    }
-
-                    Debug.Log("Passed stage 4.2");
-
-                    // Load original scene and ensure instance modifications didn't influence it
-                    {
-                        EditorApplication.LoadScene("unitTest4Scene_1.prefab");
-
-                        SceneObject parentSO0 = Scene.Root.FindChild("parentSO0", false);
-                        SceneObject parentSO1 = Scene.Root.FindChild("parentSO1", false);
-                        SceneObject parentSO1_0 = parentSO1.FindChild("parentSO1_0", false);
-
-                        UT1_Component1 parentComp1_0 = parentSO1_0.GetComponent<UT1_Component1>();
-
-                        SceneObject prefabInstance = parentSO0.GetChild(0);
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
-                        SceneObject so0_0 = so0.FindChild("so0_0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-                        SceneObject so1_1 = so1.FindChild("so1_1", false);
-
-                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp1 = so1.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1 = so0_1.GetComponent<UT1_Component1>();
-
-                        Assert(parentComp1_0.otherSO == so1_0);
-                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
-                        Assert(so1_1 != null);
-                        Assert(so0_0 == null);
-                        Assert(comp0 == null);
-                        Assert(comp0_1_0.otherSO == so1_1);
-                        Assert(comp0_1_0.otherComponent2 == comp1);
-                        Assert(comp0_1_0.a == 123);
-                        Assert(comp0_1_0.b == "modifiedValue");
-                        Assert(comp1.otherSO == so1_0);
-                        Assert(comp1.otherComponent2 == comp0_1_0);
-                        Assert(comp0_1.b == "originalValue2");
-                        Assert(MathEx.ApproxEquals(so1.LocalPosition.y, 999.0f));
-                    }
-
-                    Debug.Log("Passed stage 4.3");
-
-                    // Modify prefab and ensure both prefab and instance modifications remain
-                    {
-                        // unitTest4Scene_0.prefab:
-                        // so0 (Comp1)
-                        //  - so0_1
-                        //    - so0_1_0 (Comp1)
-                        // so1 (Comp1, Comp2)
-                        //  - so1_1
-                        //  - so1_2 (Comp1)
-
-                        // unitTest4Scene_0.prefab (unitTest4Scene_2.prefab instance):
-                        // so0 (Comp1)
-                        //  - so0_0
-                        //  - so0_1 (Comp1)
-                        //    - so0_1_0 (Comp1)
-                        // so1 (Comp2)
-                        //  - so1_2 (Comp1)
-
-                        Scene.Load("unitTest4Scene_0.prefab");
-
-                        SceneObject sceneRoot = Scene.Root;
-                        SceneObject so0 = sceneRoot.FindChild("so0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1 = sceneRoot.FindChild("so1_modified", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        SceneObject so1_2 = new SceneObject("so1_2");
-                        so1_2.Parent = so1;
-
-                        so0.AddComponent<UT1_Component1>();
-                        so0_1.RemoveComponent<UT1_Component1>();
-                        so1_0.Destroy();
-
-                        UT1_Component1 comp3 = so1_2.AddComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-                        comp0_1_0.b = "modifiedValueAgain";
-                        so1.Name = "so1_modifiedAgain";
-
-                        comp3.otherSO = so0_1;
-                        comp3.otherComponent2 = comp0_1_0;
-
-                        EditorApplication.SaveScene("unitTest4Scene_0.prefab");
-                    }
-
-                    Debug.Log("Passed stage 4.4");
-
-                    // Reload the scene and ensure both instance and prefab modifications remain
-                    {
-                        EditorApplication.LoadScene("unitTest4Scene_2.prefab");
-
-                        SceneObject root = Scene.Root;
-                        SceneObject parent2SO0 = root.FindChild("parent2SO0", false);
-                        SceneObject parent2SO1 = root.FindChild("parent2SO1", false);
-                        SceneObject parent2SO1_0 = parent2SO1.FindChild("parent2SO1_0", false);
-
-                        SceneObject prefabInstance = parent2SO0.GetChild(0);
-
-                        SceneObject so0 = prefabInstance.FindChild("so0", false);
-                        SceneObject so1 = prefabInstance.FindChild("so1_modifiedAgain", false);
-                        SceneObject so0_0 = so0.FindChild("so0_0", false);
-                        SceneObject so0_1 = so0.FindChild("so0_1", false);
-                        SceneObject so1_0 = so1.FindChild("so1_0", false);
-                        SceneObject so1_1 = so1.FindChild("so1_1", false);
-                        SceneObject so1_2 = so1.FindChild("so1_2", false);
-                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
-
-                        UT1_Component1 parentComp1_0 = parent2SO1_0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
-                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
-                        UT1_Component1 comp11 = so1.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
-                        UT1_Component1 comp3 = so1_2.AddComponent<UT1_Component1>();
-
-                        // Check instance modifications (they should override any prefab modifications)
-                        Assert(so0_0 != null);
-                        Assert(comp0 != null);
-                        Assert(so1_1 == null);
-                        Assert(comp11 == null);
-
-                        Assert(comp0.otherSO == so0_1_0);
-                        Assert(comp0.otherComponent == comp1);
-
-                        Assert(parentComp1_0.otherSO == so1_0);
-                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
-
-                        Assert(comp0_1_0.otherSO == parent2SO1_0);
-                        Assert(comp0_1_0.otherComponent2 == parentComp1_0);
-                        Assert(comp0_1_0.b == "instanceValue");
-
-                        // Check prefab modifications
-                        Assert(so1_0 == null);
-                        Assert(so1.Name == "so1_modifiedAgain");
-                        Assert(comp3.otherSO == so0_1);
-                        Assert(comp3.otherComponent2 == comp0_1_0);
-                    }
-
-                    Debug.Log("Passed stage 4.5");
-                }
-            }
-            catch
-            {
-                PrintSceneState();
-
-                throw;
-            }
-            finally
-            {
-                
-
-                if (!string.IsNullOrEmpty(oldScene))
-                    Scene.Load(ProjectLibrary.GetPath(oldScene));
-                else
-                    Scene.Clear();
-
-                ProjectLibrary.Delete("unitTest4Scene_0.prefab");
-                ProjectLibrary.Delete("unitTest4Scene_1.prefab");
-                ProjectLibrary.Delete("unitTest4Scene_2.prefab");
-            }
-        }
-
-        /// <summary>
-        /// Runs all tests.
-        /// </summary>
-        static void RunTests()
-        {
-            UnitTest1_ManagedSerialization();
-            UnitTest2_SerializableProperties();
-            UnitTest3_ManagedDiff();
-            UnitTest4_Prefabs();
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UT1_GameObjectClone(SceneObject so);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UT3_GenerateDiff(UT_DiffObj oldObj, UT_DiffObj newObj);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UT3_ApplyDiff(UT_DiffObj obj);
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+using DebugUnit = System.Diagnostics.Debug;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains various managed unit tests.
+    /// </summary>
+    class UnitTests
+    {
+        /// <summary>
+        /// Triggers an exception when a unit test condition fails.
+        /// </summary>
+        /// <param name="success">True if the unit test condition succeeded, false otherwise.</param>
+        static void Assert(bool success)
+        {
+            if (!success)
+                throw new InvalidOperationException("Unit test failed.");
+        }
+
+        /// <summary>
+        /// Tests managed object serialization and deserialization.
+        /// </summary>
+        static void UnitTest1_ManagedSerialization()
+        {
+            SceneObject otherSO = new SceneObject("OtherSO");
+            UT1_Component2 dbgComponent2 = otherSO.AddComponent<UT1_Component2>();
+            dbgComponent2.a2 = 33;
+
+            SceneObject so = new SceneObject("TestSO");
+            UT1_Component1 dbgComponent = so.AddComponent<UT1_Component1>();
+
+            dbgComponent.a = 5;
+            dbgComponent.b = "SomeTestVal";
+            dbgComponent.complex.someValue = 19;
+            dbgComponent.complex.anotherValue = "AnotherValue";
+            dbgComponent.complex2.someValue2 = 21;
+            dbgComponent.complex2.anotherValue2 = "AnotherValue2";
+
+            dbgComponent.arrA = new int[5];
+            dbgComponent.arrA[4] = 5;
+            dbgComponent.arrB = new string[5];
+            dbgComponent.arrB[4] = "ArrAnotherValue";
+            dbgComponent.arrComplex = new UT1_SerzObj[5];
+            dbgComponent.arrComplex[4].someValue = 99;
+            dbgComponent.arrComplex[4].anotherValue = "ArrComplexAnotherValue";
+            dbgComponent.arrComplex2 = new UT1_SerzCls[5];
+            dbgComponent.arrComplex2[4] = new UT1_SerzCls();
+            dbgComponent.arrComplex2[4].someValue2 = 101;
+            dbgComponent.arrComplex2[4].anotherValue2 = "ArrComplex2AnotherValue";
+
+            dbgComponent.listA = new List<int>();
+            dbgComponent.listA.Add(5);
+            dbgComponent.listB = new List<string>();
+            dbgComponent.listB.Add("ListAnotherValue");
+            dbgComponent.listB.Add(null);
+            dbgComponent.listComplex = new List<UT1_SerzObj>();
+            dbgComponent.listComplex.Add(new UT1_SerzObj());
+            dbgComponent.listComplex.Add(new UT1_SerzObj(99, "ListComplexAnotherValue"));
+            dbgComponent.listComplex2 = new List<UT1_SerzCls>();
+            dbgComponent.listComplex2.Add(new UT1_SerzCls());
+            dbgComponent.listComplex2[0].someValue2 = 101;
+            dbgComponent.listComplex2[0].anotherValue2 = "ListComplexAnotherValue";
+            dbgComponent.listComplex2.Add(null);
+
+            dbgComponent.dictA = new Dictionary<int, string>();
+            dbgComponent.dictA[5] = "value";
+            dbgComponent.dictA[10] = "anotherValue";
+
+            dbgComponent.dictB = new Dictionary<string, UT1_SerzObj>();
+            dbgComponent.dictB["key1"] = new UT1_SerzObj(99, "DictComplexValue");
+
+            dbgComponent.otherComponent = dbgComponent2;
+            dbgComponent.otherSO = otherSO;
+
+            Internal_UT1_GameObjectClone(so);
+
+            System.Diagnostics.Debug.Assert(so.GetNumChildren() == 1);
+
+            for (int i = 0; i < so.GetNumChildren(); i++)
+            {
+                SceneObject childSO = so.GetChild(i);
+
+                UT1_Component1 otherComponent = childSO.GetComponent<UT1_Component1>();
+                DebugUnit.Assert(otherComponent.a == 5);
+                DebugUnit.Assert(otherComponent.b == "SomeTestVal");
+                DebugUnit.Assert(otherComponent.complex.someValue == 19);
+                DebugUnit.Assert(otherComponent.complex2.anotherValue2 == "AnotherValue2");
+
+                DebugUnit.Assert(otherComponent.arrA[4] == 5);
+                DebugUnit.Assert(otherComponent.arrB[4] == "ArrAnotherValue");
+                DebugUnit.Assert(otherComponent.arrComplex[4].someValue == 99);
+                DebugUnit.Assert(otherComponent.arrComplex2[4].anotherValue2 == "ArrComplex2AnotherValue");
+
+                DebugUnit.Assert(otherComponent.listA[0] == 5);
+                DebugUnit.Assert(otherComponent.listB[0] == "ListAnotherValue");
+                DebugUnit.Assert(otherComponent.listComplex[1].someValue == 99);
+                DebugUnit.Assert(otherComponent.listComplex2[0].anotherValue2 == "ListComplexAnotherValue");
+            }
+
+            so.Destroy();
+            otherSO.Destroy();
+        }
+
+        /// <summary>
+        /// Tests serializable properties used for inspection.
+        /// </summary>
+        static void UnitTest2_SerializableProperties()
+        {
+            SerializableObject obj = new SerializableObject(typeof(UT1_SerzCls), new UT1_SerzCls());
+
+            SerializableProperty prop = obj.Fields[0].GetProperty();
+            prop.SetValue(33);
+            DebugUnit.Assert(prop.GetValue<int>() == 33);
+
+            SerializableProperty prop2 = obj.Fields[2].GetProperty();
+
+            UT1_SerzCls child = new UT1_SerzCls();
+            child.anotherValue2 = "potato";
+            prop2.SetValue<UT1_SerzCls>(child);
+
+            DebugUnit.Assert(prop2.GetValue<UT1_SerzCls>() != null);
+            DebugUnit.Assert(prop2.GetValue<UT1_SerzCls>().anotherValue2 == "potato");
+        }
+
+        /// <summary>
+        /// Tests managed diff creation used by prefabs.
+        /// </summary>
+        static void UnitTest3_ManagedDiff()
+        {
+            UT_DiffObj original = new UT_DiffObj();
+            UT_DiffObj modified = new UT_DiffObj();
+
+            modified.plain2 = "banana";
+            modified.complex = new UT_DiffChildObj();
+            modified.complex2 = null;
+            modified.complex3.plain2 = "tomato";
+
+            modified.arrPlain1 = new[] {-1, -2, -3, -4};
+            modified.arrPlain2[2] = "cherry";
+            modified.arrComplex = new UT_DiffChildObj[3];
+            modified.arrComplex2[0].plain1 = -10;
+
+            modified.listPlain1[0] = -20;
+            modified.listPlain2 = new List<string>();
+            modified.listComplex = new List<UT_DiffChildObj>();
+            modified.listComplex.Add(new UT_DiffChildObj());
+            modified.listComplex2[1].plain2 = "orange";
+
+            modified.dictPlain1.Remove(20);
+            modified.dictPlain1[-30] = -30;
+            modified.dictComplex = new Dictionary<int, UT_DiffChildObj>();
+            modified.dictComplex[-40] = new UT_DiffChildObj();
+            modified.dictComplex2[31].plain1 = -50;
+
+            Internal_UT3_GenerateDiff(original, modified);
+            Internal_UT3_ApplyDiff(original);
+
+            DebugUnit.Assert(original.plain1 == modified.plain1);
+            DebugUnit.Assert(original.plain2 == modified.plain2);
+            DebugUnit.Assert(original.complex.plain2 == modified.complex.plain2);
+            DebugUnit.Assert(original.complex2 == modified.complex2);
+            DebugUnit.Assert(original.complex3.plain2 == modified.complex3.plain2);
+
+            DebugUnit.Assert(original.arrPlain1.Length == modified.arrPlain1.Length);
+            for (int i = 0; i < original.arrPlain1.Length; i++)
+                DebugUnit.Assert(original.arrPlain1[i] == modified.arrPlain1[i]);
+
+            for (int i = 0; i < original.arrPlain2.Length; i++)
+                DebugUnit.Assert(original.arrPlain2[i] == modified.arrPlain2[i]);
+
+            for (int i = 0; i < original.arrComplex.Length; i++)
+                DebugUnit.Assert(original.arrComplex[i] == modified.arrComplex[i]);
+
+            DebugUnit.Assert(original.arrComplex2[0].plain1 == modified.arrComplex2[0].plain1);
+
+            for (int i = 0; i < original.listPlain1.Count; i++)
+                DebugUnit.Assert(original.listPlain1[i] == modified.listPlain1[i]);
+
+            DebugUnit.Assert(original.listPlain2.Count == modified.listPlain2.Count);
+
+            for (int i = 0; i < original.listComplex.Count; i++)
+                DebugUnit.Assert(original.listComplex[i].plain1 == modified.listComplex[i].plain1);
+
+            DebugUnit.Assert(original.listComplex2[1].plain2 == modified.listComplex2[1].plain2);
+
+            foreach (var entry in modified.dictPlain1)
+            {
+                if (!original.dictPlain1.ContainsKey(entry.Key))
+                    DebugUnit.Assert(false);
+
+                DebugUnit.Assert(entry.Value == original.dictPlain1[entry.Key]);
+            }
+
+            foreach (var entry in modified.dictPlain2)
+            {
+                if (!original.dictPlain2.ContainsKey(entry.Key))
+                    DebugUnit.Assert(false);
+
+                DebugUnit.Assert(entry.Value == original.dictPlain2[entry.Key]);
+            }
+
+            foreach (var entry in modified.dictComplex)
+            {
+                if (!original.dictComplex.ContainsKey(entry.Key))
+                    DebugUnit.Assert(false);
+
+                DebugUnit.Assert(entry.Value.plain1 == original.dictComplex[entry.Key].plain1);
+            }
+
+            foreach (var entry in modified.dictComplex2)
+            {
+                if (!original.dictComplex2.ContainsKey(entry.Key))
+                    DebugUnit.Assert(false);
+
+                DebugUnit.Assert(entry.Value.plain1 == original.dictComplex2[entry.Key].plain1);
+            }
+        }
+
+        /// <summary>
+        /// Tests saving, loading and updating of prefabs.
+        /// </summary>
+        private static void UnitTest4_Prefabs()
+        {
+            if (!EditorApplication.IsProjectLoaded)
+            {
+                Debug.LogWarning("Skipping unit test as no project is loaded.");
+                return;
+            }
+
+            if (EditorApplication.IsSceneModified())
+            {
+                Debug.LogWarning("Cannot perform unit test as the current scene is modified.");
+                return;
+            }
+
+            Action PrintSceneState = () =>
+            {
+                SceneObject root = Scene.Root;
+
+                Stack<SceneObject> todo = new Stack<SceneObject>();
+                todo.Push(root);
+
+                StringBuilder output = new StringBuilder();
+                while (todo.Count > 0)
+                {
+                    SceneObject so = todo.Pop();
+
+                    int numChildren = so.GetNumChildren();
+                    for (int i = numChildren - 1; i >= 0; i--)
+                    {
+                        SceneObject child = so.GetChild(i);
+
+                        output.AppendLine(child.Name);
+                        todo.Push(child);
+                    }  
+                }
+
+                Debug.Log(output);
+            };
+
+            // Disabled because it's a slow test, enable only when relevant (or when a build machine is set up)
+            return;
+
+            string oldScene = Scene.ActiveSceneUUID;
+            Scene.Clear();
+
+            try
+            {
+                // Simple scene save & load
+                {
+                    {
+                        // unitTest4Scene_0.prefab:
+                        // so0 (Comp1)
+                        //  - so0_0
+                        //  - so0_1 (Comp1)
+                        //    - so0_1_0 (Comp1)
+                        // so1 (Comp2)
+                        //  - so1_0
+
+                        SceneObject so0 = new SceneObject("so0");
+                        SceneObject so1 = new SceneObject("so1");
+                        SceneObject so0_0 = new SceneObject("so0_0");
+                        SceneObject so0_1 = new SceneObject("so0_1");
+                        SceneObject so1_0 = new SceneObject("so1_0");
+                        SceneObject so0_1_0 = new SceneObject("so0_1_0");
+
+                        so0_0.Parent = so0;
+                        so0_1.Parent = so0;
+                        so1_0.Parent = so1;
+                        so0_1_0.Parent = so0_1;
+
+                        so0_1_0.LocalPosition = new Vector3(10.0f, 15.0f, 20.0f);
+                        so0_1.LocalPosition = new Vector3(1.0f, 2.0f, 3.0f);
+                        so1_0.LocalPosition = new Vector3(0, 123.0f, 0.0f);
+
+                        UT1_Component1 comp0 = so0.AddComponent<UT1_Component1>();
+                        UT1_Component2 comp1 = so1.AddComponent<UT1_Component2>();
+                        UT1_Component1 comp1_1 = so0_1.AddComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.AddComponent<UT1_Component1>();
+
+                        comp0.otherSO = so0_1_0;
+                        comp0.otherComponent = comp1;
+
+                        comp1_1.b = "originalValue2";
+
+                        comp0_1_0.b = "testValue";
+                        comp0_1_0.otherSO = so0;
+                        comp0_1_0.otherComponent2 = comp0;
+
+                        EditorApplication.SaveScene("unitTest4Scene_0.prefab");
+                    }
+                    {
+                        EditorApplication.LoadScene("unitTest4Scene_0.prefab");
+
+                        SceneObject sceneRoot = Scene.Root;
+                        SceneObject so0 = sceneRoot.FindChild("so0", false);
+                        SceneObject so1 = sceneRoot.FindChild("so1", false);
+                        SceneObject so0_0 = so0.FindChild("so0_0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        Assert(so0_0 != null);
+                        Assert(so0_1 != null);
+                        Assert(so0_1_0 != null);
+
+                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
+                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+
+                        Assert(comp0 != null);
+                        Assert(comp1 != null);
+                        Assert(comp0_1_0 != null);
+                        Assert(comp0_1_0.b == "testValue");
+                        Assert(comp0.otherSO == so0_1_0);
+                        Assert(comp0.otherComponent == comp1);
+                        Assert(comp0_1_0.otherSO == so0);
+                        Assert(comp0_1_0.otherComponent2 == comp0);
+                    }
+                }
+
+                Debug.Log("Passed stage 1");
+
+                // Load & save a scene that contains a prefab and references its objects
+                {
+                    {
+                        // unitTest4Scene_1.prefab:
+                        // parentSO0
+                        //  - [unitTest4Scene_0.prefab]
+                        // parentSO1
+                        //  - parentSO1_0 (Comp1)
+
+                        Scene.Clear();
+
+                        SceneObject parentSO0 = new SceneObject("parentSO0", false);
+                        SceneObject parentSO1 = new SceneObject("parentSO1", false);
+                        SceneObject parentSO1_0 = new SceneObject("parentSO1_0", false);
+
+                        parentSO1_0.Parent = parentSO1;
+                        parentSO0.LocalPosition = new Vector3(50.0f, 50.0f, 50.0f);
+
+                        UT1_Component1 parentComp1_0 = parentSO1_0.AddComponent<UT1_Component1>();
+
+                        Prefab scene0Prefab = ProjectLibrary.Load<Prefab>("unitTest4Scene_0.prefab");
+                        SceneObject prefabInstance = scene0Prefab.Instantiate();
+                        prefabInstance.Parent = parentSO0;
+                        prefabInstance.LocalPosition = Vector3.Zero;
+
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+
+                        parentComp1_0.otherSO = so1_0;
+                        parentComp1_0.otherComponent2 = comp0_1_0;
+
+                        EditorApplication.SaveScene("unitTest4Scene_1.prefab");
+                    }
+                    {
+                        EditorApplication.LoadScene("unitTest4Scene_1.prefab");
+
+                        SceneObject parentSO0 = Scene.Root.FindChild("parentSO0", false);
+                        SceneObject parentSO1 = Scene.Root.FindChild("parentSO1", false);
+                        SceneObject parentSO1_0 = parentSO1.FindChild("parentSO1_0", false);
+
+                        UT1_Component1 parentComp1_0 = parentSO1_0.GetComponent<UT1_Component1>();
+
+                        SceneObject prefabInstance = parentSO0.GetChild(0);
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+
+                        Assert(parentComp1_0.otherSO == so1_0);
+                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
+                    }
+                }
+
+                Debug.Log("Passed stage 2");
+
+                // Modify prefab, reload the scene and ensure it is updated with modified prefab
+                {
+                    {
+                        // unitTest4Scene_0.prefab:
+                        // so0
+                        //  - so0_1 (Comp1)
+                        //    - so0_1_0 (Comp1)
+                        // so1 (Comp1, Comp2)
+                        //  - so1_0
+                        //  - so1_1
+
+                        Scene.Load("unitTest4Scene_0.prefab");
+
+                        SceneObject sceneRoot = Scene.Root;
+                        SceneObject so0 = sceneRoot.FindChild("so0", false);
+                        SceneObject so0_0 = so0.FindChild("so0_0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1 = sceneRoot.FindChild("so1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        SceneObject so1_1 = new SceneObject("so1_1");
+                        so1_1.Parent = so1;
+
+                        so0.RemoveComponent<UT1_Component1>();
+                        UT1_Component1 comp1 = so1.AddComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+
+                        so0_0.Destroy();
+
+                        comp1.otherSO = so1_0;
+                        comp1.otherComponent2 = comp0_1_0;
+
+                        comp0_1_0.otherSO = so1_1;
+                        comp0_1_0.otherComponent2 = comp1;
+                        comp0_1_0.a = 123;
+                        comp0_1_0.b = "modifiedValue";
+
+                        so1.Name = "so1_modified";
+                        so1.LocalPosition = new Vector3(0, 999.0f, 0.0f);
+
+                        EditorApplication.SaveScene("unitTest4Scene_0.prefab");
+                    }
+
+                    {
+                        EditorApplication.LoadScene("unitTest4Scene_1.prefab");
+
+                        SceneObject parentSO0 = Scene.Root.FindChild("parentSO0", false);
+                        SceneObject parentSO1 = Scene.Root.FindChild("parentSO1", false);
+                        SceneObject parentSO1_0 = parentSO1.FindChild("parentSO1_0", false);
+
+                        UT1_Component1 parentComp1_0 = parentSO1_0.GetComponent<UT1_Component1>();
+
+                        SceneObject prefabInstance = parentSO0.GetChild(0);
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
+                        SceneObject so0_0 = so0.FindChild("so0_0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+                        SceneObject so1_1 = so1.FindChild("so1_1", false);
+
+                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp1 = so1.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+
+                        Assert(parentComp1_0.otherSO == so1_0);
+                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
+                        Assert(so1_1 != null);
+                        Assert(so0_0 == null);
+                        Assert(comp0 == null);
+                        Assert(comp0_1_0.otherSO == so1_1);
+                        Assert(comp0_1_0.otherComponent2 == comp1);
+                        Assert(comp0_1_0.a == 123);
+                        Assert(comp0_1_0.b == "modifiedValue");
+                        Assert(comp1.otherSO == so1_0);
+                        Assert(comp1.otherComponent2 == comp0_1_0);
+                        Assert(MathEx.ApproxEquals(so1.LocalPosition.y, 999.0f));
+                    }
+                }
+
+                Debug.Log("Passed stage 3");
+
+                // Make instance specific changes to the prefab, modify the prefab itself and ensure
+                // both changes persist
+                {
+                    // Create new scene referencing the prefab and make instance modifications
+                    {
+                        // unitTest4Scene_2.prefab:
+                        // parent2SO0
+                        //  - [unitTest4Scene_0.prefab]
+                        // parent2SO1
+                        //  - parent2SO1_0 (Comp1)
+
+                        // unitTest4Scene_0.prefab (unitTest4Scene_2.prefab instance):
+                        // so0 (Comp1(INSTANCE))
+                        //  - so0_0 (INSTANCE)
+                        //  - so0_1 (Comp1)
+                        //    - so0_1_0 (Comp1)
+                        // so1 (Comp2)
+                        //  - so1_0
+
+                        Scene.Clear();
+
+                        SceneObject parent2SO0 = new SceneObject("parent2SO0");
+                        SceneObject parent2SO1 = new SceneObject("parent2SO1");
+                        SceneObject parent2SO1_0 = new SceneObject("parent2SO1_0");
+
+                        parent2SO1_0.Parent = parent2SO1;
+
+                        UT1_Component1 parentComp1_0 = parent2SO1_0.AddComponent<UT1_Component1>();
+
+                        Prefab scene0Prefab = ProjectLibrary.Load<Prefab>("unitTest4Scene_0.prefab");
+                        SceneObject prefabInstance = scene0Prefab.Instantiate();
+                        prefabInstance.Parent = parent2SO0;
+
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
+
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so1_1 = so1.FindChild("so1_1", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1 = so0_1.GetComponent<UT1_Component1>();
+
+                        SceneObject so0_0 = new SceneObject("so0_0");
+                        so0_0.Parent = so0;
+                        UT1_Component1 comp0 = so0.AddComponent<UT1_Component1>();
+
+                        so1.RemoveComponent<UT1_Component1>();
+                        so1_1.Destroy();
+
+                        comp0.otherSO = so0_1_0;
+                        comp0.otherComponent = comp1;
+
+                        parentComp1_0.otherSO = so1_0;
+                        parentComp1_0.otherComponent2 = comp0_1_0;
+
+                        comp0_1_0.otherSO = parent2SO1_0;
+                        comp0_1_0.otherComponent2 = parentComp1_0;
+                        comp0_1_0.b = "instanceValue";
+
+                        comp0_1.b = "instanceValue2";
+
+                        EditorApplication.SaveScene("unitTest4Scene_2.prefab");
+                    }
+
+                    Debug.Log("Passed stage 4.1");
+
+                    // Reload the scene and ensure instance modifications remain
+                    {
+                        EditorApplication.LoadScene("unitTest4Scene_2.prefab");
+
+                        SceneObject root = Scene.Root;
+                        SceneObject parent2SO0 = root.FindChild("parent2SO0", false);
+                        SceneObject parent2SO1 = root.FindChild("parent2SO1", false);
+                        SceneObject parent2SO1_0 = parent2SO1.FindChild("parent2SO1_0", false);
+
+                        SceneObject prefabInstance = parent2SO0.GetChild(0);
+
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
+                        SceneObject so0_0 = so0.FindChild("so0_0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so1_1 = so1.FindChild("so1_1", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        UT1_Component1 parentComp1_0 = parent2SO1_0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
+                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
+                        UT1_Component1 comp11 = so1.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1 = so0_1.GetComponent<UT1_Component1>();
+
+                        Assert(so0_0 != null);
+                        Assert(comp0 != null);
+                        Assert(so1_1 == null);
+                        Assert(comp11 == null);
+
+                        Assert(comp0.otherSO == so0_1_0);
+                        Assert(comp0.otherComponent == comp1);
+
+                        Assert(parentComp1_0.otherSO == so1_0);
+                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
+
+                        Assert(comp0_1_0.otherSO == parent2SO1_0);
+                        Assert(comp0_1_0.otherComponent2 == parentComp1_0);
+                        Assert(comp0_1_0.b == "instanceValue");
+
+                        Assert(comp0_1.b == "instanceValue2");
+                    }
+
+                    Debug.Log("Passed stage 4.2");
+
+                    // Load original scene and ensure instance modifications didn't influence it
+                    {
+                        EditorApplication.LoadScene("unitTest4Scene_1.prefab");
+
+                        SceneObject parentSO0 = Scene.Root.FindChild("parentSO0", false);
+                        SceneObject parentSO1 = Scene.Root.FindChild("parentSO1", false);
+                        SceneObject parentSO1_0 = parentSO1.FindChild("parentSO1_0", false);
+
+                        UT1_Component1 parentComp1_0 = parentSO1_0.GetComponent<UT1_Component1>();
+
+                        SceneObject prefabInstance = parentSO0.GetChild(0);
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1_modified", false);
+                        SceneObject so0_0 = so0.FindChild("so0_0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+                        SceneObject so1_1 = so1.FindChild("so1_1", false);
+
+                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp1 = so1.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1 = so0_1.GetComponent<UT1_Component1>();
+
+                        Assert(parentComp1_0.otherSO == so1_0);
+                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
+                        Assert(so1_1 != null);
+                        Assert(so0_0 == null);
+                        Assert(comp0 == null);
+                        Assert(comp0_1_0.otherSO == so1_1);
+                        Assert(comp0_1_0.otherComponent2 == comp1);
+                        Assert(comp0_1_0.a == 123);
+                        Assert(comp0_1_0.b == "modifiedValue");
+                        Assert(comp1.otherSO == so1_0);
+                        Assert(comp1.otherComponent2 == comp0_1_0);
+                        Assert(comp0_1.b == "originalValue2");
+                        Assert(MathEx.ApproxEquals(so1.LocalPosition.y, 999.0f));
+                    }
+
+                    Debug.Log("Passed stage 4.3");
+
+                    // Modify prefab and ensure both prefab and instance modifications remain
+                    {
+                        // unitTest4Scene_0.prefab:
+                        // so0 (Comp2)
+                        //  - so0_1
+                        //    - so0_1_0 (Comp1)
+                        // so1 (Comp1, Comp2)
+                        //  - so1_1
+                        //  - so1_2 (Comp1)
+
+                        // unitTest4Scene_0.prefab (unitTest4Scene_2.prefab instance):
+                        // so0 (Comp1)
+                        //  - so0_0
+                        //  - so0_1 (Comp1)
+                        //    - so0_1_0 (Comp1)
+                        // so1 (Comp2)
+                        //  - so1_2 (Comp1)
+
+                        Scene.Load("unitTest4Scene_0.prefab");
+
+                        SceneObject sceneRoot = Scene.Root;
+                        SceneObject so0 = sceneRoot.FindChild("so0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1 = sceneRoot.FindChild("so1_modified", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        SceneObject so1_2 = new SceneObject("so1_2");
+                        so1_2.Parent = so1;
+
+                        so0.AddComponent<UT1_Component2>();
+                        so0_1.RemoveComponent<UT1_Component1>();
+                        so1_0.Destroy();
+
+                        UT1_Component1 comp3 = so1_2.AddComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+                        comp0_1_0.b = "modifiedValueAgain";
+                        so1.Name = "so1_modifiedAgain";
+
+                        comp3.otherSO = so0_1;
+                        comp3.otherComponent2 = comp0_1_0;
+
+                        EditorApplication.SaveScene("unitTest4Scene_0.prefab");
+                    }
+
+                    Debug.Log("Passed stage 4.4");
+
+                    // Reload the scene and ensure both instance and prefab modifications remain
+                    {
+                        EditorApplication.LoadScene("unitTest4Scene_2.prefab");
+
+                        SceneObject root = Scene.Root;
+                        SceneObject parent2SO0 = root.FindChild("parent2SO0", false);
+                        SceneObject parent2SO1 = root.FindChild("parent2SO1", false);
+                        SceneObject parent2SO1_0 = parent2SO1.FindChild("parent2SO1_0", false);
+
+                        SceneObject prefabInstance = parent2SO0.GetChild(0);
+
+                        SceneObject so0 = prefabInstance.FindChild("so0", false);
+                        SceneObject so1 = prefabInstance.FindChild("so1_modifiedAgain", false);
+                        SceneObject so0_0 = so0.FindChild("so0_0", false);
+                        SceneObject so0_1 = so0.FindChild("so0_1", false);
+                        SceneObject so1_0 = so1.FindChild("so1_0", false);
+                        SceneObject so1_1 = so1.FindChild("so1_1", false);
+                        SceneObject so1_2 = so1.FindChild("so1_2", false);
+                        SceneObject so0_1_0 = so0_1.FindChild("so0_1_0", false);
+
+                        UT1_Component1 parentComp1_0 = parent2SO1_0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0 = so0.GetComponent<UT1_Component1>();
+                        UT1_Component2 comp1 = so1.GetComponent<UT1_Component2>();
+                        UT1_Component1 comp11 = so1.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp0_1_0 = so0_1_0.GetComponent<UT1_Component1>();
+                        UT1_Component1 comp3 = so1_2.GetComponent<UT1_Component1>();
+
+                        // Check instance modifications (they should override any prefab modifications)
+                        Assert(so0_0 != null);
+                        Assert(comp0 != null);
+                        Assert(so1_1 == null);
+                        Assert(comp11 == null);
+
+                        Assert(comp0.otherSO == so0_1_0);
+                        Assert(comp0.otherComponent == comp1);
+
+                        Assert(parentComp1_0.otherSO == so1_0);
+                        Assert(parentComp1_0.otherComponent2 == comp0_1_0);
+
+                        Assert(comp0_1_0.otherSO == parent2SO1_0);
+                        Assert(comp0_1_0.otherComponent2 == parentComp1_0);
+                        Assert(comp0_1_0.b == "instanceValue");
+
+                        // Check prefab modifications
+                        Assert(so1_0 == null);
+                        Assert(so1.Name == "so1_modifiedAgain");
+
+                        Assert(comp3.otherSO == so0_1);
+                        Assert(comp3.otherComponent2 == comp0_1_0);
+                    }
+
+                    Debug.Log("Passed stage 4.5");
+                }
+            }
+            catch
+            {
+                PrintSceneState();
+
+                throw;
+            }
+            finally
+            {
+                
+
+                if (!string.IsNullOrEmpty(oldScene))
+                    Scene.Load(ProjectLibrary.GetPath(oldScene));
+                else
+                    Scene.Clear();
+
+                ProjectLibrary.Delete("unitTest4Scene_0.prefab");
+                ProjectLibrary.Delete("unitTest4Scene_1.prefab");
+                ProjectLibrary.Delete("unitTest4Scene_2.prefab");
+            }
+        }
+
+        /// <summary>
+        /// Runs all tests.
+        /// </summary>
+        static void RunTests()
+        {
+            UnitTest1_ManagedSerialization();
+            UnitTest2_SerializableProperties();
+            UnitTest3_ManagedDiff();
+            UnitTest4_Prefabs();
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UT1_GameObjectClone(SceneObject so);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UT3_GenerateDiff(UT_DiffObj oldObj, UT_DiffObj newObj);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UT3_ApplyDiff(UT_DiffObj obj);
+    }
+}

+ 17 - 0
MBansheeEngine/Component.cs

@@ -39,6 +39,17 @@ namespace BansheeEngine
             get { return Internal_GetSceneObject(mCachedPtr); }
             get { return Internal_GetSceneObject(mCachedPtr); }
         }
         }
 
 
+        /// <summary>
+        /// Destroys the component, removing it from its scene object and stopping component updates.
+        /// </summary>
+        /// <param name="immediate">If true the component will be fully destroyed immediately. This means that objects
+        ///                         that are still referencing this component might fail. Normally destruction is delayed
+        ///                         until the end of the frame to give other objects a chance to stop using it.</param>
+        public void Destroy(bool immediate = false)
+        {
+            Internal_Destroy(mCachedPtr, immediate);
+        }
+
         /// <summary>
         /// <summary>
         /// Calculates bounds of the visible content for this component.
         /// Calculates bounds of the visible content for this component.
         /// </summary>
         /// </summary>
@@ -64,10 +75,16 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern Component[] Internal_GetComponents(SceneObject parent);
         internal static extern Component[] Internal_GetComponents(SceneObject parent);
 
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern Component[] Internal_GetComponentsPerType(SceneObject parent, Type type);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern Component Internal_RemoveComponent(SceneObject parent, Type type);
         internal static extern Component Internal_RemoveComponent(SceneObject parent, Type type);
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern SceneObject Internal_GetSceneObject(IntPtr nativeInstance);
         internal static extern SceneObject Internal_GetSceneObject(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
     }
     }
 }
 }

+ 22 - 10
MBansheeEngine/SceneObject.cs

@@ -264,15 +264,28 @@ namespace BansheeEngine
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Searches for a component of a specific type.
+        /// Searches for a component of a specific type. If there are multiple components matching the type, only the first
+        /// one found is returned.
         /// </summary>
         /// </summary>
-        /// <typeparam name="T">Type of the component to search for.</typeparam>
+        /// <typeparam name="T">Type of the component to search for. Includes any components derived from the type.
+        /// </typeparam>
         /// <returns>Component instance if found, null otherwise.</returns>
         /// <returns>Component instance if found, null otherwise.</returns>
         public T GetComponent<T>() where T : Component
         public T GetComponent<T>() where T : Component
         {
         {
             return (T)Component.Internal_GetComponent(this, typeof(T));
             return (T)Component.Internal_GetComponent(this, typeof(T));
         }
         }
 
 
+        /// <summary>
+        /// Searches for all components of a specific type. 
+        /// </summary>
+        /// <typeparam name="T">Type of the component to search for. Includes any components derived from the type.
+        /// </typeparam>
+        /// <returns>All components matching the specified type.</returns>
+        public Component[] GetComponents<T>() where T : Component
+        {
+            return Component.Internal_GetComponentsPerType(this, typeof(T));
+        }
+
         /// <summary>
         /// <summary>
         /// Returns a list of all components attached to this object.
         /// Returns a list of all components attached to this object.
         /// </summary>
         /// </summary>
@@ -283,18 +296,20 @@ namespace BansheeEngine
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Removes a component from the scene object.
+        /// Removes a component from the scene object. If there are multiple components matching the type, only the first
+        /// one found is removed.
         /// </summary>
         /// </summary>
-        /// <typeparam name="T">Type of the component to remove.</typeparam>
+        /// <typeparam name="T">Type of the component to remove. Includes any components derived from the type.</typeparam>
         public void RemoveComponent<T>() where T : Component
         public void RemoveComponent<T>() where T : Component
         {
         {
             Component.Internal_RemoveComponent(this, typeof(T));
             Component.Internal_RemoveComponent(this, typeof(T));
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Removes a component from the scene object.
+        /// Removes a component from the scene object. If there are multiple components matching the type, only the first
+        /// one found is removed.
         /// </summary>
         /// </summary>
-        /// <param name="type">Type of the component to remove.</param>
+        /// <param name="type">Type of the component to remove. Includes any components derived from the type.</param>
         public void RemoveComponent(Type type)
         public void RemoveComponent(Type type)
         {
         {
             Component.Internal_RemoveComponent(this, type);
             Component.Internal_RemoveComponent(this, type);
@@ -427,7 +442,7 @@ namespace BansheeEngine
         /// </summary>
         /// </summary>
         /// <param name="immediate">If true the scene object will be fully destroyed immediately. This means that objects
         /// <param name="immediate">If true the scene object will be fully destroyed immediately. This means that objects
         ///                         that are still referencing this scene object might fail. Normally destruction is delayed
         ///                         that are still referencing this scene object might fail. Normally destruction is delayed
-        ///                         until the end of the frame to give other object's a chance to stop using it.</param>
+        ///                         until the end of the frame to give other objects a chance to stop using it.</param>
         public void Destroy(bool immediate = false)
         public void Destroy(bool immediate = false)
         {
         {
             Internal_Destroy(mCachedPtr, immediate);
             Internal_Destroy(mCachedPtr, immediate);
@@ -466,9 +481,6 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SceneObject[] Internal_FindChildren(IntPtr nativeInstance, string name, bool recursive);
         private static extern SceneObject[] Internal_FindChildren(IntPtr nativeInstance, string name, bool recursive);
 
 
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Prefab Internal_GetPrefab(IntPtr nativeInstance);
-
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetPosition(IntPtr nativeInstance, out Vector3 value);
         private static extern void Internal_GetPosition(IntPtr nativeInstance, out Vector3 value);
 
 

+ 2 - 0
SBansheeEngine/Include/BsScriptComponent.h

@@ -69,7 +69,9 @@ namespace BansheeEngine
 		static MonoObject* internal_addComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static MonoObject* internal_addComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static MonoObject* internal_getComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static MonoObject* internal_getComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static MonoArray* internal_getComponents(MonoObject* parentSceneObject);
 		static MonoArray* internal_getComponents(MonoObject* parentSceneObject);
+		static MonoArray* internal_getComponentsPerType(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static void internal_removeComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static void internal_removeComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static MonoObject* internal_getSceneObject(ScriptComponent* nativeInstance);
 		static MonoObject* internal_getSceneObject(ScriptComponent* nativeInstance);
+		static void internal_destroy(ScriptComponent* nativeInstance, bool immediate);
 	};
 	};
 }
 }

+ 65 - 18
SBansheeEngine/Source/BsScriptComponent.cpp

@@ -30,8 +30,10 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_AddComponent", &ScriptComponent::internal_addComponent);
 		metaData.scriptClass->addInternalCall("Internal_AddComponent", &ScriptComponent::internal_addComponent);
 		metaData.scriptClass->addInternalCall("Internal_GetComponent", &ScriptComponent::internal_getComponent);
 		metaData.scriptClass->addInternalCall("Internal_GetComponent", &ScriptComponent::internal_getComponent);
 		metaData.scriptClass->addInternalCall("Internal_GetComponents", &ScriptComponent::internal_getComponents);
 		metaData.scriptClass->addInternalCall("Internal_GetComponents", &ScriptComponent::internal_getComponents);
+		metaData.scriptClass->addInternalCall("Internal_GetComponentsPerType", &ScriptComponent::internal_getComponentsPerType);
 		metaData.scriptClass->addInternalCall("Internal_RemoveComponent", &ScriptComponent::internal_removeComponent);
 		metaData.scriptClass->addInternalCall("Internal_RemoveComponent", &ScriptComponent::internal_removeComponent);
 		metaData.scriptClass->addInternalCall("Internal_GetSceneObject", &ScriptComponent::internal_getSceneObject);
 		metaData.scriptClass->addInternalCall("Internal_GetSceneObject", &ScriptComponent::internal_getSceneObject);
+		metaData.scriptClass->addInternalCall("Internal_Destroy", &ScriptComponent::internal_destroy);
 	}
 	}
 
 
 	MonoObject* ScriptComponent::internal_addComponent(MonoObject* parentSceneObject, MonoReflectionType* type)
 	MonoObject* ScriptComponent::internal_addComponent(MonoObject* parentSceneObject, MonoReflectionType* type)
@@ -42,22 +44,7 @@ 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();
 	}
 	}
 
 
@@ -69,6 +56,9 @@ namespace BansheeEngine
 		if (checkIfDestroyed(so))
 		if (checkIfDestroyed(so))
 			return nullptr;
 			return nullptr;
 
 
+		MonoType* baseType = mono_reflection_type_get_type(type);
+		::MonoClass* baseClass = mono_type_get_class(baseType);
+
 		const Vector<HComponent>& mComponents = so->getComponents();
 		const Vector<HComponent>& mComponents = so->getComponents();
 		for(auto& component : mComponents)
 		for(auto& component : mComponents)
 		{
 		{
@@ -76,7 +66,11 @@ namespace BansheeEngine
 			{
 			{
 				GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
 				GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
 
 
-				if(managedComponent->getRuntimeType() == type)
+				MonoReflectionType* componentReflType = managedComponent->getRuntimeType();
+				MonoType* componentType = mono_reflection_type_get_type(componentReflType);
+				::MonoClass* componentClass = mono_type_get_class(componentType);
+				
+				if(mono_class_is_subclass_of(componentClass, baseClass, true))
 				{
 				{
 					return managedComponent->getManagedInstance();
 					return managedComponent->getManagedInstance();
 				}
 				}
@@ -86,6 +80,47 @@ namespace BansheeEngine
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
+	MonoArray* ScriptComponent::internal_getComponentsPerType(MonoObject* parentSceneObject, MonoReflectionType* type)
+	{
+		ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject);
+		HSceneObject so = static_object_cast<SceneObject>(scriptSO->getNativeHandle());
+
+		MonoType* baseType = mono_reflection_type_get_type(type);
+		::MonoClass* baseClass = mono_type_get_class(baseType);
+
+		Vector<MonoObject*> managedComponents;
+
+		if (!checkIfDestroyed(so))
+		{
+			const Vector<HComponent>& mComponents = so->getComponents();
+			for (auto& component : mComponents)
+			{
+				if (component->getTypeId() == TID_ManagedComponent)
+				{
+					GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
+
+					MonoReflectionType* componentReflType = managedComponent->getRuntimeType();
+					MonoType* componentType = mono_reflection_type_get_type(componentReflType);
+					::MonoClass* componentClass = mono_type_get_class(componentType);
+
+					if (mono_class_is_subclass_of(componentClass, baseClass, true))
+						managedComponents.push_back(managedComponent->getManagedInstance());
+				}
+			}
+		}
+
+		MonoArray* componentArray = mono_array_new(MonoManager::instance().getDomain(),
+			metaData.scriptClass->_getInternalClass(), (UINT32)managedComponents.size());
+
+		for (UINT32 i = 0; i < (UINT32)managedComponents.size(); i++)
+		{
+			void* elemAddr = mono_array_addr_with_size(componentArray, sizeof(MonoObject*), i);
+			memcpy(elemAddr, &managedComponents[i], sizeof(MonoObject*));
+		}
+
+		return componentArray;
+	}
+
 	MonoArray* ScriptComponent::internal_getComponents(MonoObject* parentSceneObject)
 	MonoArray* ScriptComponent::internal_getComponents(MonoObject* parentSceneObject)
 	{
 	{
 		ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject);
 		ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject);
@@ -127,7 +162,9 @@ namespace BansheeEngine
 		if (checkIfDestroyed(so))
 		if (checkIfDestroyed(so))
 			return;
 			return;
 
 
-		// We only allow single component per type
+		MonoType* baseType = mono_reflection_type_get_type(type);
+		::MonoClass* baseClass = mono_type_get_class(baseType);
+
 		const Vector<HComponent>& mComponents = so->getComponents();
 		const Vector<HComponent>& mComponents = so->getComponents();
 		for(auto& component : mComponents)
 		for(auto& component : mComponents)
 		{
 		{
@@ -135,7 +172,11 @@ namespace BansheeEngine
 			{
 			{
 				GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
 				GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
 
 
-				if(managedComponent->getRuntimeType() == type)
+				MonoReflectionType* componentReflType = managedComponent->getRuntimeType();
+				MonoType* componentType = mono_reflection_type_get_type(componentReflType);
+				::MonoClass* componentClass = mono_type_get_class(componentType);
+
+				if (mono_class_is_subclass_of(componentClass, baseClass, true))
 				{
 				{
 					managedComponent->destroy();
 					managedComponent->destroy();
 					return;
 					return;
@@ -159,6 +200,12 @@ namespace BansheeEngine
 		return scriptSO->getManagedInstance();
 		return scriptSO->getManagedInstance();
 	}
 	}
 
 
+	void ScriptComponent::internal_destroy(ScriptComponent* nativeInstance, bool immediate)
+	{
+		if (!checkIfDestroyed(nativeInstance->mManagedComponent))
+			nativeInstance->mManagedComponent->destroy(immediate);
+	}
+
 	bool ScriptComponent::checkIfDestroyed(const GameObjectHandleBase& handle)
 	bool ScriptComponent::checkIfDestroyed(const GameObjectHandleBase& handle)
 	{
 	{
 		if (handle.isDestroyed())
 		if (handle.isDestroyed())

+ 0 - 4
SBansheeEngine/Source/BsScriptSceneObject.cpp

@@ -9,10 +9,6 @@
 #include "BsMonoManager.h"
 #include "BsMonoManager.h"
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
-#include "BsScriptPrefab.h"
-#include "BsPrefab.h"
-#include "BsPrefabUtility.h"
-#include "BsResources.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {