BsPrefabDiff.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #include "BsPrefabDiff.h"
  2. #include "BsPrefabDiffRTTI.h"
  3. #include "BsSceneObject.h"
  4. #include "BsMemorySerializer.h"
  5. #include "BsBinarySerializer.h"
  6. #include "BsBinaryDiff.h"
  7. namespace BansheeEngine
  8. {
  9. RTTITypeBase* PrefabComponentDiff::getRTTIStatic()
  10. {
  11. return PrefabComponentDiffRTTI::instance();
  12. }
  13. RTTITypeBase* PrefabComponentDiff::getRTTI() const
  14. {
  15. return PrefabComponentDiff::getRTTIStatic();
  16. }
  17. RTTITypeBase* PrefabObjectDiff::getRTTIStatic()
  18. {
  19. return PrefabObjectDiffRTTI::instance();
  20. }
  21. RTTITypeBase* PrefabObjectDiff::getRTTI() const
  22. {
  23. return PrefabObjectDiff::getRTTIStatic();
  24. }
  25. SPtr<PrefabDiff> PrefabDiff::create(const HSceneObject& prefab, const HSceneObject& instance)
  26. {
  27. if (prefab->getPrefabLink() != instance->getPrefabLink() || prefab->getLinkId() != instance->getLinkId())
  28. return nullptr;
  29. SPtr<PrefabDiff> output = bs_shared_ptr<PrefabDiff>();
  30. output->mRoot = generateDiff(prefab, instance);
  31. return output;
  32. }
  33. void PrefabDiff::apply(const HSceneObject& object)
  34. {
  35. if (mRoot == nullptr)
  36. return;
  37. applyDiff(mRoot, object);
  38. }
  39. void PrefabDiff::applyDiff(const SPtr<PrefabObjectDiff>& diff, const HSceneObject& object)
  40. {
  41. if (diff->id != object->getLinkId())
  42. return;
  43. object->setName(diff->name);
  44. const Vector<HComponent>& components = object->getComponents();
  45. for (auto& removedId : diff->removedComponents)
  46. {
  47. for (auto& component : components)
  48. {
  49. if (removedId == component->getLinkId())
  50. {
  51. component->destroy();
  52. break;
  53. }
  54. }
  55. }
  56. UINT32 childCount = object->getNumChildren();
  57. for (auto& removedId : diff->removedChildren)
  58. {
  59. for (UINT32 i = 0; i < childCount; i++)
  60. {
  61. HSceneObject child = object->getChild(i);
  62. if (removedId == child->getLinkId())
  63. {
  64. child->destroy();
  65. break;
  66. }
  67. }
  68. }
  69. for (auto& addedComponentData : diff->addedComponents)
  70. {
  71. BinarySerializer bs;
  72. SPtr<Component> component = std::static_pointer_cast<Component>(bs._decodeIntermediate(addedComponentData));
  73. object->addComponentInternal(component);
  74. }
  75. for (auto& addedChildData : diff->addedChildren)
  76. {
  77. BinarySerializer bs;
  78. SPtr<SceneObject> sceneObject = std::static_pointer_cast<SceneObject>(bs._decodeIntermediate(addedChildData));
  79. sceneObject->setParent(object);
  80. }
  81. for (auto& componentDiff : diff->componentDiffs)
  82. {
  83. for (auto& component : components)
  84. {
  85. if (componentDiff->id == component->getLinkId())
  86. {
  87. IDiff& diffHandler = component->getRTTI()->getDiffHandler();
  88. diffHandler.applyDiff(component.getInternalPtr(), componentDiff->data);
  89. break;
  90. }
  91. }
  92. }
  93. for (auto& childDiff : diff->childDiffs)
  94. {
  95. for (UINT32 i = 0; i < childCount; i++)
  96. {
  97. HSceneObject child = object->getChild(i);
  98. if (childDiff->id == child->getLinkId())
  99. {
  100. applyDiff(childDiff, child);
  101. break;
  102. }
  103. }
  104. }
  105. }
  106. SPtr<PrefabObjectDiff> PrefabDiff::generateDiff(const HSceneObject& prefab, const HSceneObject& instance)
  107. {
  108. SPtr<PrefabObjectDiff> output;
  109. if (prefab->getName() != instance->getName())
  110. {
  111. if (output == nullptr)
  112. output = bs_shared_ptr<PrefabObjectDiff>();
  113. }
  114. UINT32 prefabChildCount = prefab->getNumChildren();
  115. UINT32 instanceChildCount = instance->getNumChildren();
  116. // Find modified and removed children
  117. for (UINT32 i = 0; i < prefabChildCount; i++)
  118. {
  119. HSceneObject prefabChild = prefab->getChild(i);
  120. SPtr<PrefabObjectDiff> childDiff;
  121. bool foundMatching = false;
  122. for (UINT32 j = 0; j < instanceChildCount; j++)
  123. {
  124. HSceneObject instanceChild = instance->getChild(j);
  125. if (prefabChild->getLinkId() == instanceChild->getLinkId())
  126. {
  127. childDiff = generateDiff(prefabChild, instanceChild);
  128. foundMatching = true;
  129. break;
  130. }
  131. }
  132. if (foundMatching)
  133. {
  134. if (childDiff != nullptr)
  135. {
  136. if (output == nullptr)
  137. output = bs_shared_ptr<PrefabObjectDiff>();
  138. output->childDiffs.push_back(childDiff);
  139. }
  140. }
  141. else
  142. {
  143. if (output == nullptr)
  144. output = bs_shared_ptr<PrefabObjectDiff>();
  145. output->removedChildren.push_back(prefabChild->getLinkId());
  146. }
  147. }
  148. // Find added children
  149. for (UINT32 i = 0; i < instanceChildCount; i++)
  150. {
  151. HSceneObject instanceChild = instance->getChild(i);
  152. bool foundMatching = false;
  153. if (instanceChild->getLinkId() != -1)
  154. {
  155. for (UINT32 j = 0; j < prefabChildCount; j++)
  156. {
  157. HSceneObject prefabChild = prefab->getChild(j);
  158. if (prefabChild->getLinkId() == instanceChild->getLinkId())
  159. {
  160. foundMatching = true;
  161. break;
  162. }
  163. }
  164. }
  165. if (!foundMatching)
  166. {
  167. BinarySerializer bs;
  168. SPtr<SerializedObject> obj = bs._encodeIntermediate(instanceChild.get());
  169. if (output == nullptr)
  170. output = bs_shared_ptr<PrefabObjectDiff>();
  171. output->addedChildren.push_back(obj);
  172. }
  173. }
  174. const Vector<HComponent>& prefabComponents = prefab->getComponents();
  175. const Vector<HComponent>& instanceComponents = instance->getComponents();
  176. UINT32 prefabComponentCount = (UINT32)prefabComponents.size();
  177. UINT32 instanceComponentCount = (UINT32)instanceComponents.size();
  178. // Find modified and removed components
  179. for (UINT32 i = 0; i < prefabComponentCount; i++)
  180. {
  181. HComponent prefabComponent = prefabComponents[i];
  182. SPtr<PrefabComponentDiff> childDiff;
  183. bool foundMatching = false;
  184. for (UINT32 j = 0; j < instanceComponentCount; j++)
  185. {
  186. HComponent instanceComponent = instanceComponents[j];
  187. if (prefabComponent->getLinkId() == instanceComponent->getLinkId())
  188. {
  189. BinarySerializer bs;
  190. SPtr<SerializedObject> encodedPrefab = bs._encodeIntermediate(prefabComponent.get());
  191. SPtr<SerializedObject> encodedInstance = bs._encodeIntermediate(instanceComponent.get());
  192. IDiff& diffHandler = prefabComponent->getRTTI()->getDiffHandler();
  193. SPtr<SerializedObject> diff = diffHandler.generateDiff(encodedPrefab, encodedInstance);
  194. if (diff != nullptr)
  195. {
  196. childDiff = bs_shared_ptr<PrefabComponentDiff>();
  197. childDiff->id = prefabComponent->getLinkId();
  198. childDiff->data = diff;
  199. }
  200. foundMatching = true;
  201. break;
  202. }
  203. }
  204. if (foundMatching)
  205. {
  206. if (childDiff != nullptr)
  207. {
  208. if (output == nullptr)
  209. output = bs_shared_ptr<PrefabObjectDiff>();
  210. output->componentDiffs.push_back(childDiff);
  211. }
  212. }
  213. else
  214. {
  215. if (output == nullptr)
  216. output = bs_shared_ptr<PrefabObjectDiff>();
  217. output->removedComponents.push_back(prefabComponent->getLinkId());
  218. }
  219. }
  220. // Find added components
  221. for (UINT32 i = 0; i < instanceComponentCount; i++)
  222. {
  223. HComponent instanceComponent = instanceComponents[i];
  224. bool foundMatching = false;
  225. if (instanceComponent->getLinkId() != -1)
  226. {
  227. for (UINT32 j = 0; j < prefabChildCount; j++)
  228. {
  229. HComponent prefabComponent = prefabComponents[j];
  230. if (prefabComponent->getLinkId() == instanceComponent->getLinkId())
  231. {
  232. foundMatching = true;
  233. break;
  234. }
  235. }
  236. }
  237. if (!foundMatching)
  238. {
  239. BinarySerializer bs;
  240. SPtr<SerializedObject> obj = bs._encodeIntermediate(instanceComponent.get());
  241. if (output == nullptr)
  242. output = bs_shared_ptr<PrefabObjectDiff>();
  243. output->addedChildren.push_back(obj);
  244. }
  245. }
  246. if (output != nullptr)
  247. {
  248. output->name = instance->getName();
  249. output->id = instance->getLinkId();
  250. }
  251. return output;
  252. }
  253. RTTITypeBase* PrefabDiff::getRTTIStatic()
  254. {
  255. return PrefabDiffRTTI::instance();
  256. }
  257. RTTITypeBase* PrefabDiff::getRTTI() const
  258. {
  259. return PrefabDiff::getRTTIStatic();
  260. }
  261. }