bool EditorUtility::calculateMeshBounds(const HSceneObject& object, AABox& bounds)
	{
		bounds = AABox(Vector3::ZERO, Vector3::ZERO);
		if (object.isDestroyed())
			return false;

		bool foundOne = false;
		const Vector<HComponent>& components = object->getComponents();
		for (auto& component : components)
		{
			Bounds curBounds;
			if (component->calculateBounds(curBounds))
			{
				if (!foundOne)
				{
					bounds = curBounds.getBox();
					foundOne = true;
				}
				else
					bounds.merge(curBounds.getBox());
			}
			else
			{
				if (!foundOne)
					bounds = curBounds.getBox();
			}
		}

		return foundOne;
	}
Esempio n. 2
0
	void GUIWidget::_updateTransform(const HSceneObject& parent)
	{
		// If the widgets parent scene object moved, we need to mark it as dirty
		// as the GUIManager batching relies on object positions, so it needs to be updated.
		const float diffEpsilon = 0.0001f;

		Vector3 position = parent->getWorldPosition();
		Quaternion rotation = parent->getWorldRotation();
		Vector3 scale = parent->getWorldScale();

		if(!mWidgetIsDirty)
		{
			if(!Math::approxEquals(mPosition, position, diffEpsilon))
				mWidgetIsDirty = true;
			else
			{
				if(!Math::approxEquals(mRotation, rotation, diffEpsilon))
					mWidgetIsDirty = true;
				else
				{
					if(Math::approxEquals(mScale, scale))
						mWidgetIsDirty = true;
				}
			}
		}

		mPosition = position;
		mRotation = rotation;
		mScale = scale;
		mTransform = parent->getWorldTfrm();
	}
Esempio n. 3
0
	Vector<HBone> CAnimation::findChildBones()
	{
		Stack<HSceneObject> todo;
		todo.push(SO());

		Vector<HBone> bones;
		while (todo.size() > 0)
		{
			HSceneObject currentSO = todo.top();
			todo.pop();

			HBone bone = currentSO->getComponent<CBone>();
			if (bone != nullptr)
			{
				bone->_setParent(static_object_cast<CAnimation>(getHandle()), true);
				bones.push_back(bone);
			}

			int childCount = currentSO->getNumChildren();
			for (int i = 0; i < childCount; i++)
			{
				HSceneObject child = currentSO->getChild(i);
				if (child->getComponent<CAnimation>() != nullptr)
					continue;

				todo.push(child);
			}
		}

		return bones;
	}
	void PrefabUtility::clearPrefabIds(const HSceneObject& sceneObject, bool recursive)
	{
		Stack<HSceneObject> todo;
		todo.push(sceneObject);

		while (!todo.empty())
		{
			HSceneObject currentSO = todo.top();
			todo.pop();

			for (auto& component : currentSO->mComponents)
				component->mLinkId = (UINT32)-1;

			if (recursive)
			{
				UINT32 numChildren = (UINT32)currentSO->getNumChildren();
				for (UINT32 i = 0; i < numChildren; i++)
				{
					HSceneObject child = currentSO->getChild(i);
					child->mLinkId = (UINT32)-1;

					if (child->mPrefabLinkUUID.empty())
						todo.push(child);
				}
			}
		}
	}
Esempio n. 5
0
	void CCollider::updateParentRigidbody()
	{
		if (mIsTrigger)
		{
			setRigidbody(HRigidbody());
			return;
		}

		HSceneObject currentSO = SO();
		while (currentSO != nullptr)
		{
			HRigidbody parent = currentSO->getComponent<CRigidbody>();
			if (parent != nullptr)
			{
				if(currentSO->getActive() && isValidParent(parent))
					setRigidbody(parent);
				else
					setRigidbody(HRigidbody());

				return;
			}

			currentSO = currentSO->getParent();
		}

		// Not found
		setRigidbody(HRigidbody());
	}
	bool ScriptEditorUtility::internal_IsInternal(ScriptSceneObject* soPtr)
	{
		if (ScriptSceneObject::checkIfDestroyed(soPtr))
			return false;

		HSceneObject so = soPtr->getHandle();
		return so->hasFlag(SOF_Internal);
	}
