diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index 3779181b7..4c50d94bb 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -10,7 +10,10 @@ #include "Engine/Core/Log.h" #include "Engine/Serialization/JsonTools.h" #include "Engine/Content/Factories/JsonAssetFactory.h" +#include "Engine/Core/Cache.h" #include "Engine/Debug/Exceptions/JsonParseException.h" +#include "Engine/Scripting/Scripting.h" +#include "Engine/Utilities/StringConverter.h" JsonAssetBase::JsonAssetBase(const SpawnParams& params, const AssetInfo* info) : Asset(params, info) @@ -175,51 +178,54 @@ void JsonAssetBase::onRename(const StringView& newPath) REGISTER_JSON_ASSET(JsonAsset, "FlaxEngine.JsonAsset"); -//////////////////////////////////////////////////////////////////////////////////// - -#include "Engine/Physics/PhysicalMaterial.h" - -// Unmanaged json asset types that are serialized to JsonAsset and should be created by auto by asset. -// This allows to reuse JsonAsset without creating dedicated asset types. It has been designed for lightweight resources. - -typedef ISerializable* (*UnmanagedJsonInstanceCreator)(); - -template -ISerializable* Create() -{ - return New(); -} - -// Key: managed class typename, Value: unmanaged instance spawner function -Dictionary UnmanagedTypes(32); - -void InitUnmanagedJsonTypes() -{ - UnmanagedTypes[TEXT("FlaxEngine.PhysicalMaterial")] = &Create; -} - -//////////////////////////////////////////////////////////////////////////////////// - JsonAsset::JsonAsset(const SpawnParams& params, const AssetInfo* info) : JsonAssetBase(params, info) , Instance(nullptr) { - if (UnmanagedTypes.IsEmpty()) - InitUnmanagedJsonTypes(); } Asset::LoadResult JsonAsset::loadAsset() { // Base auto result = JsonAssetBase::loadAsset(); - if (result != LoadResult::Ok) + if (result != LoadResult::Ok || IsInternalType()) return result; - UnmanagedJsonInstanceCreator instanceSpawner = nullptr; - if (UnmanagedTypes.TryGet(DataTypeName, instanceSpawner)) + // Try to scripting type for this data + const StringAsANSI<> dataTypeNameAnsi(DataTypeName.Get(), DataTypeName.Length()); + const auto typeHandle = Scripting::FindScriptingType(StringAnsiView(dataTypeNameAnsi.Get(), DataTypeName.Length())); + if (typeHandle) { - Instance = instanceSpawner(); - Instance->Deserialize(*Data, nullptr); + auto& type = typeHandle.GetType(); + switch (type.Type) + { + case ScriptingTypes::Class: + { + // Ensure that object can deserialized + const ScriptingType::InterfaceImplementation* interfaces = type.GetInterface(&ISerializable::TypeInitializer); + if (!interfaces) + { + LOG(Warning, "Cannot deserialize {0} from Json Asset because it doesn't implement ISerializable interface.", type.ToString()); + break; + } + + // Allocate object + const auto instance = Allocator::Allocate(type.Size); + if (!instance) + return LoadResult::Failed; + Instance = instance; + _dtor = type.Class.Dtor; + type.Class.Ctor(instance); + + // Deserialize object + auto modifier = Cache::ISerializeModifier.Get(); + modifier->EngineBuild = DataEngineBuild; + ((ISerializable*)((byte*)instance + interfaces->VTableOffset))->Deserialize(*Data, modifier.Value); + // TODO: delete object when containing BinaryModule gets unloaded + break; + } + default: ; + } } return result; @@ -230,5 +236,11 @@ void JsonAsset::unload(bool isReloading) // Base JsonAssetBase::unload(isReloading); - SAFE_DELETE(Instance); + if (Instance) + { + _dtor(Instance); + Allocator::Free(Instance); + Instance = nullptr; + _dtor = nullptr; + } } diff --git a/Source/Engine/Content/JsonAsset.h b/Source/Engine/Content/JsonAsset.h index d5f785418..a6d452ff0 100644 --- a/Source/Engine/Content/JsonAsset.h +++ b/Source/Engine/Content/JsonAsset.h @@ -78,13 +78,15 @@ protected: API_CLASS(NoSpawn) class JsonAsset : public JsonAssetBase { DECLARE_ASSET_HEADER(JsonAsset); +private: + ScriptingType::Dtor _dtor; public: /// /// The deserialized unmanaged object instance (e.g. PhysicalMaterial). /// - ISerializable* Instance; + void* Instance; protected: diff --git a/Source/Engine/Core/ISerializable.h b/Source/Engine/Core/ISerializable.h new file mode 100644 index 000000000..cfc5e1976 --- /dev/null +++ b/Source/Engine/Core/ISerializable.h @@ -0,0 +1,60 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Serialization/JsonFwd.h" +#include "Engine/Core/Compiler.h" +#include "Engine/Core/Config.h" + +class JsonWriter; +class ISerializeModifier; + +/// +/// Interface for objects that can be serialized/deserialized to/from JSON format. +/// +API_INTERFACE() class FLAXENGINE_API ISerializable +{ +DECLARE_SCRIPTING_TYPE_MINIMAL(ISerializable); +public: + + typedef rapidjson_flax::Document SerializeDocument; + + /// + /// Serialization output stream + /// + typedef rapidjson_flax::Value DeserializeStream; + + /// + /// Serialization input stream + /// + typedef JsonWriter SerializeStream; + +public: + + /// + /// Finalizes an instance of the class. + /// + virtual ~ISerializable() = default; + + /// + /// Serialize object to the output stream compared to the values of the other object instance (eg. default class object). If other object is null then serialize all properties. + /// + /// The output stream. + /// The instance of the object to compare with and serialize only the modified properties. If null, then serialize all properties. + virtual void Serialize(SerializeStream& stream, const void* otherObj) = 0; + + /// + /// Deserialize object from the input stream + /// + /// The input stream. + /// The deserialization modifier object. Always valid. + virtual void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) = 0; + + /// + /// Deserialize object from the input stream child member. Won't deserialize it if member is missing. + /// + /// The input stream. + /// The input stream member to lookup. + /// The deserialization modifier object. Always valid. + void DeserializeIfExists(DeserializeStream& stream, const char* memberName, ISerializeModifier* modifier); +}; diff --git a/Source/Engine/Serialization/ISerializable.h b/Source/Engine/Serialization/ISerializable.h index cc7ebd0d7..537f64ee9 100644 --- a/Source/Engine/Serialization/ISerializable.h +++ b/Source/Engine/Serialization/ISerializable.h @@ -2,57 +2,5 @@ #pragma once -#include "JsonFwd.h" -#include "Engine/Core/Compiler.h" - -class JsonWriter; -class ISerializeModifier; - -/// -/// Interface for objects that can be serialized/deserialized to/from JSON format. -/// -class FLAXENGINE_API ISerializable -{ -public: - - typedef rapidjson_flax::Document SerializeDocument; - - /// - /// Serialization output stream - /// - typedef rapidjson_flax::Value DeserializeStream; - - /// - /// Serialization input stream - /// - typedef JsonWriter SerializeStream; - -public: - - /// - /// Finalizes an instance of the class. - /// - virtual ~ISerializable() = default; - - /// - /// Serialize object to the output stream compared to the values of the other object instance (eg. default class object). If other object is null then serialize all properties. - /// - /// The output stream. - /// The instance of the object to compare with and serialize only the modified properties. If null, then serialize all properties. - virtual void Serialize(SerializeStream& stream, const void* otherObj) = 0; - - /// - /// Deserialize object from the input stream - /// - /// The input stream. - /// The deserialization modifier object. Always valid. - virtual void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) = 0; - - /// - /// Deserialize object from the input stream child member. Won't deserialize it if member is missing. - /// - /// The input stream. - /// The input stream member to lookup. - /// The deserialization modifier object. Always valid. - void DeserializeIfExists(DeserializeStream& stream, const char* memberName, ISerializeModifier* modifier); -}; +// ISerializable moved to Core module +#include "Engine/Core/ISerializable.h"