/// <summary> /// Performs work to dispose collection objects. /// </summary> public void Dispose() { foreach (var assembly in AssembliesToPatch) { assembly.Value.Dispose(); } AssembliesToPatch.Clear(); // Clear to allow GC collection. PatcherPlugins.Clear(); }
/// <summary> /// Adds all patchers from all managed assemblies specified in a directory. /// </summary> /// <param name="directory">Directory to search patcher DLLs from.</param> public void AddPatchersFromDirectory(string directory) { if (!Directory.Exists(directory)) { return; } var sortedPatchers = new SortedDictionary <string, PatcherPlugin>(); var patchers = TypeLoader.FindPluginTypes(directory, ToPatcherPlugin); foreach (var keyValuePair in patchers) { var assemblyPath = keyValuePair.Key; var patcherCollection = keyValuePair.Value; if (patcherCollection.Count == 0) { continue; } var ass = Assembly.LoadFile(assemblyPath); foreach (var patcherPlugin in patcherCollection) { try { var type = ass.GetType(patcherPlugin.TypeName); var methods = type.GetMethods(ALL); patcherPlugin.Initializer = CreateDelegate <Action>(methods.FirstOrDefault(m => m.Name.Equals("Initialize", StringComparison.InvariantCultureIgnoreCase) && m.GetParameters().Length == 0 && m.ReturnType == typeof(void))); patcherPlugin.Finalizer = CreateDelegate <Action>(methods.FirstOrDefault(m => m.Name.Equals("Finish", StringComparison.InvariantCultureIgnoreCase) && m.GetParameters().Length == 0 && m.ReturnType == typeof(void))); patcherPlugin.TargetDLLs = CreateDelegate <Func <IEnumerable <string> > >(type.GetProperty("TargetDLLs", ALL).GetGetMethod()); var patcher = methods.FirstOrDefault(m => m.Name.Equals("Patch", StringComparison.CurrentCultureIgnoreCase) && m.ReturnType == typeof(void) && m.GetParameters().Length == 1 && (m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition) || m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition).MakeByRefType())); patcherPlugin.Patcher = (ref AssemblyDefinition pAss) => { //we do the array fuckery here to get the ref result out object[] args = { pAss }; patcher.Invoke(null, args); pAss = (AssemblyDefinition)args[0]; }; sortedPatchers.Add($"{ass.GetName().Name}/{type.FullName}", patcherPlugin); } catch (Exception e) { Logger.LogError($"Failed to load patcher [{patcherPlugin.TypeName}]: {e.Message}"); if (e is ReflectionTypeLoadException re) { Logger.LogDebug(TypeLoader.TypeLoadExceptionToString(re)); } else { Logger.LogDebug(e.ToString()); } } } var assName = ass.GetName(); Logger.Log(patcherCollection.Any() ? LogLevel.Info : LogLevel.Debug, $"Loaded {patcherCollection.Count} patcher method{(patcherCollection.Count == 1 ? "" : "s")} from [{assName.Name} {assName.Version}]"); } foreach (KeyValuePair <string, PatcherPlugin> patcher in sortedPatchers) { PatcherPlugins.Add(patcher.Value); } }