Esempio n. 7
0
	void CAnimation::updateSceneObjectMapping()
	{
		Vector<SceneObjectMappingInfo> newMappingInfos;
		for(auto& entry : mMappingInfos)
		{
			if (entry.isMappedToBone)
				newMappingInfos.push_back(entry);
			else
				unmapSceneObject(entry.sceneObject);
		}

		if (mPrimaryPlayingClip.isLoaded())
		{
			HSceneObject root = SO();

			const auto& findMappings = [&](const String& name, AnimationCurveFlags flags)
			{
				if (flags.isSet(AnimationCurveFlag::ImportedCurve))
					return;

				HSceneObject currentSO = root->findPath(name);

				bool found = false;
				for (UINT32 i = 0; i < (UINT32)newMappingInfos.size(); i++)
				{
					if (newMappingInfos[i].sceneObject == currentSO)
					{
						found = true;
						break;
					}
				}

				if (!found)
				{
					SceneObjectMappingInfo newMappingInfo;
					newMappingInfo.isMappedToBone = false;
					newMappingInfo.sceneObject = currentSO;

					newMappingInfos.push_back(newMappingInfo);
					mapCurveToSceneObject(name, currentSO);
				}
			};

			SPtr<AnimationCurves> curves = mPrimaryPlayingClip->getCurves();
			for(auto& curve : curves->position)
				findMappings(curve.name, curve.flags);

			for(auto& curve : curves->rotation)
				findMappings(curve.name, curve.flags);

			for(auto& curve : curves->scale)
				findMappings(curve.name, curve.flags);
		}

		mMappingInfos = newMappingInfos;
	}
Esempio n. 8
0
	void Light::_updateTransform(const HSceneObject& parent)
	{
		UINT32 curHash = parent->getTransformHash();
		if (curHash != _getLastModifiedHash())
		{
			setPosition(parent->getWorldPosition());
			setRotation(parent->getWorldRotation());
			_setLastModifiedHash(curHash);
		}
	}
Esempio n. 9
0
PhysXRigidbody::PhysXRigidbody(PxPhysics* physx, PxScene* scene, const HSceneObject& linkedSO)
    :Rigidbody(linkedSO)
{
    PxTransform tfrm = toPxTransform(linkedSO->getWorldPosition(), linkedSO->getWorldRotation());

    mInternal = physx->createRigidDynamic(tfrm);
    mInternal->userData = this;

    scene->addActor(*mInternal);
}
Esempio n. 10
0
	void CmdDeleteSO::recordSO(const HSceneObject& sceneObject)
	{
		MemorySerializer serializer;
		mSerializedObject = serializer.encode(mSceneObject.get(), mSerializedObjectSize);

		HSceneObject parent = mSceneObject->getParent();
		if (parent != nullptr)
			mSerializedObjectParentId = parent->getInstanceId();

		mSceneObjectProxy = CmdUtility::createProxy(mSceneObject);
	}
	void ScriptPrefabUtility::internal_UpdateFromPrefab(ScriptSceneObject* soPtr)
	{
		if (ScriptSceneObject::checkIfDestroyed(soPtr))
			return;

		HSceneObject so = soPtr->getNativeSceneObject();
		HSceneObject prefabParent = so->getPrefabParent();

		if(prefabParent != nullptr)
			PrefabUtility::updateFromPrefab(prefabParent);
	}
Esempio n. 12
0
	void PrefabUtility::recordInstanceData(const HSceneObject& so, SceneObjectProxy& output,
		UnorderedMap<UINT32, GameObjectInstanceDataPtr>& linkedInstanceData)
	{
		struct StackData
		{
			HSceneObject so;
			SceneObjectProxy* proxy;
		};

		Stack<StackData> todo;
		todo.push({so, &output});

		output.instanceData = so->_getInstanceData();
		output.linkId = (UINT32)-1;

		while (!todo.empty())
		{
			StackData curData = todo.top();
			todo.pop();

			const Vector<HComponent>& components = curData.so->getComponents();
			for (auto& component : components)
			{
				curData.proxy->components.push_back(ComponentProxy());

				ComponentProxy& componentProxy = curData.proxy->components.back();
				componentProxy.instanceData = component->_getInstanceData();
				componentProxy.linkId = component->getLinkId();

				linkedInstanceData[componentProxy.linkId] = componentProxy.instanceData;
			}

			UINT32 numChildren = curData.so->getNumChildren();
			curData.proxy->children.resize(numChildren);

			for (UINT32 i = 0; i < numChildren; i++)
			{
				HSceneObject child = curData.so->getChild(i);

				SceneObjectProxy& childProxy = curData.proxy->children[i];

				childProxy.instanceData = child->_getInstanceData();
				childProxy.linkId = child->getLinkId();

				linkedInstanceData[childProxy.linkId] = childProxy.instanceData;

				if (child->mPrefabLinkUUID.empty())
				{
					todo.push({ child, &curData.proxy->children[i] });
				}
			}
		}
	}
