Skip to content

Commit

Permalink
v1.1.0
Browse files Browse the repository at this point in the history
# CHANGED
- Package version increased to v1.1.0

# ADDED
- Added configuration option for whitelisting assemblies on GenesisSettings. This is an recommended feature for data providers to optionally limit which assemblies are searched via reflection.
- Added new overloads to ReflectionTools to make it easier to search via reflection using a whitelist of assemblies.

# FIXED
- Modified assertion for TypeExtensions where wrong Type was being checked as interface
- Mitigated inspector performance issue for CodeGeneratorConfigDrawer that was causing CPU and GC spikes every editor frame.

REMOVED
- Removed unused methods GetRealTypeName and GetEnumName in ReflectionTools
  • Loading branch information
jzapdot committed Apr 25, 2020
1 parent db2134b commit 31794e5
Show file tree
Hide file tree
Showing 11 changed files with 530 additions and 52 deletions.
75 changes: 75 additions & 0 deletions Scripts/Editor/Config/AssembliesConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
namespace JCMG.Genesis.Editor
{
/// <summary>
/// A configuration for enabling user customization of assemblies to search for types via reflection.
/// </summary>
public sealed class AssembliesConfig : AbstractConfigurableConfig
{
/// <summary>
/// Returns true if reflection-based logic should only search types in <see cref="WhiteListedAssemblies"/>,
/// otherwise false.
/// </summary>
public bool DoUseWhitelistOfAssemblies
{
get
{
var value = _settings.GetOrSetValue(DO_USE_WHITE_LIST_KEY, DEFAULT_DO_USE_WHITE_LIST_VALUE).ToLower();

// If for some reason we can't parse this bool, default to false for white-listing.
if(!bool.TryParse(value, out var result))
{
result = false;
}

return result;
}
set
{
_settings.SetValue(DO_USE_WHITE_LIST_KEY, value.ToString().ToLower());
}
}

/// <summary>
/// An array of assemblies white-listed for use in reflection; only types from these assemblies will be searched
/// if <see cref="DoUseWhitelistOfAssemblies"/> is true.
/// </summary>
public string[] WhiteListedAssemblies
{
get
{
return _settings.GetOrSetValue(WHITE_LIST_ASSEMBLIES_KEY, DEFAULT_ASSEMBLIES_VALUE).ArrayFromCSV();
}
set
{
_settings.SetValue(WHITE_LIST_ASSEMBLIES_KEY, value.ToCSV());
}
}

/// <summary>
/// Used for UI
/// </summary>
internal string RawWhiteListedAssemblies
{
get { return _settings.GetOrSetValue(WHITE_LIST_ASSEMBLIES_KEY, DEFAULT_ASSEMBLIES_VALUE); }
set { _settings.SetValue(WHITE_LIST_ASSEMBLIES_KEY, value); }
}

// Keys
private const string DO_USE_WHITE_LIST_KEY = "Genesis.DoUseWhiteListedAssemblies";
private const string WHITE_LIST_ASSEMBLIES_KEY = "Genesis.WhiteListedAssemblies";

// Defaults
private const string DEFAULT_DO_USE_WHITE_LIST_VALUE = "false";
private const string DEFAULT_ASSEMBLIES_VALUE = "Assembly-CSharp, Assembly-CSharp-Editor";

/// <summary>Configures preferences</summary>
/// <param name="settings"></param>
public override void Configure(GenesisSettings settings)
{
base.Configure(settings);

settings.SetIfNotPresent(DO_USE_WHITE_LIST_KEY, DEFAULT_DO_USE_WHITE_LIST_VALUE);
settings.SetIfNotPresent(WHITE_LIST_ASSEMBLIES_KEY, DEFAULT_ASSEMBLIES_VALUE);
}
}
}
11 changes: 11 additions & 0 deletions Scripts/Editor/Config/AssembliesConfig.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 83 additions & 0 deletions Scripts/Editor/Drawers/AssembliesConfigDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using UnityEditor;

