BsCmdRecordSO.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. clear();
  14. }
  15. void CmdRecordSO::clear()
  16. {
  17. mSceneObject = nullptr;
  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. MemorySerializer serializer;
  39. mSerializedObject = serializer.encode(mSceneObject.get(), mSerializedObjectSize, &bs_alloc);
  40. HSceneObject parent = mSceneObject->getParent();
  41. if (parent != nullptr)
  42. mSerializedObjectParentId = parent->getInstanceId();
  43. mSceneObjectProxy = createProxy(mSceneObject);
  44. }
  45. void CmdRecordSO::revert()
  46. {
  47. if (mSceneObject == nullptr)
  48. return;
  49. HSceneObject parent;
  50. if (mSerializedObjectParentId != 0)
  51. parent = GameObjectManager::instance().getObject(mSerializedObjectParentId);
  52. GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds);
  53. if (!mSceneObject.isDestroyed())
  54. mSceneObject->destroy();
  55. MemorySerializer serializer;
  56. std::shared_ptr<SceneObject> restored = std::static_pointer_cast<SceneObject>(serializer.decode(mSerializedObject, mSerializedObjectSize));
  57. restoreIds(restored->getHandle());
  58. }
  59. CmdRecordSO::SceneObjProxy CmdRecordSO::createProxy(const HSceneObject& sceneObject)
  60. {
  61. struct TempData
  62. {
  63. TempData(SceneObjProxy& proxy, const HSceneObject& so)
  64. :proxy(proxy), obj(so)
  65. { }
  66. SceneObjProxy& proxy;
  67. HSceneObject obj;
  68. };
  69. SceneObjProxy rootProxy;
  70. Stack<TempData> todo;
  71. todo.push(TempData(rootProxy, sceneObject));
  72. while (!todo.empty())
  73. {
  74. TempData data = todo.top();
  75. todo.pop();
  76. data.proxy.instanceData = data.obj->_getInstanceData();
  77. const Vector<HComponent>& components = data.obj->getComponents();
  78. for (auto& component : components)
  79. data.proxy.componentInstanceData.push_back(component->_getInstanceData());
  80. UINT32 numChildren = data.obj->getNumChildren();
  81. data.proxy.children.resize(numChildren);
  82. for (UINT32 i = 0; i < numChildren; i++)
  83. {
  84. todo.push(TempData(data.proxy.children[i], data.obj->getChild(i)));
  85. }
  86. }
  87. return rootProxy;
  88. }
  89. void CmdRecordSO::restoreIds(const HSceneObject& restored)
  90. {
  91. // Note: This method relies that all restored GameObject handles pointing to the
  92. // same object also have the same shared handle data (Since I only update instance
  93. // data on a single handle I know exists, and expect all others will be updated
  94. // by that as well).
  95. struct TempData
  96. {
  97. TempData(SceneObjProxy& proxy, const HSceneObject& restoredObj)
  98. :proxy(proxy), restoredObj(restoredObj)
  99. { }
  100. SceneObjProxy& proxy;
  101. HSceneObject restoredObj;
  102. };
  103. Stack<TempData> todo;
  104. todo.push(TempData(mSceneObjectProxy, restored));
  105. while (!todo.empty())
  106. {
  107. TempData data = todo.top();
  108. todo.pop();
  109. data.restoredObj->_setInstanceData(data.proxy.instanceData);
  110. // Find components that are still active and swap the old ones with restored ones,
  111. // keep any other as is.
  112. const Vector<HComponent>& restoredComponents = data.restoredObj->getComponents();
  113. UINT32 idx = 0;
  114. for (auto& restoredComponent : restoredComponents)
  115. {
  116. restoredComponent->_setInstanceData(data.proxy.componentInstanceData[idx]);
  117. GameObjectPtr restoredPtr = std::static_pointer_cast<GameObject>(restoredComponent.getInternalPtr());
  118. HComponent restoredComponentCopy = restoredComponent; // To remove const
  119. restoredComponentCopy._setHandleData(restoredPtr);
  120. idx++;
  121. }
  122. // Find children that are still active and swap the old ones with restored ones,
  123. // keep any other as is
  124. UINT32 restoredNumChildren = data.restoredObj->getNumChildren();
  125. for (UINT32 i = 0; i < restoredNumChildren; i++)
  126. {
  127. todo.push(TempData(data.proxy.children[i], data.restoredObj->getChild(i)));
  128. }
  129. }
  130. }
  131. }