Decompiled source of ScoutBadger v1.4.2

plugins/com.github.Kirshoo.ScoutBadger.dll

Decompiled 3 weeks ago
using System;
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.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using ScoutBadger.Configuration;
using ScoutBadger.Patches;
using ScoutBadger.Saves;
using ScoutBadger.UIHelpers;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.Kirshoo.ScoutBadger")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.2.0")]
[assembly: AssemblyInformationalVersion("1.4.2+f1562877dd950e2a759d23094aeab8f05392a601")]
[assembly: AssemblyProduct("com.github.Kirshoo.ScoutBadger")]
[assembly: AssemblyTitle("ScoutBadger")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace ScoutBadger
{
	[BepInPlugin("com.github.Kirshoo.ScoutBadger", "ScoutBadger", "1.4.2")]
	public class Plugin : BaseUnityPlugin
	{
		internal static SaveManager SaveManager;

		public const string Id = "com.github.Kirshoo.ScoutBadger";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "ScoutBadger";

		public static string Version => "1.4.2";

		private bool IsCompatible(BuildVersion version)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (version.MajorVersion == 2)
			{
				return version.MinorVersion >= 0;
			}
			return false;
		}

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BuildVersion val = default(BuildVersion);
			((BuildVersion)(ref val))..ctor(Application.version, "???");
			Log.LogDebug((object)$"Running on version {val}");
			if (!IsCompatible(val))
			{
				Log.LogError((object)("Incompatible version of the game detected. " + Name + " v" + Version + " will be disabled."));
			}
			else
			{
				BindConfig();
				SaveManager = new SaveManager(SaveConfig.SafeFile);
				SaveManager.Load();
				Harmony val2 = new Harmony("com.github.Kirshoo.ScoutBadger");
				val2.PatchAll(typeof(AchievementManagerPatch));
				val2.PatchAll(typeof(EndScreenPatch.BadgeRoutinePatch));
				val2.PatchAll(typeof(BadgeUIPatch));
				Log.LogDebug((object)"Preloading Achievements Context manager.");
				_ = AchievementContext.Instance;
				Log.LogInfo((object)("Plugin " + Name + " is loaded!"));
			}
		}

		private void OnApplicationQuit()
		{
			SaveManager.Save();
		}

		private void BindConfig()
		{
			SaveConfig.BindConfig(((BaseUnityPlugin)this).Config);
			VisualConfig.BindConfig(((BaseUnityPlugin)this).Config);
		}
	}
}
namespace ScoutBadger.UIHelpers
{
	internal class BadgeRepetitionText
	{
		private static TMP_FontAsset fontAsset;

		private const string fontname = "DarumaDropOne-Regular SDF";

		public const string RepetitionObjectName = "RepetitionText";

		public GameObject gameObject;

		private TextMeshProUGUI textComponent;

		private BadgeRepetitionText()
		{
		}

		public static BadgeRepetitionText CreateTextObject()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			BadgeRepetitionText badgeRepetitionText = new BadgeRepetitionText();
			GameObject val = new GameObject("RepetitionText");
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).font = LoadFont();
			((TMP_Text)val2).text = "";
			((TMP_Text)val2).fontSizeMax = 40f;
			((TMP_Text)val2).fontSizeMin = 18f;
			((TMP_Text)val2).horizontalAlignment = (HorizontalAlignmentOptions)4;
			badgeRepetitionText.gameObject = val;
			badgeRepetitionText.textComponent = val2;
			return badgeRepetitionText;
		}

		private static TMP_FontAsset LoadFont()
		{
			if ((Object)(object)fontAsset != (Object)null)
			{
				return fontAsset;
			}
			TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset asset) => ((Object)asset).name == "DarumaDropOne-Regular SDF"));
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogDebug((object)"Unable to load DarumaDropOne-Regular SDF! Falling back to default font.");
				val = Resources.GetBuiltinResource<TMP_FontAsset>("LiberationSans SDF.asset");
			}
			fontAsset = val;
			return fontAsset;
		}

		public void UpdateCount(int newCount)
		{
			if (newCount < 1)
			{
				((TMP_Text)textComponent).text = "";
				return;
			}
			if (newCount > 99)
			{
				newCount = 99;
			}
			((TMP_Text)textComponent).text = $"x{newCount}";
		}
	}
}
namespace ScoutBadger.Saves
{
	[Serializable]
	public class BadgeEntry
	{
		public ACHIEVEMENTTYPE LinkedAchievement;

