BsCmdRecordSO.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #include "BsCmdRecordSO.h"
  2. #include "BsSceneObject.h"
  3. #include "BsComponent.h"
  4. #include "BsMemorySerializer.h"
  5. namespace BansheeEngine
  6. {
  7. CmdRecordSO::CmdRecordSO(const HSceneObject& sceneObject)
  8. :mSceneObject(sceneObject), mSerializedObject(nullptr), mSerializedObjectParentId(0), mSerializedObjectSize(0)
  9. {
  10. }
  11. CmdRecordSO::~CmdRecordSO()
  12. {
  13. mSceneObject = nullptr;
  14. clear();
  15. }
  16. void CmdRecordSO::clear()
  17. {
  18. mSerializedObjectSize = 0;
  19. mSerializedObjectParentId = 0;
  20. if (mSerializedObject != nullptr)
  21. {
  22. bs_free(mSerializedObject);
  23. mSerializedObject = nullptr;
  24. }
  25. }
  26. void CmdRecordSO::execute(const HSceneObject& sceneObject)
  27. {
  28. // Register command and commit it
  29. CmdRecordSO* command = new (bs_alloc<CmdRecordSO>()) CmdRecordSO(sceneObject);
  30. UndoRedo::instance().registerCommand(command);
  31. command->commit();
  32. }
  33. void CmdRecordSO::commit()
  34. {
  35. clear();
  36. if (mSceneObject == nullptr || mSceneObject.isDestroyed())
  37. return;
  38. recordSO(mSceneObject);
  39. }
  40. void CmdRecordSO::revert()
  41. {
  42. if (mSceneObject == nullptr)
  43. return;
  44. HSceneObject parent;
  45. if (mSerializedObjectParentId != 0)
  46. parent = GameObjectManager::instance().getObject(mSerializedObjectParentId);
  47. GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds);
  48. if (!mSceneObject.isDestroyed())
  49. mSceneObject->destroy();
  50. MemorySerializer serializer;
  51. std::shared_ptr<SceneObject> restored = std::static_pointer_cast<SceneObject>(serializer.decode(mSerializedObject, mSerializedObjectSize));
  52. restoreIds(restored->getHandle());
  53. restored->setParent(parent);
  54. }
  55. void CmdRecordSO::recordSO(const HSceneObject& sceneObject)
  56. {
  57. MemorySerializer serializer;
  58. mSerializedObject = serializer.encode(mSceneObject.get(), mSerializedObjectSize, &bs_alloc);
  59. HSceneObject parent = mSceneObject->getParent();
  60. if (parent != nullptr)
  61. mSerializedObjectParentId = parent->getInstanceId();
  62. mSceneObjectProxy = createProxy(mSceneObject);
  63. }
  64. CmdRecordSO::SceneObjProxy CmdRecordSO::createProxy(const HSceneObject& sceneObject)
  65. {
  66. struct TempData
  67. {
  68. TempData(SceneObjProxy& proxy, const HSceneObject& so)
  69. :proxy(proxy), obj(so)
  70. { }
  71. SceneObjProxy& proxy;
  72. HSceneObject obj;
  73. };
  74. SceneObjProxy rootProxy;
  75. Stack<TempData> todo;
  76. todo.push(TempData(rootProxy, sceneObject));
  77. while (!todo.empty())
  78. {
  79. TempData data = todo.top();
  80. todo.pop();
  81. data.proxy.instanceData = data.obj->_getInstanceData();
  82. const Vector<HComponent>& components = data.obj->getComponents();
  83. for (auto& component : components)
  84. data.proxy.componentInstanceData.push_back(component->_getInstanceData());
  85. UINT32 numChildren = data.obj->getNumChildren();
  86. data.proxy.children.resize(numChildren);
  87. for (UINT32 i = 0; i < numChildren; i++)
  88. {
  89. todo.push(TempData(data.proxy.children[i], data.obj->getChild(i)));
  90. }
  91. }
  92. return rootProxy;
  93. }
  94. void CmdRecordSO::restoreIds(const HSceneObject& restored)
  95. {
  96. // Note: This method relies that all restored GameObject handles pointing to the
  97. // same object also have the same shared handle data (Since I only update instance
  98. // data on a single handle I know exists, and expect all others will be updated
  99. // by that as well).
  100. struct TempData
  101. {
  102. TempData(SceneObjProxy& proxy, const HSceneObject& restoredObj)
  103. :proxy(proxy), restoredObj(restoredObj)
  104. { }
  105. SceneObjProxy& proxy;
  106. HSceneObject restoredObj;
  107. };
  108. Stack<TempData> todo;
  109. todo.push(TempData(mSceneObjectProxy, restored));
  110. while (!todo.empty())
  111. {
  112. TempData data = todo.top();
  113. todo.pop();
  114. data.restoredObj->_setInstanceData(data.proxy.instanceData);
  115. // Find components that are still active and swap the old ones with restored ones,
  116. // keep any other as is.
  117. const Vector<HComponent>& restoredComponents = data.restoredObj->getComponents();
  118. UINT32 idx = 0;
  119. for (auto& restoredComponent : restoredComponents)
  120. {
  121. restoredComponent->_setInstanceData(data.proxy.componentInstanceData[idx]);
  122. GameObjectPtr restoredPtr = std::static_pointer_cast<GameObject>(restoredComponent.getInternalPtr());
  123. HComponent restoredComponentCopy = restoredComponent; // To remove const
  124. restoredComponentCopy._setHandleData(restoredPtr);
  125. idx++;
  126. }
  127. // Find children that are still active and swap the old ones with restored ones,
  128. // keep any other as is
  129. UINT32 restoredNumChildren = data.restoredObj->getNumChildren();
  130. for (UINT32 i = 0; i < restoredNumChildren; i++)
  131. {
  132. todo.push(TempData(data.proxy.children[i], data.restoredObj->getChild(i)));
  133. }
  134. }
  135. }
  136. }