namespace JCMG.Genesis.Editor
{
internal sealed class AssembliesConfigDrawer : AbstractSettingsDrawer
{
/// <summary>
/// The display title for this drawer
/// </summary>
public override string Title => TITLE;

private readonly AssembliesConfig _config;

// UI
private const string TITLE = "Assemblies";
private const string DO_USE_WHITE_LIST_LABEL = "Do Use Whitelist";
private const string DO_USE_WHITE_LIST_DESCRIPTION = "If enabled, searching via reflection for Data Providers " +
"will be limited to the array of assemblies below. Otherwise " +
"all loaded assemblies will be searched.";

private const string ASSEMBLY_WHITE_LIST_LABEL = "Assembly Whitelist";
private const string ASSEMBLY_WHITE_LIST_DESCRIPTION = "The comma delimited array of assemblies that searching " +
"via reflection for Data Providers should be limited to.";

public AssembliesConfigDrawer()
{
_config = new AssembliesConfig();
}

/// <summary>Initializes any setup for the drawer prior to rendering any GUI.</summary>
/// <param name="settings"></param>
public override void Initialize(GenesisSettings settings)
{
base.Initialize(settings);

_config.Configure(settings);
}

protected override void DrawContentBody(GenesisSettings settings)
{
// Do Use white-list
EditorGUILayout.HelpBox(DO_USE_WHITE_LIST_DESCRIPTION, MessageType.Info);
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(DO_USE_WHITE_LIST_LABEL);

using (var scope = new EditorGUI.ChangeCheckScope())
{
var newValue = EditorGUILayout.Toggle(_config.DoUseWhitelistOfAssemblies);

if (scope.changed)
{
_config.DoUseWhitelistOfAssemblies = newValue;

EditorUtility.SetDirty(settings);
}
}
}

// White-Listed Assemblies
EditorGUILayout.HelpBox(ASSEMBLY_WHITE_LIST_DESCRIPTION, MessageType.Info);
using (new EditorGUI.DisabledScope(!_config.DoUseWhitelistOfAssemblies))
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(ASSEMBLY_WHITE_LIST_LABEL);

using (var scope = new EditorGUI.ChangeCheckScope())
{
var newValue = EditorGUILayout.TextField(_config.RawWhiteListedAssemblies);

if (scope.changed)
{
_config.RawWhiteListedAssemblies = newValue;

EditorUtility.SetDirty(settings);
}
}
}
}
}
}
}
11 changes: 11 additions & 0 deletions Scripts/Editor/Drawers/AssembliesConfigDrawer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 15 additions & 16 deletions Scripts/Editor/Drawers/CodeGeneratorSettingsDrawer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,31 @@ internal sealed class CodeGeneratorSettingsDrawer : AbstractSettingsDrawer

private readonly CodeGeneratorConfig _codeGeneratorConfig;

private string[] _availableDataProviderNames;
private string[] _availableDataProviderTypes;
private string[] _availableGeneratorNames;
private string[] _availableGeneratorTypes;
private string[] _availablePostProcessorNames;
private string[] _availablePostProcessorTypes;
private string[] _availablePreProcessorNames;
private string[] _availablePreProcessorTypes;
private ICodeGenerationPlugin[] _instances;
private readonly string[] _availableDataProviderNames;
private readonly string[] _availableDataProviderTypes;
private readonly string[] _availableGeneratorNames;
private readonly string[] _availableGeneratorTypes;
private readonly string[] _availablePostProcessorNames;
private readonly string[] _availablePostProcessorTypes;
private readonly string[] _availablePreProcessorNames;
private readonly string[] _availablePreProcessorTypes;

