Decompiled source of PreloadManager v1.0.1

BepInEx/patchers/PreloadManager.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Mono.Cecil;
using Newtonsoft.Json;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PreloadManager")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PreloadManager")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("92838ac6-755a-4434-8fa6-d7c941a4e5f7")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace BepInEx.PreloadManager;

public static class Patcher
{
	public static ManualLogSource Logger = Logger.CreateLogSource(Id);

	private static readonly ConfigFile Config = new ConfigFile(Path.Combine(Paths.ConfigPath, Prefix + "." + Id + ".cfg"), true);

	public static ConfigEntry<bool> DisablePreloader;

	public static ConfigEntry<bool> DisableJsonSearch;

	public static ConfigEntry<string> ModList;

	public static string Prefix => "PXC";

	public static string Id => "PreloadManager";

	public static string JsonPattern => Id + ".json";

	public static List<string> PluginToNeuter { get; set; }

	public static IEnumerable<string> TargetDLLs { get; } = new string[0];


	public static void Initialize()
	{
		DateTime now = DateTime.Now;
		string text = "Preloader";
		DisablePreloader = Config.Bind<bool>(text, "Disable Preloader", false, "This will disable this preloader entirely");
		DisableJsonSearch = Config.Bind<bool>(text, "Disable Json Search", false, "Disable searching for any '" + JsonPattern + "' files in the config and plugin directories");
		ModList = Config.Bind<string>(text, "Mod List", "", "This is the list of mods to patch separated by semi-colons (;) and/or a path to a json file\n\nInternal path variables:\n%ConfigPath% = Config directory\n%PluginPath% = Plugin directory");
		if (DisablePreloader.Value)
		{
			Logger.LogMessage((object)"Preloader was disabled in the config - Skipping initialization!");
			return;
		}
		List<string> RawItemList = new List<string>();
		RawItemList = Utilities.ConvertFlatToList(ModList.Value);
		if (!DisableJsonSearch.Value)
		{
			List<string> searchPattern = new List<string> { "*" + JsonPattern + "*" };
			Utilities.InternalVars.Values.ToList().ForEach(delegate(string path)
			{
				List<FileInfo> list2 = Utilities.FindFilesParallel(searchPattern, path).ToList();
				if (list2 != null || list2.Count >= 1)
				{
					list2.ForEach(delegate(FileInfo file)
					{
						if (RawItemList == null)
						{
							RawItemList = new List<string>();
						}
						RawItemList.Add(file.FullName);
					});
				}
			});
		}
		List<string> list = Utilities.ResolvePluginList(RawItemList);
		if (list != null)
		{
			PluginToNeuter = list.Distinct().ToList();
		}
		if (PluginToNeuter == null || PluginToNeuter.Count < 1)
		{
			Logger.LogMessage((object)"Preloader has zero mods configured to modify - Skipping initialization!");
			return;
		}
		Logger.LogMessage((object)$"Initializing preloader event hooks to modify {PluginToNeuter.Count} plugins...");
		PluginToNeuter.ForEach(delegate(string plugin)
		{
			Logger.LogMessage((object)("Plugin to neuter: " + plugin));
		});
		AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
		TimeSpan value = DateTime.Now - now;
		Logger.LogMessage((object)("Finished initialization in: " + Utilities.ToFriendlyTime(value)));
	}

	private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs e)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		Harmony harmony = new Harmony(Id);
		List<PluginData> pluginInfo = Utilities.GetPluginInfo(e.LoadedAssembly);
		if (pluginInfo == null || pluginInfo.Count < 1)
		{
			return;
		}
		List<PluginData> list = pluginInfo.Where((PluginData b) => PluginToNeuter.Any((string p) => Regex.IsMatch(p, "^" + Regex.Escape(b.name.Trim()) + "$", RegexOptions.IgnoreCase))).ToList();
		if (list == null || list.Count < 1)
		{
			return;
		}
		HarmonyMethod harmonyMethod = new HarmonyMethod(typeof(Patcher).GetMethod("Neuter", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy));
		list.ForEach(delegate(PluginData plugin)
		{
			plugin.methods.ForEach(delegate(MethodInfo method)
			{
				string text = $"{plugin.name} v{plugin.version}";
				Logger.LogMessage((object)("Attempting to remove '" + method.Name + "' from: " + text));
				try
				{
					harmony.Patch((MethodBase)method, harmonyMethod, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Logger.LogMessage((object)("Successfully neutered: " + text));
				}
				catch (Exception ex)
				{
					Logger.LogError((object)("Failed to neuter: " + text + " - PLEASE REPORT THIS ON GITHUB!"));
					Logger.LogError((object)("Exception: " + ex.Message));
				}
			});
		});
	}

	private static bool Neuter()
	{
		return false;
	}

	public static void Patch(AssemblyDefinition _)
	{
	}
}
public class PluginData
{
	public string name;

