From d0e37ba6ef842b68b404635a29f5746e86670601 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Mon, 31 Jan 2022 10:33:05 +0100 Subject: [PATCH] Fix crash on native type in JsonAsset due to scripting hot-reload in Editor --- Source/Engine/Content/JsonAsset.cpp | 70 ++++++++++++++++++++++------- Source/Engine/Content/JsonAsset.h | 8 ++++ Source/Engine/Level/Level.cpp | 1 + 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index fc4a7ec1a..e8aa901d9 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -5,6 +5,7 @@ #if USE_EDITOR #include "Engine/Platform/File.h" #include "Engine/Core/Types/DataContainer.h" +#include "Engine/Level/Level.h" #else #include "Storage/ContentStorageManager.h" #endif @@ -205,11 +206,40 @@ JsonAsset::JsonAsset(const SpawnParams& params, const AssetInfo* info) Asset::LoadResult JsonAsset::loadAsset() { - // Base - auto result = JsonAssetBase::loadAsset(); + const auto result = JsonAssetBase::loadAsset(); if (result != LoadResult::Ok || IsInternalType()) return result; + if (CreateInstance()) + return LoadResult::Failed; +#if USE_EDITOR + if (Instance) + { + // Reload instance when module with this type gets reloaded + Level::ScriptsReloadStart.Bind(this); + Level::ScriptsReloaded.Bind(this); + } +#endif + + return LoadResult::Ok; +} + +void JsonAsset::unload(bool isReloading) +{ + if (Instance) + { +#if USE_EDITOR + Level::ScriptsReloadStart.Unbind(this); + Level::ScriptsReloaded.Unbind(this); +#endif + DeleteInstance(); + } + + JsonAssetBase::unload(isReloading); +} + +bool JsonAsset::CreateInstance() +{ // Try to scripting type for this data const StringAsANSI<> dataTypeNameAnsi(DataTypeName.Get(), DataTypeName.Length()); const auto typeHandle = Scripting::FindScriptingType(StringAnsiView(dataTypeNameAnsi.Get(), DataTypeName.Length())); @@ -231,7 +261,7 @@ Asset::LoadResult JsonAsset::loadAsset() // Allocate object const auto instance = Allocator::Allocate(type.Size); if (!instance) - return LoadResult::Failed; + return true; Instance = instance; InstanceType = typeHandle; _dtor = type.Class.Dtor; @@ -241,27 +271,37 @@ Asset::LoadResult JsonAsset::loadAsset() auto modifier = Cache::ISerializeModifier.Get(); modifier->EngineBuild = DataEngineBuild; ((ISerializable*)((byte*)instance + interface->VTableOffset))->Deserialize(*Data, modifier.Value); - // TODO: delete object when containing BinaryModule gets unloaded break; } - default: ; } } - return result; + return false; } -void JsonAsset::unload(bool isReloading) +void JsonAsset::DeleteInstance() { - // Base - JsonAssetBase::unload(isReloading); + ASSERT_LOW_LAYER(Instance && _dtor); + InstanceType = ScriptingTypeHandle(); + _dtor(Instance); + Allocator::Free(Instance); + Instance = nullptr; + _dtor = nullptr; +} - if (Instance) +#if USE_EDITOR + +void JsonAsset::OnScriptsReloadStart() +{ + DeleteInstance(); +} + +void JsonAsset::OnScriptsReloaded() +{ + if (CreateInstance()) { - InstanceType = ScriptingTypeHandle(); - _dtor(Instance); - Allocator::Free(Instance); - Instance = nullptr; - _dtor = nullptr; + LOG(Warning, "Failed to reload {0} instance {1}.", ToString(), DataTypeName); } } + +#endif diff --git a/Source/Engine/Content/JsonAsset.h b/Source/Engine/Content/JsonAsset.h index 7f3592721..566f90501 100644 --- a/Source/Engine/Content/JsonAsset.h +++ b/Source/Engine/Content/JsonAsset.h @@ -117,4 +117,12 @@ protected: // [JsonAssetBase] LoadResult loadAsset() override; void unload(bool isReloading) override; + +private: + bool CreateInstance(); + void DeleteInstance(); +#if USE_EDITOR + void OnScriptsReloadStart(); + void OnScriptsReloaded(); +#endif }; diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index a5f7ed6e8..39e358faf 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -146,6 +146,7 @@ Delegate Level::SceneUnloaded; #if USE_EDITOR Action Level::ScriptsReloadStart; Action Level::ScriptsReload; +Action Level::ScriptsReloaded; Action Level::ScriptsReloadEnd; #endif Array Level::Tags;