Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LogNeuter v1.0.3
plugins/LogNeuter.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("LogNeuter")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("LogNeuter")] [assembly: AssemblyCopyright("Copyright © BlueAmulet 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("de27b4d1-820d-4505-a953-6001420281e4")] [assembly: AssemblyFileVersion("1.0.3")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.0.3.0")] namespace LogNeuter; [BepInPlugin("BlueAmulet.LogNeuter", "LogNeuter", "1.0.3")] public class LogNeuter : BaseUnityPlugin { internal const string Name = "LogNeuter"; internal const string Author = "BlueAmulet"; internal const string Version = "1.0.3"; private const string ID = "BlueAmulet.LogNeuter"; private static ManualLogSource Log; private static ConfigFile ConfigFile; private const int ConfVersion = 1; private static ConfigEntry<int> version; private static ConfigEntry<bool> fixSpatializer; private static ConfigEntry<bool> fixLookRotation; private static ConfigEntry<bool> genBlockAll; private static bool allowSave = false; private static bool warnSave = true; private static readonly Harmony harmony = new Harmony("BlueAmulet.LogNeuter"); private static readonly HarmonyMethod transpiler = new HarmonyMethod(AccessTools.Method(typeof(LogNeuter), "Transpiler", (Type[])null, (Type[])null)); private static readonly Dictionary<string, HashSet<string>> staticLogs = new Dictionary<string, HashSet<string>>(); private static readonly Dictionary<string, List<Regex>> dynamicLogs = new Dictionary<string, List<Regex>>(); private static StreamWriter genFile; public void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Expected O, but got Unknown //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Expected O, but got Unknown //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigFile = ((BaseUnityPlugin)this).Config; SceneManager.sceneLoaded += OnSceneLoaded; MethodBase methodBase = AccessTools.Method(typeof(ConfigFile), "Save", (Type[])null, (Type[])null); HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(LogNeuter), "PrefixConfigSave", (Type[])null, (Type[])null)); harmony.Patch(methodBase, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (AccessTools.DeclaredPropertyGetter(typeof(ConfigFile), "OrphanedEntries")?.Invoke(((BaseUnityPlugin)this).Config, null) is Dictionary<ConfigDefinition, string> dictionary) { ConfigDefinition key = new ConfigDefinition("Config", "Version"); if (dictionary.Count != 0 && !dictionary.ContainsKey(key)) { dictionary[key] = "0"; } } warnSave = false; version = ((BaseUnityPlugin)this).Config.Bind<int>("Config", "Version", 1, "Disable broken spatialize on audio sources"); fixSpatializer = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "FixSpatializer", true, "Disable broken spatialize on audio sources"); fixLookRotation = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "FixLookRotation", true, "Mask \"Look rotation viewing vector is zero\" messages"); genBlockAll = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "GenBlockAll", false, "Generate a config file that blocks all logging"); warnSave = true; if (version.Value < 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Configuration out of date, expected version {1}, got {version.Value}"); } else if (version.Value > 1) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Configuration too new, expected version {1}, got {version.Value}"); } if (genBlockAll.Value) { Assembly assembly = Array.Find(AppDomain.CurrentDomain.GetAssemblies(), (Assembly a) => a.GetName().Name == "Assembly-CSharp"); if (assembly != null) { genFile = new StreamWriter(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), "BlueAmulet.LogNeuter.Generated.cfg"), append: false, Encoding.UTF8); genFile.WriteLine("## This is a generated file, it does not actively do anything and only serves as reference for the real config file"); Harmony val2 = new Harmony("BlueAmulet.LogNeuter.Generated"); HarmonyMethod val3 = new HarmonyMethod(AccessTools.Method(typeof(LogNeuter), "TranspilerGen", (Type[])null, (Type[])null)); Type[] types = assembly.GetTypes(); foreach (Type type in types) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Scanning " + type.FullName)); MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { try { val2.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null); val2.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)3, "BlueAmulet.LogNeuter.Generated"); } catch (HarmonyException) { } } } genFile.Close(); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find Assembly-CSharp, generation skipped"); } } if (fixLookRotation.Value) { MethodBase methodBase2 = AccessTools.Method(typeof(Quaternion), "LookRotation", new Type[2] { typeof(Vector3), typeof(Vector3) }, (Type[])null); HarmonyMethod val5 = new HarmonyMethod(AccessTools.Method(typeof(LogNeuter), "TranspilerLookRotation", (Type[])null, (Type[])null)); harmony.Patch(methodBase2, (HarmonyMethod)null, (HarmonyMethod)null, val5, (HarmonyMethod)null, (HarmonyMethod)null); } if (File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { MethodBase methodBase3 = null; string text = null; foreach (string item in File.ReadLines(((BaseUnityPlugin)this).Config.ConfigFilePath)) { string text2 = item.Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]")) { PatchMethod(methodBase3); methodBase3 = null; staticLogs.Clear(); text = text2.Substring(1, text2.Length - 2); if (!text.Contains("|")) { continue; } string[] array = text.Split(new char[1] { '|' }, 2); if (array.Length == 2) { string text3 = array[0]; if (!text3.Contains(",")) { text3 += ", Assembly-CSharp"; } Type type2 = Type.GetType(text3); if (type2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find type: " + array[0])); continue; } try { methodBase3 = AccessTools.Method(type2, array[1], (Type[])null, (Type[])null); if (methodBase3 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find method: " + text)); } } catch (AmbiguousMatchException ex) { methodBase3 = null; ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Unknown entry: " + text)); } } else { if (text == null) { continue; } if (text2.StartsWith("^") && text2.EndsWith("$")) { if (!dynamicLogs.ContainsKey(text)) { dynamicLogs[text] = new List<Regex>(); } dynamicLogs[text].Add(new Regex(text2, RegexOptions.Compiled)); } else { if (!staticLogs.ContainsKey(text)) { staticLogs[text] = new HashSet<string>(); } staticLogs[text].Add(text2); } } } PatchMethod(methodBase3); } else { allowSave = true; ((BaseUnityPlugin)this).Config.Save(); allowSave = false; } int num = 0; foreach (MethodBase patchedMethod in harmony.GetPatchedMethods()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched " + patchedMethod.DeclaringType.Name + "." + patchedMethod.Name)); num++; } ((BaseUnityPlugin)this).Logger.LogInfo((object)(num + " patches applied")); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (!fixSpatializer.Value) { return; } int num = 0; AudioSource[] array = Resources.FindObjectsOfTypeAll<AudioSource>(); foreach (AudioSource val in array) { if (val.spatialize) { val.spatialize = false; num++; } } if (num > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Fixed {num} spatilization settings"); } } private static bool PrefixConfigSave(ref ConfigFile __instance) { if (__instance == ConfigFile && !allowSave) { if (warnSave) { Log.LogWarning((object)"Saving LogNeuter config blocked for data loss prevention"); } return false; } return true; } private static IEnumerable<CodeInstruction> TranspilerLookRotation(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); Label label = generator.DefineLabel(); list[0].labels.Add(label); list.InsertRange(0, new List<CodeInstruction> { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(Vector3), "zero")), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Vector3), "op_Equality", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Brfalse_S, (object)label), new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(Quaternion), "identity")), new CodeInstruction(OpCodes.Ret, (object)null) }); return list; } private static void PatchMethod(MethodBase patchMethod) { //IL_0043: Expected O, but got Unknown if (!(patchMethod != null)) { return; } string key = SectionName(patchMethod); if (staticLogs.ContainsKey(key) || dynamicLogs.ContainsKey(key)) { try { harmony.Patch(patchMethod, (HarmonyMethod)null, (HarmonyMethod)null, transpiler, (HarmonyMethod)null, (HarmonyMethod)null); } catch (HarmonyException val) { HarmonyException val2 = val; Log.LogError((object)val2); } } } private static string SectionName(MethodBase method) { Type declaringType = method.DeclaringType; string name = declaringType.Assembly.GetName().Name; if (name == "Assembly-CSharp") { return declaringType.FullName + "|" + method.Name; } return declaringType.FullName + ", " + name + "|" + method.Name; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original) { //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown string text = SectionName(original); bool flag = false; List<CodeInstruction> list = new List<CodeInstruction>(instructions); for (int i = 1; i < list.Count; i++) { CodeInstruction val = list[i]; if (!(val.opcode == OpCodes.Call) || !(val.operand is MethodInfo methodInfo) || !methodInfo.IsStatic || !(methodInfo.DeclaringType == typeof(Debug)) || !methodInfo.Name.StartsWith("Log") || !(methodInfo.Name != "LogException")) { continue; } CodeInstruction val2 = list[i - 1]; if (val2.opcode == OpCodes.Ldstr) { if (staticLogs.ContainsKey(text) && staticLogs[text].Contains((string)val2.operand)) { list[i] = new CodeInstruction(OpCodes.Pop, (object)null); flag = true; } } else if (dynamicLogs.ContainsKey(text)) { string text2 = methodInfo.Name + methodInfo.GetParameters().Length; MethodInfo methodInfo2 = AccessTools.Method(typeof(LogNeuter), text2, (Type[])null, (Type[])null); if (methodInfo2 != null) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2); list.Insert(i, new CodeInstruction(OpCodes.Ldstr, (object)text)); flag = true; } } } if (!flag) { Log.LogWarning((object)("Made no changes to method: " + text)); } return list; } private static void GenWriteEntry(ref bool wroteHeader, string section, HashSet<string> strings, string log) { if (!strings.Contains(log)) { strings.Add(log); if (!wroteHeader) { genFile.WriteLine(); genFile.WriteLine("[" + section + "]"); wroteHeader = true; } if (!log.Contains("=")) { genFile.WriteLine(log); } } } private static IEnumerable<CodeInstruction> TranspilerGen(IEnumerable<CodeInstruction> instructions, MethodBase original) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); Stream baseStream = genFile.BaseStream; if (baseStream != null && baseStream.CanWrite) { string section = SectionName(original); bool wroteHeader = false; HashSet<string> strings = new HashSet<string>(); for (int i = 1; i < list.Count; i++) { CodeInstruction val = list[i]; if (!(val.opcode == OpCodes.Call) || !(val.operand is MethodInfo methodInfo) || !methodInfo.IsStatic || !(methodInfo.DeclaringType == typeof(Debug)) || !methodInfo.Name.StartsWith("Log")) { continue; } CodeInstruction val2 = list[i - 1]; if (val2.opcode == OpCodes.Ldstr) { GenWriteEntry(ref wroteHeader, section, strings, (string)val2.operand); } else { if (!(val2.opcode == OpCodes.Call) || !(val2.operand is MethodInfo methodInfo2) || !methodInfo2.IsStatic || !(methodInfo2.DeclaringType == typeof(string)) || !(methodInfo2.Name == "Format")) { continue; } ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 0 || !(parameters[0].ParameterType == typeof(string))) { continue; } int num = i; do { num--; } while ((list[num].opcode != OpCodes.Ldstr || !((string)list[num].operand).Contains("{")) && num > 0); CodeInstruction val3 = list[num]; if (val3.opcode == OpCodes.Ldstr) { string text = (string)val3.operand; if (text.Contains("{") && text.Contains("}")) { string text2 = Regex.Escape(text); text2 = text2.Replace("\\ ", " "); text2 = Regex.Replace(text2, "\\\\{[0-9]+}", ".*?"); GenWriteEntry(ref wroteHeader, section, strings, "^" + text2 + "$"); } } } } } return list; } private static bool MatchAny(string section, string log) { if (section == null || !dynamicLogs.ContainsKey(section)) { return false; } foreach (Regex item in dynamicLogs[section]) { if (item.IsMatch(log)) { return true; } } return false; } public static void Log1(object message, string section) { if (!MatchAny(section, message.ToString())) { Debug.Log(message); } } public static void LogWarning1(object message, string section) { if (!MatchAny(section, message.ToString())) { Debug.LogWarning(message); } } public static void LogWarning2(object message, Object context, string section) { if (!MatchAny(section, message.ToString())) { Debug.LogWarning(message, context); } } public static void LogError1(object message, string section) { if (!MatchAny(section, message.ToString())) { Debug.LogError(message); } } public static void LogError2(object message, Object context, string section) { if (!MatchAny(section, message.ToString())) { Debug.LogError(message, context); } } }