Skip to content
9 changes: 7 additions & 2 deletions Code/Runtime/Save Data/Objects/SaveObjectController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,13 @@ public static void Initialize()
AllGlobalSaveObjects = new List<SaveObject>();
AllGlobalSaveValues = new Dictionary<SaveObject, List<SaveValueBase>>();

var objTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
#if UNITY_6000_0_OR_NEWER
var assemblies = UnityEngine.Assemblies.CurrentAssemblies.GetLoadedAssemblies();
#else
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
#endif

var objTypes = assemblies.SelectMany(x => x.GetTypes())
.Where(x => x.IsClass && typeof(SaveObject).IsAssignableFrom(x) && !x.IsAbstract && x.FullName != typeof(SaveObject).FullName)
.Select(type => (SaveObject)ScriptableObject.CreateInstance(type))
.Select(t => t.GetType())
Expand Down
22 changes: 19 additions & 3 deletions Shared Systems/Runtime/Helpers/AssemblyClassDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,25 @@ public T GetDefinedType<T>()

try
{
return AssemblyHelper.GetClassesOfType<T>(false).FirstOrDefault(t =>
t.GetType().Assembly.FullName == Assembly && t.GetType().FullName == Type);
}
// We try first to resolve the type with his name :
// https://stackoverflow.com/questions/1825147/type-gettypenamespace-a-b-classname-returns-null
string assemblyQualifiedName = $"{Type}, {Assembly}";
Type targetType = System.Type.GetType(assemblyQualifiedName);

// If it failed, we use the fallback (without instantiation.)
if (targetType == null)
{
targetType = AssemblyHelper.GetClassesNamesOfType<T>(false)
.FirstOrDefault(t => t.Assembly.FullName == Assembly && t.FullName == Type);
}

if (targetType != null)
{
return (T)Activator.CreateInstance(targetType);
}

