Fix crash on native type in JsonAsset due to scripting hot-reload in Editor

This commit is contained in:
Wojciech Figat
2022-01-31 10:33:05 +01:00
parent f8eba66b5e
commit d0e37ba6ef
3 changed files with 64 additions and 15 deletions

View File

@@ -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<JsonAsset, &JsonAsset::OnScriptsReloadStart>(this);
Level::ScriptsReloaded.Bind<JsonAsset, &JsonAsset::OnScriptsReloaded>(this);
}
#endif
return LoadResult::Ok;
}
void JsonAsset::unload(bool isReloading)
{
if (Instance)
{
#if USE_EDITOR
Level::ScriptsReloadStart.Unbind<JsonAsset, &JsonAsset::OnScriptsReloadStart>(this);
Level::ScriptsReloaded.Unbind<JsonAsset, &JsonAsset::OnScriptsReloaded>(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

View File

@@ -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
};

View File

@@ -146,6 +146,7 @@ Delegate<Scene*, const Guid&> Level::SceneUnloaded;
#if USE_EDITOR
Action Level::ScriptsReloadStart;
Action Level::ScriptsReload;
Action Level::ScriptsReloaded;
Action Level::ScriptsReloadEnd;
#endif
Array<String> Level::Tags;