Editor/SerializedPropertyExtensions.cs
using ExtendedEditor.TypeLibraryFixes;
using Sandbox;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace ExtendedEditor;
public static class SerializedPropertyExtensions // TODO: use one from new editor library
{
extension(SerializedProperty target)
{
public SerializedProperty CreateProxy(Type type)
{
return new SerializedPropertyProxy(target, type, target.GetAttributes());
}
public SerializedProperty CreateProxy(Type type, params IEnumerable<Attribute> attributes)
{
return new SerializedPropertyProxy(target, type, attributes);
}
public SerializedProperty CreateProxy(params IEnumerable<Attribute> attributes) =>
target.CreateProxy(target.PropertyType, attributes);
public SerializedProperty FixForGenerics()
{
if(!IsGenericTypeDefinitionInside(target.PropertyType))
return target;
var propertyClassType = target.GetType();
bool isProperty = propertyClassType.FullName == "Sandbox.Internal.TypeSerializedProperty";
bool isField = propertyClassType.FullName == "Sandbox.Internal.TypeSerializedField";
if(!isProperty && !isField)
{
Log.Warning($"Can't fix {propertyClassType}");
return target;
}
var typeSerializedObjectField = propertyClassType.GetField("typeSerializedObject", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if(typeSerializedObjectField is null)
{
Log.Warning($"Can't fix, field 'typeSerializedObject' not found.");
return target;
}
var serializedObject = (SerializedObject)typeSerializedObjectField!.GetValue(target)!;
var objectClassType = serializedObject!.GetType();
var typeDescriptionField = objectClassType.GetField("TypeDescription", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if(typeDescriptionField is null)
{
Log.Warning($"Can't fix, field 'typeDescriptionField' not found.");
return target;
}
var getTargetObjectMethod = objectClassType.GetMethod("GetTargetObject", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if(getTargetObjectMethod is null)
{
Log.Warning($"Can't fix, method 'getTargetObjectMethod' not found.");
return target;
}
var parent = getTargetObjectMethod!.Invoke(serializedObject, null);
if(isProperty)
{
var property = parent!.GetType()!.GetProperty(target.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!;
if(property is null)
{
Log.Warning($"Can't fix, property '{target.Name}' not found.");
return target;
}
var proxy = new SerializedPropertyProxy(target, property!.PropertyType, target.GetAttributes());
proxy.ProxyValueGet(() => property.GetValue(parent)!);
proxy.ProxyValueSet(x => property.SetValue(parent, x));
return proxy;
}
else
{
var field = parent!.GetType()!.GetField(target.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!;
if(field is null)
{
Log.Warning($"Can't fix, field '{target.Name}' not found.");
return target;
}
var proxy = new SerializedPropertyProxy(target, field!.FieldType, target.GetAttributes());
proxy.ProxyValueGet(() => field.GetValue(parent)!);
proxy.ProxyValueSet(x => field.SetValue(parent, x));
return proxy;
}
}
static bool IsGenericTypeDefinitionInside(Type type)
{
if(type.IsGenericParameter)
return true;
if(type.IsGenericTypeDefinition)
return true;
if(type.IsGenericType)
{
foreach(var arg in type.GetGenericArguments())
{
if(arg.IsGenericParameter)
return true;
if(IsGenericTypeDefinitionInside(arg))
return true;
}
}
return false;
}
}
}