Esempio n. 13
0
	void Prefab::initialize(const HSceneObject& sceneObject)
	{
		sceneObject->mPrefabDiff = nullptr;
		UINT32 newNextLinkId = PrefabUtility::generatePrefabIds(sceneObject, mNextLinkId);

		if (newNextLinkId < mNextLinkId)
		{
			BS_EXCEPT(InternalErrorException, "Prefab ran out of IDs to assign. " \
				"Consider increasing the size of the prefab ID data type.");
		}

		mNextLinkId = newNextLinkId;

		// If there are any child prefab instances, make sure to update their diffs so they are saved with this prefab
		Stack<HSceneObject> todo;
		todo.push(sceneObject);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			UINT32 childCount = current->getNumChildren();
			for (UINT32 i = 0; i < childCount; i++)
			{
				HSceneObject child = current->getChild(i);

				if (!child->mPrefabLinkUUID.empty())
					PrefabUtility::recordPrefabDiff(child);
				else
					todo.push(child);
			}
		}

		// Clone the hierarchy for internal storage
		mRoot = sceneObject->clone(false);
		mRoot->mParent = nullptr;

		// Remove objects with "dont save" flag
		todo.push(mRoot);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			if (current->hasFlag(SOF_DontSave))
				current->destroy();
			else
			{
				UINT32 numChildren = current->getNumChildren();
				for (UINT32 i = 0; i < numChildren; i++)
					todo.push(current->getChild(i));
			}
		}
	}
Esempio n. 14
0
	void ScriptLight::internal_updateTransform(ScriptLight* thisPtr, ScriptSceneObject* parent)
	{
		HSceneObject parentSO = parent->getNativeSceneObject();

		if (!parentSO.isDestroyed())
		{
			thisPtr->getInternal()->_updateTransform(parentSO);

			if (parentSO->getActive() != thisPtr->getInternal()->getIsActive())
			{
				thisPtr->getInternal()->setIsActive(parentSO->getActive());
			}
		}
	}
Esempio n. 15
0
	void ScriptGUIWidget::internal_UpdateTransform(ScriptGUIWidget* thisPtr, ScriptSceneObject* parent)
	{
		HSceneObject parentSO = parent->getNativeSceneObject();

		SPtr<GUIWidget> widget = thisPtr->getInternal();
		if (!parentSO.isDestroyed() && widget != nullptr)
		{
			widget->_updateTransform(parentSO);
			widget->_updateRT();

			if (parentSO->getActive() != widget->getIsActive())
				widget->setIsActive(parentSO->getActive());
		}
	}
Esempio n. 16
0
	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();
		}
	}
	MonoObject* ScriptPrefabUtility::internal_getPrefabParent(ScriptSceneObject* nativeInstance)
	{
		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
			return nullptr;

		HSceneObject so = nativeInstance->getNativeSceneObject();
		HSceneObject parent = so->getPrefabParent();

		if(parent != nullptr)
		{
			ScriptSceneObject* scriptParent = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(parent);
			return scriptParent->getManagedInstance();
		}

		return nullptr;
	}
