Decompiled source of CoronerFix v1.0.1

BepInEx\patchers\CoronerFix\CoronerFix.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("v0id")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Preloader patch for Coroner that silences false-positive \"Could not access dying player\" console spam.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("CoronerFix")]
[assembly: AssemblyTitle("CoronerFix")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CoronerFix
{
	public static class Patcher
	{
		private static readonly ManualLogSource Logger = Logger.CreateLogSource("CoronerFix");

		public static IEnumerable<string> TargetDLLs { get; } = new string[1] { "Coroner.dll" };

		public static void Initialize()
		{
			Logger.LogInfo((object)"Preloader initialized. Scanning for Coroner.dll...");
			try
			{
				string pluginPath = Paths.PluginPath;
				if (Directory.Exists(pluginPath))
				{
					string[] files = Directory.GetFiles(pluginPath, "Coroner.dll", SearchOption.AllDirectories);
					for (int i = 0; i < files.Length; i++)
					{
						TryPatchFile(files[i]);
					}
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error during scan/patch: {arg}");
			}
		}

		public static void Patch(AssemblyDefinition assembly)
		{
			if (((AssemblyNameReference)assembly.Name).Name == "Coroner")
			{
				PatchAssembly(assembly, null);
			}
		}

		public static void Finish()
		{
		}

		public static bool TryPatchFile(string filePath)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			try
			{
				DefaultAssemblyResolver val = new DefaultAssemblyResolver();
				((BaseAssemblyResolver)val).AddSearchDirectory(Paths.ManagedPath);
				((BaseAssemblyResolver)val).AddSearchDirectory(Paths.BepInExAssemblyDirectory);
				string directoryName = Path.GetDirectoryName(filePath);
				if (!string.IsNullOrEmpty(directoryName))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(directoryName);
				}
				using MemoryStream memoryStream = new MemoryStream(File.ReadAllBytes(filePath));
				ReaderParameters val2 = new ReaderParameters
				{
					AssemblyResolver = (IAssemblyResolver)(object)val
				};
				AssemblyDefinition val3 = AssemblyDefinition.ReadAssembly((Stream)memoryStream, val2);
				try
				{
					if (PatchAssembly(val3, (IAssemblyResolver?)(object)val))
					{
						string text = filePath + ".orig";
						if (!File.Exists(text))
						{
							File.Copy(filePath, text, overwrite: false);
						}
						using MemoryStream memoryStream2 = new MemoryStream();
						val3.Write((Stream)memoryStream2);
						File.WriteAllBytes(filePath, memoryStream2.ToArray());
						Logger.LogInfo((object)("Successfully patched and updated: " + filePath));
						return true;
					}
					Logger.LogInfo((object)(filePath + " is already compatible / patched."));
				}
				finally
				{
					((IDisposable)val3)?.Dispose();
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Failed to patch {filePath}: {arg}");
			}
			return false;
		}

		private static bool PatchAssembly(AssemblyDefinition asm, IAssemblyResolver? resolver)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			ModuleDefinition mainModule = asm.MainModule;
			int num = 0;
			Enumerator<TypeDefinition> enumerator = mainModule.Types.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					TypeDefinition current = enumerator.Current;
					List<TypeDefinition> list = new List<TypeDefinition>();
					list.Add(current);
					list.AddRange((IEnumerable<TypeDefinition>)current.NestedTypes);
					foreach (TypeDefinition item in list)
					{
						if (!(((MemberReference)item).FullName == "Coroner.Patch.CauseOfDeathPatchState"))
						{
							continue;
						}
						Enumerator<MethodDefinition> enumerator3 = item.Methods.GetEnumerator();
						try
						{
							while (enumerator3.MoveNext())
							{
								MethodDefinition current3 = enumerator3.Current;
								if (!current3.HasBody)
								{
									continue;
								}
								ILProcessor iLProcessor = current3.Body.GetILProcessor();
								Instruction[] array = current3.Body.Instructions.ToArray();
								foreach (Instruction val in array)
								{
									if (val.Operand != null && val.Operand.ToString().Contains("PluginLogger::Log"))
									{
										iLProcessor.InsertAfter(val, Instruction.Create(OpCodes.Pop));
										val.OpCode = OpCodes.Pop;
										val.Operand = null;
										num++;
									}
								}
							}
						}
						finally
						{
							((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
						}
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			if (num > 0)
			{
				Logger.LogInfo((object)$"Silenced {num} log calls in CauseOfDeathPatchState.");
			}
			return num > 0;
		}
	}
}