using System.Collections.Generic;
using Mono.Cecil;
namespace StardewModdingAPI.Framework.ModLoading
{
/// A minimal assembly definition resolver which resolves references to known assemblies.
internal class AssemblyDefinitionResolver : IAssemblyResolver
{
/*********
** Fields
*********/
/// The underlying assembly resolver.
private readonly DefaultAssemblyResolverWrapper Resolver = new();
/// The known assemblies.
private readonly IDictionary Lookup = new Dictionary();
/// The directory paths to search for assemblies.
private readonly HashSet SearchPaths = new();
/*********
** Public methods
*********/
/// Construct an instance.
public AssemblyDefinitionResolver()
{
foreach (string path in this.Resolver.GetSearchDirectories())
this.SearchPaths.Add(path);
}
/// Add known assemblies to the resolver.
/// The known assemblies.
public void Add(params AssemblyDefinition[] assemblies)
{
foreach (AssemblyDefinition assembly in assemblies)
this.AddWithExplicitNames(assembly, assembly.Name.Name, assembly.Name.FullName);
}
/// Add a known assembly to the resolver with the given names. This overrides the assembly names that would normally be assigned.
/// The assembly to add.
/// The assembly names for which it should be returned.
public void AddWithExplicitNames(AssemblyDefinition assembly, params string[] names)
{
this.Resolver.AddAssembly(assembly);
foreach (string name in names)
this.Lookup[name] = assembly;
}
/// Resolve an assembly reference.
/// The assembly name.
/// The assembly can't be resolved.
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return this.ResolveName(name.Name) ?? this.Resolver.Resolve(name);
}
/// Resolve an assembly reference.
/// The assembly name.
/// The assembly reader parameters.
/// The assembly can't be resolved.
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
return this.ResolveName(name.Name) ?? this.Resolver.Resolve(name, parameters);
}
/// Add a directory path to search for assemblies, if it's non-null and not already added.
/// The path to search.
/// Returns whether the path was successfully added.
public bool TryAddSearchDirectory(string? path)
{
if (path is not null && this.SearchPaths.Add(path))
{
this.Resolver.AddSearchDirectory(path);
return true;
}
return false;
}
/// Remove a directory path to search for assemblies, if it's non-null.
/// The path to remove.
/// Returns whether the path was in the list and removed.
public bool RemoveSearchDirectory(string? path)
{
if (path is not null && this.SearchPaths.Remove(path))
{
this.Resolver.RemoveSearchDirectory(path);
return true;
}
return false;
}
///
public void Dispose()
{
this.Resolver.Dispose();
}
/*********
** Private methods
*********/
/// Resolve a known assembly definition based on its short or full name.
/// The assembly's short or full name.
private AssemblyDefinition? ResolveName(string name)
{
return this.Lookup.TryGetValue(name, out AssemblyDefinition? match)
? match
: null;
}
/// An internal wrapper around to allow access to its protected methods.
private class DefaultAssemblyResolverWrapper : DefaultAssemblyResolver
{
/// Add an assembly to the resolver.
/// The assembly to add.
public void AddAssembly(AssemblyDefinition assembly)
{
this.RegisterAssembly(assembly);
}
}
}
}