Add SoftTypeReference<T> to scripting API for lazy-load type references (via typename)

This commit is contained in:
Wojtek Figat
2023-05-24 22:56:29 +02:00
parent 982639f215
commit 7efb3e3f3d
5 changed files with 298 additions and 14 deletions

View 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);
}
}
}

View 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