BsScriptObjectManager.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsScriptObjectManager.h"
  4. #include "BsScriptObject.h"
  5. #include "BsMonoManager.h"
  6. #include "Serialization/BsScriptAssemblyManager.h"
  7. #include "Scene/BsGameObjectManager.h"
  8. #include "BsMonoAssembly.h"
  9. namespace bs
  10. {
  11. ScriptObjectManager::ScriptObjectManager()
  12. :mFinalizedQueueIdx(0)
  13. {
  14. }
  15. ScriptObjectManager::~ScriptObjectManager()
  16. {
  17. processFinalizedObjects();
  18. }
  19. void ScriptObjectManager::registerScriptObject(ScriptObjectBase* instance)
  20. {
  21. mScriptObjects.insert(instance);
  22. }
  23. void ScriptObjectManager::unregisterScriptObject(ScriptObjectBase* instance)
  24. {
  25. mScriptObjects.erase(instance);
  26. }
  27. void ScriptObjectManager::refreshAssemblies(const Vector<std::pair<String, Path>>& assemblies)
  28. {
  29. Map<ScriptObjectBase*, ScriptObjectBackup> backupData;
  30. onRefreshStarted();
  31. // Make sure any managed game objects are properly destroyed so their OnDestroy callbacks fire before unloading the domain
  32. GameObjectManager::instance().destroyQueuedObjects();
  33. // Make sure all objects that are finalized due to reasons other than assembly refreshed are destroyed
  34. processFinalizedObjects(false);
  35. for (auto& scriptObject : mScriptObjects)
  36. backupData[scriptObject] = scriptObject->beginRefresh();
  37. for (auto& scriptObject : mScriptObjects)
  38. scriptObject->_clearManagedInstance();
  39. MonoManager::instance().unloadScriptDomain();
  40. // Unload script domain should trigger finalizers on everything, but since we usually delay
  41. // their processing we need to manually trigger it here.
  42. processFinalizedObjects(true);
  43. for (auto& scriptObject : mScriptObjects)
  44. assert(scriptObject->isPersistent() && "Non-persistent ScriptObject alive after domain unload.");
  45. ScriptAssemblyManager::instance().clearAssemblyInfo();
  46. for (auto& assemblyPair : assemblies)
  47. {
  48. MonoManager::instance().loadAssembly(assemblyPair.second.toWString(), assemblyPair.first);
  49. ScriptAssemblyManager::instance().loadAssemblyInfo(assemblyPair.first);
  50. }
  51. Vector<ScriptObjectBase*> scriptObjCopy(mScriptObjects.size()); // Store originals as we could add new objects during the next iteration
  52. UINT32 idx = 0;
  53. for (auto& scriptObject : mScriptObjects)
  54. scriptObjCopy[idx++] = scriptObject;
  55. onRefreshDomainLoaded();
  56. for (auto& scriptObject : scriptObjCopy)
  57. scriptObject->_restoreManagedInstance();
  58. for (auto& scriptObject : scriptObjCopy)
  59. scriptObject->endRefresh(backupData[scriptObject]);
  60. onRefreshComplete();
  61. }
  62. void ScriptObjectManager::notifyObjectFinalized(ScriptObjectBase* instance)
  63. {
  64. assert(instance != nullptr);
  65. Lock lock(mMutex);
  66. mFinalizedObjects[mFinalizedQueueIdx].push_back(instance);
  67. }
  68. void ScriptObjectManager::update()
  69. {
  70. processFinalizedObjects();
  71. }
  72. void ScriptObjectManager::processFinalizedObjects(bool assemblyRefresh)
  73. {
  74. UINT32 readQueueIdx = 0;
  75. {
  76. Lock lock(mMutex);
  77. readQueueIdx = mFinalizedQueueIdx;
  78. mFinalizedQueueIdx = (mFinalizedQueueIdx + 1) % 2;
  79. }
  80. for (auto& finalizedObj : mFinalizedObjects[readQueueIdx])
  81. finalizedObj->_onManagedInstanceDeleted(assemblyRefresh);
  82. mFinalizedObjects[readQueueIdx].clear();
  83. }
  84. }