// Consolidated decompiled source — SunkenlandModding-BepInExPack_Sunkenland v5.4.22 // Generated by Hexium's decompiled-source browser. Best-effort concatenation of every type in this // version's manifest — decompiler output isn't guaranteed to compile as-is. using System.Runtime.CompilerServices; using System; using System.Runtime.InteropServices; using System.Text; using BepInEx; using BepInEx.ConsoleUtil; using MonoMod.Utils; using System.Reflection; using BepInEx.Logging; using UnityEngine; using System.Collections.Generic; using System.Linq; using System.Reflection.Emit; using HarmonyLib; using System.ComponentModel; using System.IO; using BepInEx.Configuration; using BepInEx.Unix; using Microsoft.Win32.SafeHandles; using UnityInjector.ConsoleUtil; using BepInEx.Bootstrap; using Mono.Cecil; using System.Threading; using HarmonyLib.Tools; using System.Collections; using System.Diagnostics; using System.Text.RegularExpressions; using System.Security.Permissions; using System.Collections.ObjectModel; using System.Globalization; using HarmonyLib.Public.Patching; using BepInEx.Preloader.RuntimeFixes; using BepInEx.Preloader.Patching; using Mono.Cecil.Cil; using HarmonyXInterop; using MonoMod.RuntimeDetour; using MonoMod.RuntimeDetour.Platforms; using JetBrains.Annotations; using HarmonyLib.Internal; using HarmonyLib.Internal.Patching; using MonoMod.Utils.Cil; using MonoMod.Cil; using System.Linq.Expressions; using System.Security.Cryptography; using System.Runtime.Serialization; using HarmonyLib.Internal.Util; // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: UnityEngine.UnityLogWriter ---- namespace UnityEngine { internal sealed class UnityLogWriter { [MethodImpl(MethodImplOptions.InternalCall)] public static extern void WriteStringToUnityLogImpl(string s); [MethodImpl(MethodImplOptions.InternalCall)] public static extern void WriteStringToUnityLog(string s); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: UnityInjector.ConsoleUtil.ConsoleEncoding ---- namespace UnityInjector.ConsoleUtil { internal class ConsoleEncoding : Encoding { private byte[] _byteBuffer = new byte[256]; private char[] _charBuffer = new char[256]; private byte[] _zeroByte = new byte[0]; private char[] _zeroChar = new char[0]; private readonly uint _codePage; public override int CodePage => (int)_codePage; public static Encoding OutputEncoding => new ConsoleEncoding(ConsoleCodePage); public static uint ConsoleCodePage { get { return GetConsoleOutputCP(); } set { SetConsoleOutputCP(value); } } private void ExpandByteBuffer(int count) { if (_byteBuffer.Length < count) { _byteBuffer = new byte[count]; } } private void ExpandCharBuffer(int count) { if (_charBuffer.Length < count) { _charBuffer = new char[count]; } } private void ReadByteBuffer(byte[] bytes, int index, int count) { for (int i = 0; i < count; i++) { bytes[index + i] = _byteBuffer[i]; } } private void ReadCharBuffer(char[] chars, int index, int count) { for (int i = 0; i < count; i++) { chars[index + i] = _charBuffer[i]; } } private void WriteByteBuffer(byte[] bytes, int index, int count) { ExpandByteBuffer(count); for (int i = 0; i < count; i++) { _byteBuffer[i] = bytes[index + i]; } } private void WriteCharBuffer(char[] chars, int index, int count) { ExpandCharBuffer(count); for (int i = 0; i < count; i++) { _charBuffer[i] = chars[index + i]; } } public static uint GetActiveCodePage() { return GetACP(); } private ConsoleEncoding(uint codePage) { _codePage = codePage; } public static ConsoleEncoding GetEncoding(uint codePage) { return new ConsoleEncoding(codePage); } public override int GetByteCount(char[] chars, int index, int count) { WriteCharBuffer(chars, index, count); return WideCharToMultiByte(_codePage, 0u, _charBuffer, count, _zeroByte, 0, IntPtr.Zero, IntPtr.Zero); } public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { int byteCount = GetByteCount(chars, charIndex, charCount); WriteCharBuffer(chars, charIndex, charCount); ExpandByteBuffer(byteCount); int result = WideCharToMultiByte(_codePage, 0u, chars, charCount, _byteBuffer, byteCount, IntPtr.Zero, IntPtr.Zero); ReadByteBuffer(bytes, byteIndex, byteCount); return result; } public override int GetCharCount(byte[] bytes, int index, int count) { WriteByteBuffer(bytes, index, count); return MultiByteToWideChar(_codePage, 0u, bytes, count, _zeroChar, 0); } public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { int charCount = GetCharCount(bytes, byteIndex, byteCount); WriteByteBuffer(bytes, byteIndex, byteCount); ExpandCharBuffer(charCount); int result = MultiByteToWideChar(_codePage, 0u, bytes, byteCount, _charBuffer, charCount); ReadCharBuffer(chars, charIndex, charCount); return result; } public override int GetMaxByteCount(int charCount) { return charCount * 2; } public override int GetMaxCharCount(int byteCount) { return byteCount; } [DllImport("kernel32.dll")] private static extern uint GetConsoleOutputCP(); [DllImport("kernel32.dll")] private static extern uint GetACP(); [DllImport("kernel32.dll", SetLastError = true)] private static extern int MultiByteToWideChar(uint codePage, uint dwFlags, [In][MarshalAs(UnmanagedType.LPArray)] byte[] lpMultiByteStr, int cbMultiByte, [Out][MarshalAs(UnmanagedType.LPWStr)] char[] lpWideCharStr, int cchWideChar); [DllImport("kernel32.dll")] private static extern IntPtr SetConsoleOutputCP(uint codepage); [DllImport("kernel32.dll", SetLastError = true)] private static extern int WideCharToMultiByte(uint codePage, uint dwFlags, [In][MarshalAs(UnmanagedType.LPWStr)] char[] lpWideCharStr, int cchWideChar, [Out][MarshalAs(UnmanagedType.LPArray)] byte[] lpMultiByteStr, int cbMultiByte, IntPtr lpDefaultChar, IntPtr lpUsedDefaultChar); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: UnityInjector.ConsoleUtil.ConsoleWindow ---- namespace UnityInjector.ConsoleUtil { internal class ConsoleWindow { [UnmanagedFunctionPointer(CallingConvention.Winapi)] [return: MarshalAs(UnmanagedType.Bool)] private delegate bool SetForegroundWindowDelegate(IntPtr hWnd); [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate IntPtr GetForegroundWindowDelegate(); [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate IntPtr GetSystemMenuDelegate(IntPtr hwnd, bool bRevert); [UnmanagedFunctionPointer(CallingConvention.Winapi)] private delegate bool DeleteMenuDelegate(IntPtr hMenu, uint uPosition, uint uFlags); private const uint SC_CLOSE = 61536u; private const uint MF_BYCOMMAND = 0u; private const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 2048u; public static IntPtr ConsoleOutHandle; public static IntPtr OriginalStdoutHandle; private static bool methodsInited; private static SetForegroundWindowDelegate setForeground; private static GetForegroundWindowDelegate getForeground; private static GetSystemMenuDelegate getSystemMenu; private static DeleteMenuDelegate deleteMenu; public static bool IsAttached { get; private set; } public static string Title { set { if (IsAttached) { if (value == null) { throw new ArgumentNullException("value"); } if (value.Length > 24500) { throw new InvalidOperationException("Console title too long"); } if (!SetConsoleTitle(value)) { throw new InvalidOperationException("Console title invalid"); } } } } public static void Attach() { if (!IsAttached) { Initialize(); if (OriginalStdoutHandle == IntPtr.Zero) { OriginalStdoutHandle = GetStdHandle(-11); } IntPtr hWnd = getForeground(); GetConsoleWindow(); if (GetConsoleWindow() == IntPtr.Zero && !AllocConsole()) { throw new Exception("AllocConsole() failed"); } setForeground(hWnd); ConsoleOutHandle = CreateFile("CONOUT$", 3221225472u, 2, IntPtr.Zero, 3, 0, IntPtr.Zero); Kon.conOut = ConsoleOutHandle; if (!SetStdHandle(-11, ConsoleOutHandle)) { throw new Exception("SetStdHandle() failed"); } if (OriginalStdoutHandle != IntPtr.Zero && ConsoleManager.ConfigConsoleOutRedirectType.Value == ConsoleManager.ConsoleOutRedirectType.ConsoleOut) { CloseHandle(OriginalStdoutHandle); } IsAttached = true; } } public static void PreventClose() { if (IsAttached) { Initialize(); IntPtr consoleWindow = GetConsoleWindow(); IntPtr intPtr = getSystemMenu(consoleWindow, bRevert: false); if (intPtr != IntPtr.Zero) { deleteMenu(intPtr, 61536u, 0u); } } } public static void Detach() { if (IsAttached) { if (!CloseHandle(ConsoleOutHandle)) { throw new Exception("CloseHandle() failed"); } ConsoleOutHandle = IntPtr.Zero; if (!FreeConsole()) { throw new Exception("FreeConsole() failed"); } if (!SetStdHandle(-11, OriginalStdoutHandle)) { throw new Exception("SetStdHandle() failed"); } IsAttached = false; } } private static void Initialize() { if (!methodsInited) { methodsInited = true; IntPtr hModule = LoadLibraryEx("user32.dll", IntPtr.Zero, 2048u); setForeground = GetProcAddress(hModule, "SetForegroundWindow").AsDelegate(); getForeground = GetProcAddress(hModule, "GetForegroundWindow").AsDelegate(); getSystemMenu = GetProcAddress(hModule, "GetSystemMenu").AsDelegate(); deleteMenu = GetProcAddress(hModule, "DeleteMenu").AsDelegate(); } } [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool AllocConsole(); [DllImport("kernel32.dll")] private static extern IntPtr GetConsoleWindow(); [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] private static extern bool CloseHandle(IntPtr handle); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CreateFile(string fileName, uint desiredAccess, int shareMode, IntPtr securityAttributes, int creationDisposition, int flagsAndAttributes, IntPtr templateFile); [DllImport("kernel32.dll")] private static extern bool FreeConsole(); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput); [DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Auto, SetLastError = true)] private static extern bool SetConsoleTitle(string title); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: UnityInjector.ConsoleUtil.SafeConsole ---- namespace UnityInjector.ConsoleUtil { internal static class SafeConsole { private delegate ConsoleColor GetColorDelegate(); private delegate void SetColorDelegate(ConsoleColor value); private delegate string GetStringDelegate(); private delegate void SetStringDelegate(string value); private static GetColorDelegate _getBackgroundColor; private static SetColorDelegate _setBackgroundColor; private static GetColorDelegate _getForegroundColor; private static SetColorDelegate _setForegroundColor; private static GetStringDelegate _getTitle; private static SetStringDelegate _setTitle; public static bool BackgroundColorExists { get; private set; } public static ConsoleColor BackgroundColor { get { return _getBackgroundColor(); } set { _setBackgroundColor(value); } } public static bool ForegroundColorExists { get; private set; } public static ConsoleColor ForegroundColor { get { return _getForegroundColor(); } set { _setForegroundColor(value); } } public static bool TitleExists { get; private set; } public static string Title { get { return _getTitle(); } set { _setTitle(value); } } static SafeConsole() { InitColors(typeof(Console)); } private static void InitColors(Type tConsole) { MethodInfo method = tConsole.GetMethod("get_ForegroundColor", BindingFlags.Static | BindingFlags.Public); MethodInfo method2 = tConsole.GetMethod("set_ForegroundColor", BindingFlags.Static | BindingFlags.Public); MethodInfo method3 = tConsole.GetMethod("get_BackgroundColor", BindingFlags.Static | BindingFlags.Public); MethodInfo method4 = tConsole.GetMethod("set_BackgroundColor", BindingFlags.Static | BindingFlags.Public); MethodInfo method5 = tConsole.GetMethod("get_Title", BindingFlags.Static | BindingFlags.Public); MethodInfo method6 = tConsole.GetMethod("set_Title", BindingFlags.Static | BindingFlags.Public); _setForegroundColor = (((object)method2 != null) ? ((SetColorDelegate)Delegate.CreateDelegate(typeof(SetColorDelegate), method2)) : ((SetColorDelegate)delegate { })); _setBackgroundColor = (((object)method4 != null) ? ((SetColorDelegate)Delegate.CreateDelegate(typeof(SetColorDelegate), method4)) : ((SetColorDelegate)delegate { })); _getForegroundColor = (((object)method != null) ? ((GetColorDelegate)Delegate.CreateDelegate(typeof(GetColorDelegate), method)) : ((GetColorDelegate)(() => ConsoleColor.Gray))); _getBackgroundColor = (((object)method3 != null) ? ((GetColorDelegate)Delegate.CreateDelegate(typeof(GetColorDelegate), method3)) : ((GetColorDelegate)(() => ConsoleColor.Black))); _getTitle = (((object)method5 != null) ? ((GetStringDelegate)Delegate.CreateDelegate(typeof(GetStringDelegate), method5)) : ((GetStringDelegate)(() => string.Empty))); _setTitle = (((object)method6 != null) ? ((SetStringDelegate)Delegate.CreateDelegate(typeof(SetStringDelegate), method6)) : ((SetStringDelegate)delegate { })); BackgroundColorExists = _setBackgroundColor != null && _getBackgroundColor != null; ForegroundColorExists = _setForegroundColor != null && _getForegroundColor != null; TitleExists = _setTitle != null && _getTitle != null; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.UnityInput ---- namespace BepInEx { public static class UnityInput { private static IInputSystem _current; public static IInputSystem Current { get { if (_current != null) { return _current; } try { try { Input.GetKeyDown(KeyCode.A); _current = new LegacyInputSystem(); BepInEx.Logging.Logger.LogDebug("[UnityInput] Using LegacyInputSystem"); } catch (InvalidOperationException) { _current = new NewInputSystem(); BepInEx.Logging.Logger.LogDebug("[UnityInput] Using NewInputSystem"); } } catch (Exception arg) { BepInEx.Logging.Logger.LogWarning($"[UnityInput] Failed to detect available input systems - {arg}"); _current = new NullInputSystem(); } return _current; } } public static bool LegacyInputSystemAvailable => Current is LegacyInputSystem; } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.IInputSystem ---- namespace BepInEx { public interface IInputSystem { Vector3 mousePosition { get; } Vector2 mouseScrollDelta { get; } bool mousePresent { get; } bool anyKey { get; } bool anyKeyDown { get; } IEnumerable SupportedKeyCodes { get; } bool GetKey(string name); bool GetKey(KeyCode key); bool GetKeyDown(string name); bool GetKeyDown(KeyCode key); bool GetKeyUp(string name); bool GetKeyUp(KeyCode key); bool GetMouseButton(int button); bool GetMouseButtonDown(int button); bool GetMouseButtonUp(int button); void ResetInputAxes(); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.NewInputSystem ---- namespace BepInEx { internal class NewInputSystem : IInputSystem { private delegate bool GetButtonDelegate(KeyCode key); private delegate Vector2 GetMouseVectorDelegate(); private delegate bool GetMouseStateDelegate(); private static bool initialized; private static readonly Dictionary keyCodeToIndex = new Dictionary(); private static readonly Dictionary keyToKeyCodeNameRemap = new Dictionary { ["LeftCtrl"] = "LeftControl", ["RightCtrl"] = "RightControl", ["LeftMeta"] = "LeftApple", ["RightMeta"] = "RightApple", ["ContextMenu"] = "Menu", ["PrintScreen"] = "Print", ["Enter"] = "Return" }; private static GetButtonDelegate _getKey; private static GetButtonDelegate _getKeyDown; private static GetButtonDelegate _getKeyUp; private static GetButtonDelegate _getMouseButton; private static GetButtonDelegate _getMouseButtonDown; private static GetButtonDelegate _getMouseButtonUp; private static GetMouseVectorDelegate _getMousePosition; private static GetMouseVectorDelegate _getMouseScrollDelta; private static GetMouseStateDelegate _getMousePresent; private static GetMouseStateDelegate _getKeyboardAnyKeyIsPressed; private static GetMouseStateDelegate _getKeyboardAnyKeyWasPressedThisFrame; public Vector3 mousePosition => _getMousePosition(); public Vector2 mouseScrollDelta => _getMouseScrollDelta(); public bool mousePresent => _getMousePresent(); public bool anyKey { get { if (_getKeyboardAnyKeyIsPressed()) { return true; } if (!GetMouseButton(0) && !GetMouseButton(1) && !GetMouseButton(2) && !GetMouseButton(3)) { return GetMouseButton(4); } return true; } } public bool anyKeyDown { get { if (_getKeyboardAnyKeyWasPressedThisFrame()) { return true; } if (!GetMouseButtonDown(0) && !GetMouseButtonDown(1) && !GetMouseButtonDown(2) && !GetMouseButtonDown(3)) { return GetMouseButtonDown(4); } return true; } } public IEnumerable SupportedKeyCodes => keyCodeToIndex.Keys.ToArray(); public NewInputSystem() { Init(); } private static void Init() { if (initialized) { return; } Assembly assembly = Assembly.Load("Unity.InputSystem"); Type type = assembly.GetType("UnityEngine.InputSystem.Key"); foreach (object value3 in Enum.GetValues(type)) { string text = value3.ToString(); int value = (int)value3; string value2; if (text.StartsWith("Numpad")) { text = text.Replace("Numpad", "Keypad"); } else if (text.StartsWith("Digit")) { text = text.Replace("Digit", "Alpha"); } else if (keyToKeyCodeNameRemap.TryGetValue(text, out value2)) { text = value2; } if (TryEnumParse(text, out var val)) { keyCodeToIndex[val] = value; } else { BepInEx.Logging.Logger.LogDebug("[UnityInput] Unknown key name: " + text + ", skipping remapping"); } } FieldInfo keyCodeToIndexField = AccessTools.Field(typeof(NewInputSystem), "keyCodeToIndex"); MethodInfo tryGetValueMethod = AccessTools.Method(typeof(Dictionary), "TryGetValue"); Type type2 = assembly.GetType("UnityEngine.InputSystem.Keyboard"); MethodInfo currentProperty = AccessTools.PropertyGetter(type2, "current"); MethodInfo indexer = AccessTools.Method(type2, "get_Item", new Type[1] { type }); Type buttonControlType = assembly.GetType("UnityEngine.InputSystem.Controls.ButtonControl"); _getKey = GenerateKeyGetter("InputSystemGetKey", "isPressed"); _getKeyDown = GenerateKeyGetter("InputSystemGetKeyDown", "wasPressedThisFrame"); _getKeyUp = GenerateKeyGetter("InputSystemGetKeyUp", "wasReleasedThisFrame"); Type mouseType = assembly.GetType("UnityEngine.InputSystem.Mouse"); MethodInfo mouseCurrentProperty = AccessTools.PropertyGetter(mouseType, "current"); string[] source = new string[5] { "leftButton", "rightButton", "middleButton", "backButton", "forwardButton" }; MethodInfo[] buttonPropertyGetters = source.Select((string p) => AccessTools.PropertyGetter(mouseType, p)).ToArray(); _getMouseButton = GenerateMouseGetter("InputSystemGetMouseButton", "isPressed"); _getMouseButtonDown = GenerateMouseGetter("InputSystemGetMouseButtonDown", "wasPressedThisFrame"); _getMouseButtonUp = GenerateMouseGetter("InputSystemGetMouseButtonUp", "wasReleasedThisFrame"); _getMousePosition = GetPositionDelegate("InputSystemGetMousePosition", "position"); _getMouseScrollDelta = GetPositionDelegate("InputSystemGetMouseScrollDelta", "scroll"); DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition("InputSystemGetMouseEnabled", typeof(bool), Type.EmptyTypes); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(OpCodes.Call, mouseCurrentProperty); iLGenerator.Emit(OpCodes.Callvirt, AccessTools.PropertyGetter(mouseType, "enabled")); iLGenerator.Emit(OpCodes.Ret); _getMousePresent = dynamicMethodDefinition.Generate().CreateDelegate(); MethodInfo anyKeyProperty = AccessTools.PropertyGetter(type2, "anyKey"); _getKeyboardAnyKeyIsPressed = GetAnyKeyDelegate("InputSystemGetKeyboardAnyKeyIsPressed", "isPressed"); _getKeyboardAnyKeyWasPressedThisFrame = GetAnyKeyDelegate("InputSystemGetKeyboardAnyKeyWasPressedThisFrame", "wasPressedThisFrame"); initialized = true; GetButtonDelegate GenerateKeyGetter(string name, string property) { MethodInfo meth = AccessTools.PropertyGetter(buttonControlType, property); DynamicMethodDefinition dynamicMethodDefinition2 = new DynamicMethodDefinition(name, typeof(bool), new Type[1] { typeof(KeyCode) }); ILGenerator iLGenerator2 = dynamicMethodDefinition2.GetILGenerator(); LocalBuilder local = iLGenerator2.DeclareLocal(typeof(int)); Label label = iLGenerator2.DefineLabel(); iLGenerator2.Emit(OpCodes.Ldsfld, keyCodeToIndexField); iLGenerator2.Emit(OpCodes.Ldarg_0); iLGenerator2.Emit(OpCodes.Ldloca, local); iLGenerator2.Emit(OpCodes.Callvirt, tryGetValueMethod); iLGenerator2.Emit(OpCodes.Brfalse, label); iLGenerator2.Emit(OpCodes.Call, currentProperty); iLGenerator2.Emit(OpCodes.Ldloc, local); iLGenerator2.Emit(OpCodes.Callvirt, indexer); iLGenerator2.Emit(OpCodes.Callvirt, meth); iLGenerator2.Emit(OpCodes.Ret); iLGenerator2.MarkLabel(label); iLGenerator2.Emit(OpCodes.Ldc_I4_0); iLGenerator2.Emit(OpCodes.Ret); return dynamicMethodDefinition2.Generate().CreateDelegate(); } GetButtonDelegate GenerateMouseGetter(string name, string property) { MethodInfo meth = AccessTools.PropertyGetter(buttonControlType, property); DynamicMethodDefinition dynamicMethodDefinition2 = new DynamicMethodDefinition(name, typeof(bool), new Type[1] { typeof(KeyCode) }); ILGenerator il = dynamicMethodDefinition2.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, 323); il.Emit(OpCodes.Sub); Label[] array = buttonPropertyGetters.Select((MethodInfo _) => il.DefineLabel()).ToArray(); Label label = il.DefineLabel(); il.Emit(OpCodes.Switch, array); il.Emit(OpCodes.Br, label); for (int num = 0; num < array.Length; num++) { il.MarkLabel(array[num]); il.Emit(OpCodes.Call, mouseCurrentProperty); il.Emit(OpCodes.Callvirt, buttonPropertyGetters[num]); il.Emit(OpCodes.Callvirt, meth); il.Emit(OpCodes.Ret); } il.MarkLabel(label); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ret); return dynamicMethodDefinition2.Generate().CreateDelegate(); } GetMouseStateDelegate GetAnyKeyDelegate(string name, string property) { MethodInfo meth = AccessTools.PropertyGetter(buttonControlType, property); DynamicMethodDefinition dynamicMethodDefinition2 = new DynamicMethodDefinition(name, typeof(bool), Type.EmptyTypes); ILGenerator iLGenerator2 = dynamicMethodDefinition2.GetILGenerator(); iLGenerator2.Emit(OpCodes.Call, currentProperty); iLGenerator2.Emit(OpCodes.Callvirt, anyKeyProperty); iLGenerator2.Emit(OpCodes.Callvirt, meth); iLGenerator2.Emit(OpCodes.Ret); return dynamicMethodDefinition2.Generate().CreateDelegate(); } GetMouseVectorDelegate GetPositionDelegate(string name, string property) { MethodInfo methodInfo = AccessTools.PropertyGetter(mouseType, property); MethodInfo meth = AccessTools.Method(methodInfo.ReturnType, "ReadValue"); DynamicMethodDefinition dynamicMethodDefinition2 = new DynamicMethodDefinition(name, typeof(Vector2), Type.EmptyTypes); ILGenerator iLGenerator2 = dynamicMethodDefinition2.GetILGenerator(); iLGenerator2.Emit(OpCodes.Call, mouseCurrentProperty); iLGenerator2.Emit(OpCodes.Callvirt, methodInfo); iLGenerator2.Emit(OpCodes.Callvirt, meth); iLGenerator2.Emit(OpCodes.Ret); return dynamicMethodDefinition2.Generate().CreateDelegate(); } } public bool GetKey(string name) { return _getKey(GetKeyCode(name)); } public bool GetKey(KeyCode key) { return _getKey(key); } public bool GetKeyDown(string name) { return _getKeyDown(GetKeyCode(name)); } public bool GetKeyDown(KeyCode key) { return _getKeyDown(key); } public bool GetKeyUp(string name) { return _getKeyUp(GetKeyCode(name)); } public bool GetKeyUp(KeyCode key) { return _getKeyUp(key); } public bool GetMouseButton(int button) { return _getMouseButton((KeyCode)(323 + button)); } public bool GetMouseButtonDown(int button) { return _getMouseButtonDown((KeyCode)(323 + button)); } public bool GetMouseButtonUp(int button) { return _getMouseButtonUp((KeyCode)(323 + button)); } public void ResetInputAxes() { } private static KeyCode GetKeyCode(string name) { return (KeyCode)Enum.Parse(typeof(KeyCode), name, ignoreCase: true); } private static bool TryEnumParse(string name, out T val) { try { val = (T)Enum.Parse(typeof(T), name, ignoreCase: true); return true; } catch (Exception) { val = default(T); return false; } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.LegacyInputSystem ---- namespace BepInEx { internal class LegacyInputSystem : IInputSystem { public Vector3 mousePosition => Input.mousePosition; public Vector2 mouseScrollDelta => Input.mouseScrollDelta; public bool mousePresent => Input.mousePresent; public bool anyKey => Input.anyKey; public bool anyKeyDown => Input.anyKeyDown; public IEnumerable SupportedKeyCodes { get; } = (KeyCode[])Enum.GetValues(typeof(KeyCode)); public bool GetKey(string name) { return Input.GetKey(name); } public bool GetKey(KeyCode key) { return Input.GetKey(key); } public bool GetKeyDown(string name) { return Input.GetKeyDown(name); } public bool GetKeyDown(KeyCode key) { return Input.GetKeyDown(key); } public bool GetKeyUp(string name) { return Input.GetKeyUp(name); } public bool GetKeyUp(KeyCode key) { return Input.GetKeyUp(key); } public bool GetMouseButton(int button) { return Input.GetMouseButton(button); } public bool GetMouseButtonDown(int button) { return Input.GetMouseButtonDown(button); } public bool GetMouseButtonUp(int button) { return Input.GetMouseButtonUp(button); } public void ResetInputAxes() { Input.ResetInputAxes(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.NullInputSystem ---- namespace BepInEx { internal class NullInputSystem : IInputSystem { private static readonly KeyCode[] NoKeys = new KeyCode[0]; public Vector3 mousePosition => Vector3.zero; public Vector2 mouseScrollDelta => Vector2.zero; public bool mousePresent => false; public bool anyKey => false; public bool anyKeyDown => false; public IEnumerable SupportedKeyCodes => NoKeys; public bool GetKey(string name) { return false; } public bool GetKey(KeyCode key) { return false; } public bool GetKeyDown(string name) { return false; } public bool GetKeyDown(KeyCode key) { return false; } public bool GetKeyUp(string name) { return false; } public bool GetKeyUp(KeyCode key) { return false; } public bool GetMouseButton(int button) { return false; } public bool GetMouseButtonDown(int button) { return false; } public bool GetMouseButtonUp(int button) { return false; } public void ResetInputAxes() { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.ConsoleManager ---- namespace BepInEx { internal static class ConsoleManager { public enum ConsoleOutRedirectType { [Description("Auto")] Auto, [Description("Console Out")] ConsoleOut, [Description("Standard Out")] StandardOut } private const uint SHIFT_JIS_CP = 932u; private static readonly bool? EnableConsoleArgOverride; private const string ENABLE_CONSOLE_ARG = "--enable-console"; public static readonly ConfigEntry ConfigConsoleEnabled; public static readonly ConfigEntry ConfigPreventClose; public static readonly ConfigEntry ConfigConsoleShiftJis; public static readonly ConfigEntry ConfigConsoleOutRedirectType; internal static IConsoleDriver Driver { get; set; } public static bool ConsoleActive => Driver?.ConsoleActive ?? false; public static TextWriter StandardOutStream => Driver?.StandardOut; public static TextWriter ConsoleStream => Driver?.ConsoleOut; public static bool ConsoleEnabled => EnableConsoleArgOverride ?? ConfigConsoleEnabled.Value; static ConsoleManager() { ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind("Logging.Console", "Enabled", defaultValue: false, "Enables showing a console for log output."); ConfigPreventClose = ConfigFile.CoreConfig.Bind("Logging.Console", "PreventClose", defaultValue: false, "If enabled, will prevent closing the console (either by deleting the close button or in other platform-specific way)."); ConfigConsoleShiftJis = ConfigFile.CoreConfig.Bind("Logging.Console", "ShiftJisEncoding", defaultValue: false, "If true, console is set to the Shift-JIS encoding, otherwise UTF-8 encoding."); ConfigConsoleOutRedirectType = ConfigFile.CoreConfig.Bind("Logging.Console", "StandardOutType", ConsoleOutRedirectType.Auto, new StringBuilder().AppendLine("Hints console manager on what handle to assign as StandardOut. Possible values:").AppendLine("Auto - lets BepInEx decide how to redirect console output").AppendLine("ConsoleOut - prefer redirecting to console output; if possible, closes original standard output") .AppendLine("StandardOut - prefer redirecting to standard output; if possible, closes console out") .ToString()); try { string[] commandLineArgs = Environment.GetCommandLineArgs(); for (int i = 0; i < commandLineArgs.Length; i++) { if (commandLineArgs[i] == "--enable-console" && i + 1 < commandLineArgs.Length && bool.TryParse(commandLineArgs[i + 1], out var result)) { EnableConsoleArgOverride = result; } } } catch (Exception) { } } public static void Initialize(bool alreadyActive) { if (PlatformHelper.Is(Platform.Unix)) { Driver = new LinuxConsoleDriver(); } else if (PlatformHelper.Is(Platform.Windows)) { Driver = new WindowsConsoleDriver(); } Driver.Initialize(alreadyActive); } private static void DriverCheck() { if (Driver == null) { throw new InvalidOperationException("Driver has not been initialized"); } } public static void CreateConsole() { if (!ConsoleActive) { DriverCheck(); uint codepage = (ConfigConsoleShiftJis.Value ? 932u : ((uint)Encoding.UTF8.CodePage)); Driver.CreateConsole(codepage); if (ConfigPreventClose.Value) { Driver.PreventClose(); } } } public static void DetachConsole() { if (ConsoleActive) { DriverCheck(); Driver.DetachConsole(); } } public static void SetConsoleTitle(string title) { DriverCheck(); Driver.SetConsoleTitle(title); } public static void SetConsoleColor(ConsoleColor color) { DriverCheck(); Driver.SetConsoleColor(color); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.IConsoleDriver ---- namespace BepInEx { internal interface IConsoleDriver { TextWriter StandardOut { get; } TextWriter ConsoleOut { get; } bool ConsoleActive { get; } bool ConsoleIsExternal { get; } void PreventClose(); void Initialize(bool alreadyActive); void CreateConsole(uint codepage); void DetachConsole(); void SetConsoleColor(ConsoleColor color); void SetConsoleTitle(string title); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.WindowsConsoleDriver ---- namespace BepInEx { internal class WindowsConsoleDriver : IConsoleDriver { private static readonly ConstructorInfo FileStreamCtor = new ConstructorInfo[2] { AccessTools.Constructor(typeof(FileStream), new Type[2] { typeof(SafeFileHandle), typeof(FileAccess) }), AccessTools.Constructor(typeof(FileStream), new Type[2] { typeof(IntPtr), typeof(FileAccess) }) }.FirstOrDefault((ConstructorInfo m) => (object)m != null); public TextWriter StandardOut { get; private set; } public TextWriter ConsoleOut { get; private set; } public bool ConsoleActive { get; private set; } public bool ConsoleIsExternal => true; public void PreventClose() { ConsoleWindow.PreventClose(); } public void Initialize(bool alreadyActive) { ConsoleActive = alreadyActive; StandardOut = Console.Out; } private static FileStream OpenFileStream(IntPtr handle) { SafeFileHandle safeFileHandle = new SafeFileHandle(handle, ownsHandle: false); object[] args = AccessTools.ActualParameters(FileStreamCtor, new object[3] { safeFileHandle, safeFileHandle.DangerousGetHandle(), FileAccess.Write }); return (FileStream)Activator.CreateInstance(typeof(FileStream), args); } public void CreateConsole(uint codepage) { ConsoleWindow.Attach(); ConsoleEncoding.ConsoleCodePage = codepage; IntPtr outHandle = GetOutHandle(); if (outHandle == IntPtr.Zero) { StandardOut = TextWriter.Null; ConsoleOut = TextWriter.Null; return; } FileStream stream = OpenFileStream(outHandle); StandardOut = new StreamWriter(stream, Utility.UTF8NoBom) { AutoFlush = true }; FileStream stream2 = OpenFileStream(ConsoleWindow.ConsoleOutHandle); ConsoleOut = new StreamWriter(stream2, ConsoleEncoding.OutputEncoding) { AutoFlush = true }; ConsoleActive = true; } private IntPtr GetOutHandle() { switch (ConsoleManager.ConfigConsoleOutRedirectType.Value) { case ConsoleManager.ConsoleOutRedirectType.ConsoleOut: return ConsoleWindow.ConsoleOutHandle; case ConsoleManager.ConsoleOutRedirectType.StandardOut: return ConsoleWindow.OriginalStdoutHandle; default: if (!(ConsoleWindow.OriginalStdoutHandle != IntPtr.Zero)) { return ConsoleWindow.ConsoleOutHandle; } return ConsoleWindow.OriginalStdoutHandle; } } public void DetachConsole() { ConsoleWindow.Detach(); ConsoleOut.Close(); ConsoleOut = null; ConsoleActive = false; } public void SetConsoleColor(ConsoleColor color) { SafeConsole.ForegroundColor = color; Kon.ForegroundColor = color; } public void SetConsoleTitle(string title) { ConsoleWindow.Title = title; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.PluginInfo ---- namespace BepInEx { public class PluginInfo : ICacheable { public BepInPlugin Metadata { get; internal set; } public IEnumerable Processes { get; internal set; } public IEnumerable Dependencies { get; internal set; } public IEnumerable Incompatibilities { get; internal set; } public string Location { get; internal set; } public BaseUnityPlugin Instance { get; internal set; } internal string TypeName { get; set; } internal Version TargettedBepInExVersion { get; set; } void ICacheable.Save(BinaryWriter bw) { bw.Write(TypeName); bw.Write(Metadata.GUID); bw.Write(Metadata.Name); bw.Write(Metadata.Version.ToString()); List list = Processes.ToList(); bw.Write(list.Count); foreach (BepInProcess item in list) { bw.Write(item.ProcessName); } List list2 = Dependencies.ToList(); bw.Write(list2.Count); foreach (BepInDependency item2 in list2) { ((ICacheable)item2).Save(bw); } List list3 = Incompatibilities.ToList(); bw.Write(list3.Count); foreach (BepInIncompatibility item3 in list3) { ((ICacheable)item3).Save(bw); } bw.Write(TargettedBepInExVersion.ToString(4)); } void ICacheable.Load(BinaryReader br) { TypeName = br.ReadString(); Metadata = new BepInPlugin(br.ReadString(), br.ReadString(), br.ReadString()); int num = br.ReadInt32(); List list = new List(num); for (int i = 0; i < num; i++) { list.Add(new BepInProcess(br.ReadString())); } Processes = list; int num2 = br.ReadInt32(); List list2 = new List(num2); for (int j = 0; j < num2; j++) { BepInDependency bepInDependency = new BepInDependency(""); ((ICacheable)bepInDependency).Load(br); list2.Add(bepInDependency); } Dependencies = list2; int num3 = br.ReadInt32(); List list3 = new List(num3); for (int k = 0; k < num3; k++) { BepInIncompatibility bepInIncompatibility = new BepInIncompatibility(""); ((ICacheable)bepInIncompatibility).Load(br); list3.Add(bepInIncompatibility); } Incompatibilities = list3; TargettedBepInExVersion = new Version(br.ReadString()); } public override string ToString() { return $"{Metadata?.Name} {Metadata?.Version}"; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.BepInPlugin ---- namespace BepInEx { [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class BepInPlugin : Attribute { public string GUID { get; protected set; } public string Name { get; protected set; } public Version Version { get; protected set; } public BepInPlugin(string GUID, string Name, string Version) { this.GUID = GUID; this.Name = Name; try { this.Version = new Version(Version); } catch { this.Version = null; } } internal static BepInPlugin FromCecilType(TypeDefinition td) { CustomAttribute customAttribute = MetadataHelper.GetCustomAttributes(td, inherit: false).FirstOrDefault(); if (customAttribute == null) { return null; } return new BepInPlugin((string)customAttribute.ConstructorArguments[0].Value, (string)customAttribute.ConstructorArguments[1].Value, (string)customAttribute.ConstructorArguments[2].Value); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.BepInDependency ---- namespace BepInEx { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class BepInDependency : Attribute, ICacheable { [Flags] public enum DependencyFlags { HardDependency = 1, SoftDependency = 2 } public string DependencyGUID { get; protected set; } public DependencyFlags Flags { get; protected set; } public Version MinimumVersion { get; protected set; } public BepInDependency(string DependencyGUID, DependencyFlags Flags = DependencyFlags.HardDependency) { this.DependencyGUID = DependencyGUID; this.Flags = Flags; MinimumVersion = new Version(); } public BepInDependency(string DependencyGUID, string MinimumDependencyVersion) : this(DependencyGUID) { MinimumVersion = new Version(MinimumDependencyVersion); } internal static IEnumerable FromCecilType(TypeDefinition td) { return MetadataHelper.GetCustomAttributes(td, inherit: true).Select(delegate(CustomAttribute customAttribute) { string dependencyGUID = (string)customAttribute.ConstructorArguments[0].Value; object value = customAttribute.ConstructorArguments[1].Value; return (value is string minimumDependencyVersion) ? new BepInDependency(dependencyGUID, minimumDependencyVersion) : new BepInDependency(dependencyGUID, (DependencyFlags)value); }).ToList(); } void ICacheable.Save(BinaryWriter bw) { bw.Write(DependencyGUID); bw.Write((int)Flags); bw.Write(MinimumVersion.ToString()); } void ICacheable.Load(BinaryReader br) { DependencyGUID = br.ReadString(); Flags = (DependencyFlags)br.ReadInt32(); MinimumVersion = new Version(br.ReadString()); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.BepInIncompatibility ---- namespace BepInEx { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class BepInIncompatibility : Attribute, ICacheable { public string IncompatibilityGUID { get; protected set; } public BepInIncompatibility(string IncompatibilityGUID) { this.IncompatibilityGUID = IncompatibilityGUID; } internal static IEnumerable FromCecilType(TypeDefinition td) { return (from customAttribute in MetadataHelper.GetCustomAttributes(td, inherit: true) select new BepInIncompatibility((string)customAttribute.ConstructorArguments[0].Value)).ToList(); } void ICacheable.Save(BinaryWriter bw) { bw.Write(IncompatibilityGUID); } void ICacheable.Load(BinaryReader br) { IncompatibilityGUID = br.ReadString(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.BepInProcess ---- namespace BepInEx { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class BepInProcess : Attribute { public string ProcessName { get; protected set; } public BepInProcess(string ProcessName) { this.ProcessName = ProcessName; } internal static List FromCecilType(TypeDefinition td) { return (from customAttribute in MetadataHelper.GetCustomAttributes(td, inherit: true) select new BepInProcess((string)customAttribute.ConstructorArguments[0].Value)).ToList(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.MetadataHelper ---- namespace BepInEx { public static class MetadataHelper { internal static IEnumerable GetCustomAttributes(TypeDefinition td, bool inherit) where T : Attribute { List list = new List(); Type type = typeof(T); TypeDefinition typeDefinition = td; do { list.AddRange(typeDefinition.CustomAttributes.Where((CustomAttribute ca) => ca.AttributeType.FullName == type.FullName)); typeDefinition = typeDefinition.BaseType?.Resolve(); } while (inherit && typeDefinition?.FullName != "System.Object"); return list; } public static BepInPlugin GetMetadata(Type pluginType) { object[] customAttributes = pluginType.GetCustomAttributes(typeof(BepInPlugin), inherit: false); if (customAttributes.Length == 0) { return null; } return (BepInPlugin)customAttributes[0]; } public static BepInPlugin GetMetadata(object plugin) { return GetMetadata(plugin.GetType()); } public static T[] GetAttributes(Type pluginType) where T : Attribute { return (T[])pluginType.GetCustomAttributes(typeof(T), inherit: true); } public static IEnumerable GetAttributes(object plugin) where T : Attribute { return GetAttributes(plugin.GetType()); } public static IEnumerable GetDependencies(Type plugin) { return plugin.GetCustomAttributes(typeof(BepInDependency), inherit: true).Cast(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.BuildInfoAttribute ---- namespace BepInEx { internal class BuildInfoAttribute : Attribute { public string Info { get; } public BuildInfoAttribute(string info) { Info = info; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.BaseUnityPlugin ---- namespace BepInEx { public abstract class BaseUnityPlugin : MonoBehaviour { public PluginInfo Info { get; } protected ManualLogSource Logger { get; } public ConfigFile Config { get; } protected BaseUnityPlugin() { BepInPlugin metadata = MetadataHelper.GetMetadata(this); if (metadata == null) { throw new InvalidOperationException("Can't create an instance of " + GetType().FullName + " because it inherits from BaseUnityPlugin and the BepInPlugin attribute is missing."); } if (!Chainloader.IsEditor && Chainloader.PluginInfos.TryGetValue(metadata.GUID, out var value)) { Info = value; } else { Info = new PluginInfo { Metadata = metadata, Instance = this, Dependencies = MetadataHelper.GetDependencies(GetType()), Processes = MetadataHelper.GetAttributes(GetType()), Location = GetType().Assembly.Location }; } Logger = BepInEx.Logging.Logger.CreateLogSource(metadata.Name); string text = (Chainloader.IsEditor ? "." : Paths.ConfigPath); Config = new ConfigFile(Utility.CombinePaths(text, metadata.GUID + ".cfg"), saveOnInit: false, metadata); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Paths ---- namespace BepInEx { public static class Paths { public static string[] DllSearchPaths { get; private set; } public static string BepInExAssemblyDirectory { get; private set; } public static string BepInExAssemblyPath { get; private set; } public static string BepInExRootPath { get; private set; } public static string ExecutablePath { get; private set; } public static string GameRootPath { get; private set; } public static string ManagedPath { get; private set; } public static string ConfigPath { get; private set; } public static string BepInExConfigPath { get; private set; } public static string CachePath { get; private set; } public static string PatcherPluginPath { get; private set; } public static string PluginPath { get; private set; } public static string ProcessName { get; private set; } internal static void SetExecutablePath(string executablePath, string bepinRootPath = null, string managedPath = null, string[] dllSearchPath = null) { ExecutablePath = executablePath; ProcessName = Path.GetFileNameWithoutExtension(executablePath); GameRootPath = (PlatformHelper.Is(Platform.MacOS) ? Utility.ParentDirectory(executablePath, 4) : Path.GetDirectoryName(executablePath)); ManagedPath = managedPath ?? Utility.CombinePaths(GameRootPath, ProcessName + "_Data", "Managed"); BepInExRootPath = bepinRootPath ?? Path.Combine(GameRootPath, "BepInEx"); ConfigPath = Path.Combine(BepInExRootPath, "config"); BepInExConfigPath = Path.Combine(ConfigPath, "BepInEx.cfg"); PluginPath = Path.Combine(BepInExRootPath, "plugins"); PatcherPluginPath = Path.Combine(BepInExRootPath, "patchers"); BepInExAssemblyDirectory = Path.Combine(BepInExRootPath, "core"); BepInExAssemblyPath = Path.Combine(BepInExAssemblyDirectory, Assembly.GetExecutingAssembly().GetName().Name + ".dll"); CachePath = Path.Combine(BepInExRootPath, "cache"); DllSearchPaths = (dllSearchPath ?? new string[0]).Concat(new string[1] { ManagedPath }).Distinct().ToArray(); } internal static void SetManagedPath(string managedPath) { if (managedPath != null) { ManagedPath = managedPath; } } internal static void SetPluginPath(string pluginPath) { PluginPath = Utility.CombinePaths(BepInExRootPath, pluginPath); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.ThreadingHelper ---- namespace BepInEx { public sealed class ThreadingHelper : MonoBehaviour, ISynchronizeInvoke { private sealed class InvokeResult : IAsyncResult { internal bool ExceptionThrown; public bool IsCompleted { get; private set; } public WaitHandle AsyncWaitHandle { get; } public object AsyncState { get; private set; } public bool CompletedSynchronously { get; private set; } public InvokeResult() { AsyncWaitHandle = new EventWaitHandle(initialState: false, EventResetMode.ManualReset); } public void Finish(object result, bool completedSynchronously) { AsyncState = result; CompletedSynchronously = completedSynchronously; IsCompleted = true; ((EventWaitHandle)AsyncWaitHandle).Set(); } } private readonly object _invokeLock = new object(); private Action _invokeList; private Thread _mainThread; public static ThreadingHelper Instance { get; private set; } public static ISynchronizeInvoke SynchronizingObject => Instance; public bool InvokeRequired { get { if (_mainThread != null) { return _mainThread != Thread.CurrentThread; } return true; } } internal static void Initialize() { GameObject gameObject = new GameObject("BepInEx_ThreadingHelper"); if (Chainloader.ConfigHideBepInExGOs.Value) { gameObject.hideFlags = HideFlags.HideAndDontSave; } UnityEngine.Object.DontDestroyOnLoad(gameObject); Instance = gameObject.AddComponent(); } public void StartSyncInvoke(Action action) { if (action == null) { throw new ArgumentNullException("action"); } lock (_invokeLock) { _invokeList = (Action)Delegate.Combine(_invokeList, action); } } private void Update() { if (_mainThread == null) { _mainThread = Thread.CurrentThread; } if (_invokeList == null) { return; } Action invokeList; lock (_invokeLock) { invokeList = _invokeList; _invokeList = null; } foreach (Action item in invokeList.GetInvocationList().Cast()) { try { item(); } catch (Exception ex) { LogInvocationException(ex); } } } public void StartAsyncInvoke(Func action) { if (!ThreadPool.QueueUserWorkItem(DoWork)) { throw new NotSupportedException("Failed to queue the action on ThreadPool"); } void DoWork(object _) { try { Action action2 = action(); if (action2 != null) { StartSyncInvoke(action2); } } catch (Exception ex) { LogInvocationException(ex); } } } private static void LogInvocationException(Exception ex) { BepInEx.Logging.Logger.Log(LogLevel.Error, ex); if (ex.InnerException != null) { BepInEx.Logging.Logger.Log(LogLevel.Error, "INNER: " + ex.InnerException); } } IAsyncResult ISynchronizeInvoke.BeginInvoke(Delegate method, object[] args) { InvokeResult result = new InvokeResult(); if (!InvokeRequired) { result.Finish(Invoke(), completedSynchronously: true); } else { StartSyncInvoke(delegate { result.Finish(Invoke(), completedSynchronously: false); }); } return result; object Invoke() { try { return method.DynamicInvoke(args); } catch (Exception result2) { result.ExceptionThrown = true; return result2; } } } object ISynchronizeInvoke.EndInvoke(IAsyncResult result) { InvokeResult invokeResult = (InvokeResult)result; invokeResult.AsyncWaitHandle.WaitOne(); if (invokeResult.ExceptionThrown) { throw (Exception)invokeResult.AsyncState; } return invokeResult.AsyncState; } object ISynchronizeInvoke.Invoke(Delegate method, object[] args) { IAsyncResult result = ((ISynchronizeInvoke)this).BeginInvoke(method, args); return ((ISynchronizeInvoke)this).EndInvoke(result); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.ThreadingExtensions ---- namespace BepInEx { public static class ThreadingExtensions { public static IEnumerable RunParallel(this IEnumerable data, Func work, int workerCount = -1) { foreach (TOut item in data.ToList().RunParallel(work)) { yield return item; } } public static IEnumerable RunParallel(this IList data, Func work, int workerCount = -1) { if (workerCount < 0) { workerCount = Mathf.Max(2, Environment.ProcessorCount); } else if (workerCount == 0) { throw new ArgumentException("Need at least 1 worker", "workerCount"); } int perThreadCount = Mathf.CeilToInt((float)data.Count / (float)workerCount); int doneCount = 0; object lockObj = new object(); ManualResetEvent are = new ManualResetEvent(initialState: false); IEnumerable doneItems = null; Exception exceptionThrown = null; for (int i = 0; i < workerCount; i++) { int first = i * perThreadCount; int last = Mathf.Min(first + perThreadCount, data.Count); ThreadPool.QueueUserWorkItem(delegate { List list = new List(perThreadCount); try { for (int j = first; j < last; j++) { if (exceptionThrown != null) { break; } list.Add(work(data[j])); } } catch (Exception ex) { exceptionThrown = ex; } lock (lockObj) { IEnumerable enumerable2; if (doneItems != null) { enumerable2 = list.Concat(doneItems); } else { IEnumerable enumerable3 = list; enumerable2 = enumerable3; } doneItems = enumerable2; int num = doneCount; doneCount = num + 1; are.Set(); } }); } bool isDone; do { are.WaitOne(); IEnumerable enumerable; lock (lockObj) { enumerable = doneItems; doneItems = null; isDone = doneCount == workerCount; } if (enumerable == null) { continue; } foreach (TOut item in enumerable) { yield return item; } } while (!isDone); if (exceptionThrown != null) { throw new TargetInvocationException("An exception was thrown inside one of the threads", exceptionThrown); } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Utility ---- namespace BepInEx { public static class Utility { private static bool? sreEnabled; public static bool CLRSupportsDynamicAssemblies => CheckSRE(); public static Encoding UTF8NoBom { get; } = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); private static bool CheckSRE() { if (sreEnabled.HasValue) { return sreEnabled.Value; } try { new CustomAttributeBuilder(null, new object[0]); } catch (PlatformNotSupportedException) { sreEnabled = false; return sreEnabled.Value; } catch (ArgumentNullException) { } sreEnabled = true; return sreEnabled.Value; } public static bool TryDo(Action action, out Exception exception) { exception = null; try { action(); return true; } catch (Exception ex) { exception = ex; return false; } } public static string CombinePaths(params string[] parts) { return parts.Aggregate(Path.Combine); } public static string ParentDirectory(string path, int levels = 1) { for (int i = 0; i < levels; i++) { path = Path.GetDirectoryName(path); } return path; } public static bool SafeParseBool(string input, bool defaultValue = false) { if (!bool.TryParse(input, out var result)) { return defaultValue; } return result; } public static string ConvertToWWWFormat(string path) { return "file://" + path.Replace('\\', '/'); } public static bool IsNullOrWhiteSpace(this string self) { return self?.All(char.IsWhiteSpace) ?? true; } public static IEnumerable TopologicalSort(IEnumerable nodes, Func> dependencySelector) { List sorted_list = new List(); HashSet visited = new HashSet(); HashSet sorted = new HashSet(); foreach (TNode node in nodes) { Stack stack = new Stack(); if (!Visit(node, stack)) { throw new Exception("Cyclic Dependency:\r\n" + stack.Select((TNode x) => $" - {x}").Aggregate((string a, string b) => a + "\r\n" + b)); } } return sorted_list; bool Visit(TNode node, Stack stack2) { if (visited.Contains(node)) { if (!sorted.Contains(node)) { return false; } } else { visited.Add(node); stack2.Push(node); foreach (TNode item in dependencySelector(node)) { if (!Visit(item, stack2)) { return false; } } sorted.Add(node); sorted_list.Add(node); stack2.Pop(); } return true; } } private static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, Func loader, out T assembly) where T : class { assembly = null; List list = new List(); list.Add(directory); list.AddRange(Directory.GetDirectories(directory, "*", SearchOption.AllDirectories)); foreach (string item in list) { string text = Path.Combine(item, assemblyName.Name + ".dll"); if (File.Exists(text)) { try { assembly = loader(text); } catch (Exception) { continue; } return true; } } return false; } public static bool IsSubtypeOf(this TypeDefinition self, Type td) { if (self.FullName == td.FullName) { return true; } if (self.FullName != "System.Object") { return self.BaseType?.Resolve()?.IsSubtypeOf(td) == true; } return false; } public static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, out Assembly assembly) { return TryResolveDllAssembly(assemblyName, directory, Assembly.LoadFile, out assembly); } public static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, ReaderParameters readerParameters, out AssemblyDefinition assembly) { return TryResolveDllAssembly(assemblyName, directory, (string s) => AssemblyDefinition.ReadAssembly(s, readerParameters), out assembly); } public static bool TryOpenFileStream(string path, FileMode mode, out FileStream fileStream, FileAccess access = FileAccess.ReadWrite, FileShare share = FileShare.Read) { try { fileStream = new FileStream(path, mode, access, share); return true; } catch (IOException) { fileStream = null; return false; } } public static bool TryParseAssemblyName(string fullName, out AssemblyName assemblyName) { try { assemblyName = new AssemblyName(fullName); return true; } catch (Exception) { assemblyName = null; return false; } } public static IEnumerable GetUniqueFilesInDirectories(IEnumerable directories, string pattern = "*") { Dictionary dictionary = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (string directory in directories) { string[] files = Directory.GetFiles(directory, pattern); foreach (string text in files) { string fileName = Path.GetFileName(text); if (!dictionary.ContainsKey(fileName)) { dictionary[fileName] = text; } } } return dictionary.Values; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.DiskLogListener ---- namespace BepInEx.Logging { public class DiskLogListener : ILogListener, IDisposable { public LogLevel DisplayedLogLevel { get; set; } public TextWriter LogWriter { get; protected set; } public Timer FlushTimer { get; protected set; } public bool WriteFromUnityLog { get; set; } public DiskLogListener(string localPath, LogLevel displayedLogLevel = LogLevel.Info, bool appendLog = false, bool includeUnityLog = false) { WriteFromUnityLog = includeUnityLog; DisplayedLogLevel = displayedLogLevel; int num = 1; FileStream fileStream; while (!Utility.TryOpenFileStream(Path.Combine(Paths.BepInExRootPath, localPath), appendLog ? FileMode.Append : FileMode.Create, out fileStream, FileAccess.Write)) { if (num == 5) { Logger.LogError("Couldn't open a log file for writing. Skipping log file creation"); return; } Logger.LogWarning("Couldn't open log file '" + localPath + "' for writing, trying another..."); localPath = $"LogOutput.log.{num++}"; } LogWriter = TextWriter.Synchronized(new StreamWriter(fileStream, Utility.UTF8NoBom)); FlushTimer = new Timer(delegate { LogWriter?.Flush(); }, null, 2000, 2000); } public void LogEvent(object sender, LogEventArgs eventArgs) { if ((WriteFromUnityLog || !(eventArgs.Source is UnityLogSource)) && (eventArgs.Level & DisplayedLogLevel) != LogLevel.None) { LogWriter.WriteLine(eventArgs.ToString()); } } public void Dispose() { FlushTimer?.Dispose(); LogWriter?.Flush(); LogWriter?.Dispose(); } ~DiskLogListener() { Dispose(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.HarmonyLogSource ---- namespace BepInEx.Logging { internal class HarmonyLogSource : ILogSource, IDisposable { private static readonly ConfigEntry LogChannels = ConfigFile.CoreConfig.Bind("Harmony.Logger", "LogChannels", HarmonyLib.Tools.Logger.LogChannel.Warn | HarmonyLib.Tools.Logger.LogChannel.Error, "Specifies which Harmony log channels to listen to.\nNOTE: IL channel dumps the whole patch methods, use only when needed!"); private static readonly Dictionary LevelMap = new Dictionary { [HarmonyLib.Tools.Logger.LogChannel.Info] = LogLevel.Info, [HarmonyLib.Tools.Logger.LogChannel.Warn] = LogLevel.Warning, [HarmonyLib.Tools.Logger.LogChannel.Error] = LogLevel.Error, [HarmonyLib.Tools.Logger.LogChannel.IL] = LogLevel.Debug }; public string SourceName { get; } = "HarmonyX"; public event EventHandler LogEvent; public HarmonyLogSource() { HarmonyLib.Tools.Logger.ChannelFilter = LogChannels.Value; HarmonyLib.Tools.Logger.MessageReceived += HandleHarmonyMessage; } private void HandleHarmonyMessage(object sender, HarmonyLib.Tools.Logger.LogEventArgs e) { if (LevelMap.TryGetValue(e.LogChannel, out var value)) { this.LogEvent?.Invoke(this, new LogEventArgs(e.Message, value, this)); } } public void Dispose() { HarmonyLib.Tools.Logger.MessageReceived -= HandleHarmonyMessage; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.LogEventArgs ---- namespace BepInEx.Logging { public class LogEventArgs : EventArgs { public object Data { get; protected set; } public LogLevel Level { get; protected set; } public ILogSource Source { get; protected set; } public LogEventArgs(object data, LogLevel level, ILogSource source) { Data = data; Level = level; Source = source; } public override string ToString() { return $"[{Level,-7}:{Source.SourceName,10}] {Data}"; } public string ToStringLine() { return ToString() + Environment.NewLine; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.Logger ---- namespace BepInEx.Logging { public static class Logger { private sealed class LogSourceCollection : ThreadSafeCollection, ICollection, IEnumerable, IEnumerable { public override void Add(ILogSource item) { if (item == null) { throw new ArgumentNullException("item", "Log sources cannot be null when added to the source list."); } lock (Lock) { item.LogEvent += InternalLogEvent; List list = new List(BaseList.Count + 1); list.AddRange(BaseList); list.Add(item); BaseList = list; } } public override void Clear() { if (base.Count == 0) { return; } lock (Lock) { for (int i = 0; i < BaseList.Count; i++) { BaseList[i].LogEvent -= InternalLogEvent; } BaseList = new List(0); } } public override bool Remove(ILogSource item) { if (item == null) { return false; } lock (Lock) { bool num = base.Remove(item); if (num) { item.LogEvent -= InternalLogEvent; } return num; } } } private sealed class LogListenerCollection : ThreadSafeCollection { public void SendLogEvent(object sender, LogEventArgs eventArgs) { List baseList = BaseList; for (int i = 0; i < baseList.Count; i++) { baseList[i].LogEvent(sender, eventArgs); } } } private class ThreadSafeCollection : ICollection, IEnumerable, IEnumerable where T : class { protected readonly object Lock = new object(); protected List BaseList = new List(0); public int Count => BaseList.Count; public bool IsReadOnly => false; public IEnumerator GetEnumerator() { return BaseList.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); } public virtual void Add(T item) { if (item == null) { throw new ArgumentNullException("item", "item can't be null"); } lock (Lock) { List list = new List(BaseList.Count + 1); list.AddRange(BaseList); list.Add(item); BaseList = list; } } public virtual void Clear() { if (Count == 0) { return; } lock (Lock) { BaseList = new List(0); } } public bool Contains(T item) { return BaseList.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { BaseList.CopyTo(array, arrayIndex); } public virtual bool Remove(T item) { if (item == null) { return false; } lock (Lock) { List list = new List(BaseList.Count); bool result = false; for (int i = 0; i < BaseList.Count; i++) { T val = BaseList[i]; if (val.Equals(item)) { result = true; } else { list.Add(val); } } BaseList = list; return result; } } } private static readonly LogListenerCollection _Listeners = new LogListenerCollection(); private static readonly ManualLogSource InternalLogSource = CreateLogSource("BepInEx"); private static bool internalLogsInitialized; public static ICollection Listeners => _Listeners; public static ICollection Sources { get; } = new LogSourceCollection(); internal static void InitializeInternalLoggers() { if (!internalLogsInitialized) { Sources.Add(new HarmonyLogSource()); internalLogsInitialized = true; } } internal static void InternalLogEvent(object sender, LogEventArgs eventArgs) { _Listeners.SendLogEvent(sender, eventArgs); } internal static void Log(LogLevel level, object data) { InternalLogSource.Log(level, data); } internal static void LogFatal(object data) { Log(LogLevel.Fatal, data); } internal static void LogError(object data) { Log(LogLevel.Error, data); } internal static void LogWarning(object data) { Log(LogLevel.Warning, data); } internal static void LogMessage(object data) { Log(LogLevel.Message, data); } internal static void LogInfo(object data) { Log(LogLevel.Info, data); } internal static void LogDebug(object data) { Log(LogLevel.Debug, data); } public static ManualLogSource CreateLogSource(string sourceName) { ManualLogSource manualLogSource = new ManualLogSource(sourceName); Sources.Add(manualLogSource); return manualLogSource; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.LogLevel ---- namespace BepInEx.Logging { [Flags] public enum LogLevel { None = 0, Fatal = 1, Error = 2, Warning = 4, Message = 8, Info = 0x10, Debug = 0x20, All = 0x3F } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.LogLevelExtensions ---- namespace BepInEx.Logging { public static class LogLevelExtensions { public static LogLevel GetHighestLevel(this LogLevel levels) { Array values = Enum.GetValues(typeof(LogLevel)); Array.Sort(values); foreach (LogLevel item in values) { if ((levels & item) != LogLevel.None) { return item; } } return LogLevel.None; } public static ConsoleColor GetConsoleColor(this LogLevel level) { level = level.GetHighestLevel(); return level switch { LogLevel.Fatal => ConsoleColor.Red, LogLevel.Error => ConsoleColor.DarkRed, LogLevel.Warning => ConsoleColor.Yellow, LogLevel.Message => ConsoleColor.White, LogLevel.Debug => ConsoleColor.DarkGray, _ => ConsoleColor.Gray, }; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.ILogListener ---- namespace BepInEx.Logging { public interface ILogListener : IDisposable { void LogEvent(object sender, LogEventArgs eventArgs); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.ILogSource ---- namespace BepInEx.Logging { public interface ILogSource : IDisposable { string SourceName { get; } event EventHandler LogEvent; } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.ManualLogSource ---- namespace BepInEx.Logging { public class ManualLogSource : ILogSource, IDisposable { public string SourceName { get; } public event EventHandler LogEvent; public ManualLogSource(string sourceName) { SourceName = sourceName; } public void Log(LogLevel level, object data) { this.LogEvent?.Invoke(this, new LogEventArgs(data, level, this)); } public void LogFatal(object data) { Log(LogLevel.Fatal, data); } public void LogError(object data) { Log(LogLevel.Error, data); } public void LogWarning(object data) { Log(LogLevel.Warning, data); } public void LogMessage(object data) { Log(LogLevel.Message, data); } public void LogInfo(object data) { Log(LogLevel.Info, data); } public void LogDebug(object data) { Log(LogLevel.Debug, data); } public void Dispose() { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.TraceLogSource ---- namespace BepInEx.Logging { public class TraceLogSource : TraceListener { private static TraceLogSource traceListener; public static bool IsListening { get; protected set; } protected ManualLogSource LogSource { get; } public static ILogSource CreateSource() { if (traceListener == null) { traceListener = new TraceLogSource(); Trace.Listeners.Add(traceListener); IsListening = true; } return traceListener.LogSource; } protected TraceLogSource() { LogSource = new ManualLogSource("Trace"); } public override void Write(string message) { LogSource.LogInfo(message); } public override void WriteLine(string message) { LogSource.LogInfo(message); } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) { TraceEvent(eventCache, source, eventType, id, string.Format(format, args)); } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) { LogSource.Log(eventType switch { TraceEventType.Critical => LogLevel.Fatal, TraceEventType.Error => LogLevel.Error, TraceEventType.Warning => LogLevel.Warning, TraceEventType.Information => LogLevel.Info, _ => LogLevel.Debug, }, (message ?? "").Trim()); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.ConsoleLogListener ---- namespace BepInEx.Logging { public class ConsoleLogListener : ILogListener, IDisposable { private static readonly ConfigEntry ConfigConsoleDisplayedLevel = ConfigFile.CoreConfig.Bind("Logging.Console", "LogLevels", LogLevel.Fatal | LogLevel.Error | LogLevel.Warning | LogLevel.Message | LogLevel.Info, "Which log levels to show in the console output."); internal bool WriteUnityLogs { get; set; } = true; public void LogEvent(object sender, LogEventArgs eventArgs) { if ((WriteUnityLogs || !(sender is UnityLogSource)) && (eventArgs.Level & ConfigConsoleDisplayedLevel.Value) != LogLevel.None) { ConsoleManager.SetConsoleColor(eventArgs.Level.GetConsoleColor()); ConsoleManager.ConsoleStream?.Write(eventArgs.ToStringLine()); ConsoleManager.SetConsoleColor(ConsoleColor.Gray); } } public void Dispose() { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.UnityLogListener ---- namespace BepInEx.Logging { public class UnityLogListener : ILogListener, IDisposable { internal static readonly Action WriteStringToUnityLog; private ConfigEntry LogConsoleToUnity = ConfigFile.CoreConfig.Bind("Logging", "LogConsoleToUnityLog", defaultValue: false, new StringBuilder().AppendLine("If enabled, writes Standard Output messages to Unity log").AppendLine("NOTE: By default, Unity does so automatically. Only use this option if no console messages are visible in Unity log").ToString()); static UnityLogListener() { MethodInfo[] methods = typeof(UnityEngine.UnityLogWriter).GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { try { methodInfo.Invoke(null, new object[1] { "" }); } catch { continue; } WriteStringToUnityLog = (Action)Delegate.CreateDelegate(typeof(Action), methodInfo); break; } if (WriteStringToUnityLog == null) { Logger.LogError("Unable to start Unity log writer"); } } public void LogEvent(object sender, LogEventArgs eventArgs) { if (!(eventArgs.Source is UnityLogSource) && (LogConsoleToUnity.Value || eventArgs.Source.SourceName != "Console")) { WriteStringToUnityLog?.Invoke(eventArgs.ToStringLine()); } } public void Dispose() { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Logging.UnityLogSource ---- namespace BepInEx.Logging { public class UnityLogSource : ILogSource, IDisposable { private bool disposed; public string SourceName { get; } = "Unity Log"; public event EventHandler LogEvent; private static event EventHandler InternalUnityLogMessage; public UnityLogSource() { InternalUnityLogMessage += UnityLogMessageHandler; } private void UnityLogMessageHandler(object sender, LogEventArgs eventArgs) { LogEventArgs e = new LogEventArgs(eventArgs.Data, eventArgs.Level, this); this.LogEvent?.Invoke(this, e); } public void Dispose() { if (!disposed) { InternalUnityLogMessage -= UnityLogMessageHandler; disposed = true; } } static UnityLogSource() { Application.LogCallback logCallback = OnUnityLogMessageReceived; EventInfo eventInfo = typeof(Application).GetEvent("logMessageReceived", BindingFlags.Static | BindingFlags.Public); if ((object)eventInfo != null) { eventInfo.AddEventHandler(null, logCallback); return; } typeof(Application).GetMethod("RegisterLogCallback", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[1] { logCallback }); } private static void OnUnityLogMessageReceived(string message, string stackTrace, LogType type) { LogLevel level; switch (type) { case LogType.Error: case LogType.Assert: case LogType.Exception: level = LogLevel.Error; break; case LogType.Warning: level = LogLevel.Warning; break; default: level = LogLevel.Info; break; } if (type == LogType.Exception) { message = message + "\nStack trace:\n" + stackTrace; } UnityLogSource.InternalUnityLogMessage?.Invoke(null, new LogEventArgs(message, level, null)); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Bootstrap.Chainloader ---- namespace BepInEx.Bootstrap { public static class Chainloader { private static readonly List _plugins = new List(); private static bool? isEditor; private static bool _loaded = false; private static bool _initialized = false; private static readonly string CurrentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; private static readonly Version CurrentAssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version; internal static readonly ConfigEntry ConfigHideBepInExGOs = ConfigFile.CoreConfig.Bind("Chainloader", "HideManagerGameObject", defaultValue: false, new StringBuilder().AppendLine("If enabled, hides BepInEx Manager GameObject from Unity.").AppendLine("This can fix loading issues in some games that attempt to prevent BepInEx from being loaded.").AppendLine("Use this only if you know what this option means, as it can affect functionality of some older plugins.") .ToString()); private static readonly ConfigEntry ConfigUnityLogging = ConfigFile.CoreConfig.Bind("Logging", "UnityLogListening", defaultValue: true, "Enables showing unity log messages in the BepInEx logging system."); private static readonly ConfigEntry ConfigDiskWriteUnityLog = ConfigFile.CoreConfig.Bind("Logging.Disk", "WriteUnityLog", defaultValue: false, "Include unity log messages in log file output."); private static readonly ConfigEntry ConfigDiskAppend = ConfigFile.CoreConfig.Bind("Logging.Disk", "AppendLog", defaultValue: false, "Appends to the log file instead of overwriting, on game startup."); private static readonly ConfigEntry ConfigDiskLogging = ConfigFile.CoreConfig.Bind("Logging.Disk", "Enabled", defaultValue: true, "Enables writing log messages to disk."); private static readonly ConfigEntry ConfigDiskConsoleDisplayedLevel = ConfigFile.CoreConfig.Bind("Logging.Disk", "LogLevels", LogLevel.Fatal | LogLevel.Error | LogLevel.Warning | LogLevel.Message | LogLevel.Info, "Which log leves are saved to the disk log output."); public static Dictionary PluginInfos { get; } = new Dictionary(); private static string UnityVersion { [MethodImpl(MethodImplOptions.NoInlining)] get { return Application.unityVersion; } } private static bool IsHeadless { get { MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Application), "isBatchMode"); if ((object)methodInfo != null) { return (bool)methodInfo.Invoke(null, null); } return SystemInfo.graphicsDeviceID == 0; } } internal static bool IsEditor { [MethodImpl(MethodImplOptions.NoInlining)] get { bool? flag = isEditor; if (!flag.HasValue) { bool? flag2 = (isEditor = Application.isEditor); return flag2 == true; } return flag == true; } } [Obsolete("Use PluginInfos instead")] public static List Plugins { get { lock (_plugins) { _plugins.RemoveAll((BaseUnityPlugin x) => x == null); return _plugins.ToList(); } } } public static List DependencyErrors { get; } = new List(); public static GameObject ManagerObject { get; private set; } private static Regex allowedGuidRegex { get; } = new Regex("^[a-zA-Z0-9\\._\\-]+$"); public static void Initialize(string gameExePath, bool startConsole = true, ICollection preloaderLogEvents = null) { if (!_initialized) { ThreadingHelper.Initialize(); if (gameExePath != null) { Paths.SetExecutablePath(gameExePath); } if (ConsoleManager.ConsoleEnabled && startConsole) { ConsoleManager.CreateConsole(); BepInEx.Logging.Logger.Listeners.Add(new ConsoleLogListener()); } BepInEx.Logging.Logger.InitializeInternalLoggers(); if (ConfigDiskLogging.Value) { BepInEx.Logging.Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskConsoleDisplayedLevel.Value, ConfigDiskAppend.Value, ConfigDiskWriteUnityLog.Value)); } if (!TraceLogSource.IsListening) { BepInEx.Logging.Logger.Sources.Add(TraceLogSource.CreateSource()); } ReplayPreloaderLogs(preloaderLogEvents); if (ConfigUnityLogging.Value) { BepInEx.Logging.Logger.Sources.Add(new UnityLogSource()); } if (!IsHeadless) { BepInEx.Logging.Logger.Listeners.Add(new UnityLogListener()); } else if (BepInEx.Logging.Logger.Listeners.FirstOrDefault((ILogListener l) => l is ConsoleLogListener) is ConsoleLogListener consoleLogListener) { consoleLogListener.WriteUnityLogs = false; } if (PlatformHelper.Is(Platform.Unix)) { BepInEx.Logging.Logger.LogInfo("Detected Unity version: v" + UnityVersion); } BepInEx.Logging.Logger.LogMessage("Chainloader ready"); _initialized = true; } } private static void ReplayPreloaderLogs(ICollection preloaderLogEvents) { if (preloaderLogEvents == null) { return; } UnityLogListener item = new UnityLogListener(); BepInEx.Logging.Logger.Listeners.Add(item); ILogListener logListener = BepInEx.Logging.Logger.Listeners.FirstOrDefault((ILogListener logger) => logger is ConsoleLogListener); if (logListener != null) { BepInEx.Logging.Logger.Listeners.Remove(logListener); } ManualLogSource manualLogSource = BepInEx.Logging.Logger.CreateLogSource("Preloader"); foreach (LogEventArgs preloaderLogEvent in preloaderLogEvents) { BepInEx.Logging.Logger.InternalLogEvent(manualLogSource, preloaderLogEvent); } BepInEx.Logging.Logger.Sources.Remove(manualLogSource); BepInEx.Logging.Logger.Listeners.Remove(item); if (logListener != null) { BepInEx.Logging.Logger.Listeners.Add(logListener); } } public static PluginInfo ToPluginInfo(TypeDefinition type) { if (type.IsInterface || type.IsAbstract) { return null; } try { if (!type.IsSubtypeOf(typeof(BaseUnityPlugin))) { return null; } } catch (AssemblyResolutionException) { return null; } BepInPlugin bepInPlugin = BepInPlugin.FromCecilType(type); if (bepInPlugin == null) { BepInEx.Logging.Logger.LogWarning("Skipping over type [" + type.FullName + "] as no metadata attribute is specified"); return null; } if (string.IsNullOrEmpty(bepInPlugin.GUID) || !allowedGuidRegex.IsMatch(bepInPlugin.GUID)) { BepInEx.Logging.Logger.LogWarning("Skipping type [" + type.FullName + "] because its GUID [" + bepInPlugin.GUID + "] is of an illegal format."); return null; } if (bepInPlugin.Version == null) { BepInEx.Logging.Logger.LogWarning("Skipping type [" + type.FullName + "] because its version is invalid."); return null; } if (bepInPlugin.Name == null) { BepInEx.Logging.Logger.LogWarning("Skipping type [" + type.FullName + "] because its name is null."); return null; } List processes = BepInProcess.FromCecilType(type); IEnumerable dependencies = BepInDependency.FromCecilType(type); IEnumerable incompatibilities = BepInIncompatibility.FromCecilType(type); Version targettedBepInExVersion = type.Module.AssemblyReferences.FirstOrDefault((AssemblyNameReference reference) => reference.Name == "BepInEx")?.Version ?? new Version(); return new PluginInfo { Metadata = bepInPlugin, Processes = processes, Dependencies = dependencies, Incompatibilities = incompatibilities, TypeName = type.FullName, TargettedBepInExVersion = targettedBepInExVersion }; } private static bool HasBepinPlugins(AssemblyDefinition ass) { if (ass.MainModule.AssemblyReferences.All((AssemblyNameReference r) => r.Name != CurrentAssemblyName)) { return false; } if (ass.MainModule.GetTypeReferences().All((TypeReference r) => r.FullName != typeof(BepInPlugin).FullName)) { return false; } return true; } private static bool PluginTargetsWrongBepin(PluginInfo pluginInfo) { Version targettedBepInExVersion = pluginInfo.TargettedBepInExVersion; if (targettedBepInExVersion.Major != CurrentAssemblyVersion.Major) { return true; } if (targettedBepInExVersion.Minor > CurrentAssemblyVersion.Minor) { return true; } if (targettedBepInExVersion.Minor < CurrentAssemblyVersion.Minor) { return false; } return targettedBepInExVersion.Build > CurrentAssemblyVersion.Build; } public static void Start() { if (_loaded) { return; } if (!_initialized) { throw new InvalidOperationException("BepInEx has not been initialized. Please call Chainloader.Initialize prior to starting the chainloader instance."); } if (!Directory.Exists(Paths.PluginPath)) { Directory.CreateDirectory(Paths.PluginPath); } if (!Directory.Exists(Paths.PatcherPluginPath)) { Directory.CreateDirectory(Paths.PatcherPluginPath); } try { PropertyInfo property = typeof(Application).GetProperty("productName", BindingFlags.Static | BindingFlags.Public); if (ConsoleManager.ConsoleActive) { ConsoleManager.SetConsoleTitle($"{CurrentAssemblyName} {CurrentAssemblyVersion} - {property?.GetValue(null, null) ?? Paths.ProcessName}"); } BepInEx.Logging.Logger.LogMessage("Chainloader started"); ManagerObject = new GameObject("BepInEx_Manager"); if (ConfigHideBepInExGOs.Value) { ManagerObject.hideFlags = HideFlags.HideAndDontSave; } UnityEngine.Object.DontDestroyOnLoad(ManagerObject); Dictionary> dictionary = TypeLoader.FindPluginTypes(Paths.PluginPath, ToPluginInfo, HasBepinPlugins, "chainloader"); foreach (KeyValuePair> item in dictionary) { foreach (PluginInfo item2 in item.Value) { item2.Location = item.Key; } } List list = dictionary.SelectMany((KeyValuePair> p) => p.Value).ToList(); Dictionary dictionary2 = new Dictionary(); BepInEx.Logging.Logger.LogInfo(string.Format("{0} plugin{1} to load", list.Count, (list.Count == 1) ? "" : "s")); SortedDictionary> dependencyDict = new SortedDictionary>(StringComparer.InvariantCultureIgnoreCase); Dictionary pluginsByGUID = new Dictionary(); foreach (IGrouping item3 in from info in list group info by info.Metadata.GUID) { PluginInfo pluginInfo = null; foreach (PluginInfo item4 in item3.OrderByDescending((PluginInfo x) => x.Metadata.Version)) { if (pluginInfo != null) { BepInEx.Logging.Logger.LogWarning($"Skipping [{item4}] because a newer version exists ({pluginInfo})"); continue; } List list2 = item4.Processes.ToList(); if (list2.Count != 0 && list2.All((BepInProcess x) => !string.Equals(x.ProcessName.Replace(".exe", ""), Paths.ProcessName, StringComparison.InvariantCultureIgnoreCase))) { BepInEx.Logging.Logger.LogWarning(string.Format("Skipping [{0}] because of process filters ({1})", item4, string.Join(", ", item4.Processes.Select((BepInProcess p) => p.ProcessName).ToArray()))); continue; } pluginInfo = item4; dependencyDict[item4.Metadata.GUID] = item4.Dependencies.Select((BepInDependency d) => d.DependencyGUID); pluginsByGUID[item4.Metadata.GUID] = item4; } } foreach (PluginInfo item5 in pluginsByGUID.Values.ToList()) { if (item5.Incompatibilities.Any((BepInIncompatibility incompatibility) => pluginsByGUID.ContainsKey(incompatibility.IncompatibilityGUID))) { pluginsByGUID.Remove(item5.Metadata.GUID); dependencyDict.Remove(item5.Metadata.GUID); string[] value = (from x in item5.Incompatibilities select x.IncompatibilityGUID into x where pluginsByGUID.ContainsKey(x) select x).ToArray(); string text = string.Format("Could not load [{0}] because it is incompatible with: {1}", item5, string.Join(", ", value)); DependencyErrors.Add(text); BepInEx.Logging.Logger.LogError(text); } else if (PluginTargetsWrongBepin(item5)) { string text2 = $"Plugin [{item5}] targets a wrong version of BepInEx ({item5.TargettedBepInExVersion}) and might not work until you update"; DependencyErrors.Add(text2); BepInEx.Logging.Logger.LogWarning(text2); } } string[] emptyDependencies = new string[0]; List list3 = Utility.TopologicalSort(dependencyDict.Keys, (string x) => (!dependencyDict.TryGetValue(x, out var value5)) ? emptyDependencies : value5).ToList(); HashSet hashSet = new HashSet(); Dictionary dictionary3 = new Dictionary(); foreach (string item6 in list3) { if (!pluginsByGUID.TryGetValue(item6, out var value2)) { continue; } bool flag = false; List list4 = new List(); foreach (BepInDependency dependency in value2.Dependencies) { if (!dictionary3.TryGetValue(dependency.DependencyGUID, out var value3) || value3 < dependency.MinimumVersion) { if (IsHardDependency(dependency)) { list4.Add(dependency); } } else if (hashSet.Contains(dependency.DependencyGUID) && IsHardDependency(dependency)) { flag = true; break; } } dictionary3.Add(item6, value2.Metadata.Version); if (flag) { string text3 = $"Skipping [{value2}] because it has a dependency that was not loaded. See previous errors for details."; DependencyErrors.Add(text3); BepInEx.Logging.Logger.LogWarning(text3); continue; } if (list4.Count != 0) { string text4 = string.Format("Could not load [{0}] because it has missing dependencies: {1}", value2, string.Join(", ", list4.Select((BepInDependency s) => (!IsEmptyVersion(s.MinimumVersion)) ? $"{s.DependencyGUID} (v{s.MinimumVersion} or newer)" : s.DependencyGUID).ToArray())); DependencyErrors.Add(text4); BepInEx.Logging.Logger.LogError(text4); hashSet.Add(item6); continue; } try { BepInEx.Logging.Logger.LogInfo($"Loading [{value2}]"); if (!dictionary2.TryGetValue(value2.Location, out var value4)) { value4 = (dictionary2[value2.Location] = Assembly.LoadFile(value2.Location)); } PluginInfos[item6] = value2; value2.Instance = (BaseUnityPlugin)ManagerObject.AddComponent(value4.GetType(value2.TypeName)); _plugins.Add(value2.Instance); } catch (Exception ex) { hashSet.Add(item6); PluginInfos.Remove(item6); BepInEx.Logging.Logger.LogError($"Error loading [{value2}] : {ex.Message}"); if (ex is ReflectionTypeLoadException ex2) { BepInEx.Logging.Logger.LogDebug(TypeLoader.TypeLoadExceptionToString(ex2)); } else { BepInEx.Logging.Logger.LogDebug(ex); } } } } catch (Exception ex3) { try { ConsoleManager.CreateConsole(); } catch { } BepInEx.Logging.Logger.LogFatal("Error occurred starting the game"); BepInEx.Logging.Logger.LogFatal(ex3.ToString()); } BepInEx.Logging.Logger.LogMessage("Chainloader startup complete"); _loaded = true; static bool IsEmptyVersion(Version v) { if (v.Major == 0 && v.Minor == 0 && v.Build <= 0) { return v.Revision <= 0; } return false; } static bool IsHardDependency(BepInDependency dep) { return (dep.Flags & BepInDependency.DependencyFlags.HardDependency) != 0; } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Bootstrap.ICacheable ---- namespace BepInEx.Bootstrap { public interface ICacheable { void Save(BinaryWriter bw); void Load(BinaryReader br); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Bootstrap.CachedAssembly`1 ---- namespace BepInEx.Bootstrap { public class CachedAssembly where T : ICacheable { public List CacheItems { get; set; } public long Timestamp { get; set; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Bootstrap.TypeLoader ---- namespace BepInEx.Bootstrap { public static class TypeLoader { public static readonly DefaultAssemblyResolver Resolver; public static readonly ReaderParameters ReaderParameters; private static readonly ConfigEntry EnableAssemblyCache; public static event AssemblyResolveEventHandler AssemblyResolve; static TypeLoader() { EnableAssemblyCache = ConfigFile.CoreConfig.Bind("Caching", "EnableAssemblyCache", defaultValue: true, "Enable/disable assembly metadata cache\nEnabling this will speed up discovery of plugins and patchers by caching the metadata of all types BepInEx discovers."); Resolver = new DefaultAssemblyResolver(); ReaderParameters = new ReaderParameters { AssemblyResolver = Resolver }; Resolver.ResolveFailure += delegate(object sender, AssemblyNameReference reference) { if (!Utility.TryParseAssemblyName(reference.FullName, out var assemblyName)) { return TypeLoader.AssemblyResolve?.Invoke(sender, reference); } foreach (string item in new string[3] { Paths.BepInExAssemblyDirectory, Paths.PluginPath, Paths.PatcherPluginPath }.Concat(Paths.DllSearchPaths)) { if (Utility.TryResolveDllAssembly(assemblyName, item, ReaderParameters, out var assembly)) { return assembly; } } return TypeLoader.AssemblyResolve?.Invoke(sender, reference); }; } public static Dictionary> FindPluginTypes(string directory, Func typeSelector, Func assemblyFilter = null, string cacheName = null) where T : ICacheable, new() { Dictionary> dictionary = new Dictionary>(); Dictionary> dictionary2 = null; if (cacheName != null) { dictionary2 = LoadAssemblyCache(cacheName); } string[] files = Directory.GetFiles(Path.GetFullPath(directory), "*.dll", SearchOption.AllDirectories); foreach (string text in files) { try { if (dictionary2 != null && dictionary2.TryGetValue(text, out var value) && File.GetLastWriteTimeUtc(text).Ticks == value.Timestamp) { dictionary[text] = value.CacheItems; continue; } AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(text, ReaderParameters); if (assemblyFilter != null && !assemblyFilter(assemblyDefinition)) { dictionary[text] = new List(); assemblyDefinition.Dispose(); continue; } List value2 = (from t in assemblyDefinition.MainModule.Types.Select(typeSelector) where t != null select t).ToList(); dictionary[text] = value2; assemblyDefinition.Dispose(); } catch (BadImageFormatException ex) { Logger.LogDebug("Skipping loading " + text + " because it's not a valid .NET assembly. Full error: " + ex.Message); } catch (Exception ex2) { Logger.LogError(ex2.ToString()); } } if (cacheName != null) { SaveAssemblyCache(cacheName, dictionary); } return dictionary; } public static Dictionary> LoadAssemblyCache(string cacheName) where T : ICacheable, new() { if (!EnableAssemblyCache.Value) { return null; } Dictionary> dictionary = new Dictionary>(); try { string path = Path.Combine(Paths.CachePath, cacheName + "_typeloader.dat"); if (!File.Exists(path)) { return null; } using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)); int num = binaryReader.ReadInt32(); for (int i = 0; i < num; i++) { string key = binaryReader.ReadString(); long timestamp = binaryReader.ReadInt64(); int num2 = binaryReader.ReadInt32(); List list = new List(); for (int j = 0; j < num2; j++) { T item = new T(); item.Load(binaryReader); list.Add(item); } dictionary[key] = new CachedAssembly { Timestamp = timestamp, CacheItems = list }; } } catch (Exception ex) { Logger.LogWarning("Failed to load cache \"" + cacheName + "\"; skipping loading cache. Reason: " + ex.Message + "."); } return dictionary; } public static void SaveAssemblyCache(string cacheName, Dictionary> entries) where T : ICacheable { if (!EnableAssemblyCache.Value) { return; } try { if (!Directory.Exists(Paths.CachePath)) { Directory.CreateDirectory(Paths.CachePath); } using BinaryWriter binaryWriter = new BinaryWriter(File.OpenWrite(Path.Combine(Paths.CachePath, cacheName + "_typeloader.dat"))); binaryWriter.Write(entries.Count); foreach (KeyValuePair> entry in entries) { binaryWriter.Write(entry.Key); binaryWriter.Write(File.GetLastWriteTimeUtc(entry.Key).Ticks); binaryWriter.Write(entry.Value.Count); foreach (T item in entry.Value) { item.Save(binaryWriter); } } } catch (Exception ex) { Logger.LogWarning("Failed to save cache \"" + cacheName + "\"; skipping saving cache. Reason: " + ex.Message + "."); } } public static string TypeLoadExceptionToString(ReflectionTypeLoadException ex) { StringBuilder stringBuilder = new StringBuilder(); Exception[] loaderExceptions = ex.LoaderExceptions; foreach (Exception ex2 in loaderExceptions) { stringBuilder.AppendLine(ex2.Message); if (ex2 is FileNotFoundException ex3) { if (!string.IsNullOrEmpty(ex3.FusionLog)) { stringBuilder.AppendLine("Fusion Log:"); stringBuilder.AppendLine(ex3.FusionLog); } } else if (ex2 is FileLoadException ex4 && !string.IsNullOrEmpty(ex4.FusionLog)) { stringBuilder.AppendLine("Fusion Log:"); stringBuilder.AppendLine(ex4.FusionLog); } stringBuilder.AppendLine(); } return stringBuilder.ToString(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.ConsoleUtil.Kon ---- namespace BepInEx.ConsoleUtil { internal class Kon { private struct CONSOLE_SCREEN_BUFFER_INFO { internal COORD dwSize; internal COORD dwCursorPosition; internal short wAttributes; internal SMALL_RECT srWindow; internal COORD dwMaximumWindowSize; } private struct COORD { internal short X; internal short Y; } private struct SMALL_RECT { internal short Left; internal short Top; internal short Right; internal short Bottom; } private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); internal static IntPtr conOut = IntPtr.Zero; public static ConsoleColor ForegroundColor { get { return GetConsoleColor(isBackground: false); } set { SetConsoleColor(isBackground: false, value); } } public static ConsoleColor BackgroundColor { get { return GetConsoleColor(isBackground: true); } set { SetConsoleColor(isBackground: true, value); } } [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetConsoleScreenBufferInfo(IntPtr hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetConsoleTextAttribute(IntPtr hConsoleOutput, short attributes); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); private static short ConsoleColorToColorAttribute(short color, bool isBackground) { if ((color & -16) != 0) { throw new ArgumentException("Arg_InvalidConsoleColor"); } if (isBackground) { color <<= 4; } return color; } private static CONSOLE_SCREEN_BUFFER_INFO GetBufferInfo(bool throwOnNoConsole, out bool succeeded) { succeeded = false; if (!(conOut == INVALID_HANDLE_VALUE)) { if (!GetConsoleScreenBufferInfo(conOut, out var lpConsoleScreenBufferInfo)) { bool consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-12), out lpConsoleScreenBufferInfo); if (!consoleScreenBufferInfo) { consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-10), out lpConsoleScreenBufferInfo); } if (!consoleScreenBufferInfo && Marshal.GetLastWin32Error() == 6 && !throwOnNoConsole) { return default(CONSOLE_SCREEN_BUFFER_INFO); } } succeeded = true; return lpConsoleScreenBufferInfo; } if (!throwOnNoConsole) { return default(CONSOLE_SCREEN_BUFFER_INFO); } throw new Exception("IO.IO_NoConsole"); } private static void SetConsoleColor(bool isBackground, ConsoleColor c) { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); short num = ConsoleColorToColorAttribute((short)c, isBackground); bool succeeded; CONSOLE_SCREEN_BUFFER_INFO bufferInfo = GetBufferInfo(throwOnNoConsole: false, out succeeded); if (succeeded) { short wAttributes = bufferInfo.wAttributes; wAttributes &= (short)(isBackground ? (-241) : (-16)); wAttributes = (short)((ushort)wAttributes | (ushort)num); SetConsoleTextAttribute(conOut, wAttributes); } } private static ConsoleColor GetConsoleColor(bool isBackground) { bool succeeded; CONSOLE_SCREEN_BUFFER_INFO bufferInfo = GetBufferInfo(throwOnNoConsole: false, out succeeded); if (!succeeded) { if (!isBackground) { return ConsoleColor.Gray; } return ConsoleColor.Black; } return ColorAttributeToConsoleColor((short)(bufferInfo.wAttributes & 0xF0)); } private static ConsoleColor ColorAttributeToConsoleColor(short c) { if ((short)(c & 0xFF) != 0) { c >>= 4; } return (ConsoleColor)c; } public static void ResetConsoleColor() { SetConsoleColor(isBackground: true, ConsoleColor.Black); SetConsoleColor(isBackground: false, ConsoleColor.Gray); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.ConsoleWriter ---- namespace BepInEx.Unix { internal static class ConsoleWriter { private static Func cStreamWriterConstructor; private static Func CStreamWriterConstructor { get { if (cStreamWriterConstructor != null) { return cStreamWriterConstructor; } Type cStreamWriter = AccessTools.TypeByName("System.IO.CStreamWriter"); cStreamWriterConstructor = new int[2][] { new int[3] { 0, 1, 2 }, new int[2] { 0, 1 } }.Select(GetCtor).FirstOrDefault((Func f) => f != null); if (cStreamWriterConstructor == null) { throw new AmbiguousMatchException("Failed to find suitable constructor for CStreamWriter"); } return cStreamWriterConstructor; Func GetCtor(int[] perm) { Type[] parameters = new Type[3] { typeof(Stream), typeof(Encoding), typeof(bool) }; ConstructorInfo ctor = AccessTools.Constructor(cStreamWriter, perm.Select((int i) => parameters[i]).ToArray()); if ((object)ctor != null) { return delegate(Stream stream, Encoding encoding, bool l) { object[] vals = new object[3] { stream, encoding, l }; return (StreamWriter)ctor.Invoke(perm.Select((int i) => vals[i]).ToArray()); }; } return null; } } } public static TextWriter CreateConsoleStreamWriter(Stream stream, Encoding encoding, bool leaveOpen) { StreamWriter streamWriter = CStreamWriterConstructor(stream, encoding, leaveOpen); streamWriter.AutoFlush = true; return streamWriter; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.LinuxConsoleDriver ---- namespace BepInEx.Unix { internal class LinuxConsoleDriver : IConsoleDriver { private static readonly ConfigEntry ForceCustomTtyDriverConfig; public static bool UseMonoTtyDriver { get; } public TextWriter StandardOut { get; private set; } public TextWriter ConsoleOut { get; private set; } public bool ConsoleActive { get; private set; } public bool ConsoleIsExternal => false; public bool StdoutRedirected { get; private set; } public TtyInfo TtyInfo { get; private set; } static LinuxConsoleDriver() { ForceCustomTtyDriverConfig = ConfigFile.CoreConfig.Bind("Logging.Console", "ForceBepInExTTYDriver", defaultValue: false, "If enabled, forces to use custom BepInEx TTY driver for handling terminal output on unix."); UseMonoTtyDriver = false; if (!ForceCustomTtyDriverConfig.Value && (object)typeof(Console).Assembly.GetType("System.ConsoleDriver") != null) { UseMonoTtyDriver = (object)typeof(Console).Assembly.GetType("System.ParameterizedStrings") != null; } } public void PreventClose() { } public void Initialize(bool alreadyActive) { ConsoleActive = true; StdoutRedirected = UnixStreamHelper.isatty(1) != 1; Stream stream = UnixStreamHelper.CreateDuplicateStream(1); if (UseMonoTtyDriver && !StdoutRedirected) { TextWriter textWriter = ConsoleWriter.CreateConsoleStreamWriter(stream, Console.Out.Encoding, leaveOpen: true); StandardOut = TextWriter.Synchronized(textWriter); object value = AccessTools.Field(AccessTools.TypeByName("System.ConsoleDriver"), "driver").GetValue(null); AccessTools.Field(AccessTools.TypeByName("System.TermInfoDriver"), "stdout").SetValue(value, textWriter); } else { StreamWriter streamWriter = new StreamWriter(stream, Console.Out.Encoding); streamWriter.AutoFlush = true; StandardOut = TextWriter.Synchronized(streamWriter); TtyInfo = TtyHandler.GetTtyInfo(); } ConsoleOut = StandardOut; } public void CreateConsole(uint codepage) { Logger.LogWarning("An external console currently cannot be spawned on a Unix platform."); } public void DetachConsole() { throw new PlatformNotSupportedException("Cannot detach console on a Unix platform"); } public void SetConsoleColor(ConsoleColor color) { if (!StdoutRedirected) { if (UseMonoTtyDriver) { SafeConsole.ForegroundColor = color; } else { ConsoleOut.Write(TtyInfo.GetAnsiCode(color)); } } } public void SetConsoleTitle(string title) { if (!StdoutRedirected) { if (UseMonoTtyDriver && SafeConsole.TitleExists) { SafeConsole.Title = title; } else { ConsoleOut.Write("\u001b]2;" + title.Replace("\\", "\\\\") + "\a"); } } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.TtyInfo ---- namespace BepInEx.Unix { internal class TtyInfo { public string TerminalType { get; set; } = "default"; public int MaxColors { get; set; } public string[] ForegroundColorStrings { get; set; } public static TtyInfo Default { get; } = new TtyInfo { MaxColors = 0 }; public string GetAnsiCode(ConsoleColor color) { if (MaxColors <= 0 || ForegroundColorStrings == null) { return string.Empty; } int num = (int)color % MaxColors; return ForegroundColorStrings[num]; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.TtyHandler ---- namespace BepInEx.Unix { internal static class TtyHandler { private static readonly string[] ncursesLocations = new string[4] { "/usr/share/terminfo", "/etc/terminfo", "/usr/lib/terminfo", "/lib/terminfo" }; private static string TryTermInfoDir(string dir, string term) { string text = $"{dir}/{(int)term[0]:x}/{term}"; if (File.Exists(text)) { return text; } text = Utility.CombinePaths(dir, term.Substring(0, 1), term); if (File.Exists(text)) { return text; } return null; } private static string FindTermInfoPath(string term) { if (string.IsNullOrEmpty(term)) { return null; } string environmentVariable = Environment.GetEnvironmentVariable("TERMINFO"); if (environmentVariable != null && Directory.Exists(environmentVariable)) { string text = TryTermInfoDir(environmentVariable, term); if (text != null) { return text; } } string[] array = ncursesLocations; foreach (string text2 in array) { if (Directory.Exists(text2)) { string text3 = TryTermInfoDir(text2, term); if (text3 != null) { return text3; } } } return null; } public static TtyInfo GetTtyInfo(string terminal = null) { terminal = terminal ?? Environment.GetEnvironmentVariable("TERM"); string text = FindTermInfoPath(terminal); if (text == null) { return TtyInfo.Default; } TtyInfo ttyInfo = TtyInfoParser.Parse(File.ReadAllBytes(text)); ttyInfo.TerminalType = terminal; return ttyInfo; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.TtyInfoParser ---- namespace BepInEx.Unix { internal static class TtyInfoParser { internal enum TermInfoNumbers { MaxColors = 13 } internal enum TermInfoStrings { SetAForeground = 359 } private static readonly int[] ansiColorMapping = new int[16] { 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 }; public static TtyInfo Parse(byte[] buffer) { int num; switch ((int)GetInt16(buffer, 0)) { case 282: num = 2; break; case 542: num = 4; break; default: return TtyInfo.Default; } int @int = GetInt16(buffer, 4); GetInt16(buffer, 6); GetInt16(buffer, 8); int num2 = 12 + GetString(buffer, 12).Length + 1 + @int; int offset = num2 + num2 % 2 + num * 13; return new TtyInfo { MaxColors = GetInteger(num, buffer, offset), ForegroundColorStrings = ansiColorMapping.Select((int x) => $"\u001b[{((x > 7) ? (82 + x) : (30 + x))}m").ToArray() }; } private static int GetInt32(byte[] buffer, int offset) { return buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24); } private static short GetInt16(byte[] buffer, int offset) { return (short)(buffer[offset] | (buffer[offset + 1] << 8)); } private static int GetInteger(int intSize, byte[] buffer, int offset) { if (intSize != 2) { return GetInt32(buffer, offset); } return GetInt16(buffer, offset); } private static string GetString(byte[] buffer, int offset) { int i; for (i = 0; buffer[offset + i] != 0; i++) { } return Encoding.ASCII.GetString(buffer, offset, i); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.UnixStream ---- namespace BepInEx.Unix { internal class UnixStream : Stream { public override bool CanRead { get { if (Access != FileAccess.Read) { return Access == FileAccess.ReadWrite; } return true; } } public override bool CanSeek => false; public override bool CanWrite { get { if (Access != FileAccess.Write) { return Access == FileAccess.ReadWrite; } return true; } } public override long Length { get { throw new InvalidOperationException(); } } public override long Position { get { throw new InvalidOperationException(); } set { throw new InvalidOperationException(); } } public FileAccess Access { get; } public IntPtr FileHandle { get; } public UnixStream(int fileDescriptor, FileAccess access) { Access = access; int fd = UnixStreamHelper.dup(fileDescriptor); FileHandle = UnixStreamHelper.fdopen(fd, (access == FileAccess.Write) ? "w" : "r"); } public override void Flush() { UnixStreamHelper.fflush(FileHandle); } public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException(); } public override void SetLength(long value) { throw new InvalidOperationException(); } public override int Read(byte[] buffer, int offset, int count) { GCHandle gCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr intPtr = UnixStreamHelper.fread(new IntPtr(gCHandle.AddrOfPinnedObject().ToInt64() + offset), (IntPtr)count, (IntPtr)1, FileHandle); gCHandle.Free(); return intPtr.ToInt32(); } public override void Write(byte[] buffer, int offset, int count) { GCHandle gCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); UnixStreamHelper.fwrite(new IntPtr(gCHandle.AddrOfPinnedObject().ToInt64() + offset), (IntPtr)count, (IntPtr)1, FileHandle); gCHandle.Free(); } private void ReleaseUnmanagedResources() { UnixStreamHelper.fclose(FileHandle); } protected override void Dispose(bool disposing) { ReleaseUnmanagedResources(); base.Dispose(disposing); } ~UnixStream() { Dispose(disposing: false); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Unix.UnixStreamHelper ---- namespace BepInEx.Unix { internal static class UnixStreamHelper { public delegate int dupDelegate(int fd); public delegate IntPtr fdopenDelegate(int fd, string mode); public delegate IntPtr freadDelegate(IntPtr ptr, IntPtr size, IntPtr nmemb, IntPtr stream); public delegate int fwriteDelegate(IntPtr ptr, IntPtr size, IntPtr nmemb, IntPtr stream); public delegate int fcloseDelegate(IntPtr stream); public delegate int fflushDelegate(IntPtr stream); public delegate int isattyDelegate(int fd); [DynDllImport("libc", new string[] { })] public static dupDelegate dup; [DynDllImport("libc", new string[] { })] public static fdopenDelegate fdopen; [DynDllImport("libc", new string[] { })] public static freadDelegate fread; [DynDllImport("libc", new string[] { })] public static fwriteDelegate fwrite; [DynDllImport("libc", new string[] { })] public static fcloseDelegate fclose; [DynDllImport("libc", new string[] { })] public static fflushDelegate fflush; [DynDllImport("libc", new string[] { })] public static isattyDelegate isatty; static UnixStreamHelper() { Dictionary> mappings = new Dictionary> { ["libc"] = new List { "libc.so.6", "libc", "/usr/lib/libSystem.dylib" } }; typeof(UnixStreamHelper).ResolveDynDllImports(mappings); } public static Stream CreateDuplicateStream(int fileDescriptor) { return new UnixStream(dup(fileDescriptor), FileAccess.Write); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.AcceptableValueBase ---- namespace BepInEx.Configuration { public abstract class AcceptableValueBase { public Type ValueType { get; } protected AcceptableValueBase(Type valueType) { ValueType = valueType; } public abstract object Clamp(object value); public abstract bool IsValid(object value); public abstract string ToDescriptionString(); } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.AcceptableValueList`1 ---- namespace BepInEx.Configuration { public class AcceptableValueList : AcceptableValueBase where T : IEquatable { public virtual T[] AcceptableValues { get; } public AcceptableValueList(params T[] acceptableValues) : base(typeof(T)) { if (acceptableValues == null) { throw new ArgumentNullException("acceptableValues"); } if (acceptableValues.Length == 0) { throw new ArgumentException("At least one acceptable value is needed", "acceptableValues"); } AcceptableValues = acceptableValues; } public override object Clamp(object value) { if (IsValid(value)) { return value; } return AcceptableValues[0]; } public override bool IsValid(object value) { if (value is T) { T v = (T)value; return AcceptableValues.Any((T x) => x.Equals(v)); } return false; } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", AcceptableValues.Select((T x) => x.ToString()).ToArray()); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.AcceptableValueRange`1 ---- namespace BepInEx.Configuration { public class AcceptableValueRange : AcceptableValueBase where T : IComparable { public virtual T MinValue { get; } public virtual T MaxValue { get; } public AcceptableValueRange(T minValue, T maxValue) : base(typeof(T)) { if (maxValue == null) { throw new ArgumentNullException("maxValue"); } if (minValue == null) { throw new ArgumentNullException("minValue"); } if (minValue.CompareTo(maxValue) >= 0) { throw new ArgumentException("minValue has to be lower than maxValue"); } MinValue = minValue; MaxValue = maxValue; } public override object Clamp(object value) { if (MinValue.CompareTo(value) > 0) { return MinValue; } if (MaxValue.CompareTo(value) < 0) { return MaxValue; } return value; } public override bool IsValid(object value) { if (MinValue.CompareTo(value) <= 0) { return MaxValue.CompareTo(value) >= 0; } return false; } public override string ToDescriptionString() { return $"# Acceptable value range: From {MinValue} to {MaxValue}"; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.ConfigEntry`1 ---- namespace BepInEx.Configuration { public sealed class ConfigEntry : ConfigEntryBase { private T _typedValue; public T Value { get { return _typedValue; } set { value = ClampValue(value); if (!object.Equals(_typedValue, value)) { _typedValue = value; OnSettingChanged(this); } } } public override object BoxedValue { get { return Value; } set { Value = (T)value; } } public event EventHandler SettingChanged; internal ConfigEntry(ConfigFile configFile, ConfigDefinition definition, T defaultValue, ConfigDescription configDescription) : base(configFile, definition, typeof(T), defaultValue, configDescription) { configFile.SettingChanged += delegate(object sender, SettingChangedEventArgs args) { if (args.ChangedSetting == this) { this.SettingChanged?.Invoke(sender, args); } }; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.ConfigEntryBase ---- namespace BepInEx.Configuration { public abstract class ConfigEntryBase { public ConfigFile ConfigFile { get; } public ConfigDefinition Definition { get; } public ConfigDescription Description { get; } public Type SettingType { get; } public object DefaultValue { get; } public abstract object BoxedValue { get; set; } internal ConfigEntryBase(ConfigFile configFile, ConfigDefinition definition, Type settingType, object defaultValue, ConfigDescription configDescription) { ConfigFile = configFile ?? throw new ArgumentNullException("configFile"); Definition = definition ?? throw new ArgumentNullException("definition"); SettingType = settingType ?? throw new ArgumentNullException("settingType"); Description = configDescription ?? ConfigDescription.Empty; if (Description.AcceptableValues != null && !SettingType.IsAssignableFrom(Description.AcceptableValues.ValueType)) { throw new ArgumentException("configDescription.AcceptableValues is for a different type than the type of this setting"); } DefaultValue = defaultValue; BoxedValue = defaultValue; } public string GetSerializedValue() { return TomlTypeConverter.ConvertToString(BoxedValue, SettingType); } public void SetSerializedValue(string value) { try { object boxedValue = TomlTypeConverter.ConvertToValue(value, SettingType); BoxedValue = boxedValue; } catch (Exception ex) { Logger.Log(LogLevel.Warning, $"Config value of setting \"{Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } } protected T ClampValue(T value) { if (Description.AcceptableValues != null) { return (T)Description.AcceptableValues.Clamp(value); } return value; } protected void OnSettingChanged(object sender) { ConfigFile.OnSettingChanged(sender, this); } public void WriteDescription(StreamWriter writer) { if (!string.IsNullOrEmpty(Description.Description)) { writer.WriteLine("## " + Description.Description.Replace("\n", "\n## ")); } writer.WriteLine("# Setting type: " + SettingType.Name); writer.WriteLine("# Default value: " + TomlTypeConverter.ConvertToString(DefaultValue, SettingType)); if (Description.AcceptableValues != null) { writer.WriteLine(Description.AcceptableValues.ToDescriptionString()); } else if (SettingType.IsEnum) { writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(SettingType))); if (SettingType.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any()) { writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)"); } } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.ConfigDefinition ---- namespace BepInEx.Configuration { public class ConfigDefinition : IEquatable { private static readonly char[] _invalidConfigChars = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' }; public string Section { get; } public string Key { get; } public ConfigDefinition(string section, string key) { CheckInvalidConfigChars(section, "section"); CheckInvalidConfigChars(key, "key"); Key = key; Section = section; } private static void CheckInvalidConfigChars(string val, string name) { if (val == null) { throw new ArgumentNullException(name); } if (val != val.Trim()) { throw new ArgumentException("Cannot use whitespace characters at start or end of section and key names", name); } if (val.Any((char c) => _invalidConfigChars.Contains(c))) { throw new ArgumentException("Cannot use any of the following characters in section and key names: = \\n \\t \\ \" ' [ ]", name); } } [Obsolete("description argument is no longer used, put it in a ConfigDescription instead")] public ConfigDefinition(string section, string key, string description) { Key = key ?? ""; Section = section ?? ""; } public bool Equals(ConfigDefinition other) { if (other == null) { return false; } if (string.Equals(Key, other.Key)) { return string.Equals(Section, other.Section); } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } return Equals(obj as ConfigDefinition); } public override int GetHashCode() { return (((Key != null) ? Key.GetHashCode() : 0) * 397) ^ ((Section != null) ? Section.GetHashCode() : 0); } public static bool operator ==(ConfigDefinition left, ConfigDefinition right) { return object.Equals(left, right); } public static bool operator !=(ConfigDefinition left, ConfigDefinition right) { return !object.Equals(left, right); } public override string ToString() { return Section + "." + Key; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.ConfigDescription ---- namespace BepInEx.Configuration { public class ConfigDescription { public string Description { get; } public AcceptableValueBase AcceptableValues { get; } public object[] Tags { get; } public static ConfigDescription Empty { get; } = new ConfigDescription("", null); public ConfigDescription(string description, AcceptableValueBase acceptableValues = null, params object[] tags) { AcceptableValues = acceptableValues; Tags = tags; Description = description ?? throw new ArgumentNullException("description"); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.ConfigFile ---- namespace BepInEx.Configuration { public class ConfigFile : IDictionary, ICollection>, IEnumerable>, IEnumerable { private readonly BepInPlugin _ownerMetadata; private readonly object _ioLock = new object(); internal static ConfigFile CoreConfig { get; } = new ConfigFile(Paths.BepInExConfigPath, saveOnInit: true); protected Dictionary Entries { get; } = new Dictionary(); private Dictionary OrphanedEntries { get; } = new Dictionary(); [Obsolete("Use Keys instead")] public ReadOnlyCollection ConfigDefinitions { get { lock (_ioLock) { return Entries.Keys.ToList().AsReadOnly(); } } } public string ConfigFilePath { get; } public bool SaveOnConfigSet { get; set; } = true; public int Count { get { lock (_ioLock) { return Entries.Count; } } } public bool IsReadOnly => false; ConfigEntryBase IDictionary.this[ConfigDefinition key] { get { lock (_ioLock) { return Entries[key]; } } set { throw new InvalidOperationException("Directly setting a config entry is not supported"); } } public ConfigEntryBase this[ConfigDefinition key] { get { lock (_ioLock) { return Entries[key]; } } } public ConfigEntryBase this[string section, string key] => this[new ConfigDefinition(section, key)]; public ICollection Keys { get { lock (_ioLock) { return Entries.Keys.ToArray(); } } } ICollection IDictionary.Values { get { lock (_ioLock) { return Entries.Values.ToArray(); } } } public event EventHandler ConfigReloaded; public event EventHandler SettingChanged; [Obsolete("Use Values instead")] public ConfigEntryBase[] GetConfigEntries() { lock (_ioLock) { return Entries.Values.ToArray(); } } public ConfigFile(string configPath, bool saveOnInit) : this(configPath, saveOnInit, null) { } public ConfigFile(string configPath, bool saveOnInit, BepInPlugin ownerMetadata) { _ownerMetadata = ownerMetadata; if (configPath == null) { throw new ArgumentNullException("configPath"); } configPath = Path.GetFullPath(configPath); ConfigFilePath = configPath; if (File.Exists(ConfigFilePath)) { Reload(); } else if (saveOnInit) { Save(); } } public void Reload() { lock (_ioLock) { OrphanedEntries.Clear(); string section = string.Empty; string[] array = File.ReadAllLines(ConfigFilePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.StartsWith("#")) { continue; } if (text.StartsWith("[") && text.EndsWith("]")) { section = text.Substring(1, text.Length - 2); continue; } string[] array2 = text.Split(new char[1] { '=' }, 2); if (array2.Length == 2) { string key = array2[0].Trim(); string text2 = array2[1].Trim(); ConfigDefinition key2 = new ConfigDefinition(section, key); Entries.TryGetValue(key2, out var value); if (value != null) { value.SetSerializedValue(text2); } else { OrphanedEntries[key2] = text2; } } } } OnConfigReloaded(); } public void Save() { lock (_ioLock) { string directoryName = Path.GetDirectoryName(ConfigFilePath); if (directoryName != null) { Directory.CreateDirectory(directoryName); } using StreamWriter streamWriter = new StreamWriter(ConfigFilePath, append: false, Utility.UTF8NoBom); if (_ownerMetadata != null) { streamWriter.WriteLine($"## Settings file was created by plugin {_ownerMetadata.Name} v{_ownerMetadata.Version}"); streamWriter.WriteLine("## Plugin GUID: " + _ownerMetadata.GUID); streamWriter.WriteLine(); } foreach (var item in from x in Entries.Select((KeyValuePair x) => new { Key = x.Key, entry = x.Value, value = x.Value.GetSerializedValue() }).Concat(OrphanedEntries.Select((KeyValuePair x) => new { Key = x.Key, entry = (ConfigEntryBase)null, value = x.Value })) group x by x.Key.Section into x orderby x.Key select x) { streamWriter.WriteLine("[" + item.Key + "]"); foreach (var item2 in item) { streamWriter.WriteLine(); item2.entry?.WriteDescription(streamWriter); streamWriter.WriteLine(item2.Key.Key + " = " + item2.value); } streamWriter.WriteLine(); } } } [Obsolete("Use ConfigFile[key] or TryGetEntry instead")] public ConfigEntry GetSetting(ConfigDefinition configDefinition) { if (!TryGetEntry(configDefinition, out ConfigEntry entry)) { return null; } return entry; } [Obsolete("Use ConfigFile[key] or TryGetEntry instead")] public ConfigEntry GetSetting(string section, string key) { if (!TryGetEntry(section, key, out ConfigEntry entry)) { return null; } return entry; } public bool TryGetEntry(ConfigDefinition configDefinition, out ConfigEntry entry) { lock (_ioLock) { if (Entries.TryGetValue(configDefinition, out var value)) { entry = (ConfigEntry)value; return true; } entry = null; return false; } } public bool TryGetEntry(string section, string key, out ConfigEntry entry) { return TryGetEntry(new ConfigDefinition(section, key), out entry); } public ConfigEntry Bind(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription = null) { if (!TomlTypeConverter.CanConvert(typeof(T))) { throw new ArgumentException(string.Format("Type {0} is not supported by the config system. Supported types: {1}", typeof(T), string.Join(", ", (from x in TomlTypeConverter.GetSupportedTypes() select x.Name).ToArray()))); } lock (_ioLock) { if (Entries.TryGetValue(configDefinition, out var value)) { return (ConfigEntry)value; } ConfigEntry configEntry = new ConfigEntry(this, configDefinition, defaultValue, configDescription); Entries[configDefinition] = configEntry; if (OrphanedEntries.TryGetValue(configDefinition, out var value2)) { configEntry.SetSerializedValue(value2); OrphanedEntries.Remove(configDefinition); } if (SaveOnConfigSet) { Save(); } return configEntry; } } public ConfigEntry Bind(string section, string key, T defaultValue, ConfigDescription configDescription = null) { return Bind(new ConfigDefinition(section, key), defaultValue, configDescription); } public ConfigEntry Bind(string section, string key, T defaultValue, string description) { return Bind(new ConfigDefinition(section, key), defaultValue, new ConfigDescription(description, null)); } [Obsolete("Use Bind instead")] public ConfigEntry AddSetting(ConfigDefinition configDefinition, T defaultValue, ConfigDescription configDescription = null) { return Bind(configDefinition, defaultValue, configDescription); } [Obsolete("Use Bind instead")] public ConfigEntry AddSetting(string section, string key, T defaultValue, ConfigDescription configDescription = null) { return Bind(new ConfigDefinition(section, key), defaultValue, configDescription); } [Obsolete("Use Bind instead")] public ConfigEntry AddSetting(string section, string key, T defaultValue, string description) { return Bind(new ConfigDefinition(section, key), defaultValue, new ConfigDescription(description, null)); } [Obsolete("Use Bind instead")] public ConfigWrapper Wrap(string section, string key, string description = null, T defaultValue = default(T)) { lock (_ioLock) { ConfigDefinition configDefinition = new ConfigDefinition(section, key, description); return new ConfigWrapper(Bind(configDefinition, defaultValue, string.IsNullOrEmpty(description) ? null : new ConfigDescription(description, null))); } } [Obsolete("Use Bind instead")] public ConfigWrapper Wrap(ConfigDefinition configDefinition, T defaultValue = default(T)) { return Wrap(configDefinition.Section, configDefinition.Key, null, defaultValue); } internal void OnSettingChanged(object sender, ConfigEntryBase changedEntryBase) { if (changedEntryBase == null) { throw new ArgumentNullException("changedEntryBase"); } if (SaveOnConfigSet) { Save(); } EventHandler eventHandler = this.SettingChanged; if (eventHandler == null) { return; } SettingChangedEventArgs e = new SettingChangedEventArgs(changedEntryBase); foreach (EventHandler item in eventHandler.GetInvocationList().Cast>()) { try { item(sender, e); } catch (Exception data) { Logger.Log(LogLevel.Error, data); } } } private void OnConfigReloaded() { EventHandler eventHandler = this.ConfigReloaded; if (eventHandler == null) { return; } foreach (EventHandler item in eventHandler.GetInvocationList().Cast()) { try { item(this, EventArgs.Empty); } catch (Exception data) { Logger.Log(LogLevel.Error, data); } } } public IEnumerator> GetEnumerator() { return Entries.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void ICollection>.Add(KeyValuePair item) { lock (_ioLock) { Entries.Add(item.Key, item.Value); } } public bool Contains(KeyValuePair item) { lock (_ioLock) { return ((ICollection>)Entries).Contains(item); } } void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { lock (_ioLock) { ((ICollection>)Entries).CopyTo(array, arrayIndex); } } bool ICollection>.Remove(KeyValuePair item) { lock (_ioLock) { return Entries.Remove(item.Key); } } public bool ContainsKey(ConfigDefinition key) { lock (_ioLock) { return Entries.ContainsKey(key); } } public void Add(ConfigDefinition key, ConfigEntryBase value) { throw new InvalidOperationException("Directly adding a config entry is not supported"); } public bool Remove(ConfigDefinition key) { lock (_ioLock) { return Entries.Remove(key); } } public void Clear() { lock (_ioLock) { Entries.Clear(); } } bool IDictionary.TryGetValue(ConfigDefinition key, out ConfigEntryBase value) { lock (_ioLock) { return Entries.TryGetValue(key, out value); } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.ConfigWrapper`1 ---- namespace BepInEx.Configuration { [Obsolete("Use ConfigFile from new Bind overloads instead")] public sealed class ConfigWrapper { public ConfigEntry ConfigEntry { get; } public ConfigDefinition Definition => ConfigEntry.Definition; public ConfigFile ConfigFile => ConfigEntry.ConfigFile; public T Value { get { return ConfigEntry.Value; } set { ConfigEntry.Value = value; } } public event EventHandler SettingChanged; internal ConfigWrapper(ConfigEntry configEntry) { ConfigWrapper configWrapper = this; ConfigEntry = configEntry ?? throw new ArgumentNullException("configEntry"); configEntry.ConfigFile.SettingChanged += delegate(object sender, SettingChangedEventArgs args) { if (args.ChangedSetting == configEntry) { configWrapper.SettingChanged?.Invoke(sender, args); } }; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.KeyboardShortcut ---- namespace BepInEx.Configuration { public struct KeyboardShortcut { public static readonly KeyboardShortcut Empty; [Obsolete("Use UnityInput.Current.SupportedKeyCodes instead")] public static readonly IEnumerable AllKeyCodes; private static KeyCode[] _modifierBlockKeyCodes; private readonly KeyCode[] _allKeys; public KeyCode MainKey { get { if (_allKeys == null || _allKeys.Length == 0) { return KeyCode.None; } return _allKeys[0]; } } public IEnumerable Modifiers => _allKeys?.Skip(1) ?? Enumerable.Empty(); static KeyboardShortcut() { Empty = default(KeyboardShortcut); AllKeyCodes = (KeyCode[])Enum.GetValues(typeof(KeyCode)); TomlTypeConverter.AddConverter(typeof(KeyboardShortcut), new TypeConverter { ConvertToString = (object o, Type type) => ((KeyboardShortcut)o).Serialize(), ConvertToObject = (string s, Type type) => Deserialize(s) }); } public KeyboardShortcut(KeyCode mainKey, params KeyCode[] modifiers) : this(new KeyCode[1] { mainKey }.Concat(modifiers).ToArray()) { if (mainKey == KeyCode.None && modifiers.Any()) { throw new ArgumentException("Can't set mainKey to KeyCode.None if there are any modifiers"); } } private KeyboardShortcut(KeyCode[] keys) { _allKeys = SanitizeKeys(keys); } private static KeyCode[] SanitizeKeys(params KeyCode[] keys) { if (keys.Length == 0 || keys[0] == KeyCode.None) { return new KeyCode[1]; } return new KeyCode[1] { keys[0] }.Concat(from x in keys.Skip(1).Distinct() where x != keys[0] orderby (int)x select x).ToArray(); } public static KeyboardShortcut Deserialize(string str) { try { return new KeyboardShortcut((from x in str.Split(new char[5] { ' ', '+', ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries) select (KeyCode)Enum.Parse(typeof(KeyCode), x)).ToArray()); } catch (SystemException ex) { BepInEx.Logging.Logger.Log(LogLevel.Error, "Failed to read keybind from settings: " + ex.Message); return Empty; } } public string Serialize() { if (_allKeys == null) { return string.Empty; } return string.Join(" + ", _allKeys.Select((KeyCode x) => x.ToString()).ToArray()); } public bool IsDown() { KeyCode mainKey = MainKey; if (mainKey == KeyCode.None) { return false; } if (UnityInput.Current.GetKeyDown(mainKey)) { return ModifierKeyTest(); } return false; } public bool IsPressed() { KeyCode mainKey = MainKey; if (mainKey == KeyCode.None) { return false; } if (UnityInput.Current.GetKey(mainKey)) { return ModifierKeyTest(); } return false; } public bool IsUp() { KeyCode mainKey = MainKey; if (mainKey == KeyCode.None) { return false; } if (UnityInput.Current.GetKeyUp(mainKey)) { return ModifierKeyTest(); } return false; } private bool ModifierKeyTest() { KeyCode[] allKeys = _allKeys; KeyCode mainKey = MainKey; if (!allKeys.All((KeyCode c) => c == mainKey || UnityInput.Current.GetKey(c))) { return false; } if (_modifierBlockKeyCodes == null) { _modifierBlockKeyCodes = UnityInput.Current.SupportedKeyCodes.Except(new KeyCode[8] { KeyCode.Mouse0, KeyCode.Mouse1, KeyCode.Mouse2, KeyCode.Mouse3, KeyCode.Mouse4, KeyCode.Mouse5, KeyCode.Mouse6, KeyCode.None }).ToArray(); } return _modifierBlockKeyCodes.All((KeyCode c) => !UnityInput.Current.GetKey(c) || allKeys.Contains(c)); } public override string ToString() { if (MainKey == KeyCode.None) { return "Not set"; } return string.Join(" + ", _allKeys.Select((KeyCode c) => c.ToString()).ToArray()); } public override bool Equals(object obj) { if (obj is KeyboardShortcut keyboardShortcut && MainKey == keyboardShortcut.MainKey) { return Modifiers.SequenceEqual(keyboardShortcut.Modifiers); } return false; } public override int GetHashCode() { if (MainKey == KeyCode.None) { return 0; } return _allKeys.Aggregate(_allKeys.Length, (int current, KeyCode item) => (int)(current * 31 + item)); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.SettingChangedEventArgs ---- namespace BepInEx.Configuration { public sealed class SettingChangedEventArgs : EventArgs { public ConfigEntryBase ChangedSetting { get; } public SettingChangedEventArgs(ConfigEntryBase changedSetting) { ChangedSetting = changedSetting; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.TomlTypeConverter ---- namespace BepInEx.Configuration { public static class TomlTypeConverter { private static bool _lazyLoadedConverters; private static Dictionary TypeConverters { get; } = new Dictionary { [typeof(string)] = new TypeConverter { ConvertToString = (object obj, Type type) => ((string)obj).Escape(), ConvertToObject = (string str, Type type) => Regex.IsMatch(str, "^\"?\\w:\\\\(?!\\\\)(?!.+\\\\\\\\)") ? str : str.Unescape() }, [typeof(bool)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString().ToLowerInvariant(), ConvertToObject = (string str, Type type) => bool.Parse(str) }, [typeof(byte)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => byte.Parse(str) }, [typeof(sbyte)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => sbyte.Parse(str) }, [typeof(byte)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => byte.Parse(str) }, [typeof(short)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => short.Parse(str) }, [typeof(ushort)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => ushort.Parse(str) }, [typeof(int)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => int.Parse(str) }, [typeof(uint)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => uint.Parse(str) }, [typeof(long)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => long.Parse(str) }, [typeof(ulong)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => ulong.Parse(str) }, [typeof(float)] = new TypeConverter { ConvertToString = (object obj, Type type) => ((float)obj).ToString(NumberFormatInfo.InvariantInfo), ConvertToObject = (string str, Type type) => float.Parse(str, NumberFormatInfo.InvariantInfo) }, [typeof(double)] = new TypeConverter { ConvertToString = (object obj, Type type) => ((double)obj).ToString(NumberFormatInfo.InvariantInfo), ConvertToObject = (string str, Type type) => double.Parse(str, NumberFormatInfo.InvariantInfo) }, [typeof(decimal)] = new TypeConverter { ConvertToString = (object obj, Type type) => ((decimal)obj).ToString(NumberFormatInfo.InvariantInfo), ConvertToObject = (string str, Type type) => decimal.Parse(str, NumberFormatInfo.InvariantInfo) }, [typeof(Enum)] = new TypeConverter { ConvertToString = (object obj, Type type) => obj.ToString(), ConvertToObject = (string str, Type type) => Enum.Parse(type, str, ignoreCase: true) } }; public static string ConvertToString(object value, Type valueType) { return (GetConverter(valueType) ?? throw new InvalidOperationException($"Cannot convert from type {valueType}")).ConvertToString(value, valueType); } public static T ConvertToValue(string value) { return (T)ConvertToValue(value, typeof(T)); } public static object ConvertToValue(string value, Type valueType) { return (GetConverter(valueType) ?? throw new InvalidOperationException("Cannot convert to type " + valueType.Name)).ConvertToObject(value, valueType); } public static TypeConverter GetConverter(Type valueType) { if ((object)valueType == null) { throw new ArgumentNullException("valueType"); } if (valueType.IsEnum) { return TypeConverters[typeof(Enum)]; } if (!TypeConverters.TryGetValue(valueType, out var value) && !_lazyLoadedConverters) { _lazyLoadedConverters = true; LazyLoadConverters(); TypeConverters.TryGetValue(valueType, out value); } return value; } public static bool AddConverter(Type type, TypeConverter converter) { if ((object)type == null) { throw new ArgumentNullException("type"); } if (converter == null) { throw new ArgumentNullException("converter"); } if (CanConvert(type)) { Logger.LogWarning("Tried to add a TomlConverter when one already exists for type " + type.FullName); return false; } TypeConverters.Add(type, converter); return true; } public static bool CanConvert(Type type) { return GetConverter(type) != null; } public static IEnumerable GetSupportedTypes() { return TypeConverters.Keys; } private static void LazyLoadConverters() { try { LazyTomlConverterLoader.AddUnityEngineConverters(); } catch (Exception ex) { Logger.LogWarning("Failed to load UnityEngine Toml converters - " + ex.Message); } } private static string Escape(this string txt) { if (string.IsNullOrEmpty(txt)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(txt.Length + 2); foreach (char c in txt) { switch (c) { case '\0': stringBuilder.Append("\\0"); break; case '\a': stringBuilder.Append("\\a"); break; case '\b': stringBuilder.Append("\\b"); break; case '\t': stringBuilder.Append("\\t"); break; case '\n': stringBuilder.Append("\\n"); break; case '\v': stringBuilder.Append("\\v"); break; case '\f': stringBuilder.Append("\\f"); break; case '\r': stringBuilder.Append("\\r"); break; case '\'': stringBuilder.Append("\\'"); break; case '\\': stringBuilder.Append("\\"); break; case '"': stringBuilder.Append("\\\""); break; default: stringBuilder.Append(c); break; } } return stringBuilder.ToString(); } private static string Unescape(this string txt) { if (string.IsNullOrEmpty(txt)) { return txt; } StringBuilder stringBuilder = new StringBuilder(txt.Length); int num = 0; while (num < txt.Length) { int num2 = txt.IndexOf('\\', num); if (num2 < 0 || num2 == txt.Length - 1) { num2 = txt.Length; } stringBuilder.Append(txt, num, num2 - num); if (num2 >= txt.Length) { break; } char c = txt[num2 + 1]; switch (c) { case '0': stringBuilder.Append('\0'); break; case 'a': stringBuilder.Append('\a'); break; case 'b': stringBuilder.Append('\b'); break; case 't': stringBuilder.Append('\t'); break; case 'n': stringBuilder.Append('\n'); break; case 'v': stringBuilder.Append('\v'); break; case 'f': stringBuilder.Append('\f'); break; case 'r': stringBuilder.Append('\r'); break; case '\'': stringBuilder.Append('\''); break; case '"': stringBuilder.Append('"'); break; case '\\': stringBuilder.Append('\\'); break; default: stringBuilder.Append('\\').Append(c); break; } num = num2 + 2; } return stringBuilder.ToString(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.LazyTomlConverterLoader ---- namespace BepInEx.Configuration { internal static class LazyTomlConverterLoader { [MethodImpl(MethodImplOptions.NoInlining)] public static void AddUnityEngineConverters() { TypeConverter converter = new TypeConverter { ConvertToString = (object obj, Type type) => ColorUtility.ToHtmlStringRGBA((Color)obj), ConvertToObject = delegate(string str, Type type) { if (!ColorUtility.TryParseHtmlString("#" + str.Trim('#', ' '), out var color)) { throw new FormatException("Invalid color string, expected hex #RRGGBBAA"); } return color; } }; TomlTypeConverter.AddConverter(typeof(Color), converter); TypeConverter converter2 = new TypeConverter { ConvertToString = (object obj, Type type) => JsonUtility.ToJson(obj), ConvertToObject = (string str, Type type) => JsonUtility.FromJson(str, type) }; TomlTypeConverter.AddConverter(typeof(Vector2), converter2); TomlTypeConverter.AddConverter(typeof(Vector3), converter2); TomlTypeConverter.AddConverter(typeof(Vector4), converter2); TomlTypeConverter.AddConverter(typeof(Quaternion), converter2); TomlTypeConverter.AddConverter(typeof(Rect), new TypeConverter { ConvertToObject = StringToRect, ConvertToString = RectToString }); } private static object StringToRect(string s, Type type) { Rect rect = default(Rect); if (s == null) { return rect; } string[] array = s.Trim('{', '}').Replace(" ", "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }); if (array2.Length == 2 && float.TryParse(array2[1], out var result)) { switch (array2[0].Trim(new char[1] { '"' })) { case "x": rect.x = result; break; case "y": rect.y = result; break; case "width": case "z": rect.width = result; break; case "height": case "w": rect.height = result; break; } } } return rect; } private static string RectToString(object o, Type type) { Rect rect = (Rect)o; return string.Format(CultureInfo.InvariantCulture, "{{ \"x\":{0}, \"y\":{1}, \"width\":{2}, \"height\":{3} }}", rect.x, rect.y, rect.width, rect.height); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.dll :: BepInEx.Configuration.TypeConverter ---- namespace BepInEx.Configuration { public class TypeConverter { public Func ConvertToString { get; set; } public Func ConvertToObject { get; set; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/HarmonyXInterop.dll :: HarmonyXInterop.DMDUtil ---- namespace HarmonyXInterop { internal static class DMDUtil { public static MethodInfo GenerateWith(this DynamicMethodDefinition dmd, object context = null) where T : DMDGenerator, new() { return DMDGenerator.Generate(dmd, context); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/HarmonyXInterop.dll :: HarmonyXInterop.HarmonyInterop ---- namespace HarmonyXInterop { public static class HarmonyInterop { private const string BACKUP_PATH = "BepInEx_Shim_Backup"; private static Version maxAvailableShimVersion; private static readonly SortedDictionary Assemblies = new SortedDictionary(); private static readonly HashSet InteropAssemblyNames = new HashSet(); private static readonly Func UpdateWrapper = AccessTools.MethodDelegate>(AccessTools.Method(typeof(HarmonyManipulator).Assembly.GetType("HarmonyLib.PatchFunctions"), "UpdateWrapper")); private static readonly Action, bool> HarmonyLog = AccessTools.MethodDelegate, bool>>(AccessTools.Method(typeof(Logger), "Log")); private static readonly Action HarmonyLogText = AccessTools.MethodDelegate>(AccessTools.Method(typeof(Logger), "LogText")); private static readonly Dictionary shimCache = new Dictionary(); private static BinaryWriter cacheWriter; public static void Log(int channel, Func message) { HarmonyLog((Logger.LogChannel)channel, message, arg3: false); } public static void LogText(int channel, string message) { HarmonyLogText((Logger.LogChannel)channel, message, arg3: false); } public static void Initialize(string cachePath) { Directory.CreateDirectory(cachePath); string path = Path.Combine(cachePath, "harmony_interop_cache.dat"); string[] files = Directory.GetFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "0Harmony*.dll", SearchOption.AllDirectories); for (int i = 0; i < files.Length; i++) { using AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(files[i]); if (assemblyDefinition.Name.Name != "0Harmony") { Assemblies.Add(assemblyDefinition.Name.Version, assemblyDefinition.Name.Name); InteropAssemblyNames.Add(assemblyDefinition.Name.Name); } } maxAvailableShimVersion = Assemblies.LastOrDefault().Key; if (File.Exists(path)) { try { using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)); while (true) { string key = binaryReader.ReadString(); long value = binaryReader.ReadInt64(); shimCache[key] = value; } } catch (Exception) { } } try { cacheWriter = new BinaryWriter(File.Create(path)); foreach (KeyValuePair item in shimCache) { cacheWriter.Write(item.Key); cacheWriter.Write(item.Value); } cacheWriter.Flush(); } catch (IOException) { } } public static byte[] TryShim(string path, string gameRootDirectory, Action logMessage = null, ReaderParameters readerParameters = null) { HashSet hashSet = new HashSet(StringComparer.InvariantCultureIgnoreCase); List deps; byte[] result = TryShimInternal(path, gameRootDirectory, logMessage, readerParameters, out deps); foreach (string item in deps) { hashSet.Add(item); } while (hashSet.Count != 0) { string text = hashSet.First(); TryShimInternal(text, gameRootDirectory, logMessage, readerParameters, out deps); foreach (string item2 in deps) { hashSet.Add(item2); } hashSet.Remove(text); } return result; } private static bool NeedsShimming(string path, out long lastWriteTime, Action logMessage = null) { lastWriteTime = 0L; try { if (!File.Exists(path)) { return false; } } catch (Exception arg) { logMessage?.Invoke($"Failed to read path {path}: {arg}"); return false; } lastWriteTime = File.GetLastWriteTimeUtc(path).Ticks; if (shimCache.TryGetValue(path, out var value)) { return value != lastWriteTime; } return true; } private static byte[] TryShimInternal(string path, string gameRootDirectory, Action logMessage, ReaderParameters readerParameters, out List deps) { deps = new List(); if (!NeedsShimming(path, out var lastWriteTime, logMessage)) { return null; } byte[] result = null; try { string dir = Path.GetDirectoryName(path); byte[] array; try { array = File.ReadAllBytes(path); } catch (Exception) { return null; } using MemoryStream stream = new MemoryStream(array); using AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(stream, readerParameters ?? new ReaderParameters()); deps.AddRange(from a in assemblyDefinition.MainModule.AssemblyReferences select Path.Combine(dir, a.Name + ".dll") into p where NeedsShimming(p, out var _, logMessage) select p); AssemblyNameReference harmonyRef = assemblyDefinition.MainModule.AssemblyReferences.FirstOrDefault((AssemblyNameReference a) => a.Name.StartsWith("0Harmony") && !InteropAssemblyNames.Contains(a.Name)); if (harmonyRef != null) { KeyValuePair keyValuePair = Assemblies.LastOrDefault((KeyValuePair kv) => VersionMatches(kv.Key, harmonyRef.Version)); if (keyValuePair.Value != null) { logMessage?.Invoke("Shimming " + path + " to use older version of Harmony (" + keyValuePair.Value + "). Please update the plugin if possible."); harmonyRef.Name = keyValuePair.Value; using MemoryStream memoryStream = new MemoryStream(); assemblyDefinition.Write(memoryStream); try { string path2 = Path.Combine(gameRootDirectory, "BepInEx_Shim_Backup"); string directoryName = Path.GetDirectoryName(Path.GetFullPath(path).Substring(gameRootDirectory.Length + 1)); string text = Path.Combine(path2, directoryName); Directory.CreateDirectory(text); File.WriteAllBytes(Path.Combine(text, Path.GetFileName(path)), array); File.WriteAllBytes(path, memoryStream.ToArray()); lastWriteTime = File.GetLastWriteTimeUtc(path).Ticks; } catch (IOException) { lastWriteTime = 0L; } result = memoryStream.ToArray(); } } shimCache[path] = lastWriteTime; if (cacheWriter != null) { cacheWriter.Write(path); cacheWriter.Write(lastWriteTime); cacheWriter.Flush(); } } catch (Exception arg) { logMessage?.Invoke($"Failed to shim {path}: {arg}"); } return result; static bool VersionMatches(Version cmpV, Version refV) { if (maxAvailableShimVersion != null && refV <= maxAvailableShimVersion && cmpV.Major == refV.Major && cmpV.Minor == refV.Minor) { return cmpV <= refV; } return false; } } public static void ApplyPatch(MethodBase target, PatchInfoWrapper add, PatchInfoWrapper remove) { PatchInfo patchInfo = target.ToPatchInfo(); lock (patchInfo) { patchInfo.prefixes = Sync(add.prefixes, remove.prefixes, patchInfo.prefixes); patchInfo.postfixes = Sync(add.postfixes, remove.postfixes, patchInfo.postfixes); patchInfo.transpilers = Sync(WrapTranspilers(add.transpilers), WrapTranspilers(remove.transpilers), patchInfo.transpilers); patchInfo.finalizers = Sync(add.finalizers, remove.finalizers, patchInfo.finalizers); } UpdateWrapper(target, patchInfo); static PatchMethod[] WrapTranspilers(PatchMethod[] transpilers) { return transpilers.Select((PatchMethod p) => new PatchMethod { after = p.after, before = p.before, method = TranspilerInterop.WrapInterop(p.method), owner = p.owner, priority = p.priority }).ToArray(); } } private static Patch[] Sync(PatchMethod[] add, PatchMethod[] remove, Patch[] current) { if (add.Length == 0 && remove.Length == 0) { return current; } current = current.Where((Patch p) => !remove.Any((PatchMethod r) => (object)r.method == p.PatchMethod && r.owner == p.owner)).ToArray(); int initialIndex = current.Length; return current.Concat(add.Where((PatchMethod method) => method != null).Select((PatchMethod method, int i) => new Patch(method.ToHarmonyMethod(), i + initialIndex, method.owner))).ToArray(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/HarmonyXInterop.dll :: HarmonyXInterop.PatchInfoWrapper ---- namespace HarmonyXInterop { public class PatchInfoWrapper { public PatchMethod[] finalizers; public PatchMethod[] postfixes; public PatchMethod[] prefixes; public PatchMethod[] transpilers; } } // ---- BepInExPack_Sunkenland/BepInEx/core/HarmonyXInterop.dll :: HarmonyXInterop.PatchMethod ---- namespace HarmonyXInterop { public class PatchMethod { public string[] after; public string[] before; public MethodInfo method; public string owner; public int priority = -1; public HarmonyMethod ToHarmonyMethod() { return new HarmonyMethod { after = after, before = before, method = method, priority = priority }; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/HarmonyXInterop.dll :: HarmonyXInterop.PatchMethodComparer ---- namespace HarmonyXInterop { public class PatchMethodComparer : IEqualityComparer { public static PatchMethodComparer Instance { get; } = new PatchMethodComparer(); public bool Equals(PatchMethod x, PatchMethod y) { if (x == y) { return true; } if (x == null) { return false; } if (y == null) { return false; } if ((object)x.GetType() != y.GetType()) { return false; } if (object.Equals(x.method, y.method)) { return x.owner == y.owner; } return false; } public int GetHashCode(PatchMethod obj) { return ((((object)obj.method != null) ? obj.method.GetHashCode() : 0) * 397) ^ ((obj.owner != null) ? obj.owner.GetHashCode() : 0); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/HarmonyXInterop.dll :: HarmonyXInterop.TranspilerInterop ---- namespace HarmonyXInterop { internal static class TranspilerInterop { private static readonly Dictionary AllJumpCodes = new Dictionary { { OpCodes.Beq_S, OpCodes.Beq }, { OpCodes.Bge_S, OpCodes.Bge }, { OpCodes.Bge_Un_S, OpCodes.Bge_Un }, { OpCodes.Bgt_S, OpCodes.Bgt }, { OpCodes.Bgt_Un_S, OpCodes.Bgt_Un }, { OpCodes.Ble_S, OpCodes.Ble }, { OpCodes.Ble_Un_S, OpCodes.Ble_Un }, { OpCodes.Blt_S, OpCodes.Blt }, { OpCodes.Blt_Un_S, OpCodes.Blt_Un }, { OpCodes.Bne_Un_S, OpCodes.Bne_Un }, { OpCodes.Brfalse_S, OpCodes.Brfalse }, { OpCodes.Brtrue_S, OpCodes.Brtrue }, { OpCodes.Br_S, OpCodes.Br }, { OpCodes.Leave_S, OpCodes.Leave } }; private static readonly Dictionary Wrappers = new Dictionary(); private static readonly MethodInfo ResolveToken = AccessTools.Method(typeof(MethodBase), "GetMethodFromHandle", new Type[1] { typeof(RuntimeMethodHandle) }); private static readonly MethodInfo ApplyTranspilerMethod = AccessTools.Method(typeof(TranspilerInterop), "ApplyTranspiler"); public static MethodInfo WrapInterop(MethodInfo transpiler) { lock (Wrappers) { if (Wrappers.TryGetValue(transpiler, out var value)) { return value; } } using DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition("TranspilerWrapper<" + transpiler.GetID(null, null, withType: true, proxyMethod: false, simple: true) + ">", typeof(IEnumerable), new Type[3] { typeof(IEnumerable), typeof(ILGenerator), typeof(MethodBase) }); ILGenerator iLGenerator = dynamicMethodDefinition.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldtoken, transpiler); iLGenerator.Emit(OpCodes.Call, ResolveToken); iLGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Call, ApplyTranspilerMethod); iLGenerator.Emit(OpCodes.Ret); MethodInfo methodInfo = dynamicMethodDefinition.GenerateWith(); lock (Wrappers) { Wrappers[transpiler] = methodInfo; } return methodInfo; } private static IEnumerable ApplyTranspiler(MethodInfo transpiler, IEnumerable instructions, ILGenerator generator, MethodBase method) { Dictionary> unassignedValues; IEnumerable enumerable = ConvertToGeneralInstructions(transpiler, instructions, out unassignedValues); List originalInstructions = null; if (unassignedValues != null) { originalInstructions = instructions.Cast().ToList(); } List transpilerCallParameters = GetTranspilerCallParameters(generator, transpiler, method, enumerable); if (transpiler.Invoke(null, transpilerCallParameters.ToArray()) is IEnumerable enumerable2) { enumerable = enumerable2; } if (unassignedValues != null) { enumerable = ConvertToOurInstructions(enumerable, typeof(CodeInstruction), originalInstructions, unassignedValues); } return (enumerable as List) ?? enumerable.Cast().ToList(); } private static OpCode ReplaceShortJumps(OpCode opcode) { using (IEnumerator> enumerator = AllJumpCodes.Where((KeyValuePair pair) => opcode == pair.Key).GetEnumerator()) { if (enumerator.MoveNext()) { return enumerator.Current.Value; } } return opcode; } private static object ConvertInstruction(Type type, object instruction, out Dictionary unassigned) { Dictionary nonExisting = new Dictionary(); object result = AccessTools.MakeDeepCopy(instruction, type, delegate(string namePath, Traverse trvSrc, Traverse trvDest) { object value = trvSrc.GetValue(); if (trvDest.FieldExists()) { if (!(namePath == "opcode")) { return value; } return ReplaceShortJumps((OpCode)value); } nonExisting[namePath] = value; return (object)null; }); unassigned = nonExisting; return result; } private static bool ShouldAddExceptionInfo(object op, int opIndex, List originalInstructions, List newInstructions, Dictionary> unassignedValues) { int num = originalInstructions.IndexOf(op); if (num == -1) { return false; } if (!unassignedValues.TryGetValue(op, out var unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out var blocksObject)) { return false; } List blocks = blocksObject as List; if (newInstructions.Count((object instr) => instr == op) <= 1) { return true; } ExceptionBlock exceptionBlock = blocks.FirstOrDefault((ExceptionBlock block) => block.blockType != ExceptionBlockType.EndExceptionBlock); ExceptionBlock exceptionBlock2 = blocks.FirstOrDefault((ExceptionBlock block) => block.blockType == ExceptionBlockType.EndExceptionBlock); if (exceptionBlock != null && exceptionBlock2 == null) { object obj = originalInstructions.Skip(num + 1).FirstOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List; return blocks.Any(); }); if (obj != null) { int num2 = num + 1; int num3 = num2 + originalInstructions.Skip(num2).ToList().IndexOf(obj) - 1; IEnumerable first = originalInstructions.GetRange(num2, num3 - num2).Intersect(newInstructions); obj = newInstructions.Skip(opIndex + 1).FirstOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List; return blocks.Any(); }); if (obj != null) { num2 = opIndex + 1; num3 = num2 + newInstructions.Skip(opIndex + 1).ToList().IndexOf(obj) - 1; List range = newInstructions.GetRange(num2, num3 - num2); return !first.Except(range).ToList().Any(); } } } if (exceptionBlock == null && exceptionBlock2 != null) { object obj2 = originalInstructions.GetRange(0, num).LastOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List; return blocks.Any(); }); if (obj2 == null) { return true; } int num4 = originalInstructions.GetRange(0, num).LastIndexOf(obj2); int num5 = num; IEnumerable first2 = originalInstructions.GetRange(num4, num5 - num4).Intersect(newInstructions); obj2 = newInstructions.GetRange(0, opIndex).LastOrDefault(delegate(object instr) { if (!unassignedValues.TryGetValue(instr, out unassigned)) { return false; } if (!unassigned.TryGetValue("blocks", out blocksObject)) { return false; } blocks = blocksObject as List; return blocks.Any(); }); if (obj2 == null) { return true; } num4 = newInstructions.GetRange(0, opIndex).LastIndexOf(obj2); num5 = opIndex; List range2 = newInstructions.GetRange(num4, num5 - num4); return !first2.Except(range2).Any(); } return true; } private static IEnumerable ConvertInstructionsAndUnassignedValues(Type type, IEnumerable enumerable, out Dictionary> unassignedValues) { Assembly assembly = type.GetGenericTypeDefinition().Assembly; Type type2 = assembly.GetType(typeof(List<>).FullName); Type type3 = type.GetGenericArguments()[0]; Type type4 = type2.MakeGenericType(type3); object obj = Activator.CreateInstance(assembly.GetType(type4.FullName)); MethodInfo method = obj.GetType().GetMethod("Add"); unassignedValues = new Dictionary>(); foreach (object item in enumerable) { Dictionary unassigned; object obj2 = ConvertInstruction(type3, item, out unassigned); unassignedValues.Add(obj2, unassigned); method.Invoke(obj, new object[1] { obj2 }); } return obj as IEnumerable; } private static IEnumerable ConvertToOurInstructions(IEnumerable instructions, Type codeInstructionType, List originalInstructions, Dictionary> unassignedValues) { List newInstructions = instructions.Cast().ToList(); int index = -1; foreach (object item in newInstructions) { index++; object obj = AccessTools.MakeDeepCopy(item, codeInstructionType); if (unassignedValues.TryGetValue(item, out var value)) { bool addExceptionInfo = ShouldAddExceptionInfo(item, index, originalInstructions, newInstructions, unassignedValues); Traverse traverse = Traverse.Create(obj); foreach (KeyValuePair item2 in value.Where((KeyValuePair field) => addExceptionInfo || field.Key != "blocks")) { traverse.Field(item2.Key).SetValue(item2.Value); } } yield return obj; } } private static bool IsCodeInstructionsParameter(Type type) { if (type.IsGenericType) { return type.GetGenericTypeDefinition().Name.StartsWith("IEnumerable", StringComparison.Ordinal); } return false; } private static IEnumerable ConvertToGeneralInstructions(MethodInfo transpiler, IEnumerable enumerable, out Dictionary> unassignedValues) { Type type = (from p in transpiler.GetParameters() select p.ParameterType).FirstOrDefault((Type t) => IsCodeInstructionsParameter(t)); if ((object)type == null) { unassignedValues = new Dictionary>(); return enumerable; } if ((object)type != typeof(IEnumerable)) { return ConvertInstructionsAndUnassignedValues(type, enumerable, out unassignedValues); } unassignedValues = null; return (enumerable as IList) ?? ((enumerable as IEnumerable) ?? enumerable.Cast()).ToList(); } private static List GetTranspilerCallParameters(ILGenerator generator, MethodInfo transpiler, MethodBase method, IEnumerable instructions) { List parameter = new List(); (from param in transpiler.GetParameters() select param.ParameterType).Do(delegate(Type type) { if (type.IsAssignableFrom(typeof(ILGenerator))) { parameter.Add(generator); } else if (type.IsAssignableFrom(typeof(MethodBase))) { parameter.Add(method); } else if (IsCodeInstructionsParameter(type)) { parameter.Add(instructions); } }); return parameter; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Harmony.dll :: BepInEx.Harmony.ParameterByRefAttribute ---- namespace BepInEx.Harmony { [AttributeUsage(AttributeTargets.Method)] [Obsolete("Use HarmonyLib.ParameterByRefAttribute directly", true)] public class ParameterByRefAttribute : ParameterByRefAttribute { public int[] ParameterIndices => ((ParameterByRefAttribute)this).ParameterIndices; public ParameterByRefAttribute(params int[] parameterIndices) : base(parameterIndices) { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Harmony.dll :: BepInEx.Harmony.HarmonyExtensions ---- namespace BepInEx.Harmony { public static class HarmonyExtensions { [Obsolete("Use HarmonyLib.Harmony.PatchAll directly", true)] public static void PatchAll(this HarmonyLib.Harmony harmonyInstance, Type type) { HarmonyWrapper.PatchAll(type, harmonyInstance); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Harmony.dll :: BepInEx.Harmony.HarmonyWrapper ---- namespace BepInEx.Harmony { public class HarmonyWrapper { [Obsolete("Use HarmonyLib.Harmony.CreateAndPatchAll or HarmonyLib.Harmony.PatchAll", true)] public static HarmonyLib.Harmony PatchAll(Type type, HarmonyLib.Harmony harmonyInstance = null) { if (harmonyInstance == null) { return HarmonyLib.Harmony.CreateAndPatchAll(type); } harmonyInstance.PatchAll(type); return harmonyInstance; } [Obsolete("Use HarmonyLib.Harmony.CreateAndPatchAll", true)] public static HarmonyLib.Harmony PatchAll(Type type, string harmonyInstanceId) { return HarmonyLib.Harmony.CreateAndPatchAll(type, harmonyInstanceId); } [Obsolete("Use HarmonyLib.Harmony.CreateAndPatchAll or HarmonyLib.Harmony.PatchAll", true)] public static HarmonyLib.Harmony PatchAll(Assembly assembly, HarmonyLib.Harmony harmonyInstance = null) { return assembly.GetTypes().Aggregate(harmonyInstance, (HarmonyLib.Harmony current, Type type) => PatchAll(type, current)); } [Obsolete("Use HarmonyLib.Harmony.CreateAndPatchAll", true)] public static HarmonyLib.Harmony PatchAll(Assembly assembly, string harmonyInstanceId) { return HarmonyLib.Harmony.CreateAndPatchAll(assembly, harmonyInstanceId); } [Obsolete("Use HarmonyLib.Harmony.PatchAll with no arguments", true)] public static HarmonyLib.Harmony PatchAll(HarmonyLib.Harmony harmonyInstance = null) { return PatchAll(Assembly.GetCallingAssembly(), harmonyInstance); } [Obsolete("Use HarmonyLib.Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), ...)", true)] public static HarmonyLib.Harmony PatchAll(string harmonyInstanceId) { return PatchAll(Assembly.GetCallingAssembly(), harmonyInstanceId); } [Obsolete("Use HarmonyLib.Transpilers.EmitDelegate instead", true)] public static CodeInstruction EmitDelegate(T action) where T : Delegate { return Transpilers.EmitDelegate(action); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.EnvVars ---- namespace BepInEx.Preloader { public static class EnvVars { public static string DOORSTOP_INVOKE_DLL_PATH { get; private set; } public static string DOORSTOP_MANAGED_FOLDER_DIR { get; private set; } public static string DOORSTOP_PROCESS_PATH { get; private set; } public static string[] DOORSTOP_DLL_SEARCH_DIRS { get; private set; } internal static void LoadVars() { DOORSTOP_INVOKE_DLL_PATH = Environment.GetEnvironmentVariable("DOORSTOP_INVOKE_DLL_PATH"); DOORSTOP_MANAGED_FOLDER_DIR = Environment.GetEnvironmentVariable("DOORSTOP_MANAGED_FOLDER_DIR"); DOORSTOP_PROCESS_PATH = Environment.GetEnvironmentVariable("DOORSTOP_PROCESS_PATH"); DOORSTOP_DLL_SEARCH_DIRS = Environment.GetEnvironmentVariable("DOORSTOP_DLL_SEARCH_DIRS")?.Split(new char[1] { Path.PathSeparator }) ?? new string[0]; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.PreloaderRunner ---- namespace BepInEx.Preloader { internal static class PreloaderRunner { private static readonly string[] CriticalAssemblies = new string[7] { "Mono.Cecil.dll", "Mono.Cecil.Mdb.dll", "Mono.Cecil.Pdb.dll", "Mono.Cecil.Rocks.dll", "MonoMod.Utils.dll", "MonoMod.RuntimeDetour.dll", "0Harmony.dll" }; private static void LoadCriticalAssemblies() { string[] criticalAssemblies = CriticalAssemblies; foreach (string path in criticalAssemblies) { try { Assembly.LoadFile(Path.Combine(Paths.BepInExAssemblyDirectory, path)); } catch (Exception) { } } } public static void PreloaderPreMain() { PlatformUtils.SetPlatform(); string bepinRootPath = Utility.ParentDirectory(Path.GetFullPath(EnvVars.DOORSTOP_INVOKE_DLL_PATH), 2); Paths.SetExecutablePath(EnvVars.DOORSTOP_PROCESS_PATH, bepinRootPath, EnvVars.DOORSTOP_MANAGED_FOLDER_DIR, EnvVars.DOORSTOP_DLL_SEARCH_DIRS); LoadCriticalAssemblies(); AppDomain.CurrentDomain.AssemblyResolve += LocalResolve; AppDomain.CurrentDomain.AssemblyResolve -= Entrypoint.ResolveCurrentDirectory; PreloaderMain(); } private static void PreloaderMain() { if (Preloader.ConfigApplyRuntimePatches.Value) { XTermFix.Apply(); ConsoleSetOutFix.Apply(); } Preloader.Run(); } private static Assembly LocalResolve(object sender, ResolveEventArgs args) { if (!Utility.TryParseAssemblyName(args.Name, out var assemblyName)) { return null; } var source = (from a in AppDomain.CurrentDomain.GetAssemblies() select new { assembly = a, name = (Utility.TryParseAssemblyName(a.FullName, out var assemblyName2) ? assemblyName2 : null) } into a where a.name != null && a.name.Name == assemblyName.Name orderby a.name.Version descending select a).ToList(); Assembly assembly = (source.FirstOrDefault(a => a.name.Version == assemblyName.Version) ?? source.FirstOrDefault())?.assembly; if ((object)assembly != null) { return assembly; } if (Utility.TryResolveDllAssembly(assemblyName, Paths.BepInExAssemblyDirectory, out assembly) || Utility.TryResolveDllAssembly(assemblyName, Paths.PatcherPluginPath, out assembly) || Utility.TryResolveDllAssembly(assemblyName, Paths.PluginPath, out assembly)) { return assembly; } return null; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.Entrypoint ---- namespace BepInEx.Preloader { internal static class Entrypoint { private static string preloaderPath; public static void Main() { string text = $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"; try { EnvVars.LoadVars(); text = Path.Combine(Path.GetDirectoryName(EnvVars.DOORSTOP_PROCESS_PATH) ?? ".", text); preloaderPath = Path.GetDirectoryName(Path.GetFullPath(EnvVars.DOORSTOP_INVOKE_DLL_PATH)); AppDomain.CurrentDomain.AssemblyResolve += ResolveCurrentDirectory; typeof(Entrypoint).Assembly.GetType("BepInEx.Preloader.PreloaderRunner")?.GetMethod("PreloaderPreMain")?.Invoke(null, null); } catch (Exception ex) { File.WriteAllText(text, ex.ToString()); } finally { AppDomain.CurrentDomain.AssemblyResolve -= ResolveCurrentDirectory; } } internal static Assembly ResolveCurrentDirectory(object sender, ResolveEventArgs args) { AssemblyName assemblyName = new AssemblyName(args.Name); try { return Assembly.LoadFile(Path.Combine(preloaderPath, assemblyName.Name + ".dll")); } catch (Exception) { return null; } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.PlatformUtils ---- namespace BepInEx.Preloader { internal static class PlatformUtils { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct utsname_osx { private const int osx_utslen = 256; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string sysname; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string nodename; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string release; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string version; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string machine; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct utsname_linux { private const int linux_utslen = 65; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string sysname; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string nodename; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string release; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string version; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string machine; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string domainname; } [DllImport("libc.so.6", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "uname")] private static extern IntPtr uname_linux(ref utsname_linux utsname); [DllImport("/usr/lib/libSystem.dylib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "uname")] private static extern IntPtr uname_osx(ref utsname_osx utsname); public static void SetPlatform() { Platform platform = Platform.Unknown; PropertyInfo property = typeof(Environment).GetProperty("Platform", BindingFlags.Static | BindingFlags.NonPublic); string text = (((object)property == null) ? Environment.OSVersion.Platform.ToString() : property.GetValue(null, new object[0]).ToString()); text = text.ToLowerInvariant(); if (text.Contains("win")) { platform = Platform.Windows; } else if (text.Contains("mac") || text.Contains("osx")) { platform = Platform.MacOS; } else if (text.Contains("lin") || text.Contains("unix")) { platform = Platform.Linux; } if (Is(platform, Platform.Linux) && Directory.Exists("/data") && File.Exists("/system/build.prop")) { platform = Platform.Android; } else if (Is(platform, Platform.Unix) && Directory.Exists("/System/Library/AccessibilityBundles")) { platform = Platform.iOS; } MethodInfo methodInfo = typeof(Environment).GetProperty("Is64BitOperatingSystem")?.GetGetMethod(); platform = (Platform)(((object)methodInfo == null) ? ((int)platform | ((IntPtr.Size >= 8) ? 2 : 0)) : ((int)platform | (((bool)methodInfo.Invoke(null, new object[0])) ? 2 : 0))); if ((Is(platform, Platform.MacOS) || Is(platform, Platform.Linux)) && (object)Type.GetType("Mono.Runtime") != null) { IntPtr intPtr; string machine; if (Is(platform, Platform.MacOS)) { utsname_osx utsname = default(utsname_osx); intPtr = uname_osx(ref utsname); machine = utsname.machine; } else { utsname_linux utsname2 = default(utsname_linux); intPtr = uname_linux(ref utsname2); machine = utsname2.machine; } if (intPtr == IntPtr.Zero && (machine.StartsWith("aarch") || machine.StartsWith("arm"))) { platform |= Platform.ARM; } } else { typeof(object).Module.GetPEKind(out var _, out var machine2); if (machine2 == ImageFileMachine.ARM) { platform |= Platform.ARM; } } PlatformHelper.Current = platform; } private static bool Is(Platform current, Platform expected) { return (current & expected) == expected; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.Preloader ---- namespace BepInEx.Preloader { internal static class Preloader { private enum MonoModBackend { [Description("Auto")] auto, [Description("DynamicMethod")] dynamicmethod, [Description("MethodBuilder")] methodbuilder, [Description("Cecil")] cecil } private static readonly ConfigEntry ConfigEntrypointAssembly = ConfigFile.CoreConfig.Bind("Preloader.Entrypoint", "Assembly", IsPostUnity2017 ? "UnityEngine.CoreModule.dll" : "UnityEngine.dll", "The local filename of the assembly to target."); private static readonly ConfigEntry ConfigEntrypointType = ConfigFile.CoreConfig.Bind("Preloader.Entrypoint", "Type", "Application", "The name of the type in the entrypoint assembly to search for the entrypoint method."); private static readonly ConfigEntry ConfigEntrypointMethod = ConfigFile.CoreConfig.Bind("Preloader.Entrypoint", "Method", ".cctor", "The name of the method in the specified entrypoint assembly and type to hook and load Chainloader from."); internal static readonly ConfigEntry ConfigApplyRuntimePatches = ConfigFile.CoreConfig.Bind("Preloader", "ApplyRuntimePatches", defaultValue: true, "Enables or disables runtime patches.\nThis should always be true, unless you cannot start the game due to a Harmony related issue (such as running .NET Standard runtime) or you know what you're doing."); private static readonly ConfigEntry HarmonyBackend = ConfigFile.CoreConfig.Bind("Preloader", "HarmonyBackend", MonoModBackend.auto, "Specifies which MonoMod backend to use for Harmony patches. Auto uses the best available backend.\nThis setting should only be used for development purposes (e.g. debugging in dnSpy). Other code might override this setting."); private static PreloaderConsoleListener PreloaderLog { get; set; } public static bool IsPostUnity2017 { get; } = File.Exists(Path.Combine(Paths.ManagedPath, "UnityEngine.CoreModule.dll")); public static void Run() { try { InitializeHarmony(); HarmonyInteropFix.Apply(); ConsoleManager.Initialize(alreadyActive: false); AllocateConsole(); Utility.TryDo(delegate { if (ConfigApplyRuntimePatches.Value) { UnityPatches.Apply(); } }, out var exception); Logger.InitializeInternalLoggers(); Logger.Sources.Add(TraceLogSource.CreateSource()); PreloaderLog = new PreloaderConsoleListener(); Logger.Listeners.Add(PreloaderLog); Version version = typeof(Paths).Assembly.GetName().Version; string text = $"BepInEx {version} - {Paths.ProcessName}"; if (ConsoleManager.ConsoleActive) { ConsoleManager.SetConsoleTitle(text); } Logger.LogMessage($"{text} ({File.GetLastWriteTime(Paths.ExecutablePath)})"); object[] customAttributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), inherit: false); if (customAttributes.Length != 0) { Logger.LogMessage(((BuildInfoAttribute)customAttributes[0]).Info); } Logger.LogInfo("Running under Unity v" + GetUnityVersion()); Logger.LogInfo($"CLR runtime version: {Environment.Version}"); Logger.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}"); Logger.LogInfo($"System platform: {PlatformHelper.Current}"); if (exception != null) { Logger.LogWarning("Failed to apply runtime patches for Mono. See more info in the output log. Error message: " + exception.Message); } Logger.LogMessage("Preloader started"); AssemblyPatcher.AddPatcher(new PatcherPlugin { TargetDLLs = () => new string[1] { ConfigEntrypointAssembly.Value }, Patcher = PatchEntrypoint, TypeName = "BepInEx.Chainloader" }); Logger.Log(LogLevel.Info, $"Loaded 1 patcher method from [BepInEx.Preloader {version}]"); AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath); Logger.LogInfo(string.Format("{0} patcher plugin{1} loaded", AssemblyPatcher.PatcherPlugins.Count, (AssemblyPatcher.PatcherPlugins.Count == 1) ? "" : "s")); AssemblyPatcher.PatchAndLoad(Paths.DllSearchPaths); AssemblyPatcher.DisposePatchers(); Logger.LogMessage("Preloader finished"); Logger.Listeners.Remove(PreloaderLog); PreloaderLog.Dispose(); } catch (Exception ex) { try { Logger.LogFatal("Could not run preloader!"); Logger.LogFatal(ex); if (!ConsoleManager.ConsoleActive) { AllocateConsole(); Console.Write(PreloaderLog); } } catch { } string text2 = string.Empty; try { text2 = string.Join("\r\n", PreloaderConsoleListener.LogEvents.Select((LogEventArgs x) => x.ToString()).ToArray()); text2 += "\r\n"; PreloaderLog?.Dispose(); PreloaderLog = null; } catch { } File.WriteAllText(Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"), text2 + ex); } } public static void PatchEntrypoint(ref AssemblyDefinition assembly) { if (assembly.MainModule.AssemblyReferences.Any((AssemblyNameReference x) => x.Name.Contains("BepInEx"))) { throw new Exception("BepInEx has been detected to be patched! Please unpatch before using a patchless variant!"); } string entrypointType = ConfigEntrypointType.Value; string entrypointMethod = ConfigEntrypointMethod.Value; bool flag = entrypointMethod.IsNullOrWhiteSpace() || entrypointMethod == ".cctor"; TypeDefinition typeDefinition = assembly.MainModule.Types.FirstOrDefault((TypeDefinition x) => x.Name == entrypointType); if (typeDefinition == null) { throw new Exception("The entrypoint type is invalid! Please check your config/BepInEx.cfg file"); } using AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(Paths.BepInExAssemblyPath); MethodDefinition method = assemblyDefinition.MainModule.Types.First((TypeDefinition x) => x.Name == "Chainloader").Methods.First((MethodDefinition x) => x.Name == "Initialize"); MethodDefinition method2 = assemblyDefinition.MainModule.Types.First((TypeDefinition x) => x.Name == "Chainloader").Methods.First((MethodDefinition x) => x.Name == "Start"); MethodReference method3 = assembly.MainModule.ImportReference(method); MethodReference method4 = assembly.MainModule.ImportReference(method2); List list = new List(); if (flag) { MethodDefinition methodDefinition = typeDefinition.Methods.FirstOrDefault((MethodDefinition m) => m.IsConstructor && m.IsStatic); if (methodDefinition == null) { methodDefinition = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, assembly.MainModule.ImportReference(typeof(void))); typeDefinition.Methods.Add(methodDefinition); ILProcessor iLProcessor = methodDefinition.Body.GetILProcessor(); iLProcessor.Append(iLProcessor.Create(OpCodes.Ret)); } list.Add(methodDefinition); } else { list.AddRange(typeDefinition.Methods.Where((MethodDefinition x) => x.Name == entrypointMethod)); } if (!list.Any()) { throw new Exception("The entrypoint method is invalid! Please check your config.ini"); } foreach (MethodDefinition item in list) { ILProcessor iLProcessor2 = item.Body.GetILProcessor(); Instruction target = iLProcessor2.Body.Instructions.First(); iLProcessor2.InsertBefore(target, iLProcessor2.Create(OpCodes.Ldnull)); iLProcessor2.InsertBefore(target, iLProcessor2.Create(OpCodes.Ldc_I4_0)); iLProcessor2.InsertBefore(target, iLProcessor2.Create(OpCodes.Call, assembly.MainModule.ImportReference(AccessTools.PropertyGetter(typeof(PreloaderConsoleListener), "LogEvents")))); iLProcessor2.InsertBefore(target, iLProcessor2.Create(OpCodes.Call, method3)); iLProcessor2.InsertBefore(target, iLProcessor2.Create(OpCodes.Call, method4)); } } public static void AllocateConsole() { if (!ConsoleManager.ConsoleEnabled) { return; } try { ConsoleManager.CreateConsole(); Logger.Listeners.Add(new ConsoleLogListener()); } catch (Exception data) { Logger.LogError("Failed to allocate console!"); Logger.LogError(data); } } public static string GetUnityVersion() { if (PlatformHelper.Is(Platform.Windows)) { return FileVersionInfo.GetVersionInfo(Paths.ExecutablePath).FileVersion; } return "Unknown (" + (IsPostUnity2017 ? "post" : "pre") + "-2017)"; } private static void InitializeHarmony() { switch (HarmonyBackend.Value) { case MonoModBackend.dynamicmethod: case MonoModBackend.methodbuilder: case MonoModBackend.cecil: Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", HarmonyBackend.Value.ToString()); break; default: throw new ArgumentOutOfRangeException("HarmonyBackend", HarmonyBackend.Value, "Unknown backend"); case MonoModBackend.auto: break; } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.PreloaderConsoleListener ---- namespace BepInEx.Preloader { public class PreloaderConsoleListener : ILogListener, IDisposable { private static readonly ConfigEntry ConfigConsoleDisplayedLevel = ConfigFile.CoreConfig.Bind("Logging.Console", "LogLevels", LogLevel.Fatal | LogLevel.Error | LogLevel.Warning | LogLevel.Message | LogLevel.Info, "Which log levels to show in the console output."); public static List LogEvents { get; } = new List(); public void LogEvent(object sender, LogEventArgs eventArgs) { if ((eventArgs.Level & ConfigConsoleDisplayedLevel.Value) != LogLevel.None) { LogEvents.Add(eventArgs); } } public void Dispose() { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.RuntimeFixes.ConsoleSetOutFix ---- namespace BepInEx.Preloader.RuntimeFixes { internal static class ConsoleSetOutFix { private static LoggedTextWriter loggedTextWriter; internal static ManualLogSource ConsoleLogSource = Logger.CreateLogSource("Console"); public static void Apply() { loggedTextWriter = new LoggedTextWriter { Parent = Console.Out }; Console.SetOut(loggedTextWriter); Harmony.CreateAndPatchAll(typeof(ConsoleSetOutFix)); } [HarmonyPatch(typeof(Console), "SetOut")] [HarmonyPrefix] private static bool OnSetOut(TextWriter newOut) { loggedTextWriter.Parent = newOut; return false; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.RuntimeFixes.LoggedTextWriter ---- namespace BepInEx.Preloader.RuntimeFixes { internal class LoggedTextWriter : TextWriter { public override Encoding Encoding { get; } = Encoding.UTF8; public TextWriter Parent { get; set; } public override void Flush() { Parent.Flush(); } public override void Write(string value) { ConsoleSetOutFix.ConsoleLogSource.LogInfo(value); Parent.Write(value); } public override void WriteLine(string value) { ConsoleSetOutFix.ConsoleLogSource.LogInfo(value); Parent.WriteLine(value); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.RuntimeFixes.HarmonyInteropFix ---- namespace BepInEx.Preloader.RuntimeFixes { internal static class HarmonyInteropFix { public static void Apply() { HarmonyInterop.Initialize(Paths.CachePath); Harmony.CreateAndPatchAll(typeof(HarmonyInteropFix), "org.bepinex.fixes.harmonyinterop"); } [HarmonyReversePatch(HarmonyReversePatchType.Original)] [HarmonyPatch(typeof(Assembly), "LoadFile", new Type[] { typeof(string) })] private static Assembly LoadFile(string path) { return null; } [HarmonyPatch(typeof(Assembly), "LoadFile", new Type[] { typeof(string) })] [HarmonyPatch(typeof(Assembly), "LoadFrom", new Type[] { typeof(string) })] [HarmonyPrefix] private static bool OnAssemblyLoad(ref Assembly __result, string __0) { HarmonyInterop.TryShim(__0, Paths.GameRootPath, (Action)Logger.LogWarning, TypeLoader.ReaderParameters); __result = LoadFile(__0); return true; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.RuntimeFixes.TraceFix ---- namespace BepInEx.Preloader.RuntimeFixes { internal static class TraceFix { private static Type TraceImplType; private static object ListenersSyncRoot; private static TraceListenerCollection Listeners; private static PropertyInfo prop_AutoFlush; private static bool AutoFlush => (bool)prop_AutoFlush.GetValue(null, null); public static void ApplyFix() { TraceImplType = AppDomain.CurrentDomain.GetAssemblies().First((Assembly x) => x.GetName().Name == "System").GetTypes() .FirstOrDefault((Type x) => x.Name == "TraceImpl"); if ((object)TraceImplType != null) { ListenersSyncRoot = AccessTools.Property(TraceImplType, "ListenersSyncRoot").GetValue(null, null); Listeners = (TraceListenerCollection)AccessTools.Property(TraceImplType, "Listeners").GetValue(null, null); prop_AutoFlush = AccessTools.Property(TraceImplType, "AutoFlush"); new Harmony("com.bepis.bepinex.tracefix").Patch(typeof(Trace).GetMethod("DoTrace", BindingFlags.Static | BindingFlags.NonPublic), new HarmonyMethod(typeof(TraceFix).GetMethod("DoTraceReplacement", BindingFlags.Static | BindingFlags.NonPublic))); } } private static bool DoTraceReplacement(string kind, Assembly report, string message) { string source = string.Empty; try { source = report.GetName().Name; } catch (MethodAccessException) { } TraceEventType eventType = (TraceEventType)Enum.Parse(typeof(TraceEventType), kind); lock (ListenersSyncRoot) { foreach (TraceListener listener in Listeners) { listener.TraceEvent(new TraceEventCache(), source, eventType, 0, message); if (AutoFlush) { listener.Flush(); } } } return false; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.RuntimeFixes.UnityPatches ---- namespace BepInEx.Preloader.RuntimeFixes { internal static class UnityPatches { private static Harmony HarmonyInstance { get; set; } public static Dictionary AssemblyLocations { get; } = new Dictionary(StringComparer.InvariantCultureIgnoreCase); public static void Apply() { HarmonyInstance = Harmony.CreateAndPatchAll(typeof(UnityPatches)); try { TraceFix.ApplyFix(); } catch { } } [HarmonyPostfix] [HarmonyPatch(typeof(Assembly), "Location", MethodType.Getter)] public static void GetLocation(ref string __result, Assembly __instance) { if (AssemblyLocations.TryGetValue(__instance.FullName, out var value)) { __result = value; } } [HarmonyPostfix] [HarmonyPatch(typeof(Assembly), "CodeBase", MethodType.Getter)] public static void GetCodeBase(ref string __result, Assembly __instance) { if (AssemblyLocations.TryGetValue(__instance.FullName, out var value)) { __result = "file://" + value.Replace('\\', '/'); } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.RuntimeFixes.XTermFix ---- namespace BepInEx.Preloader.RuntimeFixes { internal static class XTermFix { public static int intOffset; public static void Apply() { if (!PlatformHelper.Is(Platform.Windows) && (object)typeof(Console).Assembly.GetType("System.ConsoleDriver") != null && (object)AccessTools.Method("System.TermInfoReader:DetermineVersion") == null) { DetourHelper.Native = new DetourNativeX86Platform(); Harmony harmony = new Harmony("com.bepinex.xtermfix"); harmony.Patch(AccessTools.Method("System.TermInfoReader:ReadHeader"), new HarmonyMethod(typeof(XTermFix), "ReadHeaderPrefix")); harmony.Patch(AccessTools.Method("System.TermInfoReader:Get", new Type[1] { AccessTools.TypeByName("System.TermInfoNumbers") }), null, null, new HarmonyMethod(typeof(XTermFix), "GetTermInfoNumbersTranspiler")); harmony.Patch(AccessTools.Method("System.TermInfoReader:Get", new Type[1] { AccessTools.TypeByName("System.TermInfoStrings") }), null, null, new HarmonyMethod(typeof(XTermFix), "GetTermInfoStringsTranspiler")); harmony.Patch(AccessTools.Method("System.TermInfoReader:GetStringBytes", new Type[1] { AccessTools.TypeByName("System.TermInfoStrings") }), null, null, new HarmonyMethod(typeof(XTermFix), "GetTermInfoStringsTranspiler")); DetourHelper.Native = null; } } public static int GetInt32(byte[] buffer, int offset) { byte num = buffer[offset]; int num2 = buffer[offset + 1]; int num3 = buffer[offset + 2]; int num4 = buffer[offset + 3]; return num | (num2 << 8) | (num3 << 16) | (num4 << 24); } public static short GetInt16(byte[] buffer, int offset) { byte num = buffer[offset]; int num2 = buffer[offset + 1]; return (short)(num | (num2 << 8)); } public static int GetInteger(byte[] buffer, int offset) { if (intOffset != 2) { return GetInt32(buffer, offset); } return GetInt16(buffer, offset); } public static void DetermineVersion(short magic) { switch (magic) { case 282: intOffset = 2; break; case 542: intOffset = 4; break; default: throw new Exception($"Unknown xterm header format: {magic}"); } } public static bool ReadHeaderPrefix(byte[] buffer, ref int position, ref short ___boolSize, ref short ___numSize, ref short ___strOffsets) { short @int = GetInt16(buffer, position); position += 2; DetermineVersion(@int); position += 2; ___boolSize = GetInt16(buffer, position); position += 2; ___numSize = GetInt16(buffer, position); position += 2; ___strOffsets = GetInt16(buffer, position); position += 2; position += 2; return false; } public static IEnumerable GetTermInfoNumbersTranspiler(IEnumerable instructions) { List list = instructions.ToList(); list[31] = new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(XTermFix), "intOffset")); list[36] = new CodeInstruction(OpCodes.Nop); list[39] = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(XTermFix), "GetInteger")); return list; } public static IEnumerable GetTermInfoStringsTranspiler(IEnumerable instructions) { List list = instructions.ToList(); list[32] = new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(XTermFix), "intOffset")); return list; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.Patching.AssemblyPatcherDelegate ---- namespace BepInEx.Preloader.Patching { public delegate void AssemblyPatcherDelegate(ref AssemblyDefinition assembly); } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.Patching.AssemblyPatcher ---- namespace BepInEx.Preloader.Patching { public static class AssemblyPatcher { private const BindingFlags ALL = BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly string DumpedAssembliesPath = Utility.CombinePaths(Paths.BepInExRootPath, "DumpedAssemblies", Paths.ProcessName); private static readonly Dictionary DumpedAssemblyPaths = new Dictionary(); private static readonly ConfigEntry ConfigDumpAssemblies = ConfigFile.CoreConfig.Bind("Preloader", "DumpAssemblies", defaultValue: false, "If enabled, BepInEx will save patched assemblies into BepInEx/DumpedAssemblies.\nThis can be used by developers to inspect and debug preloader patchers."); private static readonly ConfigEntry ConfigLoadDumpedAssemblies = ConfigFile.CoreConfig.Bind("Preloader", "LoadDumpedAssemblies", defaultValue: false, "If enabled, BepInEx will load patched assemblies from BepInEx/DumpedAssemblies instead of memory.\nThis can be used to be able to load patched assemblies into debuggers like dnSpy.\nIf set to true, will override DumpAssemblies."); private static readonly ConfigEntry ConfigBreakBeforeLoadAssemblies = ConfigFile.CoreConfig.Bind("Preloader", "BreakBeforeLoadAssemblies", defaultValue: false, "If enabled, BepInEx will call Debugger.Break() once before loading patched assemblies.\nThis can be used with debuggers like dnSpy to install breakpoints into patched assemblies before they are loaded."); public static List PatcherPlugins { get; } = new List(); private static IEnumerable PatcherPluginsSafe => PatcherPlugins.ToList(); public static void AddPatcher(PatcherPlugin patcher) { PatcherPlugins.Add(patcher); } private static T CreateDelegate(MethodInfo method) where T : class { if ((object)method == null) { return null; } return Delegate.CreateDelegate(typeof(T), method) as T; } private static PatcherPlugin ToPatcherPlugin(TypeDefinition type) { if (type.IsInterface || (type.IsAbstract && !type.IsSealed)) { return null; } MethodDefinition methodDefinition = type.Methods.FirstOrDefault((MethodDefinition m) => m.Name.Equals("get_TargetDLLs", StringComparison.InvariantCultureIgnoreCase) && m.IsPublic && m.IsStatic); if (methodDefinition == null || methodDefinition.ReturnType.FullName != "System.Collections.Generic.IEnumerable`1") { return null; } if (type.Methods.FirstOrDefault((MethodDefinition m) => m.Name.Equals("Patch") && m.IsPublic && m.IsStatic && m.ReturnType.FullName == "System.Void" && m.Parameters.Count == 1 && (m.Parameters[0].ParameterType.FullName == "Mono.Cecil.AssemblyDefinition&" || m.Parameters[0].ParameterType.FullName == "Mono.Cecil.AssemblyDefinition")) == null) { return null; } return new PatcherPlugin { TypeName = type.FullName }; } public static void AddPatchersFromDirectory(string directory) { if (!Directory.Exists(directory)) { return; } SortedDictionary sortedDictionary = new SortedDictionary(); foreach (KeyValuePair> item in TypeLoader.FindPluginTypes(directory, ToPatcherPlugin)) { string key = item.Key; List value = item.Value; if (value.Count == 0) { continue; } Assembly assembly = Assembly.LoadFile(key); foreach (PatcherPlugin item2 in value) { try { Type type = assembly.GetType(item2.TypeName); MethodInfo[] methods = type.GetMethods(BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); item2.Initializer = CreateDelegate(methods.FirstOrDefault((MethodInfo m) => m.Name.Equals("Initialize", StringComparison.InvariantCultureIgnoreCase) && m.GetParameters().Length == 0 && (object)m.ReturnType == typeof(void))); item2.Finalizer = CreateDelegate(methods.FirstOrDefault((MethodInfo m) => m.Name.Equals("Finish", StringComparison.InvariantCultureIgnoreCase) && m.GetParameters().Length == 0 && (object)m.ReturnType == typeof(void))); item2.TargetDLLs = CreateDelegate>>(type.GetProperty("TargetDLLs", BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetGetMethod()); MethodInfo patcher = methods.FirstOrDefault((MethodInfo m) => m.Name.Equals("Patch", StringComparison.CurrentCultureIgnoreCase) && (object)m.ReturnType == typeof(void) && m.GetParameters().Length == 1 && ((object)m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition) || (object)m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition).MakeByRefType())); item2.Patcher = delegate(ref AssemblyDefinition pAss) { object[] array = new object[1] { pAss }; patcher.Invoke(null, array); pAss = (AssemblyDefinition)array[0]; }; sortedDictionary.Add(assembly.GetName().Name + "/" + type.FullName, item2); } catch (Exception ex) { Logger.LogError("Failed to load patcher [" + item2.TypeName + "]: " + ex.Message); if (ex is ReflectionTypeLoadException ex2) { Logger.LogDebug(TypeLoader.TypeLoadExceptionToString(ex2)); } else { Logger.LogDebug(ex.ToString()); } } } AssemblyName name = assembly.GetName(); Logger.Log(value.Any() ? LogLevel.Info : LogLevel.Debug, string.Format("Loaded {0} patcher method{1} from [{2} {3}]", value.Count, (value.Count == 1) ? "" : "s", name.Name, name.Version)); } foreach (KeyValuePair item3 in sortedDictionary) { AddPatcher(item3.Value); } } private static void InitializePatchers() { foreach (PatcherPlugin item in PatcherPluginsSafe) { try { item.Initializer?.Invoke(); } catch (Exception arg) { Logger.LogError($"Failed to run Initializer of {item.TypeName}: {arg}"); } } } private static void FinalizePatching() { foreach (PatcherPlugin item in PatcherPluginsSafe) { try { item.Finalizer?.Invoke(); } catch (Exception arg) { Logger.LogError($"Failed to run Finalizer of {item.TypeName}: {arg}"); } } } public static void DisposePatchers() { PatcherPlugins.Clear(); } private static string GetAssemblyName(string fullName) { if (!Utility.TryParseAssemblyName(fullName, out var assemblyName)) { return fullName; } return assemblyName.Name; } public static void PatchAndLoad(params string[] directories) { Dictionary dictionary = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (string uniqueFilesInDirectory in Utility.GetUniqueFilesInDirectories(directories, "*.dll")) { AssemblyDefinition assemblyDefinition; try { assemblyDefinition = AssemblyDefinition.ReadAssembly(uniqueFilesInDirectory); } catch (BadImageFormatException) { continue; } if (assemblyDefinition.Name.Name == "System" || assemblyDefinition.Name.Name == "mscorlib") { assemblyDefinition.Dispose(); continue; } if (UnityPatches.AssemblyLocations.ContainsKey(assemblyDefinition.FullName)) { Logger.LogWarning("Tried to load duplicate assembly " + Path.GetFileName(uniqueFilesInDirectory) + " from Managed folder! Skipping..."); continue; } dictionary.Add(Path.GetFileName(uniqueFilesInDirectory), assemblyDefinition); UnityPatches.AssemblyLocations.Add(assemblyDefinition.FullName, Path.GetFullPath(uniqueFilesInDirectory)); } InitializePatchers(); HashSet patchedAssemblies = new HashSet(StringComparer.InvariantCultureIgnoreCase); Dictionary dictionary2 = new Dictionary(); HashSet hashSet = new HashSet(StringComparer.InvariantCultureIgnoreCase); foreach (PatcherPlugin item in PatcherPluginsSafe) { foreach (string item2 in item.TargetDLLs()) { if (!dictionary.TryGetValue(item2, out var value) || hashSet.Contains(item2)) { continue; } Logger.LogInfo("Patching [" + value.Name.Name + "] with [" + item.TypeName + "]"); try { item.Patcher?.Invoke(ref value); } catch (Exception arg) { Logger.LogError($"Failed to run [{item.TypeName}] when patching [{value.Name.Name}]. This assembly will not be patched. Error: {arg}"); patchedAssemblies.Remove(item2); hashSet.Add(item2); continue; } dictionary[item2] = value; patchedAssemblies.Add(item2); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { string assemblyName = GetAssemblyName(assemblies[i].FullName); if (!dictionary2.ContainsKey(assemblyName)) { dictionary2[assemblyName] = item.TypeName; } } } } HashSet patchedAssemblyNames = new HashSet(from kv in dictionary where patchedAssemblies.Contains(kv.Key) select kv.Value.Name.Name, StringComparer.InvariantCultureIgnoreCase); List> list = dictionary2.Where((KeyValuePair kv) => patchedAssemblyNames.Contains(kv.Key)).ToList(); if (list.Count != 0) { Logger.LogWarning(new StringBuilder().AppendLine("The following assemblies have been loaded too early and will not be patched by preloader:").AppendLine(string.Join(Environment.NewLine, list.Select((KeyValuePair kv) => "* [" + kv.Key + "] (first loaded by [" + kv.Value + "])").ToArray())).AppendLine("Expect unexpected behavior and issues with plugins and patchers not being loaded.") .ToString()); } DumpedAssemblyPaths.Clear(); if (ConfigDumpAssemblies.Value || ConfigLoadDumpedAssemblies.Value) { if (!Directory.Exists(DumpedAssembliesPath)) { Directory.CreateDirectory(DumpedAssembliesPath); } foreach (KeyValuePair item3 in dictionary) { string key = item3.Key; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(key); string extension = Path.GetExtension(key); AssemblyDefinition value2 = item3.Value; if (!patchedAssemblies.Contains(key)) { continue; } int num = 0; string text2; FileStream fileStream; while (true) { string text = ((num > 0) ? $"_{num}" : ""); text2 = Path.Combine(DumpedAssembliesPath, fileNameWithoutExtension + text + extension); if (Utility.TryOpenFileStream(text2, FileMode.Create, out fileStream)) { break; } num++; } value2.Write(fileStream); fileStream.Dispose(); DumpedAssemblyPaths[key] = text2; } } if (ConfigBreakBeforeLoadAssemblies.Value) { Logger.LogInfo("BepInEx is about load the following assemblies:\n" + string.Join("\n", patchedAssemblies.ToArray())); Logger.LogInfo("The assemblies were dumped into " + DumpedAssembliesPath); Logger.LogInfo("Load any assemblies into the debugger, set breakpoints and continue execution."); Debugger.Break(); } foreach (KeyValuePair item4 in dictionary) { string key2 = item4.Key; AssemblyDefinition value3 = item4.Value; if (patchedAssemblies.Contains(key2)) { Load(value3, key2); } value3.Dispose(); } FinalizePatching(); } public static void Load(AssemblyDefinition assembly, string filename) { if (ConfigLoadDumpedAssemblies.Value && DumpedAssemblyPaths.TryGetValue(filename, out var value)) { Assembly.LoadFile(value); return; } using MemoryStream memoryStream = new MemoryStream(); assembly.Write(memoryStream); Assembly.Load(memoryStream.ToArray()); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/BepInEx.Preloader.dll :: BepInEx.Preloader.Patching.PatcherPlugin ---- namespace BepInEx.Preloader.Patching { public class PatcherPlugin : ICacheable { public Func> TargetDLLs { get; set; } public Action Initializer { get; set; } public Action Finalizer { get; set; } public AssemblyPatcherDelegate Patcher { get; set; } public string TypeName { get; set; } = string.Empty; public void Save(BinaryWriter bw) { bw.Write(TypeName); } public void Load(BinaryReader br) { TypeName = br.ReadString(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: JetBrains.Annotations.UsedImplicitlyAttribute ---- namespace JetBrains.Annotations { [AttributeUsage(AttributeTargets.All)] internal sealed class UsedImplicitlyAttribute : Attribute { public ImplicitUseKindFlags UseKindFlags { get; } public ImplicitUseTargetFlags TargetFlags { get; } public UsedImplicitlyAttribute() : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) : this(useKindFlags, ImplicitUseTargetFlags.Default) { } public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) : this(ImplicitUseKindFlags.Default, targetFlags) { } public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) { UseKindFlags = useKindFlags; TargetFlags = targetFlags; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: JetBrains.Annotations.MeansImplicitUseAttribute ---- namespace JetBrains.Annotations { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter | AttributeTargets.GenericParameter)] internal sealed class MeansImplicitUseAttribute : Attribute { [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; } [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; } public MeansImplicitUseAttribute() : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) : this(useKindFlags, ImplicitUseTargetFlags.Default) { } public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) : this(ImplicitUseKindFlags.Default, targetFlags) { } public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) { UseKindFlags = useKindFlags; TargetFlags = targetFlags; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: JetBrains.Annotations.ImplicitUseKindFlags ---- namespace JetBrains.Annotations { [Flags] internal enum ImplicitUseKindFlags { Default = 7, Access = 1, Assign = 2, InstantiatedWithFixedConstructorSignature = 4, InstantiatedNoFixedConstructorSignature = 8 } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: JetBrains.Annotations.ImplicitUseTargetFlags ---- namespace JetBrains.Annotations { [Flags] internal enum ImplicitUseTargetFlags { Default = 1, Itself = 1, Members = 2, WithInheritors = 4, WithMembers = 3 } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.Priority ---- namespace HarmonyLib { public static class Priority { public const int Last = 0; public const int VeryLow = 100; public const int Low = 200; public const int LowerThanNormal = 300; public const int Normal = 400; public const int HigherThanNormal = 500; public const int High = 600; public const int VeryHigh = 700; public const int First = 800; } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.MethodType ---- namespace HarmonyLib { public enum MethodType { Normal, Getter, Setter, Constructor, StaticConstructor } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.ArgumentType ---- namespace HarmonyLib { public enum ArgumentType { Normal, Ref, Out, Pointer } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPatchType ---- namespace HarmonyLib { public enum HarmonyPatchType { All, Prefix, Postfix, Transpiler, Finalizer, ReversePatch } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyReversePatchType ---- namespace HarmonyLib { public enum HarmonyReversePatchType { Original, Snapshot } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyAttribute ---- namespace HarmonyLib { [MeansImplicitUse] public class HarmonyAttribute : Attribute { public HarmonyMethod info = new HarmonyMethod(); } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPatch ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class HarmonyPatch : HarmonyAttribute { public HarmonyPatch() { } public HarmonyPatch(Type declaringType) { info.declaringType = declaringType; } public HarmonyPatch(Type declaringType, Type[] argumentTypes) { info.declaringType = declaringType; info.argumentTypes = argumentTypes; } public HarmonyPatch(Type declaringType, string methodName) { info.declaringType = declaringType; info.methodName = methodName; } public HarmonyPatch(Type declaringType, string methodName, params Type[] argumentTypes) { info.declaringType = declaringType; info.methodName = methodName; info.argumentTypes = argumentTypes; } public HarmonyPatch(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.declaringType = declaringType; info.methodName = methodName; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(Type declaringType, MethodType methodType) { info.declaringType = declaringType; info.methodType = methodType; } public HarmonyPatch(Type declaringType, MethodType methodType, params Type[] argumentTypes) { info.declaringType = declaringType; info.methodType = methodType; info.argumentTypes = argumentTypes; } public HarmonyPatch(Type declaringType, MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.declaringType = declaringType; info.methodType = methodType; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(Type declaringType, string methodName, MethodType methodType) { info.declaringType = declaringType; info.methodName = methodName; info.methodType = methodType; } public HarmonyPatch(string methodName) { info.methodName = methodName; } public HarmonyPatch(string methodName, params Type[] argumentTypes) { info.methodName = methodName; info.argumentTypes = argumentTypes; } public HarmonyPatch(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.methodName = methodName; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(string methodName, MethodType methodType) { info.methodName = methodName; info.methodType = methodType; } public HarmonyPatch(MethodType methodType) { info.methodType = methodType; } public HarmonyPatch(MethodType methodType, params Type[] argumentTypes) { info.methodType = methodType; info.argumentTypes = argumentTypes; } public HarmonyPatch(MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.methodType = methodType; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(Type[] argumentTypes) { info.argumentTypes = argumentTypes; } public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations) { ParseSpecialArguments(argumentTypes, argumentVariations); } private void ParseSpecialArguments(Type[] argumentTypes, ArgumentType[] argumentVariations) { if (argumentVariations == null || argumentVariations.Length == 0) { info.argumentTypes = argumentTypes; return; } if (argumentTypes.Length < argumentVariations.Length) { throw new ArgumentException("argumentVariations contains more elements than argumentTypes", "argumentVariations"); } List list = new List(); for (int i = 0; i < argumentTypes.Length; i++) { Type type = argumentTypes[i]; switch (argumentVariations[i]) { case ArgumentType.Ref: case ArgumentType.Out: type = type.MakeByRefType(); break; case ArgumentType.Pointer: type = type.MakePointerType(); break; } list.Add(type); } info.argumentTypes = list.ToArray(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyReversePatch ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class HarmonyReversePatch : HarmonyAttribute { public HarmonyReversePatch(HarmonyReversePatchType type = HarmonyReversePatchType.Original) { info.reversePatchType = type; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPatchAll ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class)] public class HarmonyPatchAll : HarmonyAttribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPriority ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyPriority : HarmonyAttribute { public HarmonyPriority(int priority) { info.priority = priority; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyBefore ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyBefore : HarmonyAttribute { public HarmonyBefore(params string[] before) { info.before = before; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyAfter ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyAfter : HarmonyAttribute { public HarmonyAfter(params string[] after) { info.after = after; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPrepare ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyPrepare : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyCleanup ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyCleanup : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyTargetMethod ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyTargetMethod : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyTargetMethods ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyTargetMethods : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPrefix ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyPrefix : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyPostfix ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyPostfix : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyTranspiler ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyTranspiler : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyFinalizer ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class HarmonyFinalizer : Attribute { } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyArgument ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)] public class HarmonyArgument : Attribute { public string OriginalName { get; private set; } public int Index { get; private set; } public string NewName { get; private set; } public HarmonyArgument(string originalName) : this(originalName, null) { } public HarmonyArgument(int index) : this(index, null) { } public HarmonyArgument(string originalName, string newName) { OriginalName = originalName; Index = -1; NewName = newName; } public HarmonyArgument(int index, string name) { OriginalName = null; Index = index; NewName = name; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.ParameterByRefAttribute ---- namespace HarmonyLib { [AttributeUsage(AttributeTargets.Method)] public class ParameterByRefAttribute : Attribute { public int[] ParameterIndices { get; } public ParameterByRefAttribute(params int[] parameterIndices) { ParameterIndices = parameterIndices; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.InvalidHarmonyPatchArgumentException ---- namespace HarmonyLib { public class InvalidHarmonyPatchArgumentException : Exception { public MethodBase Original { get; } public MethodInfo Patch { get; } public override string Message => "(" + Patch.GetID() + "): " + base.Message; public InvalidHarmonyPatchArgumentException(string message, MethodBase original, MethodInfo patch) : base(message) { Original = original; Patch = patch; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.MemberNotFoundException ---- namespace HarmonyLib { public class MemberNotFoundException : Exception { public MemberNotFoundException(string message) : base(message) { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.Harmony ---- namespace HarmonyLib { public class Harmony { [Obsolete("No longer used, subscribe to Logger.LogChannel.Info")] public static bool DEBUG; [Obsolete("Not supported by HarmonyX", true)] public static bool SELF_PATCHING; public string Id { get; private set; } public Harmony(string id) { if (string.IsNullOrEmpty(id)) { throw new ArgumentException("id cannot be null or empty"); } Logger.Log(Logger.LogChannel.Info, delegate { Assembly assembly = typeof(Harmony).Assembly; Version version = assembly.GetName().Version; string text = assembly.Location; if (string.IsNullOrEmpty(text)) { text = new Uri(assembly.CodeBase).LocalPath; } MethodBase outsideCaller = AccessTools.GetOutsideCaller(); Assembly assembly2 = outsideCaller.DeclaringType?.Assembly; string text2 = assembly2?.Location; if (string.IsNullOrEmpty(text2)) { text2 = (((object)assembly2 != null) ? new Uri(assembly2.CodeBase).LocalPath : string.Empty); } return $"Created Harmony instance id={id}, version={version}, location={text} - Started from {outsideCaller.GetID()} location={text2}"; }); Id = id; } public void PatchAll() { Assembly assembly = new StackTrace().GetFrame(1).GetMethod().ReflectedType.Assembly; PatchAll(assembly); } public PatchProcessor ProcessorForAnnotatedClass(Type type) { List fromType = HarmonyMethodExtensions.GetFromType(type); if (fromType != null && fromType.Any()) { HarmonyMethod attributes = HarmonyMethod.Merge(fromType); return new PatchProcessor(this, type, attributes); } return null; } public void PatchAll(Assembly assembly) { if ((object)assembly == null) { throw new ArgumentNullException("assembly"); } List list = (from x in assembly.GetTypes().Select(ProcessorForAnnotatedClass) where x != null select x).ToList(); foreach (PatchProcessor item in list) { item.Patch(); } if (list.Count == 0) { Logger.Log(Logger.LogChannel.Warn, () => "Could not find any valid Harmony patches inside of assembly " + assembly.FullName); } } public DynamicMethod Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null) { PatchProcessor patchProcessor = new PatchProcessor(this, original); patchProcessor.AddPrefix(prefix); patchProcessor.AddPostfix(postfix); patchProcessor.AddTranspiler(transpiler); patchProcessor.AddFinalizer(finalizer); return patchProcessor.Patch().FirstOrDefault(); } public MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler = null) { return null; } public ReversePatcher CreateReversePatcher(MethodBase original, MethodInfo standin) { return new ReversePatcher(this, original, standin); } public void UnpatchAll(string harmonyID = null) { foreach (MethodBase item in GetAllPatchedMethods().ToList()) { Patches patchInfo = GetPatchInfo(item); UnpatchAllId(item, patchInfo.Prefixes); UnpatchAllId(item, patchInfo.Postfixes); UnpatchAllId(item, patchInfo.Transpilers); UnpatchAllId(item, patchInfo.Finalizers); } void UnpatchAllId(MethodBase original, IEnumerable patches) { foreach (Patch patch in patches) { if (harmonyID == null || patch.owner == harmonyID) { Unpatch(original, patch.patch); } } } } public void Unpatch(MethodBase original, HarmonyPatchType type, string harmonyID = null) { new PatchProcessor(this, original).Unpatch(type, harmonyID); } public void Unpatch(MethodBase original, MethodInfo patch) { new PatchProcessor(this, original).Unpatch(patch); } public static bool HasAnyPatches(string harmonyID) { return GetAllPatchedMethods().Select(GetPatchInfo).Any((Patches info) => info.Owners.Contains(harmonyID)); } public static Patches GetPatchInfo(MethodBase method) { return PatchProcessor.GetPatchInfo(method); } public IEnumerable GetPatchedMethods() { return from original in GetAllPatchedMethods() where GetPatchInfo(original).Owners.Contains(Id) select original; } public static IEnumerable GetAllPatchedMethods() { return GlobalPatchState.GetPatchedMethods(); } public static Dictionary VersionInfo(out Version currentVersion) { return PatchProcessor.VersionInfo(out currentVersion); } public void PatchAll(Type type) { if ((object)type == null) { throw new ArgumentNullException("type"); } MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { List fromMethod = HarmonyMethodExtensions.GetFromMethod(methodInfo); if (fromMethod != null && fromMethod.Any()) { object[] customAttributes = methodInfo.GetCustomAttributes(inherit: true); HarmonyMethod combinedInfo = HarmonyMethod.Merge(fromMethod); List list = fromMethod.Where(IsMethodComplete).ToList(); if (fromMethod.All((HarmonyMethod x) => (object)x.declaringType != combinedInfo.declaringType && x.methodName != combinedInfo.methodName)) { list.Add(combinedInfo); } List list2 = new List(); foreach (HarmonyMethod item in list) { foreach (int item2 in customAttributes.OfType().SelectMany((ParameterByRefAttribute x) => x.ParameterIndices)) { if (!item.argumentTypes[item2].IsByRef) { item.argumentTypes[item2] = item.argumentTypes[item2].MakeByRefType(); } } if (!item.methodType.HasValue) { item.methodType = MethodType.Normal; } if ((object)item.method == null) { item.method = methodInfo; } MethodBase originalMethod = PatchProcessor.GetOriginalMethod(item); if ((object)originalMethod != null) { list2.Add(originalMethod); } } PatchProcessor patchProcessor = new PatchProcessor(this); foreach (MethodBase item3 in list2) { patchProcessor.AddOriginal(item3); } if (customAttributes.Any((object x) => x is HarmonyPrefix)) { patchProcessor.AddPrefix(new HarmonyMethod(methodInfo)); } if (customAttributes.Any((object x) => x is HarmonyTranspiler)) { patchProcessor.AddTranspiler(new HarmonyMethod(methodInfo)); } if (customAttributes.Any((object x) => x is HarmonyPostfix)) { patchProcessor.AddPostfix(new HarmonyMethod(methodInfo)); } if (customAttributes.Any((object x) => x is HarmonyFinalizer)) { patchProcessor.AddFinalizer(new HarmonyMethod(methodInfo)); } patchProcessor.Patch(); } else if ((Logger.ChannelFilter & Logger.LogChannel.Warn) != Logger.LogChannel.None && methodInfo.GetCustomAttributes(typeof(HarmonyAttribute), inherit: true).Any()) { Logger.LogText(Logger.LogChannel.Warn, "Method " + methodInfo.FullDescription() + " has an invalid combination of Harmony attributes and will be ignored"); } } static bool IsMethodComplete(HarmonyMethod m) { if ((object)m.declaringType != null) { if (m.methodName == null && m.methodType != MethodType.Constructor) { return m.methodType == MethodType.StaticConstructor; } return true; } return false; } } public static Harmony CreateAndPatchAll(Type type, string harmonyInstanceId = null) { Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}"); harmony.PatchAll(type); return harmony; } public static Harmony CreateAndPatchAll(Assembly assembly, string harmonyInstanceId = null) { Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}"); harmony.PatchAll(assembly); return harmony; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyMethod ---- namespace HarmonyLib { public class HarmonyMethod { public MethodInfo method; public Type declaringType; public string methodName; public MethodType? methodType; public Type[] argumentTypes; public int priority = -1; public string[] before; public string[] after; public HarmonyReversePatchType? reversePatchType; public HarmonyMethod() { } private void ImportMethod(MethodInfo theMethod) { method = theMethod; if ((object)method != null) { List fromMethod = HarmonyMethodExtensions.GetFromMethod(method); if (fromMethod != null) { Merge(fromMethod).CopyTo(this); } } } public HarmonyMethod(MethodInfo method) { if ((object)method == null) { throw new ArgumentNullException("method"); } ImportMethod(method); } public HarmonyMethod(Type type, string name, Type[] parameters = null) { MethodInfo methodInfo = AccessTools.Method(type, name, parameters); if ((object)methodInfo == null) { throw new ArgumentException($"Cannot not find method for type {type} and name {name} and parameters {parameters?.Description()}"); } ImportMethod(methodInfo); } public static List HarmonyFields() { return (from s in AccessTools.GetFieldNames(typeof(HarmonyMethod)) where s != "method" select s).ToList(); } public static HarmonyMethod Merge(List attributes) { HarmonyMethod harmonyMethod = new HarmonyMethod(); if (attributes == null) { return harmonyMethod; } Traverse resultTrv = Traverse.Create(harmonyMethod); attributes.ForEach(delegate(HarmonyMethod attribute) { Traverse trv = Traverse.Create(attribute); HarmonyFields().ForEach(delegate(string f) { object value = trv.Field(f).GetValue(); if (value != null) { HarmonyMethodExtensions.SetValue(resultTrv, f, value); } }); }); return harmonyMethod; } public override string ToString() { string result = "HarmonyMethod["; Traverse trv = Traverse.Create(this); HarmonyFields().ForEach(delegate(string f) { result += $"{f}{'='}{trv.Field(f).GetValue()}"; }); return result + "]"; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonyMethodExtensions ---- namespace HarmonyLib { public static class HarmonyMethodExtensions { internal static void SetValue(Traverse trv, string name, object val) { if (val != null) { Traverse traverse = trv.Field(name); if (name == "methodType" || name == "reversePatchType") { val = Enum.ToObject(Nullable.GetUnderlyingType(traverse.GetValueType()), (int)val); } traverse.SetValue(val); } } public static void CopyTo(this HarmonyMethod from, HarmonyMethod to) { if (to == null) { return; } Traverse fromTrv = Traverse.Create(from); Traverse toTrv = Traverse.Create(to); HarmonyMethod.HarmonyFields().ForEach(delegate(string f) { object value = fromTrv.Field(f).GetValue(); if (value != null) { SetValue(toTrv, f, value); } }); } public static HarmonyMethod Clone(this HarmonyMethod original) { HarmonyMethod harmonyMethod = new HarmonyMethod(); original.CopyTo(harmonyMethod); return harmonyMethod; } public static HarmonyMethod Merge(this HarmonyMethod master, HarmonyMethod detail) { if (detail == null) { return master; } HarmonyMethod harmonyMethod = new HarmonyMethod(); Traverse resultTrv = Traverse.Create(harmonyMethod); Traverse masterTrv = Traverse.Create(master); Traverse detailTrv = Traverse.Create(detail); HarmonyMethod.HarmonyFields().ForEach(delegate(string f) { object value = masterTrv.Field(f).GetValue(); object value2 = detailTrv.Field(f).GetValue(); SetValue(resultTrv, f, value2 ?? value); }); return harmonyMethod; } private static HarmonyMethod GetHarmonyMethodInfo(object attribute) { FieldInfo field = attribute.GetType().GetField("info", AccessTools.all); if ((object)field == null) { return null; } if (field.FieldType.Name != "HarmonyMethod") { return null; } return AccessTools.MakeDeepCopy(field.GetValue(attribute)); } public static List GetFromType(Type type) { if ((object)type == null) { throw new ArgumentNullException("type"); } return (from attr in type.GetCustomAttributes(inherit: true) select GetHarmonyMethodInfo(attr) into info where info != null select info).ToList(); } public static HarmonyMethod GetMergedFromType(Type type) { return HarmonyMethod.Merge(GetFromType(type)); } public static HarmonyMethod GetMergedFromMethod(MethodBase method) { return HarmonyMethod.Merge(GetFromMethod(method)); } public static List GetFromMethod(MethodBase method) { return (from attr in method.GetCustomAttributes(inherit: true) select GetHarmonyMethodInfo(attr) into info where info != null select info).ToList(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.HarmonySharedState ---- namespace HarmonyLib { [Obsolete("Exists for legacy support", true)] internal static class HarmonySharedState { [Obsolete("Exists for legacy support", true)] public static PatchInfo GetPatchInfo(MethodBase method) { return method.ToPatchInfo(); } [Obsolete("Exists for legacy support", true)] public static IEnumerable GetPatchedMethods() { return GlobalPatchState.GetPatchedMethods(); } [Obsolete("Exists for legacy support", true)] public static void UpdatePatchInfo(MethodBase methodBase, PatchInfo patchInfo) { } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.PatchFunctions ---- namespace HarmonyLib { [Obsolete("Exists for legacy support", true)] internal static class PatchFunctions { [Obsolete("Exists for legacy support", true)] public static DynamicMethod UpdateWrapper(MethodBase original, PatchInfo info, string id) { original.GetMethodPatcher().Apply(); return null; } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.PatchInfo ---- namespace HarmonyLib { public class PatchInfo { public Patch[] prefixes; public Patch[] postfixes; public Patch[] transpilers; public Patch[] finalizers; public PatchInfo() { prefixes = new Patch[0]; postfixes = new Patch[0]; transpilers = new Patch[0]; finalizers = new Patch[0]; } private void AddPatch(ref Patch[] list, string owner, HarmonyMethod info) { if ((object)info?.method != null) { int priority = ((info.priority == -1) ? 400 : info.priority); string[] before = info.before ?? new string[0]; string[] after = info.after ?? new string[0]; AddPatch(ref list, info.method, owner, priority, before, after); } } private void AddPatch(ref Patch[] list, MethodInfo patch, string owner, int priority, string[] before, string[] after) { List list2 = list.ToList(); list2.Add(new Patch(patch, prefixes.Count() + 1, owner, priority, before, after)); list = list2.ToArray(); } private void RemovePatch(ref Patch[] list, string owner) { if (owner == "*") { list = new Patch[0]; return; } list = list.Where((Patch patch) => patch.owner != owner).ToArray(); } public void AddPrefix(MethodInfo patch, string owner, int priority, string[] before, string[] after) { AddPatch(ref prefixes, patch, owner, priority, before, after); } public void AddPrefix(string owner, HarmonyMethod info) { AddPatch(ref prefixes, owner, info); } public void RemovePrefix(string owner) { RemovePatch(ref prefixes, owner); } public void AddPostfix(MethodInfo patch, string owner, int priority, string[] before, string[] after) { AddPatch(ref postfixes, patch, owner, priority, before, after); } public void AddPostfix(string owner, HarmonyMethod info) { AddPatch(ref postfixes, owner, info); } public void RemovePostfix(string owner) { RemovePatch(ref postfixes, owner); } public void AddTranspiler(MethodInfo patch, string owner, int priority, string[] before, string[] after) { AddPatch(ref transpilers, patch, owner, priority, before, after); } public void AddTranspiler(string owner, HarmonyMethod info) { AddPatch(ref transpilers, owner, info); } public void RemoveTranspiler(string owner) { RemovePatch(ref transpilers, owner); } public void AddFinalizer(MethodInfo patch, string owner, int priority, string[] before, string[] after) { AddPatch(ref finalizers, patch, owner, priority, before, after); } public void AddFinalizer(string owner, HarmonyMethod info) { AddPatch(ref finalizers, owner, info); } public void RemoveFinalizer(string owner) { RemovePatch(ref finalizers, owner); } public void RemovePatch(MethodInfo patch) { lock (this) { prefixes = prefixes.Where((Patch p) => (object)p.patch != patch).ToArray(); postfixes = postfixes.Where((Patch p) => (object)p.patch != patch).ToArray(); transpilers = transpilers.Where((Patch p) => (object)p.patch != patch).ToArray(); finalizers = finalizers.Where((Patch p) => (object)p.patch != patch).ToArray(); } } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.Patch ---- namespace HarmonyLib { public class Patch : IComparable { public readonly int index; public readonly string owner; public readonly int priority; public readonly string[] before; public readonly string[] after; public MethodInfo patch; public MethodInfo PatchMethod { get { return patch; } set { patch = value; } } public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after) { if (patch is DynamicMethod) { throw new ArgumentException("Cannot directly reference dynamic method \"" + patch.GetID() + "\" in Harmony. Use a factory method instead that will return the dynamic method.", "patch"); } this.index = index; this.owner = owner; this.priority = priority; this.before = before; this.after = after; this.patch = patch; } public MethodInfo GetMethod(MethodBase original) { if ((object)patch.ReturnType != typeof(DynamicMethod) && (object)patch.ReturnType != typeof(MethodInfo)) { return patch; } if (!patch.IsStatic) { return patch; } ParameterInfo[] parameters = patch.GetParameters(); if (parameters.Count() != 1) { return patch; } if ((object)parameters[0].ParameterType != typeof(MethodBase)) { return patch; } return patch.Invoke(null, new object[1] { original }) as MethodInfo; } public override bool Equals(object obj) { if (obj is Patch patch) { return (object)this.patch == patch.patch; } return false; } public int CompareTo(object obj) { if (!(obj is Patch patch)) { return 0; } int num; if (patch.priority != priority) { num = priority; return -num.CompareTo(patch.priority); } num = index; return num.CompareTo(patch.index); } public override int GetHashCode() { return patch.GetHashCode(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.Patches ---- namespace HarmonyLib { public class Patches { public readonly ReadOnlyCollection Prefixes; public readonly ReadOnlyCollection Postfixes; public readonly ReadOnlyCollection Transpilers; public readonly ReadOnlyCollection Finalizers; public ReadOnlyCollection Owners { get { HashSet hashSet = new HashSet(); hashSet.UnionWith(Prefixes.Select((Patch p) => p.owner)); hashSet.UnionWith(Postfixes.Select((Patch p) => p.owner)); hashSet.UnionWith(Transpilers.Select((Patch p) => p.owner)); hashSet.UnionWith(Finalizers.Select((Patch p) => p.owner)); return hashSet.ToList().AsReadOnly(); } } public Patches(Patch[] prefixes, Patch[] postfixes, Patch[] transpilers, Patch[] finalizers) { if (prefixes == null) { prefixes = new Patch[0]; } if (postfixes == null) { postfixes = new Patch[0]; } if (transpilers == null) { transpilers = new Patch[0]; } if (finalizers == null) { finalizers = new Patch[0]; } Prefixes = prefixes.ToList().AsReadOnly(); Postfixes = postfixes.ToList().AsReadOnly(); Transpilers = transpilers.ToList().AsReadOnly(); Finalizers = finalizers.ToList().AsReadOnly(); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.PatchProcessor ---- namespace HarmonyLib { public class PatchProcessor { private readonly Harmony instance; private readonly Type container; private readonly HarmonyMethod containerAttributes; private readonly List originals = new List(); private HarmonyMethod prefix; private HarmonyMethod postfix; private HarmonyMethod transpiler; private HarmonyMethod finalizer; public PatchProcessor(Harmony instance, MethodBase original = null) { this.instance = instance; if ((object)original != null) { originals.Add(original); } } public PatchProcessor(Harmony instance, Type type, HarmonyMethod attributes) { this.instance = instance; container = type; containerAttributes = attributes ?? new HarmonyMethod(); prefix = containerAttributes.Clone(); postfix = containerAttributes.Clone(); transpiler = containerAttributes.Clone(); finalizer = containerAttributes.Clone(); PrepareType(); } [Obsolete("Use other constructors and Add* methods")] public PatchProcessor(Harmony instance, List originals, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null) { this.instance = instance; this.originals = originals; this.prefix = prefix; this.postfix = postfix; this.transpiler = transpiler; this.finalizer = finalizer; } public PatchProcessor AddOriginal(MethodBase original) { if (!originals.Contains(original)) { originals.Add(original); } return this; } public PatchProcessor SetOriginals(List originals) { this.originals.Clear(); this.originals.AddRange(originals); return this; } public PatchProcessor AddPrefix(HarmonyMethod prefix) { this.prefix = prefix; return this; } public PatchProcessor AddPrefix(MethodInfo fixMethod) { prefix = new HarmonyMethod(fixMethod); return this; } public PatchProcessor AddPostfix(HarmonyMethod postfix) { this.postfix = postfix; return this; } public PatchProcessor AddPostfix(MethodInfo fixMethod) { postfix = new HarmonyMethod(fixMethod); return this; } public PatchProcessor AddTranspiler(HarmonyMethod transpiler) { this.transpiler = transpiler; return this; } public PatchProcessor AddTranspiler(MethodInfo fixMethod) { transpiler = new HarmonyMethod(fixMethod); return this; } public PatchProcessor AddFinalizer(HarmonyMethod finalizer) { this.finalizer = finalizer; return this; } public PatchProcessor AddFinalizer(MethodInfo fixMethod) { finalizer = new HarmonyMethod(fixMethod); return this; } public static Patches GetPatchInfo(MethodBase method) { PatchInfo patchInfo = method.GetPatchInfo(); if (patchInfo == null) { return null; } lock (patchInfo) { return new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers, patchInfo.finalizers); } } public static Dictionary VersionInfo(out Version currentVersion) { currentVersion = typeof(Harmony).Assembly.GetName().Version; Dictionary assemblies = new Dictionary(); foreach (MethodBase allPatchedMethod in GetAllPatchedMethods()) { Patches patchInfo = GetPatchInfo(allPatchedMethod); AddAssemblies(patchInfo.Prefixes); AddAssemblies(patchInfo.Postfixes); AddAssemblies(patchInfo.Transpilers); AddAssemblies(patchInfo.Finalizers); } Dictionary dictionary = new Dictionary(); foreach (KeyValuePair item in assemblies) { AssemblyName assemblyName = item.Value.GetReferencedAssemblies().FirstOrDefault((AssemblyName a) => a.FullName.StartsWith("0Harmony, Version", StringComparison.Ordinal)); if (assemblyName != null) { dictionary[item.Key] = assemblyName.Version; } } return dictionary; void AddAssemblies(IEnumerable patches) { foreach (Patch patch in patches) { assemblies[patch.owner] = patch.patch.DeclaringType?.Assembly; } } } public static List GetOriginalInstructions(MethodBase original, ILGenerator generator = null) { DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition(original); ILManipulator iLManipulator = new ILManipulator(dynamicMethodDefinition.Definition.Body); ILGenerator il = generator ?? new CecilILGenerator(dynamicMethodDefinition.GetILProcessor()).GetProxy(); return iLManipulator.GetInstructions(il); } public static List GetOriginalInstructions(MethodBase original, out ILGenerator generator) { DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition(original); ILManipulator iLManipulator = new ILManipulator(dynamicMethodDefinition.Definition.Body); generator = new CecilILGenerator(dynamicMethodDefinition.GetILProcessor()).GetProxy(); return iLManipulator.GetInstructions(generator); } [Obsolete("Use GetAllPatchedMethods instead")] public static IEnumerable AllPatchedMethods() { return GlobalPatchState.GetPatchedMethods(); } public static IEnumerable GetAllPatchedMethods() { return GlobalPatchState.GetPatchedMethods(); } public List Patch() { Stopwatch sw = null; Logger.Log(Logger.LogChannel.Info, delegate { sw = Stopwatch.StartNew(); return "Patching " + instance.Id + "..."; }); List result = new List(); foreach (MethodBase original in originals) { if ((object)original == null) { throw new NullReferenceException("Null method for " + instance.Id); } Logger.Log(Logger.LogChannel.Info, () => "Patching " + original.GetID()); bool individualPrepareResult = RunMethod(defaultIfNotExisting: true, new object[1] { original }); Logger.Log(Logger.LogChannel.Info, () => $"HarmonyPrepare result: {individualPrepareResult}"); if (individualPrepareResult) { PatchInfo patchInfo = original.ToPatchInfo(); lock (patchInfo) { patchInfo.AddPrefix(instance.Id, prefix); patchInfo.AddPostfix(instance.Id, postfix); patchInfo.AddTranspiler(instance.Id, transpiler); patchInfo.AddFinalizer(instance.Id, finalizer); } original.GetMethodPatcher().Apply(); RunMethod(new object[1] { original }); } } Logger.Log(Logger.LogChannel.Info, () => $"Patching {instance.Id} took {sw.ElapsedMilliseconds}ms"); return result; } public PatchProcessor Unpatch(HarmonyPatchType type, string harmonyID) { foreach (MethodBase original in originals) { PatchInfo patchInfo = original.ToPatchInfo(); lock (patchInfo) { if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix) { patchInfo.RemovePrefix(harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix) { patchInfo.RemovePostfix(harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler) { patchInfo.RemoveTranspiler(harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Finalizer) { patchInfo.RemoveFinalizer(harmonyID); } } original.GetMethodPatcher().Apply(); } return this; } public PatchProcessor Unpatch(MethodInfo patch) { foreach (MethodBase original in originals) { original.ToPatchInfo().RemovePatch(patch); original.GetMethodPatcher().Apply(); } return this; } private void PrepareType() { if (!RunMethod(defaultIfNotExisting: true, new object[0])) { return; } MethodType? methodType = containerAttributes.methodType; if (!containerAttributes.methodType.HasValue) { containerAttributes.methodType = MethodType.Normal; } string reversePatchAttr = typeof(HarmonyReversePatch).FullName; foreach (MethodInfo item in (from m in container.GetMethods(AccessTools.all) where m.GetCustomAttributes(inherit: true).Any((object a) => a.GetType().FullName == reversePatchAttr) select m).ToList()) { MethodBase originalMethod = GetOriginalMethod(containerAttributes.Merge(new HarmonyMethod(item))); instance.CreateReversePatcher(originalMethod, item).Patch(); } IEnumerable enumerable = RunMethod>(null, new object[0]); if (enumerable != null) { originals.Clear(); originals.AddRange(enumerable); } else if (container.GetCustomAttributes(inherit: true).Any((object a) => a.GetType().FullName == typeof(HarmonyPatchAll).FullName)) { Type declaringType = containerAttributes.declaringType; originals.AddRange(AccessTools.GetDeclaredConstructors(declaringType).Cast()); originals.AddRange(AccessTools.GetDeclaredMethods(declaringType).Cast()); List declaredProperties = AccessTools.GetDeclaredProperties(declaringType); originals.AddRange((from prop in declaredProperties select prop.GetGetMethod(nonPublic: true) into method where (object)method != null select method).Cast()); originals.AddRange((from prop in declaredProperties select prop.GetSetMethod(nonPublic: true) into method where (object)method != null select method).Cast()); } else { MethodBase methodBase = RunMethod(null, new object[0]) ?? GetOriginalMethod(containerAttributes); if ((object)methodBase == null) { string text = "("; text += $"declaringType={containerAttributes.declaringType}, "; text = text + "methodName =" + containerAttributes.methodName + ", "; text += $"methodType={methodType}, "; text = text + "argumentTypes=" + containerAttributes.argumentTypes.Description(); text += ")"; throw new ArgumentException("No target method specified for class " + container.FullName + " " + text); } originals.Add(methodBase); } GetPatches(container, out var methodInfo, out var methodInfo2, out var methodInfo3, out var methodInfo4); if (prefix != null) { prefix.method = methodInfo; } if (postfix != null) { postfix.method = methodInfo2; } if (transpiler != null) { transpiler.method = methodInfo3; } if (finalizer != null) { finalizer.method = methodInfo4; } if ((object)methodInfo != null) { if (!methodInfo.IsStatic) { throw new ArgumentException("Patch method " + methodInfo.GetID() + " must be static"); } List fromMethod = HarmonyMethodExtensions.GetFromMethod(methodInfo); containerAttributes.Merge(HarmonyMethod.Merge(fromMethod)).CopyTo(prefix); } if ((object)methodInfo2 != null) { if (!methodInfo2.IsStatic) { throw new ArgumentException("Patch method " + methodInfo2.GetID() + " must be static"); } List fromMethod2 = HarmonyMethodExtensions.GetFromMethod(methodInfo2); containerAttributes.Merge(HarmonyMethod.Merge(fromMethod2)).CopyTo(postfix); } if ((object)methodInfo3 != null) { if (!methodInfo3.IsStatic) { throw new ArgumentException("Patch method " + methodInfo3.GetID() + " must be static"); } List fromMethod3 = HarmonyMethodExtensions.GetFromMethod(methodInfo3); containerAttributes.Merge(HarmonyMethod.Merge(fromMethod3)).CopyTo(transpiler); } if ((object)methodInfo4 != null) { if (!methodInfo4.IsStatic) { throw new ArgumentException("Patch method " + methodInfo4.GetID() + " must be static"); } List fromMethod4 = HarmonyMethodExtensions.GetFromMethod(methodInfo4); containerAttributes.Merge(HarmonyMethod.Merge(fromMethod4)).CopyTo(finalizer); } } internal static MethodBase GetOriginalMethod(HarmonyMethod attribute) { if (attribute == null) { throw new ArgumentNullException("attribute"); } if ((object)attribute.declaringType == null) { return MakeFailure("declaringType cannot be null"); } switch (attribute.methodType) { case MethodType.Normal: { if (string.IsNullOrEmpty(attribute.methodName)) { return MakeFailure("methodName can't be empty"); } if (attribute.methodName == ".ctor") { Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - MethodType.Constructor should be used instead of setting methodName to .ctor"); goto case MethodType.Constructor; } if (attribute.methodName == ".cctor") { Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - MethodType.StaticConstructor should be used instead of setting methodName to .cctor"); goto case MethodType.StaticConstructor; } if (attribute.methodName.StartsWith("get_") || attribute.methodName.StartsWith("set_")) { Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - MethodType.Getter and MethodType.Setter should be used instead adding get_ and set_ to property names"); } MethodInfo methodInfo = AccessTools.DeclaredMethod(attribute.declaringType, attribute.methodName, attribute.argumentTypes); if ((object)methodInfo != null) { return methodInfo; } methodInfo = AccessTools.Method(attribute.declaringType, attribute.methodName, attribute.argumentTypes); if ((object)methodInfo != null) { string text = GetPatchName(); object[] obj = new object[4] { attribute.methodName, null, null, null }; Type[] argumentTypes = attribute.argumentTypes; obj[1] = ((argumentTypes != null) ? argumentTypes.Length : 0); obj[2] = attribute.declaringType.FullDescription(); obj[3] = methodInfo.DeclaringType.FullDescription(); Logger.LogText(Logger.LogChannel.Warn, text + string.Format(" - Could not find method {0} with {1} parameters in type {2}, but it was found in base class of this type {3}", obj)); return methodInfo; } return MakeFailure("Could not find method " + attribute.methodName + " with " + attribute.argumentTypes.Description() + " parameters in type " + attribute.declaringType.FullDescription()); } case MethodType.Getter: { if (string.IsNullOrEmpty(attribute.methodName)) { return MakeFailure("methodName can't be empty"); } PropertyInfo propertyInfo2 = AccessTools.DeclaredProperty(attribute.declaringType, attribute.methodName); if ((object)propertyInfo2 != null) { MethodInfo getMethod = propertyInfo2.GetGetMethod(nonPublic: true); if ((object)getMethod == null) { return MakeFailure("Property " + attribute.methodName + " does not have a Getter"); } return getMethod; } propertyInfo2 = AccessTools.Property(attribute.declaringType, attribute.methodName); if ((object)propertyInfo2 != null) { Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - Could not find property " + attribute.methodName + " in type " + attribute.declaringType.FullDescription() + ", but it was found in base class of this type: " + propertyInfo2.DeclaringType.FullDescription()); MethodInfo getMethod2 = propertyInfo2.GetGetMethod(nonPublic: true); if ((object)getMethod2 == null) { return MakeFailure("Property " + attribute.methodName + " does not have a Getter"); } return getMethod2; } return MakeFailure("Could not find property " + attribute.methodName + " in type " + attribute.declaringType.FullDescription()); } case MethodType.Setter: { if (string.IsNullOrEmpty(attribute.methodName)) { return MakeFailure("methodName can't be empty"); } PropertyInfo propertyInfo = AccessTools.DeclaredProperty(attribute.declaringType, attribute.methodName); if ((object)propertyInfo != null) { MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true); if ((object)setMethod == null) { return MakeFailure("Property " + attribute.methodName + " does not have a Setter"); } return setMethod; } propertyInfo = AccessTools.Property(attribute.declaringType, attribute.methodName); if ((object)propertyInfo != null) { Logger.LogText(Logger.LogChannel.Warn, GetPatchName() + " - Could not find property " + attribute.methodName + " in type " + attribute.declaringType.FullDescription() + ", but it was found in base class of this type: " + propertyInfo.DeclaringType.FullDescription()); MethodInfo setMethod2 = propertyInfo.GetSetMethod(nonPublic: true); if ((object)setMethod2 == null) { return MakeFailure("Property " + attribute.methodName + " does not have a Setter"); } return setMethod2; } return MakeFailure("Could not find property " + attribute.methodName + " in type " + attribute.declaringType.FullDescription()); } case MethodType.Constructor: { ConstructorInfo constructorInfo2 = AccessTools.DeclaredConstructor(attribute.declaringType, attribute.argumentTypes); if ((object)constructorInfo2 != null) { return constructorInfo2; } return MakeFailure("Could not find constructor with " + attribute.argumentTypes.Description() + " parameters in type " + attribute.declaringType.FullDescription()); } case MethodType.StaticConstructor: { ConstructorInfo constructorInfo = AccessTools.GetDeclaredConstructors(attribute.declaringType).FirstOrDefault((ConstructorInfo c) => c.IsStatic); if ((object)constructorInfo != null) { return constructorInfo; } return MakeFailure("Could not find static constructor in type " + attribute.declaringType.FullDescription()); } default: throw new ArgumentOutOfRangeException("methodType", attribute.methodType, "Unknown method type"); } string GetPatchName() { return attribute.method?.FullDescription() ?? "Unknown patch"; } MethodBase MakeFailure(string reason) { Logger.Log(Logger.LogChannel.Error, () => "Failed to process patch " + GetPatchName() + " - " + reason); return null; } } private T RunMethod(T defaultIfNotExisting, params object[] parameters) { if ((object)container == null) { return defaultIfNotExisting; } string name = typeof(S).Name.Replace("Harmony", ""); MethodInfo patchMethod = GetPatchMethod(container, name); if ((object)patchMethod != null) { if (typeof(T).IsAssignableFrom(patchMethod.ReturnType)) { object[] emptyTypes = Type.EmptyTypes; return (T)patchMethod.Invoke(null, emptyTypes); } object[] inputs = (parameters ?? new object[0]).Union(new object[1] { instance }).ToArray(); object[] parameters2 = AccessTools.ActualParameters(patchMethod, inputs); patchMethod.Invoke(null, parameters2); return defaultIfNotExisting; } return defaultIfNotExisting; } private void RunMethod(params object[] parameters) { if ((object)container != null) { string name = typeof(S).Name.Replace("Harmony", ""); MethodInfo patchMethod = GetPatchMethod(container, name); if ((object)patchMethod != null) { object[] inputs = (parameters ?? new object[0]).Union(new object[1] { instance }).ToArray(); object[] parameters2 = AccessTools.ActualParameters(patchMethod, inputs); patchMethod.Invoke(null, parameters2); } } } private MethodInfo GetPatchMethod(Type patchType, string name) { string attributeType = typeof(T).FullName; MethodInfo methodInfo = patchType.GetMethods(AccessTools.all).FirstOrDefault((MethodInfo m) => m.GetCustomAttributes(inherit: true).Any((object a) => a.GetType().FullName == attributeType)); if ((object)methodInfo == null) { methodInfo = patchType.GetMethod(name, AccessTools.all); } return methodInfo; } private void GetPatches(Type patchType, out MethodInfo prefix, out MethodInfo postfix, out MethodInfo transpiler, out MethodInfo finalizer) { prefix = GetPatchMethod(patchType, "Prefix"); postfix = GetPatchMethod(patchType, "Postfix"); transpiler = GetPatchMethod(patchType, "Transpiler"); finalizer = GetPatchMethod(patchType, "Finalizer"); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.ReversePatcher ---- namespace HarmonyLib { public class ReversePatcher { private readonly Harmony instance; private readonly MethodBase original; private readonly MethodInfo standin; private readonly ILHook ilHook; public ReversePatcher(Harmony instance, MethodBase original, MethodInfo standin) { this.instance = instance; this.original = original; this.standin = standin; ilHook = new ILHook(standin, ApplyReversePatch, new ILHookConfig { ManualApply = true }); } private void ApplyReversePatch(ILContext ctx) { DynamicMethodDefinition dynamicMethodDefinition = new DynamicMethodDefinition(original); ILManipulator iLManipulator = new ILManipulator(dynamicMethodDefinition.Definition.Body); ctx.Body.Variables.Clear(); foreach (VariableDefinition variable in dynamicMethodDefinition.Definition.Body.Variables) { ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(variable.VariableType))); } MethodInfo transpiler = GetTranspiler(standin); if ((object)transpiler != null) { iLManipulator.AddTranspiler(transpiler); } iLManipulator.WriteTo(ctx.Body, standin); ctx.IL.Emit(OpCodes.Ret); } public void Patch(HarmonyReversePatchType type = HarmonyReversePatchType.Original) { if ((object)original == null) { throw new NullReferenceException("Null method for " + instance.Id); } ilHook.Apply(); } private MethodInfo GetTranspiler(MethodInfo method) { string methodName = method.Name; List declaredMethods = AccessTools.GetDeclaredMethods(method.DeclaringType); Type ici = typeof(IEnumerable); return declaredMethods.FirstOrDefault((MethodInfo m) => (object)m.ReturnType == ici && m.Name.StartsWith("<" + methodName + ">")); } } } // ---- BepInExPack_Sunkenland/BepInEx/core/0Harmony20.dll :: HarmonyLib.CodeMatch ---- namespace HarmonyLib { public class CodeMatch { public string name; public List opcodes = new List(); public List operands = new List(); public List