Jelajahi Sumber

Publicize AssemblyPatcher for better extendability

ghorsington 4 tahun lalu
induk
melakukan
51f5ceda12
1 mengubah file dengan 37 tambahan dan 6 penghapusan
  1. 37 6
      BepInEx.Preloader/Patching/AssemblyPatcher.cs

+ 37 - 6
BepInEx.Preloader/Patching/AssemblyPatcher.cs

@@ -17,13 +17,13 @@ namespace BepInEx.Preloader.Patching
 	///     Delegate used in patching assemblies.
 	/// </summary>
 	/// <param name="assembly">The assembly that is being patched.</param>
-	internal delegate void AssemblyPatcherDelegate(ref AssemblyDefinition assembly);
+	public delegate void AssemblyPatcherDelegate(ref AssemblyDefinition assembly);
 
 	/// <summary>
 	///     Worker class which is used for loading and patching entire folders of assemblies, or alternatively patching and
 	///     loading assemblies one at a time.
 	/// </summary>
-	internal static class AssemblyPatcher
+	public static class AssemblyPatcher
 	{
 		private const BindingFlags ALL = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase;
 
@@ -153,13 +153,31 @@ namespace BepInEx.Preloader.Patching
 		private static void InitializePatchers()
 		{
 			foreach (var assemblyPatcher in PatcherPlugins)
-				assemblyPatcher.Initializer?.Invoke();
+			{
+				try
+				{
+					assemblyPatcher.Initializer?.Invoke();
+				}
+				catch (Exception e)
+				{
+					Logger.LogError($"Failed to run Initializer of {assemblyPatcher.TypeName}: {e}");
+				}
+			}
 		}
 
 		private static void FinalizePatching()
 		{
 			foreach (var assemblyPatcher in PatcherPlugins)
-				assemblyPatcher.Finalizer?.Invoke();
+			{
+				try
+				{
+					assemblyPatcher.Finalizer?.Invoke();
+				}
+				catch (Exception e)
+				{
+					Logger.LogError($"Failed to run Finalizer of {assemblyPatcher.TypeName}: {e}");
+				}
+			}
 		}
 
 		/// <summary>
@@ -233,13 +251,26 @@ namespace BepInEx.Preloader.Patching
 			// Then, perform the actual patching
 			var patchedAssemblies = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
 			var resolvedAssemblies = new Dictionary<string, string>();
+			// TODO: Maybe instead reload the assembly and repatch with other valid patchers?
+			var invalidAssemblies = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
 			foreach (var assemblyPatcher in PatcherPlugins)
 				foreach (string targetDll in assemblyPatcher.TargetDLLs())
-					if (assemblies.TryGetValue(targetDll, out var assembly))
+					if (assemblies.TryGetValue(targetDll, out var assembly) && !invalidAssemblies.Contains(targetDll))
 					{
 						Logger.LogInfo($"Patching [{assembly.Name.Name}] with [{assemblyPatcher.TypeName}]");
 
-						assemblyPatcher.Patcher?.Invoke(ref assembly);
+						try
+						{
+							assemblyPatcher.Patcher?.Invoke(ref assembly);
+						}
+						catch (Exception e)
+						{
+							Logger.LogError($"Failed to run [{assemblyPatcher.TypeName}] when patching [{assembly.Name.Name}]. This assembly will not be patched. Error: {e}");
+							patchedAssemblies.Remove(targetDll);
+							invalidAssemblies.Add(targetDll);
+							continue;
+						}
+						
 						assemblies[targetDll] = assembly;
 						patchedAssemblies.Add(targetDll);