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()); }
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 ScriptSerializedSceneObject::internal_Restore(ScriptSerializedSceneObject* thisPtr) { HSceneObject sceneObj = thisPtr->mSO; if (sceneObj.isDestroyed()) return; HSceneObject parent = sceneObj->getParent(); UINT32 numChildren = sceneObj->getNumChildren(); HSceneObject* children = nullptr; if (!thisPtr->mRecordHierarchy) { children = bs_stack_new<HSceneObject>(numChildren); for (UINT32 i = 0; i < numChildren; i++) { HSceneObject child = sceneObj->getChild(i); children[i] = child; child->setParent(HSceneObject()); } } sceneObj->destroy(true); GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds); MemorySerializer serializer; SPtr<SceneObject> restored = std::static_pointer_cast<SceneObject>( serializer.decode(thisPtr->mSerializedObject, thisPtr->mSerializedObjectSize)); EditorUtility::restoreIds(restored->getHandle(), thisPtr->mSceneObjectProxy); restored->setParent(parent); if (!thisPtr->mRecordHierarchy) { for (UINT32 i = 0; i < numChildren; i++) children[i]->setParent(restored->getHandle()); bs_stack_delete(children, numChildren); } restored->_instantiate(); }
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()); }
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); }
void PrefabUtility::updateFromPrefab(const HSceneObject& so) { HSceneObject topLevelObject = so; while (topLevelObject != nullptr) { if (!topLevelObject->mPrefabLinkUUID.empty()) break; if (topLevelObject->mParent != nullptr) topLevelObject = topLevelObject->mParent; else topLevelObject = nullptr; } Stack<HSceneObject> todo; todo.push(topLevelObject); // Find any prefab instances Vector<HSceneObject> prefabInstanceRoots; while (!todo.empty()) { HSceneObject current = todo.top(); todo.pop(); if (!current->mPrefabLinkUUID.empty()) prefabInstanceRoots.push_back(current); UINT32 childCount = current->getNumChildren(); for (UINT32 i = 0; i < childCount; i++) { HSceneObject child = current->getChild(i); todo.push(child); } } // Stores data about the new prefab instance and its original parent and link id // (as those aren't stored in the prefab diff) struct RestoredPrefabInstance { HSceneObject newInstance; HSceneObject originalParent; SPtr<PrefabDiff> diff; UINT32 originalLinkId; }; Vector<RestoredPrefabInstance> newPrefabInstanceData; // For each prefab instance load its reference prefab from the disk and check if it changed. If it has changed // instantiate the prefab and destroy the current instance. Then apply instance specific changes stored in a // prefab diff, if any, as well as restore the original parent and link id (link id of the root prefab instance // belongs to the parent prefab if any). Finally fix any handles pointing to the old objects so that they now point // to the newly instantiated objects. To the outside world it should be transparent that we just destroyed and then // re-created from scratch the entire hierarchy. // Need to do this bottom up to ensure I don't destroy the parents before children for (auto iter = prefabInstanceRoots.rbegin(); iter != prefabInstanceRoots.rend(); ++iter) { HSceneObject current = *iter; HPrefab prefabLink = static_resource_cast<Prefab>(gResources().loadFromUUID(current->mPrefabLinkUUID, false, false)); if (prefabLink.isLoaded(false) && prefabLink->getHash() != current->mPrefabHash) { // Save IDs, destroy original, create new, restore IDs SceneObjectProxy soProxy; UnorderedMap<UINT32, GameObjectInstanceDataPtr> linkedInstanceData; recordInstanceData(current, soProxy, linkedInstanceData); HSceneObject parent = current->getParent(); SPtr<PrefabDiff> prefabDiff = current->mPrefabDiff; current->destroy(true); HSceneObject newInstance = prefabLink->_clone(); // When restoring instance IDs it is important to make all the new handles point to the old GameObjectInstanceData. // This is because old handles will have different GameObjectHandleData and we have no easy way of accessing it to // change to which GameObjectInstanceData it points. But the GameObjectManager ensures that all handles deserialized // at once (i.e. during the ::instantiate() call above) will share GameObjectHandleData so we can simply replace // to what they point to, affecting all of the handles to that object. (In another words, we can modify the // new handles at this point, but old ones must keep referencing what they already were.) restoreLinkedInstanceData(newInstance, soProxy, linkedInstanceData); restoreUnlinkedInstanceData(newInstance, soProxy); newPrefabInstanceData.push_back({ newInstance, parent, prefabDiff, newInstance->getLinkId() }); } } // Once everything is instantiated, apply diffs, restore old parents & link IDs for root. for (auto& entry : newPrefabInstanceData) { // Diffs must be applied after everything is instantiated and instance data restored since it may contain // game object handles within or external to its prefab instance. if (entry.diff != nullptr) entry.diff->apply(entry.newInstance); entry.newInstance->mPrefabDiff = entry.diff; entry.newInstance->setParent(entry.originalParent, false); entry.newInstance->mLinkId = entry.originalLinkId; } gResources().unloadAllUnused(); }
void CmdBreakPrefab::commit() { clear(); if (mSceneObject == nullptr || mSceneObject.isDestroyed()) return; HSceneObject rootObj = mSceneObject; while (rootObj != nullptr) { if (!rootObj->_getPrefabLinkUUID().empty()) break; if (rootObj->getParent() != nullptr) rootObj = rootObj->getParent(); else rootObj = nullptr; } if (rootObj != nullptr) { mPrefabRoot = rootObj; mPrefabLinkUUID = rootObj->_getPrefabLinkUUID(); mPrefabDiff = rootObj->_getPrefabDiff(); Stack<HSceneObject> todo; todo.push(mPrefabRoot); while (!todo.empty()) { HSceneObject currentSO = todo.top(); todo.pop(); const Vector<HComponent>& components = currentSO->getComponents(); for (auto& component : components) { UINT32 linkId = component->getLinkId(); if (linkId != (UINT32)-1) mLinkIds[component->getInstanceId()] = linkId; mLinkIds[component->getInstanceId()] = component->getLinkId(); } UINT32 numChildren = (UINT32)currentSO->getNumChildren(); for (UINT32 i = 0; i < numChildren; i++) { HSceneObject child = currentSO->getChild(i); UINT32 linkId = child->getLinkId(); if (linkId != (UINT32)-1) mLinkIds[child->getInstanceId()] = linkId; if (child->_getPrefabLinkUUID().empty()) todo.push(child); } } } mSceneObject->breakPrefabLink(); }