Fix serialization of ControlReference when used in prefabs

#3262
This commit is contained in:
Wojtek Figat
2025-03-07 18:55:03 +01:00
parent 06665734e7
commit bc6f4f50cb
3 changed files with 55 additions and 14 deletions

View File

@@ -492,6 +492,16 @@ namespace FlaxEngine.Json
writer.WriteValue(JsonSerializer.GetStringID(&id)); writer.WriteValue(JsonSerializer.GetStringID(&id));
} }
/// <inheritdoc />
public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer)
{
if (value is IControlReference valueRef &&
other is IControlReference otherRef &&
JsonSerializer.SceneObjectEquals(valueRef.UIControl, otherRef.UIControl))
return;
base.WriteJsonDiff(writer, value, other, serializer);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{ {
@@ -499,7 +509,7 @@ namespace FlaxEngine.Json
if (reader.TokenType == JsonToken.String && result is IControlReference controlReference) if (reader.TokenType == JsonToken.String && result is IControlReference controlReference)
{ {
JsonSerializer.ParseID((string)reader.Value, out var id); JsonSerializer.ParseID((string)reader.Value, out var id);
controlReference.UIControl = Object.Find<UIControl>(ref id); controlReference.Load(Object.Find<UIControl>(ref id));
} }
return result; return result;
} }

View File

@@ -228,6 +228,23 @@ namespace FlaxEngine.Json
CacheManagedOnly.Dispose(); CacheManagedOnly.Dispose();
} }
/// <summary>
/// The default implementation of the values comparision function used by the serialization system.
/// </summary>
/// <param name="objA">The object a.</param>
/// <param name="objB">The object b.</param>
/// <returns>True if both objects are equal, otherwise false.</returns>
public static bool SceneObjectEquals(SceneObject objA, SceneObject objB)
{
if (objA == objB)
return true;
if (objA == null || objB == null)
return false;
if (objA.HasPrefabLink && objB.HasPrefabLink)
return objA.PrefabObjectID == objB.PrefabObjectID;
return false;
}
/// <summary> /// <summary>
/// The default implementation of the values comparision function used by the serialization system. /// The default implementation of the values comparision function used by the serialization system.
/// </summary> /// </summary>

View File

@@ -22,6 +22,12 @@ namespace FlaxEngine
/// Gets the type of the control the interface uses. /// Gets the type of the control the interface uses.
/// </summary> /// </summary>
public Type ControlType { get; } public Type ControlType { get; }
/// <summary>
/// Sets control ref by force - used during loading when <see cref="UIControl.Control"/> is not loaded yet.
/// </summary>
/// <param name="control">The reference.</param>
internal void Load(UIControl control);
} }
/// <summary> /// <summary>
@@ -43,11 +49,12 @@ namespace FlaxEngine
{ {
get get
{ {
if (_uiControl == null) var control = _uiControl?.Control;
if (control == null)
return null; return null;
if (_uiControl.Control is T t) if (control is T t)
return t; return t;
Debug.Write(LogType.Warning, "Trying to get Control from ControlReference but UIControl.Control is null, or the correct type."); Debug.Write(LogType.Warning, $"Trying to get Control from ControlReference but UIControl.Control is not correct type. It should be {typeof(T)} but is {control.GetType()}.");
return null; return null;
} }
} }
@@ -58,17 +65,18 @@ namespace FlaxEngine
get => _uiControl; get => _uiControl;
set set
{ {
var control = value?.Control;
if (value == null) if (value == null)
{ {
_uiControl = null; _uiControl = null;
} }
else if (value.Control is T t) else if (control is T)
{ {
_uiControl = value; _uiControl = value;
} }
else else
{ {
Debug.Write(LogType.Warning, "Trying to set UIControl but UIControl.Control is null or not the correct type."); Debug.Write(LogType.Warning, $"Trying to set UIControl but UIControl.Control is not the correct type. It should be {typeof(T)} but is {control.GetType()}.");
} }
} }
} }
@@ -76,6 +84,12 @@ namespace FlaxEngine
/// <inheritdoc /> /// <inheritdoc />
public Type ControlType => typeof(T); public Type ControlType => typeof(T);
/// <inheritdoc />
public void Load(UIControl value)
{
_uiControl = value;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
@@ -92,26 +106,26 @@ namespace FlaxEngine
public int CompareTo(object obj) public int CompareTo(object obj)
{ {
if (obj is IControlReference other) if (obj is IControlReference other)
return CompareTo(other); return Json.JsonSerializer.SceneObjectEquals(_uiControl, other.UIControl) ? 0 : 1;
return 0; return 1;
} }
/// <inheritdoc /> /// <inheritdoc />
public int CompareTo(ControlReference<T> other) public int CompareTo(ControlReference<T> other)
{ {
return _uiControl == other._uiControl ? 0 : 1; return Json.JsonSerializer.SceneObjectEquals(_uiControl, other._uiControl) ? 0 : 1;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Equals(ControlReference<T> other) public bool Equals(ControlReference<T> other)
{ {
return _uiControl == other._uiControl; return Json.JsonSerializer.SceneObjectEquals(_uiControl, other._uiControl);
} }
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is ControlReference<T> other && _uiControl == other._uiControl; return obj is ControlReference<T> other && Json.JsonSerializer.SceneObjectEquals(_uiControl, other._uiControl);
} }
/// <summary> /// <summary>
@@ -142,13 +156,13 @@ namespace FlaxEngine
/// Checks whether the two objects are equal. /// Checks whether the two objects are equal.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(ControlReference<T> left, ControlReference<T> right) => left._uiControl == right._uiControl; public static bool operator ==(ControlReference<T> left, ControlReference<T> right) => Json.JsonSerializer.SceneObjectEquals(left._uiControl, right._uiControl);
/// <summary> /// <summary>
/// Checks whether the two objects are not equal. /// Checks whether the two objects are not equal.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(ControlReference<T> left, ControlReference<T> right) => left._uiControl != right._uiControl; public static bool operator !=(ControlReference<T> left, ControlReference<T> right) => !Json.JsonSerializer.SceneObjectEquals(left._uiControl, right._uiControl);
} }
} }
@@ -166,7 +180,7 @@ namespace FlaxEngine.TypeConverters
if (result is IControlReference control) if (result is IControlReference control)
{ {
Json.JsonSerializer.ParseID(valueStr, out var id); Json.JsonSerializer.ParseID(valueStr, out var id);
control.UIControl = Object.Find<UIControl>(ref id); control.Load(Object.Find<UIControl>(ref id));
} }
return result; return result;
} }