Esempio n. 18
0
	void Prefab::initialize(const HSceneObject& sceneObject)
	{
		sceneObject->mPrefabDiff = nullptr;
		PrefabUtility::generatePrefabIds(sceneObject);

		// If there are any child prefab instances, make sure to update their diffs so they are saved with this prefab
		Stack<HSceneObject> todo;
		todo.push(sceneObject);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			UINT32 childCount = current->getNumChildren();
			for (UINT32 i = 0; i < childCount; i++)
			{
				HSceneObject child = current->getChild(i);

				if (!child->mPrefabLinkUUID.empty())
					PrefabUtility::recordPrefabDiff(child);
				else
					todo.push(child);
			}
		}

		// Clone the hierarchy for internal storage
		if (mRoot != nullptr)
			mRoot->destroy(true);

		mRoot = sceneObject->clone(false);
		mRoot->mParent = nullptr;
		mRoot->mLinkId = -1;

		// Remove objects with "dont save" flag
		todo.push(mRoot);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			if (current->hasFlag(SOF_DontSave))
				current->destroy();
			else
			{
				UINT32 numChildren = current->getNumChildren();
				for (UINT32 i = 0; i < numChildren; i++)
					todo.push(current->getChild(i));
			}
		}
	}
Esempio n. 19
0
	void PrefabUtility::recordPrefabDiff(const HSceneObject& sceneObject)
	{
		HSceneObject topLevelObject = sceneObject;

		while (topLevelObject != nullptr)
		{
			if (!topLevelObject->mPrefabLinkUUID.empty())
				break;

			if (topLevelObject->mParent != nullptr)
				topLevelObject = topLevelObject->mParent;
			else
				topLevelObject = nullptr;
		}

		if (topLevelObject == nullptr)
			topLevelObject = sceneObject;

		Stack<HSceneObject> todo;
		todo.push(topLevelObject);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			if (!current->mPrefabLinkUUID.empty())
			{
				current->mPrefabDiff = nullptr;

				HPrefab prefabLink = static_resource_cast<Prefab>(gResources().loadFromUUID(current->mPrefabLinkUUID, false, false));
				if (prefabLink.isLoaded(false))
					current->mPrefabDiff = PrefabDiff::create(prefabLink->_getRoot(), current->getHandle());
			}

			UINT32 childCount = current->getNumChildren();
			for (UINT32 i = 0; i < childCount; i++)
			{
				HSceneObject child = current->getChild(i);
				todo.push(child);
			}
		}

		gResources().unloadAllUnused();
	}
Esempio n. 20
0
	UINT32 PrefabUtility::generatePrefabIds(const HSceneObject& sceneObject, UINT32 startingId)
	{
		Stack<HSceneObject> todo;
		todo.push(sceneObject);

		while (!todo.empty())
		{
			HSceneObject currentSO = todo.top();
			todo.pop();

			for (auto& component : currentSO->mComponents)
			{
				if (component->getLinkId() == (UINT32)-1)
					component->mLinkId = startingId++;
			}

			UINT32 numChildren = (UINT32)currentSO->getNumChildren();
			for (UINT32 i = 0; i < numChildren; i++)
			{
				HSceneObject child = currentSO->getChild(i);

				if (!child->hasFlag(SOF_DontSave))
				{
					if (child->getLinkId() == (UINT32)-1)
						child->mLinkId = startingId++;

					if(child->mPrefabLinkUUID.empty())
						todo.push(currentSO->getChild(i));
				}
			}
		}

		return startingId;
	}
Esempio n. 21
0
	HSceneObject Prefab::instantiate()
	{
		if (mRoot == nullptr)
			return HSceneObject();

#if BS_IS_BANSHEE3D
		if (gCoreApplication().isEditor())
		{
			// Update any child prefab instances in case their prefabs changed
			_updateChildInstances();
		}
#endif

		HSceneObject clone = _clone();
		clone->_instantiate();
		
		return clone;
	}
Esempio n. 22
0
	void CRigidbody::updateColliders()
	{
		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)
				{
					if (!entry->isValidParent(mThisHandle))
						continue;

					Collider* collider = entry->_getInternal();
					if (collider == nullptr)
						continue;

					entry->setRigidbody(mThisHandle, true);
					mChildren.push_back(entry);

					collider->setRigidbody(mInternal.get());
					mInternal->addCollider(collider->_getInternal());
				}
			}

			UINT32 childCount = currentSO->getNumChildren();
			for (UINT32 i = 0; i < childCount; i++)
			{
				HSceneObject child = currentSO->getChild(i);

				if (child->hasComponent<CRigidbody>())
					continue;

				todo.push(child);
			}
		}
	}
