Skip to content

Commit

Permalink
Merge pull request #78 from UnioGame/master
Browse files Browse the repository at this point in the history
speedup converters loading on application startup
  • Loading branch information
applejag authored Dec 2, 2023
2 parents 72dbb20 + fd8f1d0 commit 15f6b5d
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public struct ConverterConfig : IEquatable<ConverterConfig>

public string converterName;

public string converterType;

public List<KeyedConfig> settings;

public override string ToString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@

namespace Newtonsoft.Json.UnityConverters.Configuration
{

#pragma warning disable CA2235 // Mark all non-serializable fields
[Serializable]
public sealed class UnityConvertersConfig : ScriptableObject
{
internal const string PATH = "Assets/Resources/Newtonsoft.Json-for-Unity.Converters.asset";
internal const string PATH_FOR_RESOURCES_LOAD = "Newtonsoft.Json-for-Unity.Converters";

public bool useBakedConverters = true;

public bool useUnityContractResolver = true;

public bool useAllOutsideConverters = true;
Expand All @@ -28,6 +31,7 @@ public sealed class UnityConvertersConfig : ScriptableObject
new ConverterConfig { converterName = typeof(StringEnumConverter).FullName, enabled = true },
new ConverterConfig { converterName = typeof(VersionConverter).FullName, enabled = true },
};

}
#pragma warning restore CA2235 // Mark all non-serializable fields
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ public class UnityConvertersConfigEditor : Editor
private SerializedProperty _unityConverters;
private SerializedProperty _useAllJsonNetConverters;
private SerializedProperty _jsonNetConverters;
private SerializedProperty _useBakingConverters;

private AnimBool _outsideConvertersShow;
private AnimBool _unityConvertersShow;
private AnimBool _jsonNetConvertersShow;

private UnityConvertersConfig _config;
private GUIStyle _headerStyle;
private GUIStyle _boldHeaderStyle;

Expand All @@ -50,13 +52,15 @@ private void OnEnable()
return;
}

_config = serializedObject.targetObject as UnityConvertersConfig;
_useUnityContractResolver = serializedObject.FindProperty(nameof(UnityConvertersConfig.useUnityContractResolver));
_useAllOutsideConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.useAllOutsideConverters));
_outsideConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.outsideConverters));
_useAllUnityConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.useAllUnityConverters));
_unityConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.unityConverters));
_useAllJsonNetConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.useAllJsonNetConverters));
_jsonNetConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.jsonNetConverters));
_useBakingConverters = serializedObject.FindProperty(nameof(UnityConvertersConfig.useBakedConverters));

_outsideConvertersShow = new AnimBool(_outsideConverters.isExpanded);
_unityConvertersShow = new AnimBool(_unityConverters.isExpanded);
Expand All @@ -72,6 +76,7 @@ private void OnEnable()
AddAndSetupConverters(_outsideConverters, outsideConverterTypes, _useAllOutsideConverters.boolValue);
AddAndSetupConverters(_unityConverters, unityConverterTypes, _useAllUnityConverters.boolValue);
AddAndSetupConverters(_jsonNetConverters, jsonNetConverterTypes, _useAllJsonNetConverters.boolValue);

serializedObject.ApplyModifiedProperties();
}

Expand All @@ -90,6 +95,18 @@ public override void OnInspectorGUI()
" 'UnityEngine.ScriptableObject' via 'ScriptableObject.Create()' instead of the default" +
" 'new ScriptableObject()'.");

ToggleLeft(_useBakingConverters, "If true - use baked converters at runtime");

EditorGUILayout.Separator();
EditorGUILayout.Space();

if (GUILayout.Button("Bake Json Converters"))
{
UnityConverterInitializer.BakeConverters(_config);
EditorUtility.SetDirty(_config);
AssetDatabase.SaveAssetIfDirty(_config);
}

EditorGUILayout.Space();

