Decompiled source of RoundsDashLoader v1.0.5

RoundsDashLoader.dll

Decompiled 2 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using MonoMod.RuntimeDetour;
using Photon.Pun.Simple;
using RoundsDashLoader.Patches;
using RoundsDashLoader.Utils;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Scripting;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RoundsDashLoader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RoundsDashLoader")]
[assembly: AssemblyTitle("RoundsDashLoader")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RoundsDashLoader
{
	public static class Patcher
	{
		public static IEnumerable<string> TargetDLLs => Array.Empty<string>();

		public static void Patch(AssemblyDefinition assembly)
		{
		}

		public static void Initialize()
		{
			try
			{
				HarmonyTypeCachePatch.InstallGlobalHooks();
			}
			catch
			{
			}
		}
	}
	[BepInPlugin("000_rounds_dashloader", "RoundsDashLoader", "1.0.5")]
	[BepInProcess("Rounds.exe")]
	public class RoundsDashLoaderPlugin : BaseUnityPlugin
	{
		public const string ModId = "000_rounds_dashloader";

		public const string ModName = "RoundsDashLoader";

		public const string ModVersion = "1.0.5";

		private static Stopwatch bootStopwatch;

		private static float totalBootTimeSeconds = -1f;

		private static bool isBootDone = false;

		public static RoundsDashLoaderPlugin Instance { get; private set; }

		public static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_006d: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			bootStopwatch = Stopwatch.StartNew();
			Logger.LogInfo((object)"[RoundsDashLoader] v1.0.5 initializing Ultra-DashLoader acceleration pipeline...");
			try
			{
				QualitySettings.asyncUploadBufferSize = 32;
				QualitySettings.asyncUploadTimeSlice = 4;
				QualitySettings.asyncUploadPersistentBuffer = true;
				Application.backgroundLoadingPriority = (ThreadPriority)4;
			}
			catch
			{
			}
			DiskCacheUtil.Initialize();
			HarmonyTypeCachePatch.InstallGlobalHooks();
			try
			{
				Harmony val = new Harmony("000_rounds_dashloader");
				val.PatchAll();
				CombatOptimizationPatch.ApplyDynamicGuards(val);
				EveryonePicksPatch.Apply(val);
				Logger.LogInfo((object)"[RoundsDashLoader] Ultra-fast reflection caching, texture streaming & intro bypass patches active.");
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"[RoundsDashLoader] Error applying patches: {arg}");
			}
		}

		public static void OnBootCompleted()
		{
			if (!isBootDone)
			{
				isBootDone = true;
				if (bootStopwatch != null)
				{
					bootStopwatch.Stop();
					totalBootTimeSeconds = (float)bootStopwatch.ElapsedMilliseconds / 1000f;
				}
				Logger.LogInfo((object)"============================================================");
				Logger.LogInfo((object)$"⚡ [RoundsDashLoader] LIGHTNING BOOT COMPLETE in {totalBootTimeSeconds:F2}s!");
				Logger.LogInfo((object)$"⚡ [RoundsDashLoader] Reflection Type Hits: {HarmonyTypeCachePatch.CacheHits} (Saved MMHOOK churn)");
				Logger.LogInfo((object)$"⚡ [RoundsDashLoader] Texture Cache Hits: {TextureCachePatch.CacheHits} | New Decodes Cached: {TextureCachePatch.DecodedTextures}");
				Logger.LogInfo((object)"⚡ [RoundsDashLoader] Intro videos and splash screens bypassed.");
				Logger.LogInfo((object)"============================================================");
			}
		}

		private void OnGUI()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (isBootDone && !(totalBootTimeSeconds <= 0f) && Time.timeSinceLevelLoad < 25f)
			{
				Color color = GUI.color;
				GUI.color = new Color(0.2f, 1f, 0.6f, 0.85f);
				string text = $"⚡ DashLoader: {totalBootTimeSeconds:F2}s boot";
				GUI.Label(new Rect(15f, 12f, 300f, 24f), text);
				GUI.color = color;
			}
		}
	}
}
namespace RoundsDashLoader.Utils
{
	public static class DiskCacheUtil
	{
		private static string cacheDir;