	public Version version;

	public Type type;

	public List<MethodInfo> methods;
}
public static class Utilities
{
	public static Dictionary<string, string> InternalVars = new Dictionary<string, string>
	{
		{
			"%ConfigPath%",
			Paths.ConfigPath
		},
		{
			"%PluginPath%",
			Paths.PluginPath
		}
	};

	public static List<string> ConvertFlatToList(string list, char delimiter = ';')
	{
		if (string.IsNullOrEmpty(list))
		{
			return null;
		}
		list = Regex.Replace(list, "\\\"", "");
		return list.Split(new char[1] { delimiter }).ToList();
	}

	public static List<string> ResolvePluginList(List<string> list)
	{
		if (list == null || list.Count < 1)
		{
			return null;
		}
		List<string> retList = new List<string>();
		list.ForEach(delegate(string item)
		{
			if (Regex.IsMatch(item, "\\.json", RegexOptions.IgnoreCase))
			{
				string text = ExpandVariables(item, InternalVars);
				if (File.Exists(text))
				{
					Patcher.Logger.LogMessage((object)("Found json to load: " + text));
					List<string> collection = JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(text));
					retList.AddRange(collection);
				}
				else
				{
					Patcher.Logger.LogWarning((object)("Unable to find [ " + text + " ] to load plugin names - Skipping..."));
				}
			}
			else
			{
				retList.Add(item);
			}
		});
		return retList;
	}

	public static List<PluginData> GetPluginInfo(Assembly assembly)
	{
		List<PluginData> retList = null;
		(from t in assembly.GetTypes()
			where ((MemberInfo)t).GetCustomAttribute<BepInPlugin>() != null
			select t).ToList().ForEach(delegate(Type type)
		{
			BepInPlugin customAttribute = ((MemberInfo)type).GetCustomAttribute<BepInPlugin>();
			PluginData item = new PluginData
			{
				name = customAttribute.Name,
				version = customAttribute.Version,
				type = type,
				methods = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
					where m.Name == "Awake"
					select m).ToList()
			};
			if (retList == null)
			{
				retList = new List<PluginData>();
			}
			retList.Add(item);
		});
		return retList;
	}

	public static string ExpandVariables(string Item, Dictionary<string, string> Substitutions = null)
	{
		string text = Environment.ExpandEnvironmentVariables(Item);
		if (Substitutions != null)
		{
			foreach (KeyValuePair<string, string> Substitution in Substitutions)
			{
				text = text.Replace(Substitution.Key, Substitution.Value);
			}
		}
		return text;
	}

	public static IEnumerable<FileInfo> FindFilesParallel(List<string> searchPatterns, string path, string excludePattern = null)
	{
		return searchPatterns.AsParallel().SelectMany((string searchPattern) => GetManyFileInfo(path, searchPattern, excludePattern));
	}

	public static IEnumerable<FileInfo> GetManyFileInfo(string root, string searchPattern, string excludePattern = null)
	{
		Stack<string> pending = new Stack<string>();
		pending.Push(root);
		while (pending.Count != 0)
		{
			string path = pending.Pop();
			string[] array = null;
			try
			{
				array = Directory.GetFiles(path, searchPattern, SearchOption.AllDirectories);
			}
			catch
			{
			}
			if (array != null && array.Length != 0)
			{
				string[] array2 = array;
				foreach (string fileName in array2)
				{
					yield return new FileInfo(fileName);
				}
			}
			try
			{
				array = (string.IsNullOrEmpty(excludePattern) ? (from d in Directory.GetDirectories(path)
					where !Regex.IsMatch(d, excludePattern)
					select d).ToArray() : Directory.GetDirectories(path));
				string[] array3 = array;
				foreach (string item in array3)
				{
					pending.Push(item);
				}
			}
			catch
			{
			}
		}
	}

	public static string ToFriendlyTime(TimeSpan? InputObject, string FormatPattern = "{0:0.00}")
	{
		try
		{
			if (!InputObject.HasValue)
			{
				return null;
			}
			if (InputObject.Value.TotalSeconds < 60.0)
			{
				return string.Format(FormatPattern + " Second(s)", InputObject.Value.TotalSeconds);
			}
			if (InputObject.Value.TotalMinutes < 60.0)
			{
				return string.Format(FormatPattern + " Minute(s)", InputObject.Value.TotalMinutes);
			}
			if (InputObject.Value.TotalHours < 24.0)
			{
				return string.Format(FormatPattern + " Hour(s)", InputObject.Value.TotalHours);
			}
			return string.Format(FormatPattern + " Day(s)", InputObject.Value.TotalDays);
		}
		catch
		{
			return null;
		}
	}
}