Esempio n. 23
0
	void CmdRecordSO::revert()
	{
		if (mSceneObject == nullptr || mSceneObject.isDestroyed())
			return;

		HSceneObject parent = mSceneObject->getParent();

		UINT32 numChildren = mSceneObject->getNumChildren();
		HSceneObject* children = nullptr;
		if (!mRecordHierarchy)
		{
			children = bs_stack_new<HSceneObject>(numChildren);
			for (UINT32 i = 0; i < numChildren; i++)
			{
				HSceneObject child = mSceneObject->getChild(i);
				children[i] = child;

				child->setParent(HSceneObject());
			}
		}

		mSceneObject->destroy(true);

		GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds);

		MemorySerializer serializer;
		SPtr<SceneObject> restored = std::static_pointer_cast<SceneObject>(serializer.decode(mSerializedObject, mSerializedObjectSize));

		EditorUtility::restoreIds(restored->getHandle(), mSceneObjectProxy);
		restored->setParent(parent);

		if (!mRecordHierarchy)
		{
			for (UINT32 i = 0; i < numChildren; i++)
				children[i]->setParent(restored->getHandle());

			bs_stack_delete(children, numChildren);
		}

		restored->_instantiate();
	}
	void GUIGameObjectField::dataDropped(void* data)
	{
		DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(data);

		if (draggedSceneObjects->numObjects <= 0)
			return;

		MonoClass* sceneObjectClass = ScriptAssemblyManager::instance().getSceneObjectClass();

		if (mType == sceneObjectClass->getFullName()) // A scene object
		{
			setValue(draggedSceneObjects->objects[0], true);
		}
		else // A component
		{
			for (UINT32 i = 0; i < draggedSceneObjects->numObjects; i++)
			{
				HSceneObject so = draggedSceneObjects->objects[i];

				const Vector<HComponent>& components = so->getComponents();
				for (auto& component : components)
				{
					if (component->getTypeId() == TID_ManagedComponent) // We only care about managed components
					{
						HManagedComponent managedComponent = static_object_cast<ManagedComponent>(component);

						MonoClass* acceptedClass = MonoManager::instance().findClass(mNamespace, mType);
						MonoClass* providedClass = MonoManager::instance().findClass(managedComponent->getManagedNamespace(), managedComponent->getManagedTypeName());

						if (acceptedClass != nullptr && providedClass != nullptr)
						{
							if (providedClass->isSubClassOf(acceptedClass))
							{
								setValue(managedComponent, true);
							}
						}
					}
				}
			}
		}
	}
Esempio n. 25
0
	void CBone::updateParentAnimation()
	{
		HSceneObject currentSO = SO();
		while (currentSO != nullptr)
		{
			HAnimation parent = currentSO->getComponent<CAnimation>();
			if (parent != nullptr)
			{
				if (currentSO->getActive())
					_setParent(parent);
				else
					_setParent(HAnimation());

				return;
			}

			currentSO = currentSO->getParent();
		}

		_setParent(HAnimation());
	}
	ScriptSerializedSceneObject::ScriptSerializedSceneObject(MonoObject* instance, const HSceneObject& so, bool recordHierarchy)
		: ScriptObject(instance), mSO(so), mRecordHierarchy(recordHierarchy), mSerializedObject(nullptr), mSerializedObjectSize(0)
	{
		if (mSO.isDestroyed())
			return;

		UINT32 numChildren = mSO->getNumChildren();
		HSceneObject* children = nullptr;

		if (!mRecordHierarchy)
		{
			children = bs_stack_new<HSceneObject>(numChildren);
			for (UINT32 i = 0; i < numChildren; i++)
			{
				HSceneObject child = mSO->getChild(i);
				children[i] = child;

				child->setParent(HSceneObject());
			}
		}

		bool isInstantiated = !mSO->hasFlag(SOF_DontInstantiate);
		mSO->_setFlags(SOF_DontInstantiate);

		MemorySerializer serializer;
		mSerializedObject = serializer.encode(mSO.get(), mSerializedObjectSize);

		if (isInstantiated)
			mSO->_unsetFlags(SOF_DontInstantiate);

		mSceneObjectProxy = EditorUtility::createProxy(mSO);

		if (!mRecordHierarchy)
		{
			for (UINT32 i = 0; i < numChildren; i++)
				children[i]->setParent(mSO->getHandle());

			bs_stack_delete(children, numChildren);
		}
	}