		private static bool initialized;

		public static void Initialize()
		{
			if (initialized)
			{
				return;
			}
			try
			{
				cacheDir = Path.Combine(Paths.CachePath, "RoundsDashLoader", "textures");
				if (!Directory.Exists(cacheDir))
				{
					Directory.CreateDirectory(cacheDir);
				}
				initialized = true;
			}
			catch (Exception ex)
			{
				Debug.LogWarning("[RoundsDashLoader] Could not initialize disk cache directory: " + ex.Message);
			}
		}

		public static bool TryLoad(long hash, out byte[] rawBytes, out int width, out int height, out TextureFormat format)
		{
			rawBytes = null;
			width = 0;
			height = 0;
			format = (TextureFormat)4;
			if (!initialized || string.IsNullOrEmpty(cacheDir))
			{
				return false;
			}
			string path = Path.Combine(cacheDir, $"{hash:X16}.bin");
			if (!File.Exists(path))
			{
				return false;
			}
			try
			{
				using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 8192);
				using BinaryReader binaryReader = new BinaryReader(input);
				width = binaryReader.ReadInt32();
				height = binaryReader.ReadInt32();
				format = (TextureFormat)binaryReader.ReadInt32();
				int num = binaryReader.ReadInt32();
				rawBytes = binaryReader.ReadBytes(num);
				return rawBytes != null && rawBytes.Length == num;
			}
			catch
			{
				return false;
			}
		}

		public static void Save(long hash, byte[] rawBytes, int width, int height, TextureFormat format)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected I4, but got Unknown
			if (!initialized || string.IsNullOrEmpty(cacheDir) || rawBytes == null || rawBytes.Length == 0)
			{
				return;
			}
			string path = Path.Combine(cacheDir, $"{hash:X16}.bin");
			try
			{
				using FileStream output = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 8192);
				using BinaryWriter binaryWriter = new BinaryWriter(output);
				binaryWriter.Write(width);
				binaryWriter.Write(height);
				binaryWriter.Write((int)format);
				binaryWriter.Write(rawBytes.Length);
				binaryWriter.Write(rawBytes);
			}
			catch
			{
			}
		}
	}
	public static class FastHashUtil
	{
		private const ulong FnvOffsetBasis = 14695981039346656037uL;

		private const ulong FnvPrime = 1099511628211uL;

		public static long ComputeHash(byte[] data)
		{
			if (data == null || data.Length == 0)
			{
				return 0L;
			}
			ulong num = 14695981039346656037uL;
			int num2 = data.Length;
			int num3 = ((num2 <= 131072) ? 1 : (num2 / 2048));
			for (int i = 0; i < num2; i += num3)
			{
				num ^= data[i];
				num *= 1099511628211L;
			}
			return (long)num ^ (long)num2;
		}
	}
}
namespace RoundsDashLoader.Patches
{
	[HarmonyPatch]
	public static class CombatOptimizationPatch
	{
		public static bool IsInCombat { get; private set; }

		public static void SetCombatMode(bool active)
		{
			if (IsInCombat == active)
			{
				return;
			}
			IsInCombat = active;
			try
			{
				if (active)
				{
					GarbageCollector.GCMode = (Mode)0;
				}
				else
				{
					GarbageCollector.GCMode = (Mode)1;
				}
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(GM_ArmsRace), "StartGame")]
		[HarmonyPostfix]
		public static void Postfix_StartGame()
		{
			SetCombatMode(active: true);
		}

		[HarmonyPatch(typeof(GM_ArmsRace), "DoStartGame")]
		[HarmonyPostfix]
		public static void Postfix_DoStartGame()
		{
			SetCombatMode(active: true);
		}

		[HarmonyPatch(typeof(GM_ArmsRace), "PointOver")]
		[HarmonyPrefix]
		public static void Prefix_PointOver()
		{
			SetCombatMode(active: false);
		}