FoldedConverters(_useAllOutsideConverters, _outsideConverters, _outsideConvertersShow,
Expand Down Expand Up @@ -127,6 +144,7 @@ private void AddMissingConverters(SerializedProperty arrayProperty, IEnumerable<
var elementTypes = elements
.Select(e => TypeCache.FindType(e.FindPropertyRelative(nameof(ConverterConfig.converterName)).stringValue))
.ToArray();

Type[] missingConverters = converterTypes
.Where(type => !elementTypes.Contains(type))
.ToArray();
Expand All @@ -135,13 +153,15 @@ private void AddMissingConverters(SerializedProperty arrayProperty, IEnumerable<
{
int nextIndex = arrayProperty.arraySize;
arrayProperty.InsertArrayElementAtIndex(nextIndex);

SerializedProperty elemProp = arrayProperty.GetArrayElementAtIndex(nextIndex);

SerializedProperty enabledProp = elemProp.FindPropertyRelative(nameof(ConverterConfig.enabled));
SerializedProperty converterNameProp = elemProp.FindPropertyRelative(nameof(ConverterConfig.converterName));
SerializedProperty converterTypeProp = elemProp.FindPropertyRelative(nameof(ConverterConfig.converterType));

enabledProp.boolValue = newAreEnabledByDefault;
converterNameProp.stringValue = converterType.FullName;
converterTypeProp.stringValue = converterType.AssemblyQualifiedName;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace Newtonsoft.Json.UnityConverters
public static class UnityConverterInitializer
{
private static bool _shouldAddConvertsToDefaultSettings = true;

private static JsonSerializerSettings _defaultSettings;
/// <summary>
/// The default <see cref="JsonSerializerSettings"/> given by <c>Newtonsoft.Json-for-Unity.Converters</c>
/// </summary>
Expand Down Expand Up @@ -97,6 +97,48 @@ private static void UpdateDefaultSettings()
}
}

public static void BakeConverters(UnityConvertersConfig configuration)
{
_defaultSettings = null;

var outsideConverterTypes = FindCustomConverters().ToArray();
var unityConverterTypes = FindUnityConverters().ToArray();
var jsonNetConverterTypes = FindJsonNetConverters().ToArray();

UpdateConverter(configuration.unityConverters, unityConverterTypes);
UpdateConverter(configuration.outsideConverters, outsideConverterTypes);
UpdateConverter(configuration.jsonNetConverters, jsonNetConverterTypes);
}

public static void UpdateConverter(List<ConverterConfig> configs, Type[] types)
{
var configurations = new List<ConverterConfig>();

for (var i = 0; i < configs.Count; i++)
{
var config = configs[i];
foreach (var type in types)
{
var fullName = type.FullName;
if (fullName == null || !fullName
.Equals(config.converterName, StringComparison.OrdinalIgnoreCase)) continue;

var typeName = type.AssemblyQualifiedName;
if(string.IsNullOrEmpty(typeName)) break;

config.converterType = typeName;
var targetType = Type.GetType(typeName, false, true);
if(targetType == null) continue;

configurations.Add(config);
break;
}
}

configs.Clear();
configs.AddRange(configurations);
}

/// <summary>
/// Refreshes the settings that are found in the Resources folder
/// (specified in <see cref="UnityConvertersConfig.PATH_FOR_RESOURCES_LOAD"/>);
Expand All @@ -113,50 +155,57 @@ internal static JsonSerializerSettings GetExistingDefaultUnitySettings()

private static JsonSerializerSettings CreateJsonSettingsWithFreslyLoadedConfig()
{
//return new JsonSerializerSettings();
if (_defaultSettings != null) return _defaultSettings;

var config = Resources.Load<UnityConvertersConfig>(UnityConvertersConfig.PATH_FOR_RESOURCES_LOAD);

if (!config)
{
config = ScriptableObject.CreateInstance<UnityConvertersConfig>();
}

var settings = new JsonSerializerSettings {
_defaultSettings = new JsonSerializerSettings {
Converters = CreateConverters(config),
};

if (config.useUnityContractResolver)
{
settings.ContractResolver = new UnityTypeContractResolver();
_defaultSettings.ContractResolver = new UnityTypeContractResolver();
}

return settings;
return _defaultSettings;
}

/// <summary>
/// Create the converter instances.
/// </summary>
/// <returns>The converters.</returns>
private static List<JsonConverter> CreateConverters(UnityConvertersConfig config)
public static List<JsonConverter> CreateConverters(UnityConvertersConfig config)
{
var customs = FindFilteredCustomConverters(config)
.Concat(FindFilteredUnityConverters(config))
.Concat(FindFilteredJsonNetConverters(config))
.Select(type => CreateConverter(type))
.Where(o => o != null);

return new List<JsonConverter>(customs);
var converterTypes = new List<Type>();
var result = new List<JsonConverter>();

converterTypes.AddRange(FindFilteredCustomConverters(config));
converterTypes.AddRange(FindFilteredUnityConverters(config));
converterTypes.AddRange(FindFilteredJsonNetConverters(config));

foreach (var type in converterTypes)
{
var converter = CreateConverter(type);
if(converter == null) continue;
result.Add(converter);
}

return result;
}

private static IEnumerable<Type> FindFilteredCustomConverters(UnityConvertersConfig config)
{
return ApplyConfigFilter(FindCustomConverters(), config.useAllOutsideConverters, config.outsideConverters);
}

/// <summary>
/// Find all the valid converter types outside of Newtonsoft.Json namespaces.
/// </summary>
/// <returns>The types.</returns>
internal static IEnumerable<Type> FindCustomConverters()
public static IEnumerable<Type> FindCustomConverters()
{
var typesFromOtherDomains = AppDomain.CurrentDomain.GetAssemblies()
.Select(dll => dll.GetLoadableTypes()
Expand All @@ -166,17 +215,13 @@ internal static IEnumerable<Type> FindCustomConverters()

return FilterToJsonConvertersAndOrder(typesFromOtherDomains);
}

private static IEnumerable<Type> FindFilteredUnityConverters(UnityConvertersConfig config)
{
return ApplyConfigFilter(FindUnityConverters(), config.useAllUnityConverters, config.unityConverters);
}


/// <summary>
/// Find all the valid converter types inside this assembly, <c>Newtonsoft.Json.UnityConverters</c>
/// </summary>
/// <returns>The types.</returns>
internal static IEnumerable<Type> FindUnityConverters()
public static IEnumerable<Type> FindUnityConverters()
{
var typesFromPackageDomains = AppDomain.CurrentDomain.GetAssemblies()
.Select(dll => dll.GetLoadableTypes()
Expand All @@ -187,21 +232,44 @@ internal static IEnumerable<Type> FindUnityConverters()
return FilterToJsonConvertersAndOrder(typesFromPackageDomains);
}

private static IEnumerable<Type> FindFilteredUnityConverters(UnityConvertersConfig config)
{
var unityTypes = config.useBakedConverters
? GetUnityConvertersTypes(config)
: FindUnityConverters();

return ApplyConfigFilter(unityTypes, config.useAllUnityConverters, config.unityConverters);
}

private static IEnumerable<Type> FindFilteredCustomConverters(UnityConvertersConfig config)
{
var customTypes = config.useBakedConverters
? GetCustomConvertersTypes(config)
: FindCustomConverters();

return ApplyConfigFilter(customTypes, config.useAllOutsideConverters, config.outsideConverters);
}

private static IEnumerable<Type> FindFilteredJsonNetConverters(UnityConvertersConfig config)
{
return ApplyConfigFilter(FindJsonNetConverters(), config.useAllJsonNetConverters, config.jsonNetConverters);
var converterTypes = config.useBakedConverters
? GetJsonNetConvertersTypes(config)
: FindJsonNetConverters();

return ApplyConfigFilter(converterTypes, config.useAllJsonNetConverters, config.jsonNetConverters);
}

/// <summary>
/// Finds all the valid converter types inside the <c>Newtonsoft.Json</c> assembly.
/// </summary>
/// <returns>The types.</returns>
internal static IEnumerable<Type> FindJsonNetConverters()
public static IEnumerable<Type> FindJsonNetConverters()
{
return FilterToJsonConvertersAndOrder(typeof(JsonConverter).Assembly.GetTypes());
var types = typeof(JsonConverter).Assembly.GetTypes();
return FilterToJsonConvertersAndOrder(types);
}

private static IEnumerable<Type> FilterToJsonConvertersAndOrder(IEnumerable<Type> types)
public static IEnumerable<Type> FilterToJsonConvertersAndOrder(IEnumerable<Type> types)
{
return types
.Where(type
Expand Down Expand Up @@ -250,10 +318,56 @@ private static JsonConverter CreateConverter(Type jsonConverterType)
}
catch (Exception exception)
{
Debug.LogErrorFormat("Cannot create JsonConverter '{0}':\n{1}", jsonConverterType.FullName, exception);
Debug.LogErrorFormat("Cannot create JsonConverter '{0}':\n{1}", jsonConverterType?.FullName, exception);
}

return null;
}


public static IEnumerable<Type> GetCustomConvertersTypes(UnityConvertersConfig config)
{
var customConvertersTypes = config.outsideConverters;
var types = ConvertTypes(customConvertersTypes, config.useAllOutsideConverters);
foreach (var type in types)
yield return type;
}

public static IEnumerable<Type> GetUnityConvertersTypes(UnityConvertersConfig config)
{
var unityConvertersTypes = config.unityConverters;
var types = ConvertTypes(unityConvertersTypes, config.useAllUnityConverters);
foreach (var type in types)
yield return type;
}

public static IEnumerable<Type> GetJsonNetConvertersTypes(UnityConvertersConfig config)
{
var unityConvertersTypes = config.jsonNetConverters;
var types = ConvertTypes(unityConvertersTypes, config.useAllJsonNetConverters);
foreach (var type in types)
yield return type;
}

private static IEnumerable<Type> ConvertTypes(IEnumerable<ConverterConfig> items,bool useAll)
{
foreach (var item in items)
{
if(!useAll && !item.enabled) continue;

var typeValue = string.IsNullOrEmpty(item.converterType)
? string.Empty
: item.converterType;

var type = Type.GetType(typeValue, false, true);
#if UNITY_EDITOR
if (type == null)
{
Debug.LogErrorFormat("JsonConverter Type is NULL for {0} : {1}", item.converterName, item.converterType);
}
#endif
yield return type;
}
}
}
}

0 comments on commit 15f6b5d

Please sign in to comment.