Esempio n. 27
0
	void Prefab::_updateChildInstances()
	{
		Stack<HSceneObject> todo;
		todo.push(mRoot);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			UINT32 childCount = current->getNumChildren();
			for (UINT32 i = 0; i < childCount; i++)
			{
				HSceneObject child = current->getChild(i);

				if (!child->mPrefabLinkUUID.empty())
					PrefabUtility::updateFromPrefab(child);
				else
					todo.push(child);
			}
		}
	}
Esempio n. 28
0
	void PrefabUtility::revertToPrefab(const HSceneObject& so)
	{
		String prefabLinkUUID = so->getPrefabLink();
		HPrefab prefabLink = static_resource_cast<Prefab>(gResources().loadFromUUID(prefabLinkUUID, false, false));

		if (prefabLink == nullptr)
			return;

		// Save IDs, destroy original, create new, restore IDs
		SceneObjectProxy soProxy;
		UnorderedMap<UINT32, GameObjectInstanceDataPtr> linkedInstanceData;
		recordInstanceData(so, soProxy, linkedInstanceData);

		HSceneObject parent = so->getParent();

		// This will destroy the object but keep it in the parent's child list
		HSceneObject currentSO = so;
		so->destroyInternal(currentSO, true);

		HSceneObject newInstance = prefabLink->instantiate();
		newInstance->mParent = parent;

		restoreLinkedInstanceData(newInstance, soProxy, linkedInstanceData);
	}
Esempio n. 29
0
	void CmdRecordSO::recordSO(const HSceneObject& sceneObject)
	{
		UINT32 numChildren = mSceneObject->getNumChildren();
		HSceneObject* children = nullptr;

		if (!mRecordHierarchy)
		{
			children = bs_stack_new<HSceneObject>(numChildren);
			for (UINT32 i = 0; i < numChildren; i++)
			{
				HSceneObject child = mSceneObject->getChild(i);
				children[i] = child;

				child->setParent(HSceneObject());
			}
		}

		bool isInstantiated = !mSceneObject->hasFlag(SOF_DontInstantiate);
		mSceneObject->_setFlags(SOF_DontInstantiate);

		MemorySerializer serializer;
		mSerializedObject = serializer.encode(mSceneObject.get(), mSerializedObjectSize);

		if (isInstantiated)
			mSceneObject->_unsetFlags(SOF_DontInstantiate);

		mSceneObjectProxy = EditorUtility::createProxy(mSceneObject);

		if (!mRecordHierarchy)
		{
			for (UINT32 i = 0; i < numChildren; i++)
				children[i]->setParent(sceneObject->getHandle());

			bs_stack_delete(children, numChildren);
		}
	}
Esempio n. 30
0
	void PrefabUtility::restoreLinkedInstanceData(const HSceneObject& so, SceneObjectProxy& proxy, 
		UnorderedMap<UINT32, GameObjectInstanceDataPtr>& linkedInstanceData)
	{
		Stack<HSceneObject> todo;
		todo.push(so);

		// Root is not in the instance data map because its link ID belongs to the parent prefab, if any
		so->_setInstanceData(proxy.instanceData);

		while (!todo.empty())
		{
			HSceneObject current = todo.top();
			todo.pop();

			Vector<HComponent>& components = current->mComponents;
			for (auto& component : components)
			{
				if (component->getLinkId() != (UINT32)-1)
				{
					auto iterFind = linkedInstanceData.find(component->getLinkId());
					if (iterFind != linkedInstanceData.end())
					{
						component->_setInstanceData(iterFind->second);
						component._setHandleData(component.getInternalPtr());
					}
				}
			}

			UINT32 numChildren = current->getNumChildren();
			for (UINT32 i = 0; i < numChildren; i++)
			{
				HSceneObject child = current->getChild(i);

				if (child->getLinkId() != (UINT32)-1)
				{
					auto iterFind = linkedInstanceData.find(child->getLinkId());
					if (iterFind != linkedInstanceData.end())
						child->_setInstanceData(iterFind->second);
				}

				if (child->mPrefabLinkUUID.empty())
					todo.push(child);
			}
		}
	}