Add SoftTypeReference<T> to scripting API for lazy-load type references (via typename)
This commit is contained in:
@@ -393,13 +393,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
if (_element != null)
|
if (_element != null)
|
||||||
{
|
{
|
||||||
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value.Type);
|
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value.Type);
|
||||||
|
|
||||||
if (_element.CustomControl.Type == ScriptType.Object)
|
if (_element.CustomControl.Type == ScriptType.Object)
|
||||||
{
|
|
||||||
_element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? ScriptType.Object : TypeUtils.GetObjectType(Values[0]);
|
_element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? ScriptType.Object : TypeUtils.GetObjectType(Values[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
@@ -407,11 +404,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
base.Refresh();
|
base.Refresh();
|
||||||
|
|
||||||
if (!HasDifferentValues)
|
if (!HasDifferentValues)
|
||||||
{
|
|
||||||
_element.CustomControl.Value = new ScriptType(Values[0] as Type);
|
_element.CustomControl.Value = new ScriptType(Values[0] as Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default implementation of the inspector used to edit reference to the <see cref="FlaxEditor.Scripting.ScriptType"/>. Used to pick classes.
|
/// Default implementation of the inspector used to edit reference to the <see cref="FlaxEditor.Scripting.ScriptType"/>. Used to pick classes.
|
||||||
@@ -425,10 +420,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
base.Initialize(layout);
|
base.Initialize(layout);
|
||||||
|
|
||||||
if (_element != null)
|
if (_element != null)
|
||||||
{
|
|
||||||
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value);
|
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
@@ -436,10 +429,33 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
base.Refresh();
|
base.Refresh();
|
||||||
|
|
||||||
if (!HasDifferentValues)
|
if (!HasDifferentValues)
|
||||||
{
|
|
||||||
_element.CustomControl.Value = (ScriptType)Values[0];
|
_element.CustomControl.Value = (ScriptType)Values[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation of the inspector used to edit reference to the <see cref="FlaxEngine.SoftTypeReference"/>. Used to pick classes.
|
||||||
|
/// </summary>
|
||||||
|
[CustomEditor(typeof(SoftTypeReference)), DefaultEditor]
|
||||||
|
public class SoftTypeReferenceEditor : TypeEditorBase
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
|
{
|
||||||
|
base.Initialize(layout);
|
||||||
|
|
||||||
|
if (_element != null)
|
||||||
|
_element.CustomControl.ValueChanged += () => SetValue(new SoftTypeReference(_element.CustomControl.ValueTypeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Refresh()
|
||||||
|
{
|
||||||
|
base.Refresh();
|
||||||
|
|
||||||
|
if (!HasDifferentValues)
|
||||||
|
_element.CustomControl.ValueTypeName = ((SoftTypeReference)Values[0]).TypeName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
87
Source/Engine/Scripting/SoftTypeReference.cs
Normal file
87
Source/Engine/Scripting/SoftTypeReference.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FlaxEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The soft reference to the scripting type contained in the scripting assembly.
|
||||||
|
/// </summary>
|
||||||
|
public struct SoftTypeReference : IComparable, IComparable<SoftTypeReference>
|
||||||
|
{
|
||||||
|
private string _typeName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type full name (eg. FlaxEngine.Actor).
|
||||||
|
/// </summary>
|
||||||
|
public string TypeName
|
||||||
|
{
|
||||||
|
get => _typeName;
|
||||||
|
set => _typeName = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type (resolves soft reference).
|
||||||
|
/// </summary>
|
||||||
|
public Type Type
|
||||||
|
{
|
||||||
|
get => _typeName != null ? Type.GetType(_typeName) : null;
|
||||||
|
set => _typeName = value?.FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SoftTypeReference"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeName">The type name.</param>
|
||||||
|
public SoftTypeReference(string typeName)
|
||||||
|
{
|
||||||
|
_typeName = typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the soft type reference from full name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">The type name.</param>
|
||||||
|
/// <returns>The soft type reference.</returns>
|
||||||
|
public static implicit operator SoftTypeReference(string s)
|
||||||
|
{
|
||||||
|
return new SoftTypeReference { _typeName = s };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the soft type reference from runtime type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">The type.</param>
|
||||||
|
/// <returns>The soft type reference.</returns>
|
||||||
|
public static implicit operator SoftTypeReference(Type s)
|
||||||
|
{
|
||||||
|
return new SoftTypeReference { _typeName = s?.FullName };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return _typeName?.GetHashCode() ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int CompareTo(object obj)
|
||||||
|
{
|
||||||
|
if (obj is SoftTypeReference other)
|
||||||
|
return CompareTo(other);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int CompareTo(SoftTypeReference other)
|
||||||
|
{
|
||||||
|
return string.Compare(_typeName, other._typeName, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
151
Source/Engine/Scripting/SoftTypeReference.h
Normal file
151
Source/Engine/Scripting/SoftTypeReference.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Scripting.h"
|
||||||
|
#include "ScriptingObject.h"
|
||||||
|
#include "Engine/Core/Log.h"
|
||||||
|
#include "Engine/Core/Types/String.h"
|
||||||
|
#include "Engine/Serialization/SerializationFwd.h"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The soft reference to the scripting type contained in the scripting assembly.
|
||||||
|
/// </summary>
|
||||||
|
template<typename T = ScriptingObject>
|
||||||
|
API_STRUCT(InBuild) struct SoftTypeReference
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
StringAnsi _typeName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SoftTypeReference() = default;
|
||||||
|
|
||||||
|
SoftTypeReference(const SoftTypeReference& s)
|
||||||
|
: _typeName(s._typeName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SoftTypeReference(SoftTypeReference&& s) noexcept
|
||||||
|
: _typeName(MoveTemp(s._typeName))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SoftTypeReference(const StringView& s)
|
||||||
|
: _typeName(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SoftTypeReference(const StringAnsiView& s)
|
||||||
|
: _typeName(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SoftTypeReference(const char* s)
|
||||||
|
: _typeName(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
FORCE_INLINE SoftTypeReference& operator=(SoftTypeReference&& s) noexcept
|
||||||
|
{
|
||||||
|
_typeName = MoveTemp(s._typeName);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE SoftTypeReference& operator=(StringAnsi&& s) noexcept
|
||||||
|
{
|
||||||
|
_typeName = MoveTemp(s);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE SoftTypeReference& operator=(const SoftTypeReference& s)
|
||||||
|
{
|
||||||
|
_typeName = s._typeName;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE SoftTypeReference& operator=(const StringAnsiView& s)
|
||||||
|
{
|
||||||
|
_typeName = s;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE bool operator==(const SoftTypeReference& other) const
|
||||||
|
{
|
||||||
|
return _typeName == other._typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE bool operator!=(const SoftTypeReference& other) const
|
||||||
|
{
|
||||||
|
return _typeName != other._typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE bool operator==(const StringAnsiView& other) const
|
||||||
|
{
|
||||||
|
return _typeName == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE bool operator!=(const StringAnsiView& other) const
|
||||||
|
{
|
||||||
|
return _typeName != other;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE operator bool() const
|
||||||
|
{
|
||||||
|
return _typeName.HasChars();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Gets the type full name (eg. FlaxEngine.Actor).
|
||||||
|
StringAnsiView GetTypeName() const
|
||||||
|
{
|
||||||
|
return StringAnsiView(_typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the type (resolves soft reference).
|
||||||
|
ScriptingTypeHandle GetType() const
|
||||||
|
{
|
||||||
|
return Scripting::FindScriptingType(_typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new objects of that type (or of type T if failed to solve typename).
|
||||||
|
T* NewObject() const
|
||||||
|
{
|
||||||
|
const ScriptingTypeHandle type = Scripting::FindScriptingType(_typeName);
|
||||||
|
auto obj = ScriptingObject::NewObject<T>(type);
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
if (_typeName.HasChars())
|
||||||
|
LOG(Error, "Unknown or invalid type {0}", String(_typeName));
|
||||||
|
obj = ScriptingObject::NewObject<T>();
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
uint32 GetHash(const SoftTypeReference<T>& key)
|
||||||
|
{
|
||||||
|
return GetHash(key.GetTypeName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
namespace Serialization
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool ShouldSerialize(const SoftTypeReference<T>& v, const void* otherObj)
|
||||||
|
{
|
||||||
|
return !otherObj || v != *(SoftTypeReference<T>*)otherObj;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Serialize(ISerializable::SerializeStream& stream, const SoftTypeReference<T>& v, const void* otherObj)
|
||||||
|
{
|
||||||
|
stream.String(v.GetTypeName());
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Deserialize(ISerializable::DeserializeStream& stream, SoftTypeReference<T>& v, ISerializeModifier* modifier)
|
||||||
|
{
|
||||||
|
v = stream.GetTextAnsi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// @formatter:on
|
||||||
@@ -7,7 +7,7 @@ using Newtonsoft.Json;
|
|||||||
namespace FlaxEngine.Json
|
namespace FlaxEngine.Json
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize references to the FlaxEngine.Object as Guid.
|
/// Serialize references to the <see cref="FlaxEngine.Object"/> as Guid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||||
internal class FlaxObjectConverter : JsonConverter
|
internal class FlaxObjectConverter : JsonConverter
|
||||||
@@ -46,7 +46,7 @@ namespace FlaxEngine.Json
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize SceneReference as Guid in internal format.
|
/// Serialize <see cref="SceneReference"/> as Guid in internal format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||||
internal class SceneReferenceConverter : JsonConverter
|
internal class SceneReferenceConverter : JsonConverter
|
||||||
@@ -79,7 +79,7 @@ namespace FlaxEngine.Json
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize SoftObjectReference as Guid in internal format.
|
/// Serialize <see cref="SoftObjectReference"/> as Guid in internal format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||||
internal class SoftObjectReferenceConverter : JsonConverter
|
internal class SoftObjectReferenceConverter : JsonConverter
|
||||||
@@ -111,7 +111,36 @@ namespace FlaxEngine.Json
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize SoftObjectReference as Guid in internal format.
|
/// Serialize <see cref="SoftTypeReference"/> as typename string in internal format.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||||
|
internal class SoftTypeReferenceConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
writer.WriteValue(((SoftTypeReference)value).TypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var result = new SoftTypeReference();
|
||||||
|
if (reader.TokenType == JsonToken.String)
|
||||||
|
result.TypeName = (string)reader.Value;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType == typeof(SoftTypeReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize <see cref="Margin"/> as Guid in internal format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||||
internal class MarginConverter : JsonConverter
|
internal class MarginConverter : JsonConverter
|
||||||
@@ -237,7 +266,7 @@ namespace FlaxEngine.Json
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize LocalizedString as inlined text is not using localization (Id member is empty).
|
/// Serialize <see cref="LocalizedString"/> as inlined text is not using localization (Id member is empty).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
|
||||||
internal class LocalizedStringConverter : JsonConverter
|
internal class LocalizedStringConverter : JsonConverter
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ namespace FlaxEngine.Json
|
|||||||
settings.Converters.Add(ObjectConverter);
|
settings.Converters.Add(ObjectConverter);
|
||||||
settings.Converters.Add(new SceneReferenceConverter());
|
settings.Converters.Add(new SceneReferenceConverter());
|
||||||
settings.Converters.Add(new SoftObjectReferenceConverter());
|
settings.Converters.Add(new SoftObjectReferenceConverter());
|
||||||
|
settings.Converters.Add(new SoftTypeReferenceConverter());
|
||||||
settings.Converters.Add(new MarginConverter());
|
settings.Converters.Add(new MarginConverter());
|
||||||
settings.Converters.Add(new VersionConverter());
|
settings.Converters.Add(new VersionConverter());
|
||||||
settings.Converters.Add(new LocalizedStringConverter());
|
settings.Converters.Add(new LocalizedStringConverter());
|
||||||
|
|||||||
Reference in New Issue
Block a user