		public int ReceivedAmount;

		public DateTime FirstAcquiredAt;

		public DateTime LastAcquiredAt;
	}
	[Serializable]
	public class BadgeSaveData
	{
		public int version = 1;

		public List<BadgeEntry> entries = new List<BadgeEntry>();
	}
	internal class SaveManager
	{
		private BadgeSaveData? saveData;

		private string? filepath;

		public SaveManager(string filepath)
		{
			SetSavePath(filepath);
		}

		public void SetSavePath(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				Plugin.Log.LogWarning((object)"Provided save path is null or empty");
			}
			filepath = path;
		}

		public void Load()
		{
			if (string.IsNullOrEmpty(filepath))
			{
				throw new ArgumentException("Save path is not set. Call SetSavePath() first.");
			}
			if (!File.Exists(filepath))
			{
				saveData = new BadgeSaveData();
				return;
			}
			BadgeSaveData badgeSaveData = JsonConvert.DeserializeObject<BadgeSaveData>(File.ReadAllText(filepath));
			if (badgeSaveData == null)
			{
				Plugin.Log.LogWarning((object)"Unable to load badge save data. Falling back to default info.");
				saveData = new BadgeSaveData();
			}
			else
			{
				saveData = badgeSaveData;
			}
		}

		public void Save()
		{
			if (string.IsNullOrEmpty(filepath))
			{
				throw new ArgumentException("Save path is not set. Call SetSavePath() first.");
			}
			if (saveData == null)
			{
				Plugin.Log.LogWarning((object)"Ignoring attempt to save uninitialized data");
				return;
			}
			string contents = JsonConvert.SerializeObject((object)saveData, (Formatting)0);
			Directory.CreateDirectory(Path.GetDirectoryName(filepath));
			File.WriteAllText(filepath, contents);
		}

		public void IncrementBadgeRepetition(ACHIEVEMENTTYPE type)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			if (saveData == null)
			{
				throw new InvalidOperationException("Save data is not initialized. Call Load() first.");
			}
			if (!TryGetBadge(type, out BadgeEntry badgeEntry))
			{
				badgeEntry = new BadgeEntry
				{
					LinkedAchievement = type,
					ReceivedAmount = 0
				};
				saveData.entries.Add(badgeEntry);
			}
			DateTime now = DateTime.Now;
			if (badgeEntry.ReceivedAmount == 0)
			{
				badgeEntry.FirstAcquiredAt = now;
			}
			Plugin.Log.LogDebug((object)$"Incrementing badge count for '{type}' achievement.");
			badgeEntry.LastAcquiredAt = now;
			badgeEntry.ReceivedAmount++;
		}

		public bool TryGetBadge(ACHIEVEMENTTYPE type, out BadgeEntry badgeEntry)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			badgeEntry = GetBadge(type);
			if (badgeEntry == null)
			{
				return false;
			}
			return true;
		}

		public BadgeEntry? GetBadge(ACHIEVEMENTTYPE type)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (saveData == null)
			{
				throw new InvalidOperationException("Save data is not initialized. Call Load() first.");
			}
			return saveData.entries.Find((BadgeEntry entry) => entry.LinkedAchievement == type);
		}
	}
}
namespace ScoutBadger.Patches
{
	internal class AchievementContext
	{
		private static AchievementContext _instance = null;

		private static readonly object _lock = new object();

		internal List<ACHIEVEMENTTYPE> repeatedAchievements = new List<ACHIEVEMENTTYPE>();

		public static AchievementContext Instance
		{
			get
			{
				lock (_lock)
				{
					if (_instance == null)
					{
						_instance = new AchievementContext();
					}
					return _instance;
				}
			}
		}

		public AchievementContext()
		{
			SceneManager.activeSceneChanged += OnSceneChanged;
		}