public CodeGeneratorSettingsDrawer()
{
_codeGeneratorConfig = new CodeGeneratorConfig();

// Add per plugin interface type preferences.
var instances = CodeGeneratorTools.LoadFromPlugins();
SetTypesAndNames<IPreProcessor>(instances, out _availablePreProcessorTypes, out _availablePreProcessorNames);
SetTypesAndNames<IDataProvider>(instances, out _availableDataProviderTypes, out _availableDataProviderNames);
SetTypesAndNames<ICodeGenerator>(instances, out _availableGeneratorTypes, out _availableGeneratorNames);
SetTypesAndNames<IPostProcessor>(instances, out _availablePostProcessorTypes, out _availablePostProcessorNames);
}

public override void Initialize(GenesisSettings settings)
{
// Add default code gen preferences.
_codeGeneratorConfig.Configure(settings);

// Add per plugin interface type preferences.
_instances = CodeGeneratorTools.LoadFromPlugins();
SetTypesAndNames<IPreProcessor>(_instances, out _availablePreProcessorTypes, out _availablePreProcessorNames);
SetTypesAndNames<IDataProvider>(_instances, out _availableDataProviderTypes, out _availableDataProviderNames);
SetTypesAndNames<ICodeGenerator>(_instances, out _availableGeneratorTypes, out _availableGeneratorNames);
SetTypesAndNames<IPostProcessor>(_instances, out _availablePostProcessorTypes, out _availablePostProcessorNames);
}

protected override void DrawContentBody(GenesisSettings settings)
Expand Down
5 changes: 3 additions & 2 deletions Scripts/Editor/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ public static class TypeExtensions
/// <param name="type"></param>
public static bool ImplementsInterface<T>(this Type type)
{
Assert.IsTrue(type.IsInterface);
var interfaceType = typeof(T);
Assert.IsTrue(interfaceType.IsInterface);

return type.GetInterface(typeof(T).FullName) != null;
return type.GetInterface(interfaceType.FullName) != null;
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions Scripts/Editor/Inspectors/GenesisSettingsInspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ static GenesisSettingsInspector()
{
PREFERENCES_DRAWERS = ReflectionTools.GetAllImplementingInstancesOfInterface<ISettingsDrawer>().ToArray();
}

/// <summary>
/// <para>Implement this function to make a custom inspector.</para>
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ THE SOFTWARE.

namespace JCMG.Genesis.Editor.Plugins
{
internal sealed class ScriptableFactoryDataProvider : IDataProvider
internal sealed class ScriptableFactoryDataProvider : IDataProvider,
IConfigurable
{
/// <summary>
/// The name of the plugin.
Expand All @@ -45,6 +46,8 @@ internal sealed class ScriptableFactoryDataProvider : IDataProvider
/// </summary>
public bool RunInDryMode => true;

private AssembliesConfig _assembliesConfig;

private const string NAME = "Scriptable Factory Data";

/// <summary>
Expand All @@ -53,7 +56,12 @@ internal sealed class ScriptableFactoryDataProvider : IDataProvider
/// <returns></returns>
public CodeGeneratorData[] GetData()
{
var codeData = ReflectionTools.GetAvailableAssemblies()
// If we are only searching specific assemblies use that whitelist, otherwise get all loaded assemblies.
var assemblies = _assembliesConfig.DoUseWhitelistOfAssemblies
? ReflectionTools.GetAvailableAssemblies(_assembliesConfig.WhiteListedAssemblies)
: ReflectionTools.GetAvailableAssemblies();

var codeData = assemblies
.SelectMany(x => x.GetTypes())
.Where(
x => x.IsEnum &&
Expand All @@ -79,5 +87,14 @@ public CodeGeneratorData[] GetData()

return codeData;
}

/// <summary>
/// Configures preferences
/// </summary>
/// <param name="settings"></param>
public void Configure(GenesisSettings settings)
{
_assembliesConfig = settings.CreateAndConfigure<AssembliesConfig>();
}
}
}
Loading

0 comments on commit 31794e5

Please sign in to comment.