| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- #include "BsCmdRecordSO.h"
- #include "BsSceneObject.h"
- #include "BsComponent.h"
- #include "BsMemorySerializer.h"
- namespace BansheeEngine
- {
- CmdRecordSO::CmdRecordSO(const HSceneObject& sceneObject)
- :mSceneObject(sceneObject), mSerializedObject(nullptr), mSerializedObjectParentId(0), mSerializedObjectSize(0)
- {
- }
- CmdRecordSO::~CmdRecordSO()
- {
- clear();
- }
- void CmdRecordSO::clear()
- {
- mSceneObject = nullptr;
- mSerializedObjectSize = 0;
- mSerializedObjectParentId = 0;
- if (mSerializedObject != nullptr)
- {
- bs_free(mSerializedObject);
- mSerializedObject = nullptr;
- }
- }
- void CmdRecordSO::execute(const HSceneObject& sceneObject)
- {
- // Register command and commit it
- CmdRecordSO* command = new (bs_alloc<CmdRecordSO>()) CmdRecordSO(sceneObject);
- UndoRedo::instance().registerCommand(command);
- command->commit();
- }
- void CmdRecordSO::commit()
- {
- clear();
- if (mSceneObject == nullptr || mSceneObject.isDestroyed())
- return;
- MemorySerializer serializer;
- mSerializedObject = serializer.encode(mSceneObject.get(), mSerializedObjectSize, &bs_alloc);
- HSceneObject parent = mSceneObject->getParent();
- if (parent != nullptr)
- mSerializedObjectParentId = parent->getInstanceId();
- mSceneObjectProxy = createProxy(mSceneObject);
- }
- void CmdRecordSO::revert()
- {
- if (mSceneObject == nullptr)
- return;
- HSceneObject parent;
- if (mSerializedObjectParentId != 0)
- parent = GameObjectManager::instance().getObject(mSerializedObjectParentId);
- GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds);
- if (!mSceneObject.isDestroyed())
- mSceneObject->destroy();
- MemorySerializer serializer;
- std::shared_ptr<SceneObject> restored = std::static_pointer_cast<SceneObject>(serializer.decode(mSerializedObject, mSerializedObjectSize));
- restoreIds(restored->getHandle());
- }
- CmdRecordSO::SceneObjProxy CmdRecordSO::createProxy(const HSceneObject& sceneObject)
- {
- struct TempData
- {
- TempData(SceneObjProxy& proxy, const HSceneObject& so)
- :proxy(proxy), obj(so)
- { }
- SceneObjProxy& proxy;
- HSceneObject obj;
- };
- SceneObjProxy rootProxy;
- Stack<TempData> todo;
- todo.push(TempData(rootProxy, sceneObject));
- while (!todo.empty())
- {
- TempData data = todo.top();
- todo.pop();
- data.proxy.instanceData = data.obj->_getInstanceData();
- const Vector<HComponent>& components = data.obj->getComponents();
- for (auto& component : components)
- data.proxy.componentInstanceData.push_back(component->_getInstanceData());
- UINT32 numChildren = data.obj->getNumChildren();
- data.proxy.children.resize(numChildren);
- for (UINT32 i = 0; i < numChildren; i++)
- {
- todo.push(TempData(data.proxy.children[i], data.obj->getChild(i)));
- }
- }
- return rootProxy;
- }
- void CmdRecordSO::restoreIds(const HSceneObject& restored)
- {
- // Note: This method relies that all restored GameObject handles pointing to the
- // same object also have the same shared handle data (Since I only update instance
- // data on a single handle I know exists, and expect all others will be updated
- // by that as well).
- struct TempData
- {
- TempData(SceneObjProxy& proxy, const HSceneObject& restoredObj)
- :proxy(proxy), restoredObj(restoredObj)
- { }
- SceneObjProxy& proxy;
- HSceneObject restoredObj;
- };
- Stack<TempData> todo;
- todo.push(TempData(mSceneObjectProxy, restored));
- while (!todo.empty())
- {
- TempData data = todo.top();
- todo.pop();
- data.restoredObj->_setInstanceData(data.proxy.instanceData);
- // Find components that are still active and swap the old ones with restored ones,
- // keep any other as is.
- const Vector<HComponent>& restoredComponents = data.restoredObj->getComponents();
- UINT32 idx = 0;
- for (auto& restoredComponent : restoredComponents)
- {
- restoredComponent->_setInstanceData(data.proxy.componentInstanceData[idx]);
- GameObjectPtr restoredPtr = std::static_pointer_cast<GameObject>(restoredComponent.getInternalPtr());
- HComponent restoredComponentCopy = restoredComponent; // To remove const
- restoredComponentCopy._setHandleData(restoredPtr);
- idx++;
- }
-
- // Find children that are still active and swap the old ones with restored ones,
- // keep any other as is
- UINT32 restoredNumChildren = data.restoredObj->getNumChildren();
- for (UINT32 i = 0; i < restoredNumChildren; i++)
- {
- todo.push(TempData(data.proxy.children[i], data.restoredObj->getChild(i)));
- }
- }
- }
- }
|