		public void Reset()
		{
			Plugin.Log.LogInfo((object)"Resetting the state of context.");
			ResetRepeatedAchievements();
		}

		public void ResetRepeatedAchievements()
		{
			Plugin.Log.LogInfo((object)"Clearing all repeated achievements from the context.");
			repeatedAchievements.Clear();
		}

		public void AddAchievement(ACHIEVEMENTTYPE type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			repeatedAchievements.Add(type);
		}

		public bool ShouldAllowCrownSequence(List<ACHIEVEMENTTYPE> earnedThisRun)
		{
			return earnedThisRun.Exists((ACHIEVEMENTTYPE t) => !repeatedAchievements.Contains(t) && IsCrownRequirement(t));
		}

		public bool ShouldAllowMedalSequence(List<ACHIEVEMENTTYPE> earnedThisRun)
		{
			return earnedThisRun.Exists((ACHIEVEMENTTYPE t) => !repeatedAchievements.Contains(t) && IsMedalRequirement(t));
		}

		public bool HasAchieved(ACHIEVEMENTTYPE type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return repeatedAchievements.Contains(type);
		}

		private bool IsCrownRequirement(ACHIEVEMENTTYPE type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)type >= 1)
			{
				return (int)type <= 32;
			}
			return false;
		}

		private bool IsMedalRequirement(ACHIEVEMENTTYPE type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type >= 1 && (int)type <= 72)
			{
				return !IsAscentAchievement(type);
			}
			return false;
		}

		private bool IsAscentAchievement(ACHIEVEMENTTYPE type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)type < 33 || (int)type > 39)
			{
				return (int)type == 67;
			}
			return true;
		}

		private void OnSceneChanged(Scene oldScene, Scene newScene)
		{
			if (((Scene)(ref newScene)).name.ToLowerInvariant().StartsWith("level_"))
			{
				Reset();
			}
		}
	}
	internal class AchievementManagerPatch
	{
		private static readonly List<SteamStatBasedAchievementData> steamStatAchievements = new List<SteamStatBasedAchievementData>
		{
			new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)29, (STEAMSTATTYPE)5, 5000),
			new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)7, (STEAMSTATTYPE)2, 5),
			new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)6, (STEAMSTATTYPE)1, 20),
			new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)9, (STEAMSTATTYPE)4, 200),
			new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)8, (STEAMSTATTYPE)3, 10)
		};

		private static bool CanAwardAchievement()
		{
			if (RunSettings.blockingAchievements)
			{
				return VisualConfig.ShowBadgesInCustomRuns;
			}
			return true;
		}

		private static bool IsCustomRun()
		{
			if (!RunSettings.IsCustomRun)
			{
				return RunSettings.isMiniRun;
			}
			return true;
		}

		[HarmonyPatch(typeof(AchievementManager), "ThrowAchievement")]
		[HarmonyPostfix]
		private static void AddToEarnedAchievements(AchievementManager __instance, ACHIEVEMENTTYPE type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!__instance.runBasedValueData.achievementsEarnedThisRun.Contains(type) && CanAwardAchievement())
			{
				__instance.runBasedValueData.achievementsEarnedThisRun.Add(type);
				Plugin.Log.LogInfo((object)$"Awarding '{type}' achievement!");
				if (!IsCustomRun())
				{
					Plugin.SaveManager.IncrementBadgeRepetition(type);
				}
			}
		}

		[HarmonyPatch(typeof(AchievementManager), "ThrowAchievement")]
		[HarmonyPrefix]
		private static void AddRepeatedAchievements(AchievementManager __instance, ACHIEVEMENTTYPE type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.runBasedValueData.steamAchievementsPreviouslyUnlocked.Contains(type) && !__instance.runBasedValueData.achievementsEarnedThisRun.Contains(type) && !AchievementContext.Instance.HasAchieved(type) && CanAwardAchievement())
			{
				AchievementContext.Instance.AddAchievement(type);
			}
		}

		[HarmonyPatch(typeof(AchievementManager), "IncrementSteamStat")]
		[HarmonyPostfix]
		private static void AddSteamStatAchievementRepeat(AchievementManager __instance, int __result, STEAMSTATTYPE steamStatType, int value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (!GetAchievementStatData(__instance, steamStatType, out SteamStatBasedAchievementData achievement))
			{
				Plugin.Log.LogDebug((object)$"Unable to find achievement data for {steamStatType}");
				return;
			}
			if (AchievementContext.Instance.repeatedAchievements.Contains(achievement.achievementType))
			{
				Plugin.Log.LogDebug((object)$"Achievement {achievement.achievementType} is already been achieved.");
				return;
			}
			int num = (__result - value) / achievement.requiredValue;
			int num2 = __result / achievement.requiredValue;
			if (num2 > num)
			{
				__instance.ThrowAchievement(achievement.achievementType);
			}
		}

		private static bool GetAchievementStatData(AchievementManager manager, STEAMSTATTYPE steamStatType, out SteamStatBasedAchievementData achievement)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			achievement = new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)0, (STEAMSTATTYPE)0, 1);
			SteamStatBasedAchievementData achievementData = default(SteamStatBasedAchievementData);
			foreach (object value in Enum.GetValues(typeof(ACHIEVEMENTTYPE)))
			{
				ACHIEVEMENTTYPE val = (ACHIEVEMENTTYPE)value;
				if ((manager.TryGetSteamStatLinkedAchievement(val, ref achievementData) || TryGetSteamStatAchievement(val, out achievementData)) && achievementData.statType == steamStatType)
				{
					achievement = achievementData;
					return true;
				}
			}
			return false;
		}

		private static bool TryGetSteamStatAchievement(ACHIEVEMENTTYPE achievement, out SteamStatBasedAchievementData achievementData)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			achievementData = new SteamStatBasedAchievementData((ACHIEVEMENTTYPE)0, (STEAMSTATTYPE)0, 1);
			foreach (SteamStatBasedAchievementData steamStatAchievement in steamStatAchievements)
			{
				if (steamStatAchievement.achievementType == achievement)
				{
					achievementData = steamStatAchievement;
					return true;
				}
			}
			return false;
		}
	}
	internal class BadgeUIPatch
	{
		[HarmonyPatch(typeof(BadgeUI), "Init")]
		[HarmonyPostfix]
		private static void CreateRepetitionText(BadgeUI __instance)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)((Component)__instance).transform.Find("RepetitionText")) && !(((Object)((Component)__instance).transform.parent).name == "Grid") && !((Object)(object)__instance.data == (Object)null))
			{
				BadgeRepetitionText badgeRepetitionText = BadgeRepetitionText.CreateTextObject();
				badgeRepetitionText.gameObject.transform.SetParent(((Component)__instance).gameObject.transform, false);
				RectTransform component = badgeRepetitionText.gameObject.GetComponent<RectTransform>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.anchorMin = new Vector2(0f, 0.5f);
					component.anchorMax = new Vector2(1f, 0.5f);
					component.anchoredPosition = new Vector2(0f, -15f);
					component.pivot = new Vector2(0.5f, 0.5f);
					component.sizeDelta = new Vector2(0f, 50f);
				}
				BadgeEntry badge = Plugin.SaveManager.GetBadge(__instance.data.linkedAchievement);
				if (badge != null)
				{
					badgeRepetitionText.UpdateCount(badge.ReceivedAmount);
				}
			}
		}
	}
	internal class EndScreenPatch
	{
		[HarmonyPatch]
		public static class BadgeRoutinePatch
		{
			private const int specialCosmeticDisplayCheckLenght = 3;

			private const int crownCheckLength = 10;

			private const int crownCheckNextIterationLabelOffset = 4;

			private const int illegalIndex = -1;

			private static MethodBase TargetMethod()
			{
				Type type = typeof(EndScreen).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name.Contains("<BadgeRoutine>"));
				return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null);
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator il)
			{
				int num = -1;
				int num2 = -1;
				int num3 = -1;
				List<CodeInstruction> list = new List<CodeInstruction>(instructions);
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Singleton<Customization>), "Instance");
				for (int i = 0; i < list.Count - 4; i++)
				{
					if (IsUnlockedCosmeticInstructions(list, i) && num == -1)
					{
						num = i;
					}
					if (IsDisplayCrownCheck(list, i) && num2 == -1)
					{
						num2 = i;
					}
					if (IsDisplayMedalCheck(list, i) && num3 == -1)
					{
						num3 = i;
					}
				}
				if (num == -1)
				{
					Plugin.Log.LogError((object)"[Transpiler] Unable to find Cosmetic loading instructions");
					return instructions;
				}
				if (num2 == -1)
				{
					Plugin.Log.LogError((object)"[Transpiler] Unable to find display crown check instructions");
					return instructions;
				}
				if (num3 == -1)
				{
					Plugin.Log.LogError((object)"[Transpiler] Unable to find display medal check instructions");
					return instructions;
				}
				List<CodeInstruction> list2 = null;
				try
				{
					list2 = new List<CodeInstruction>(GetLoadBadgeDataSequence(list));
				}
				catch (InvalidOperationException ex)
				{
					Plugin.Log.LogError((object)("[Transpiler] Loading Badge Data sequence: " + ex.Message));
					return instructions;
				}
				Label label = il.DefineLabel();
				try
				{
					CodeInstruction val = FindEndOfCosmeticLoop(list);
					val.labels.Add(label);
				}
				catch (InvalidOperationException ex2)
				{
					Plugin.Log.LogError((object)("[Transpiler] Looking for end of cosmetic routine: " + ex2.Message));
					return instructions;
				}
				Label escapeLabel = (Label)list[num2 + 3 - 1].operand;
				Label escapeLabel2 = (Label)list[num3 + 3 - 1].operand;
				List<CodeInstruction> list3 = new List<CodeInstruction>(CreateCrownEligibleCheck(escapeLabel));
				List<CodeInstruction> list4 = new List<CodeInstruction>(CreateMedalEligibleCheck(escapeLabel2));
				List<CodeInstruction> collection = new List<CodeInstruction>(CreateIsRepeatedCheck(list2, label));
				int num4 = 0;
				int index = num2 + 3 + num4;
				list.InsertRange(index, list3);
				num4 += list3.Count;
				int index2 = num3 + 3 + num4;
				list.InsertRange(index2, list4);
				num4 += list4.Count;
				list.InsertRange(num + num4, collection);
				return list;
			}

			private static CodeInstruction FindEndOfCosmeticLoop(List<CodeInstruction> instructions, int startIdx = 0)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(List<CustomizationOption>).GetNestedType("Enumerator"), "MoveNext", (Type[])null, (Type[])null);
				for (int i = startIdx; i < instructions.Count - 6; i++)
				{
					if (instructions[i].opcode == OpCodes.Ldarg_0 && instructions[i + 2].opcode == OpCodes.Call && instructions[i + 3].opcode == OpCodes.Brtrue && instructions[i + 4].opcode == OpCodes.Ldarg_0 && instructions[i + 6].opcode == OpCodes.Ldarg_0)
					{
						return instructions[i + 6];
					}
				}
				throw new InvalidOperationException("Unable to find end of the cosmetics loop");
			}

			private static bool IsGetCurrentAchievementAtLocalIndexInstructions(List<CodeInstruction> instructions, int index = 0)
			{
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(List<ACHIEVEMENTTYPE>), "Item");
				if (index >= 0 && index + 2 < instructions.Count && instructions[index].opcode == OpCodes.Ldloc_3 && instructions[index + 1].opcode == OpCodes.Ldloc_S && instructions[index + 2].opcode == OpCodes.Callvirt)
				{
					return (MethodInfo)instructions[index + 2].operand == methodInfo;
				}
				return false;
			}

			private static bool IsUnlockedCosmeticInstructions(List<CodeInstruction> instructions, int index = 0)
			{
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Singleton<Customization>), "Instance");
				if (index >= 0 && index + 4 < instructions.Count && instructions[index].opcode == OpCodes.Call && (MethodInfo)instructions[index].operand == methodInfo && instructions[index + 1].opcode == OpCodes.Ldarg_0 && instructions[index + 4].opcode == OpCodes.Ldfld)
				{
					return instructions[index + 4].operand != null;
				}
				return false;
			}

			private static bool IsDisplayCrownCheck(List<CodeInstruction> instructions, int index = 0)
			{
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Singleton<AchievementManager>), "Instance");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(AchievementManager), "AllBaseAchievementsUnlocked", (Type[])null, (Type[])null);
				if (index >= 0 && index + 2 < instructions.Count && instructions[index].opcode == OpCodes.Call && (MethodInfo)instructions[index].operand == methodInfo && instructions[index + 1].opcode == OpCodes.Callvirt && (MethodInfo)instructions[index + 1].operand == methodInfo2)
				{
					if (!(instructions[index + 2].opcode == OpCodes.Brfalse))
					{
						return instructions[index + 2].opcode == OpCodes.Brfalse_S;
					}
					return true;
				}
				return false;
			}

			private static bool IsDisplayMedalCheck(List<CodeInstruction> instructions, int index = 0)
			{
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Singleton<AchievementManager>), "Instance");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(AchievementManager), "AllSixtyFourAchievementsUnlocked", (Type[])null, (Type[])null);
				if (index >= 0 && index + 2 < instructions.Count && instructions[index].opcode == OpCodes.Call && (MethodInfo)instructions[index].operand == methodInfo && instructions[index + 1].opcode == OpCodes.Callvirt && (MethodInfo)instructions[index + 1].operand == methodInfo2)
				{
					if (!(instructions[index + 2].opcode == OpCodes.Brfalse))
					{
						return instructions[index + 2].opcode == OpCodes.Brfalse_S;
					}
					return true;
				}
				return false;
			}

			private static IEnumerable<CodeInstruction> GetLoadBadgeDataSequence(List<CodeInstruction> instructions, int startIdx = 0)
			{
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(List<BadgeData>), "Item");
				for (int i = startIdx; i < instructions.Count - 5; i++)
				{
					if (instructions[i].opcode == OpCodes.Ldarg_0 && instructions[i + 2].opcode == OpCodes.Ldarg_0 && instructions[i + 4].opcode == OpCodes.Callvirt && (MethodInfo)instructions[i + 4].operand == methodInfo)
					{
						return instructions.GetRange(i, 5);
					}
				}
				throw new InvalidOperationException("Unable to find BadgeData loader");
			}

			private static IEnumerable<CodeInstruction> GetAchievementAtLocalIndexSequence(List<CodeInstruction> instructions, int startIdx)
			{
				for (int i = startIdx; i < instructions.Count - 2; i++)
				{
					if (IsGetCurrentAchievementAtLocalIndexInstructions(instructions, i))
					{
						return instructions.GetRange(i, 3);
					}
				}
				throw new InvalidOperationException("Unable to find GetAchievementAtLocalIndex sequence");
			}

			private static IEnumerable<CodeInstruction> CreateCrownEligibleCheck(Label escapeLabel)
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Expected O, but got Unknown
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Expected O, but got Unknown
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Expected O, but got Unknown
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Expected O, but got Unknown
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(AchievementContext), "Instance");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(AchievementContext), "ShouldAllowCrownSequence", (Type[])null, (Type[])null);
				return (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4]
				{
					new CodeInstruction(OpCodes.Call, (object)methodInfo),
					new CodeInstruction(OpCodes.Ldloc_3, (object)null),
					new CodeInstruction(OpCodes.Callvirt, (object)methodInfo2),
					new CodeInstruction(OpCodes.Brfalse, (object)escapeLabel)
				};
			}

			private static IEnumerable<CodeInstruction> CreateMedalEligibleCheck(Label escapeLabel)
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Expected O, but got Unknown
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Expected O, but got Unknown
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Expected O, but got Unknown
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Expected O, but got Unknown
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(AchievementContext), "Instance");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(AchievementContext), "ShouldAllowMedalSequence", (Type[])null, (Type[])null);
				return (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4]
				{
					new CodeInstruction(OpCodes.Call, (object)methodInfo),
					new CodeInstruction(OpCodes.Ldloc_3, (object)null),
					new CodeInstruction(OpCodes.Callvirt, (object)methodInfo2),
					new CodeInstruction(OpCodes.Brfalse, (object)escapeLabel)
				};
			}

			private static IEnumerable<CodeInstruction> CreateAdditionalRepeatedCrownCheck(IEnumerable<CodeInstruction> achievementAtLocalIndexSeq, Label escapeLabel)
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Expected O, but got Unknown
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Expected O, but got Unknown
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Expected O, but got Unknown
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Expected O, but got Unknown
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(AchievementContext), "Instance");
				FieldInfo fieldInfo = AccessTools.Field(typeof(AchievementContext), "repeatedAchievements");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(List<ACHIEVEMENTTYPE>), "Contains", new Type[1] { typeof(ACHIEVEMENTTYPE) }, (Type[])null);
				return ((IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
				{
					new CodeInstruction(OpCodes.Call, (object)methodInfo),
					new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo)
				}).Concat(achievementAtLocalIndexSeq).Concat((IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
				{
					new CodeInstruction(OpCodes.Callvirt, (object)methodInfo2),
					new CodeInstruction(OpCodes.Brtrue, (object)escapeLabel)
				});
			}

			private static IEnumerable<CodeInstruction> CreateIsRepeatedCheck(IEnumerable<CodeInstruction> badgeDataSeq, Label escapeLabel)
			{
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Expected O, but got Unknown
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Expected O, but got Unknown
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Expected O, but got Unknown
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b7: Expected O, but got Unknown
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Expected O, but got Unknown
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Expected O, but got Unknown
				//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Expected O, but got Unknown
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: Expected O, but got Unknown
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(AchievementContext), "Instance");
				FieldInfo fieldInfo = AccessTools.Field(typeof(AchievementContext), "repeatedAchievements");
				FieldInfo fieldInfo2 = AccessTools.Field(typeof(BadgeData), "linkedAchievement");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(List<ACHIEVEMENTTYPE>), "Contains", new Type[1] { typeof(ACHIEVEMENTTYPE) }, (Type[])null);
				return badgeDataSeq.Concat((IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
				{
					new CodeInstruction(OpCodes.Ldnull, (object)null),
					new CodeInstruction(OpCodes.Ceq, (object)null),
					new CodeInstruction(OpCodes.Brtrue, (object)escapeLabel)
				}).Concat((IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
				{
					new CodeInstruction(OpCodes.Call, (object)methodInfo),
					new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo)
				}).Concat(badgeDataSeq)
					.Concat((IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
					{
						new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo2),
						new CodeInstruction(OpCodes.Callvirt, (object)methodInfo2),
						new CodeInstruction(OpCodes.Brtrue, (object)escapeLabel)
					});
			}
		}
	}
}
namespace ScoutBadger.Configuration
{
	internal static class SaveConfig
	{
		private static readonly string defaultSavefile = Path.Combine(Paths.ConfigPath, "ScoutBadger", "badges.json");

		private static ConfigEntry<string> _customSavefile = null;

		public static string SafeFile
		{
			get
			{
				if (_customSavefile == null)
				{
					throw new InvalidOperationException("SaveConfig is not bound to a config file");
				}
				string value = defaultSavefile;
				if (_customSavefile.Value != "")
				{
					value = _customSavefile.Value;
				}
				return value;
			}
		}

		public static void BindConfig(ConfigFile config)
		{
			_customSavefile = config.Bind<string>("SaveData", "CustomFilepath", "", "Optional. Overrides default save location.");
		}
	}
	internal class VisualConfig
	{
		private static ConfigEntry<bool> showBadgesInCustom;

		public static bool ShowBadgesInCustomRuns
		{
			get
			{
				if (showBadgesInCustom == null)
				{
					throw new InvalidOperationException("SaveConfig is not bound to a config file");
				}
				return showBadgesInCustom.Value;
			}
		}

		public static void BindConfig(ConfigFile config)
		{
			showBadgesInCustom = config.Bind<bool>("Visual", "ShowBadgesInCustomRuns", true, "Show badges obtained during a Mini/Custom run");
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}