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;
}
}
}