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); } } } }