		[HarmonyPatch(typeof(GM_ArmsRace), "RoundOver")]
		[HarmonyPrefix]
		public static void Prefix_RoundOver()
		{
			SetCombatMode(active: false);
		}

		[HarmonyPatch(typeof(GM_ArmsRace), "GameOver")]
		[HarmonyPrefix]
		public static void Prefix_GameOver()
		{
			SetCombatMode(active: false);
		}

		[HarmonyPatch(typeof(CardChoice), "StartPick")]
		[HarmonyPrefix]
		public static void Prefix_StartPick()
		{
			SetCombatMode(active: false);
		}

		[HarmonyPatch(typeof(CardChoice), "RPCA_DonePicking")]
		[HarmonyPostfix]
		public static void Postfix_DonePicking()
		{
			SetCombatMode(active: false);
		}

		[HarmonyPatch(typeof(NetworkPhysicsObject), "OnCollisionEnter2D")]
		[HarmonyPrefix]
		public static bool Prefix_OnCollisionEnter2D(NetworkPhysicsObject __instance, Collision2D collision)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.photonView == (Object)null || collision == null || collision.contacts == null || collision.contacts.Length == 0)
			{
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(Player), "FullReset")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		public static bool Prefix_PlayerFullReset(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null || (Object)(object)__instance.data == (Object)null)
			{
				return false;
			}
			return true;
		}

		public static void ApplyDynamicGuards(Harmony harmony)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("ModdingUtils.Patches.PlayerPatchFullReset");
				if (type != null)
				{
					MethodInfo methodInfo = AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						HarmonyMethod val = new HarmonyMethod(typeof(CombatOptimizationPatch), "Guard_ModdingUtils_Prefix", (Type[])null)
						{
							priority = 800
						};
						harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
				}
			}
			catch
			{
			}
		}

		public static bool Guard_ModdingUtils_Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null)
			{
				return false;
			}
			return true;
		}
	}
	public static class EveryonePicksPatch
	{
		public static void Apply(Harmony harmony)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("EveryonePicks.PickBoard");
				if (!(type == null))
				{
					MethodInfo methodInfo = AccessTools.Method(type, "Draw", (Type[])null, (Type[])null);
					if (!(methodInfo == null))
					{
						HarmonyMethod val = new HarmonyMethod(typeof(EveryonePicksPatch), "Transpiler", (Type[])null);
						harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
					}
				}
			}
			catch
			{
			}
		}

		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			MethodInfo getWidth = AccessTools.PropertyGetter(typeof(Screen), "width");
			for (int i = 0; i < list.Count - 1; i++)
			{
				if (list[i].opcode == OpCodes.Ldc_R4 && Convert.ToSingle(list[i].operand) == 18f && (list[i + 1].opcode == OpCodes.Stloc_S || list[i + 1].opcode == OpCodes.Stloc))
				{
					int num = -1;
					if (list[i + 1].operand is LocalBuilder localBuilder)
					{
						num = localBuilder.LocalIndex;
					}
					else if (list[i + 1].operand is int num2)
					{
						num = num2;
					}
					else if (list[i + 1].operand is byte b)
					{
						num = b;
					}
					if (num == 8)
					{
						yield return new CodeInstruction(OpCodes.Call, (object)getWidth);
						yield return new CodeInstruction(OpCodes.Conv_R4, (object)null);
						yield return new CodeInstruction(OpCodes.Ldloc_S, (object)5);
						yield return new CodeInstruction(OpCodes.Sub, (object)null);
						yield return new CodeInstruction(OpCodes.Ldc_R4, (object)18f);
						yield return new CodeInstruction(OpCodes.Sub, (object)null);
						yield return new CodeInstruction(list[i + 1].opcode, list[i + 1].operand);
						i++;
						continue;
					}
				}
				yield return list[i];
			}
			if (list.Count > 0)
			{
				yield return list[list.Count - 1];
			}
		}
	}
	[HarmonyPatch]
	public static class HarmonyTypeCachePatch
	{
		private static readonly ConcurrentDictionary<Assembly, Type[]> AssemblyTypesCache = new ConcurrentDictionary<Assembly, Type[]>();

		private static readonly ConcurrentDictionary<Assembly, Type[]> AssemblyExportedTypesCache = new ConcurrentDictionary<Assembly, Type[]>();

		private static readonly ConcurrentDictionary<string, Type> TypeNameCache = new ConcurrentDictionary<string, Type>(StringComparer.Ordinal);

		private static readonly ConcurrentDictionary<string, MethodInfo> MethodCache = new ConcurrentDictionary<string, MethodInfo>(StringComparer.Ordinal);

		private static readonly ConcurrentDictionary<string, FieldInfo> FieldCache = new ConcurrentDictionary<string, FieldInfo>(StringComparer.Ordinal);

		private static readonly ConcurrentDictionary<string, PropertyInfo> PropertyCache = new ConcurrentDictionary<string, PropertyInfo>(StringComparer.Ordinal);

		private static Hook hookGetTypes;

		private static Hook hookGetExportedTypes;

		public static int CacheHits = 0;

		public static int FastScans = 0;

		public static void InstallGlobalHooks()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			try
			{
				HarmonyGlobalSettings.DisallowLegacyGlobalUnpatchAll = true;
				MethodInfo method = typeof(Assembly).GetMethod("GetTypes", Type.EmptyTypes);
				MethodInfo method2 = typeof(HarmonyTypeCachePatch).GetMethod("Hook_GetTypes", BindingFlags.Static | BindingFlags.Public);
				if (method != null && method2 != null)
				{
					hookGetTypes = new Hook((MethodBase)method, method2);
				}
				MethodInfo method3 = typeof(Assembly).GetMethod("GetExportedTypes", Type.EmptyTypes);
				MethodInfo method4 = typeof(HarmonyTypeCachePatch).GetMethod("Hook_GetExportedTypes", BindingFlags.Static | BindingFlags.Public);
				if (method3 != null && method4 != null)
				{
					hookGetExportedTypes = new Hook((MethodBase)method3, method4);
				}
				ManualLogSource logger = RoundsDashLoaderPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[RoundsDashLoader] Global CLR reflection hooks (Assembly.GetTypes & GetExportedTypes) active.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = RoundsDashLoaderPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[RoundsDashLoader] Reflection hooks note: " + ex.Message));
				}
			}
		}

		public static Type[] Hook_GetTypes(Func<Assembly, Type[]> orig, Assembly self)
		{
			if (self == null)
			{
				return Type.EmptyTypes;
			}
			if (AssemblyTypesCache.TryGetValue(self, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				return value;
			}
			Type[] array;
			try
			{
				array = orig(self);
			}
			catch (ReflectionTypeLoadException ex)
			{
				array = ((ex.Types != null) ? ex.Types.Where((Type t) => t != null).ToArray() : Type.EmptyTypes);
			}
			catch
			{
				array = Type.EmptyTypes;
			}
			AssemblyTypesCache[self] = array;
			Interlocked.Increment(ref FastScans);
			return array;
		}

		public static Type[] Hook_GetExportedTypes(Func<Assembly, Type[]> orig, Assembly self)
		{
			if (self == null)
			{
				return Type.EmptyTypes;
			}
			if (AssemblyExportedTypesCache.TryGetValue(self, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				return value;
			}
			Type[] array;
			try
			{
				array = orig(self);
			}
			catch (ReflectionTypeLoadException ex)
			{
				array = ((ex.Types != null) ? ex.Types.Where((Type t) => t != null).ToArray() : Type.EmptyTypes);
			}
			catch
			{
				array = Type.EmptyTypes;
			}
			AssemblyExportedTypesCache[self] = array;
			Interlocked.Increment(ref FastScans);
			return array;
		}

		[HarmonyPatch(typeof(AccessTools), "GetTypesFromAssembly")]
		[HarmonyPrefix]
		public static bool Prefix_GetTypesFromAssembly(Assembly assembly, ref Type[] __result)
		{
			if (assembly == null)
			{
				__result = Type.EmptyTypes;
				return false;
			}
			if (AssemblyTypesCache.TryGetValue(assembly, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				__result = value;
				return false;
			}
			Type[] array;
			try
			{
				array = assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				array = ((ex.Types != null) ? ex.Types.Where((Type t) => t != null).ToArray() : Type.EmptyTypes);
			}
			catch
			{
				array = Type.EmptyTypes;
			}
			AssemblyTypesCache[assembly] = array;
			Interlocked.Increment(ref FastScans);
			__result = array;
			return false;
		}

		[HarmonyPatch(typeof(AccessTools), "TypeByName")]
		[HarmonyPrefix]
		public static bool Prefix_TypeByName(string name, ref Type __result)
		{
			if (string.IsNullOrEmpty(name))
			{
				return true;
			}
			if (TypeNameCache.TryGetValue(name, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				__result = value;
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(AccessTools), "TypeByName")]
		[HarmonyPostfix]
		public static void Postfix_TypeByName(string name, Type __result)
		{
			if (!string.IsNullOrEmpty(name) && __result != null)
			{
				TypeNameCache[name] = __result;
			}
		}

		[HarmonyPatch(typeof(AccessTools), "Method", new Type[]
		{
			typeof(Type),
			typeof(string),
			typeof(Type[]),
			typeof(Type[])
		})]
		[HarmonyPrefix]
		public static bool Prefix_Method(Type type, string name, Type[] parameters, Type[] generics, ref MethodInfo __result)
		{
			if (type == null || string.IsNullOrEmpty(name))
			{
				return true;
			}
			string key = BuildMemberKey(type, name, parameters);
			if (MethodCache.TryGetValue(key, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				__result = value;
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(AccessTools), "Method", new Type[]
		{
			typeof(Type),
			typeof(string),
			typeof(Type[]),
			typeof(Type[])
		})]
		[HarmonyPostfix]
		public static void Postfix_Method(Type type, string name, Type[] parameters, Type[] generics, MethodInfo __result)
		{
			if (type != null && !string.IsNullOrEmpty(name) && __result != null)
			{
				string key = BuildMemberKey(type, name, parameters);
				MethodCache[key] = __result;
			}
		}

		[HarmonyPatch(typeof(AccessTools), "Field", new Type[]
		{
			typeof(Type),
			typeof(string)
		})]
		[HarmonyPrefix]
		public static bool Prefix_Field(Type type, string name, ref FieldInfo __result)
		{
			if (type == null || string.IsNullOrEmpty(name))
			{
				return true;
			}
			string key = type.FullName + "::" + name;
			if (FieldCache.TryGetValue(key, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				__result = value;
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(AccessTools), "Field", new Type[]
		{
			typeof(Type),
			typeof(string)
		})]
		[HarmonyPostfix]
		public static void Postfix_Field(Type type, string name, FieldInfo __result)
		{
			if (type != null && !string.IsNullOrEmpty(name) && __result != null)
			{
				string key = type.FullName + "::" + name;
				FieldCache[key] = __result;
			}
		}

		[HarmonyPatch(typeof(AccessTools), "Property", new Type[]
		{
			typeof(Type),
			typeof(string)
		})]
		[HarmonyPrefix]
		public static bool Prefix_Property(Type type, string name, ref PropertyInfo __result)
		{
			if (type == null || string.IsNullOrEmpty(name))
			{
				return true;
			}
			string key = type.FullName + "::" + name;
			if (PropertyCache.TryGetValue(key, out var value))
			{
				Interlocked.Increment(ref CacheHits);
				__result = value;
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(AccessTools), "Property", new Type[]
		{
			typeof(Type),
			typeof(string)
		})]
		[HarmonyPostfix]
		public static void Postfix_Property(Type type, string name, PropertyInfo __result)
		{
			if (type != null && !string.IsNullOrEmpty(name) && __result != null)
			{
				string key = type.FullName + "::" + name;
				PropertyCache[key] = __result;
			}
		}

		private static string BuildMemberKey(Type type, string name, Type[] parameters)
		{
			if (parameters == null || parameters.Length == 0)
			{
				return type.FullName + "::" + name;
			}
			return type.FullName + "::" + name + "(" + string.Join(",", parameters.Select((Type p) => (!(p != null)) ? "null" : p.Name)) + ")";
		}

		[HarmonyPatch(typeof(ContactTrigger), "FindDerivedTypesFromAssembly")]
		[HarmonyFinalizer]
		public static Exception Finalizer_ContactTrigger(Exception __exception)
		{
			if (__exception != null)
			{
				Interlocked.Increment(ref CacheHits);
				return null;
			}
			return null;
		}
	}
	[HarmonyPatch]
	public static class IntroAndMenuSkipPatch
	{
		private static bool skipped;

		[HarmonyPatch(typeof(SkipIntro), "Start")]
		[HarmonyPostfix]
		public static void Postfix_SkipIntroStart(SkipIntro __instance)
		{
			if ((Object)(object)__instance == (Object)null || skipped)
			{
				return;
			}
			try
			{
				if ((Object)(object)__instance.target != (Object)null)
				{
					skipped = true;
					__instance.target.Open();
				}
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(SkipIntro), "Update")]
		[HarmonyPostfix]
		public static void Postfix_SkipIntroUpdate(SkipIntro __instance)
		{
			if ((Object)(object)__instance == (Object)null || skipped)
			{
				return;
			}
			try
			{
				if ((Object)(object)__instance.target != (Object)null)
				{
					skipped = true;
					__instance.target.Open();
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	public static class MainMenuHandlerPatch
	{
		private static bool booted;

		[HarmonyPatch(typeof(MainMenuHandler), "Awake")]
		[HarmonyPostfix]
		public static void Postfix_Awake()
		{
			if (!booted)
			{
				booted = true;
				try
				{
					QualitySettings.asyncUploadTimeSlice = 4;
					QualitySettings.asyncUploadBufferSize = 32;
					QualitySettings.asyncUploadPersistentBuffer = true;
					Application.backgroundLoadingPriority = (ThreadPriority)4;
				}
				catch
				{
				}
				try
				{
					TextureCachePatch.ClearMemoryCache();
				}
				catch
				{
				}
				RoundsDashLoaderPlugin.OnBootCompleted();
			}
		}
	}
	[HarmonyPatch(typeof(Shader), "Find")]
	public static class ShaderCachePatch
	{
		private static readonly ConcurrentDictionary<string, Shader> ShaderCache = new ConcurrentDictionary<string, Shader>(StringComparer.Ordinal);

		[HarmonyPrefix]
		public static bool Prefix(string name, ref Shader __result)
		{
			if (string.IsNullOrEmpty(name))
			{
				return true;
			}
			if (ShaderCache.TryGetValue(name, out var value))
			{
				__result = value;
				return false;
			}
			return true;
		}

		[HarmonyPostfix]
		public static void Postfix(string name, Shader __result)
		{
			if (!string.IsNullOrEmpty(name) && (Object)(object)__result != (Object)null)
			{
				ShaderCache[name] = __result;
			}
		}
	}
	[HarmonyPatch(typeof(SplashScreen), "get_isFinished")]
	public static class SplashScreenPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(ref bool __result)
		{
			__result = true;
			return false;
		}
	}
	[HarmonyPatch]
	public static class TextureCachePatch
	{
		private static readonly ConcurrentDictionary<long, byte[]> MemRawCache = new ConcurrentDictionary<long, byte[]>();

		private static readonly ConcurrentDictionary<long, (int width, int height, TextureFormat format)> MemFormatCache = new ConcurrentDictionary<long, (int, int, TextureFormat)>();

		public static int DecodedTextures = 0;

		public static int CacheHits = 0;

		[HarmonyPatch(typeof(ImageConversion), "LoadImage", new Type[]
		{
			typeof(Texture2D),
			typeof(byte[])
		})]
		[HarmonyPrefix]
		public static bool Prefix_LoadImage2(Texture2D tex, byte[] data, ref bool __result)
		{
			return PrefixInternal(tex, data, markNonReadable: false, ref __result);
		}

		[HarmonyPatch(typeof(ImageConversion), "LoadImage", new Type[]
		{
			typeof(Texture2D),
			typeof(byte[])
		})]
		[HarmonyPostfix]
		public static void Postfix_LoadImage2(Texture2D tex, byte[] data, bool __result)
		{
			PostfixInternal(tex, data, markNonReadable: false, __result);
		}

		[HarmonyPatch(typeof(ImageConversion), "LoadImage", new Type[]
		{
			typeof(Texture2D),
			typeof(byte[]),
			typeof(bool)
		})]
		[HarmonyPrefix]
		public static bool Prefix_LoadImage3(Texture2D tex, byte[] data, bool markNonReadable, ref bool __result)
		{
			return PrefixInternal(tex, data, markNonReadable, ref __result);
		}

		[HarmonyPatch(typeof(ImageConversion), "LoadImage", new Type[]
		{
			typeof(Texture2D),
			typeof(byte[]),
			typeof(bool)
		})]
		[HarmonyPostfix]
		public static void Postfix_LoadImage3(Texture2D tex, byte[] data, bool markNonReadable, bool __result)
		{
			PostfixInternal(tex, data, markNonReadable, __result);
		}

		private static bool PrefixInternal(Texture2D tex, byte[] data, bool markNonReadable, ref bool __result)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)tex == (Object)null || data == null || data.Length == 0)
			{
				return true;
			}
			long num = FastHashUtil.ComputeHash(data);
			if (MemRawCache.TryGetValue(num, out var value) && MemFormatCache.TryGetValue(num, out (int, int, TextureFormat) value2) && ApplyRawToTexture(tex, value, value2.Item1, value2.Item2, value2.Item3, markNonReadable))
			{
				Interlocked.Increment(ref CacheHits);
				__result = true;
				return false;
			}
			if (DiskCacheUtil.TryLoad(num, out var rawBytes, out var width, out var height, out var format))
			{
				MemRawCache[num] = rawBytes;
				MemFormatCache[num] = (width, height, format);
				if (ApplyRawToTexture(tex, rawBytes, width, height, format, markNonReadable))
				{
					Interlocked.Increment(ref CacheHits);
					__result = true;
					return false;
				}
			}
			return true;
		}

		private static void PostfixInternal(Texture2D tex, byte[] data, bool markNonReadable, bool __result)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (!__result || (Object)(object)tex == (Object)null || data == null || data.Length == 0)
			{
				return;
			}
			long num = FastHashUtil.ComputeHash(data);
			if (MemRawCache.ContainsKey(num))
			{
				return;
			}
			try
			{
				byte[] rawTextureData = tex.GetRawTextureData();
				if (rawTextureData != null && rawTextureData.Length != 0)
				{
					MemRawCache[num] = rawTextureData;
					MemFormatCache[num] = (((Texture)tex).width, ((Texture)tex).height, tex.format);
					DiskCacheUtil.Save(num, rawTextureData, ((Texture)tex).width, ((Texture)tex).height, tex.format);
					Interlocked.Increment(ref DecodedTextures);
				}
			}
			catch
			{
			}
		}

		private static bool ApplyRawToTexture(Texture2D tex, byte[] raw, int w, int h, TextureFormat format, bool nonReadable)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				tex.Resize(w, h, format, false);
				tex.LoadRawTextureData(raw);
				tex.Apply(false, nonReadable);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public static void ClearMemoryCache()
		{
			MemRawCache.Clear();
			MemFormatCache.Clear();
		}
	}
}