return default;
}
#pragma warning disable
catch (Exception e)
{
Expand Down
67 changes: 44 additions & 23 deletions Shared Systems/Runtime/Helpers/AssemblyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,29 @@ public static class AssemblyHelper
/* ─────────────────────────────────────────────────────────────────────────────────────────────────────────────
| Fields
───────────────────────────────────────────────────────────────────────────────────────────────────────────── */

private static Assembly[] audioManagerAssemblies;


/// <summary>
/// It is intended to use this cache to avoid the use
/// of <see cref="Assembly.GetTypes"/> in each call.
/// </summary>
private static readonly Dictionary<Type, List<Type>> TypeCache = new();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't compile in the base development version of 2020.3.0

Suggested change
private static readonly Dictionary<Type, List<Type>> TypeCache = new();
private static readonly Dictionary<Type, List<Type>> TypeCache = new Dictionary<Type, List<Type>>();


private static Assembly[] _cachedAssemblies;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not match naming conventions. See: https://carter.games/unity-c-style-guide/#7-fields

Suggested change
private static Assembly[] _cachedAssemblies;
private static Assembly[] cachedAssemblies;


/* ─────────────────────────────────────────────────────────────────────────────────────────────────────────────
| Properties
───────────────────────────────────────────────────────────────────────────────────────────────────────────── */

/// <summary>
/// Gets all the cart assemblies to use when checking in internally only.
/// </summary>
private static IEnumerable<Assembly> AudioManagerAssemblies
private static IEnumerable<Assembly> CachedAssemblies
{
get
{
if (audioManagerAssemblies != null) return audioManagerAssemblies;
audioManagerAssemblies = GetAssemblies();
return audioManagerAssemblies;
if (_cachedAssemblies != null) return _cachedAssemblies;
_cachedAssemblies = GetAssemblies();
return _cachedAssemblies;
}
}

Expand Down Expand Up @@ -82,10 +88,7 @@ private static Assembly[] GetAssemblies()
/// <returns>The total in the project.</returns>
public static int CountClassesOfType<T>(bool internalCheckOnly = true)
{
var assemblies = internalCheckOnly ? AudioManagerAssemblies : AppDomain.CurrentDomain.GetAssemblies();

return assemblies.SelectMany(x => x.GetTypes())
.Count(x => x.IsClass && typeof(T).IsAssignableFrom(x));
return GetClassesNamesOfType<T>(internalCheckOnly).Count();
}


Expand All @@ -110,14 +113,11 @@ public static int CountClassesOfType<T>(params Assembly[] assemblies)
/// <returns>All the implementations of the entered class.</returns>
public static IEnumerable<T> GetClassesOfType<T>(bool internalCheckOnly = true)
{
var assemblies = internalCheckOnly ? AudioManagerAssemblies : AppDomain.CurrentDomain.GetAssemblies();

return assemblies.SelectMany(x => x.GetTypes())
.Where(x => x.IsClass && typeof(T).IsAssignableFrom(x) && !x.IsAbstract && x.FullName != typeof(T).FullName)
return GetClassesNamesOfType<T>(internalCheckOnly)
.Select(type => (T)Activator.CreateInstance(type));
}


/// <summary>
/// Gets all the classes of the entered type in the project.
/// </summary>
Expand All @@ -126,13 +126,34 @@ public static IEnumerable<T> GetClassesOfType<T>(bool internalCheckOnly = true)
/// <returns>All the implementations of the entered class.</returns>
public static IEnumerable<Type> GetClassesNamesOfType<T>(bool internalCheckOnly = true)
{
var assemblies = internalCheckOnly ? AudioManagerAssemblies : AppDomain.CurrentDomain.GetAssemblies();
Type targetType = typeof(T);

return assemblies.SelectMany(x => x.GetTypes())
.Where(x => x.IsClass && typeof(T).IsAssignableFrom(x) && x.FullName != typeof(T).FullName);
// We don't need to search in the project / assembly if we already know the type.
if (TypeCache.TryGetValue(targetType, out List<Type> cachedTypes))
return cachedTypes;

#if UNITY_6000_0_OR_NEWER
var assemblies = internalCheckOnly ? CachedAssemblies
: UnityEngine.Assemblies.CurrentAssemblies.GetLoadedAssemblies();
#else
var assemblies = internalCheckOnly ? CachedAssemblies
: AppDomain.CurrentDomain.GetAssemblies();
#endif

// Searching all the implementation of the class
var foundTypes = assemblies
.SelectMany(x => x.GetTypes())
.Where(x => x.IsClass && !x.IsAbstract && !x.ContainsGenericParameters
&& targetType.IsAssignableFrom(x) && x != targetType)
.ToList();

// Caching for later
TypeCache[targetType] = foundTypes;

return foundTypes;
}


/// <summary>
/// Gets all the classes of the entered type in the project.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,22 @@

namespace CarterGames.Shared.SaveManager
{
public static class ProjectAssemblyDefinition
internal static class ProjectAssemblyDefinition
{
public static Assembly[] ProjectEditorAssemblies
#if UNITY_EDITOR
public static Assembly[] ProjectEditorAssemblies { get; } = new Assembly[]
{
get
{
return new Assembly[]
{
Assembly.Load("CarterGames.SaveManager.Editor"),
Assembly.Load("CarterGames.SaveManager.Runtime"),
Assembly.Load("CarterGames.Shared.SaveManager.Editor"),
Assembly.Load("CarterGames.Shared.SaveManager")
};
}
}


public static Assembly[] ProjectRuntimeAssemblies
Assembly.Load("CarterGames.SaveManager.Editor"),
Assembly.Load("CarterGames.SaveManager.Runtime"),
Assembly.Load("CarterGames.Shared.SaveManager.Editor"),
Assembly.Load("CarterGames.Shared.SaveManager")
};
#else
public static Assembly[] ProjectRuntimeAssemblies { get; } = new Assembly[]
{
get
{
return new Assembly[]
{
Assembly.Load("CarterGames.SaveManager.Runtime"),
Assembly.Load("CarterGames.Shared.SaveManager")
};
}
}
Assembly.Load("CarterGames.SaveManager.Runtime"),
Assembly.Load("CarterGames.Shared.SaveManager")
};
#endif
}
}