Decompiled source of ModVerifier v1.1.0

plugins/com.github.Kirshoo.ModVerifier.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using ModVerifier.Common;
using ModVerifier.Configuration;
using Mono.Cecil;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[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.ModVerifier")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("com.github.Kirshoo.ModVerifier")]
[assembly: AssemblyTitle("ModVerifier")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 ModVerifier
{
	public interface IHashFunc
	{
		byte[] Hash(Stream input);
	}
	internal class ModScanner
	{
		private IHashFunc hash;

		public ModScanner(IHashFunc hashfunc)
		{
			hash = hashfunc;
		}

		public ModMetadata GetMetadata(string filepath)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			ModuleDefinition val = ModuleDefinition.ReadModule(filepath);
			TypeDefinition val2 = ((IEnumerable<TypeDefinition>)val.Types).FirstOrDefault((Func<TypeDefinition, bool>)((TypeDefinition t) => ((IEnumerable<CustomAttribute>)t.CustomAttributes).Any((CustomAttribute a) => ((MemberReference)a.AttributeType).FullName == "BepInEx.BepInPlugin")));
			if (val2 == null)
			{
				throw new ArgumentException("file is not a valid bepinex plugin file");
			}
			CustomAttribute val3 = ((IEnumerable<CustomAttribute>)val2.CustomAttributes).First((CustomAttribute a) => ((MemberReference)a.AttributeType).FullName == "BepInEx.BepInPlugin");
			ModMetadata result = new ModMetadata();
			CustomAttributeArgument val4 = val3.ConstructorArguments[0];
			result.GUID = ((CustomAttributeArgument)(ref val4)).Value?.ToString() ?? string.Empty;
			val4 = val3.ConstructorArguments[1];
			result.Name = ((CustomAttributeArgument)(ref val4)).Value?.ToString() ?? string.Empty;
			val4 = val3.ConstructorArguments[2];
			result.Version = ((CustomAttributeArgument)(ref val4)).Value?.ToString() ?? string.Empty;
			result.SHA256 = ComputeHash(filepath);
			return result;
		}

		public bool TryGetMetadata(string filepath, out ModMetadata metadata)
		{
			metadata = new ModMetadata();
			try
			{
				metadata = GetMetadata(filepath);
				return true;
			}
			catch (ArgumentException)
			{
				return false;
			}
		}

		private string ComputeHash(string filepath)
		{
			using FileStream input = File.OpenRead(filepath);
			byte[] array = hash.Hash(input);
			return BitConverter.ToString(array).Replace("-", "").ToUpperInvariant();
		}
	}
	public enum SourceType
	{
		Web,
		LocalFile
	}
	[BepInPlugin("com.github.Kirshoo.ModVerifier", "ModVerifier", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public class WhitelistEntry
		{
			public string guid = string.Empty;

			public string name = string.Empty;

			public string version = string.Empty;

			public string sha256 = string.Empty;
		}

		private const string WhitelistURL = "https://4ufps.github.io/peakverify.json";

		private static readonly string LogPath = Path.Combine(Paths.BepInExRootPath, "verifier_result.log");

		private static readonly StringBuilder LogBuffer = new StringBuilder();

		private static int Unauthorized = 0;

		private GameObject manager_go;

		private VerifierReportManager ReportManager;

		private ModScanner scanner = new ModScanner(new ShaHasher());

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

		internal static ManualLogSource Logger { get; private set; } = null;


		public static string Name => "ModVerifier";

		public static string Version => "1.1.0";

		private async void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			CreateManager();
			Logger.LogInfo((object)"Starting verification...");
			try
			{
				bool flag = await VerifyRunningPlugins(SourceType.Web, "https://4ufps.github.io/peakverify.json");
				Logger.LogInfo((object)string.Format("Verification finished with {0} at {1:O}", flag ? "success" : "fail", DateTime.UtcNow));
				Logger.LogInfo((object)("Writing report into " + LogPath));
				File.WriteAllText(LogPath, LogBuffer.ToString());
				UpdateText(Unauthorized);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Verification failed: " + ex.Message));
				ReportManager.SetReportError(ex.Message);
			}
			Logger.LogInfo((object)(Name + " was successfully loaded"));
		}

		private void BindConfig()
		{
			VerifierReport.BindConfig(((BaseUnityPlugin)this).Config);
		}

		private void CreateManager()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (!((Object)(object)manager_go != (Object)null))
			{
				manager_go = new GameObject("VerifierReportManager");
				ReportManager = manager_go.AddComponent<VerifierReportManager>();
				ReportManager.loadedMods = GetLoadedMods();
				ReportManager.timestamp = DateTime.UtcNow;
				Object.DontDestroyOnLoad((Object)(object)manager_go);
			}
		}

		private void UpdateText(int unauthorized)
		{
			ReportManager.SetReportText(unauthorized);
		}

		private async Task<bool> VerifyRunningPlugins(SourceType type, string source)
		{
			_ = Paths.PluginPath;
			LogBuffer.AppendLine("=== Verification Report (" + Name + " v" + Version + ") ===");
			LogBuffer.AppendLine($"Timestamp: {DateTime.UtcNow:O}");
			LogBuffer.AppendLine($"Whitelist source: {source} of type {type}\n");
			Logger.LogDebug((object)("Fetching whitelist from " + source));
			WhitelistEntry[] source2;
			try
			{
				source2 = await FetchWhitelist(type, source);
			}
			catch (JsonSerializationException val)
			{
				JsonSerializationException innerException = val;
				throw new Exception("Serializing the whitelist: malformed whitelist", (Exception?)(object)innerException);
			}
			catch (HttpRequestException ex)
			{
				throw new Exception("Fetching the whitelist: " + ex.Message, ex);
			}
			foreach (ModMetadata metadata in ReportManager.loadedMods)
			{
				bool flag = source2.Any((WhitelistEntry wMod) => string.Equals(wMod.guid, metadata.GUID, StringComparison.OrdinalIgnoreCase) && string.Equals(wMod.version, metadata.Version, StringComparison.OrdinalIgnoreCase) && string.Equals(wMod.sha256, metadata.SHA256, StringComparison.OrdinalIgnoreCase));
				LogBuffer.AppendLine(metadata.Name + " (" + metadata.GUID + ") v" + metadata.Version);
				LogBuffer.AppendLine("    SHA256: " + metadata.SHA256);
				LogBuffer.AppendLine("    Status: " + (flag ? "Allowed" : "Unauthorized!"));
				if (!flag)
				{
					Unauthorized++;
					Logger.LogWarning((object)("Unauthorized mod: " + metadata.Name + " (" + metadata.Version + ")"));
				}
			}
			return Unauthorized == 0;
		}

		private async Task<WhitelistEntry[]> FetchWhitelist(SourceType type, string source)
		{
			return type switch
			{
				SourceType.Web => await FetchWhitelistAsync(source), 
				SourceType.LocalFile => await LoadWhitelistFileAsync(source), 
				_ => throw new InvalidDataException($"Unknown source type: {type}"), 
			};
		}

		private async Task<WhitelistEntry[]> FetchWhitelistAsync(string web_url)
		{
			using HttpClient client = new HttpClient();
			return JsonConvert.DeserializeObject<WhitelistEntry[]>(await client.GetStringAsync(web_url));
		}

		private async Task<WhitelistEntry[]> LoadWhitelistFileAsync(string filepath)
		{
			return JsonConvert.DeserializeObject<WhitelistEntry[]>(await File.ReadAllTextAsync(filepath));
		}

		private List<ModMetadata> GetLoadedMods()
		{
			List<ModMetadata> list = new List<ModMetadata>();
			string[] files = Directory.GetFiles(Paths.PluginPath, "*.dll", SearchOption.AllDirectories);
			foreach (string text in files)
			{
				if (!scanner.TryGetMetadata(text, out var metadata))
				{
					Logger.LogWarning((object)("Unable to retrieve metadata from " + text));
				}
				else
				{
					list.Add(metadata);
				}
			}
			return list;
		}
	}
	public class ShaHasher : IHashFunc
	{
		private SHA256 hashfunc;

		public ShaHasher()
		{
			hashfunc = SHA256.Create();
		}

		public byte[] Hash(Stream input)
		{
			return hashfunc.ComputeHash(input);
		}
	}
	public class Utils
	{
		public struct FontLoader
		{
			[CompilerGenerated]
			private sealed class <>c__DisplayClass3_0
			{
				public string fontname;

				internal bool <LoadFontCoroutine>b__0(TMP_FontAsset asset)
				{
					return ((Object)asset).name == fontname;
				}
			}

			[CompilerGenerated]
			private sealed class <LoadFontCoroutine>d__3 : IEnumerator<object>, IEnumerator, IDisposable
			{
				private int <>1__state;

				private object <>2__current;

				public string fontname;

				public FontLoader <>4__this;

				private <>c__DisplayClass3_0 <>8__1;

				public Action<TMP_FontAsset> callback;

				private int <retries>5__2;

				private TMP_FontAsset <font>5__3;

				object IEnumerator<object>.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				object IEnumerator.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				[DebuggerHidden]
				public <LoadFontCoroutine>d__3(int <>1__state)
				{
					this.<>1__state = <>1__state;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<>8__1 = null;
					<font>5__3 = null;
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					//IL_011e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0128: Expected O, but got Unknown
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass3_0();
						<>8__1.fontname = fontname;
						<retries>5__2 = <>4__this.MAX_LOAD_FONT_RETRIES;
						<font>5__3 = null;
						break;
					case 1:
						<>1__state = -1;
						break;
					}
					if (<retries>5__2 > 0)
					{
						<font>5__3 = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset asset) => ((Object)asset).name == <>8__1.fontname));
						if (!((Object)(object)<font>5__3 != (Object)null))
						{
							<retries>5__2--;
							Plugin.Logger.LogDebug((object)$"Failed to load {<>8__1.fontname} font, retrying after {(float)(<>4__this.MAX_LOAD_FONT_RETRIES - <retries>5__2) * <>4__this.BACKOFF_DELAY_MILLISECONDS}s...");
							<>2__current = (object)new WaitForSeconds((float)(<>4__this.MAX_LOAD_FONT_RETRIES - <retries>5__2) * <>4__this.BACKOFF_DELAY_MILLISECONDS);
							<>1__state = 1;
							return true;
						}
						Plugin.Logger.LogDebug((object)("Found " + <>8__1.fontname + "! Proceeding..."));
					}
					if ((Object)(object)<font>5__3 == (Object)null)
					{
						Plugin.Logger.LogWarning((object)("Failed to load " + <>8__1.fontname + " font, fallback to built in font..."));
						<font>5__3 = Resources.GetBuiltinResource<TMP_FontAsset>("LiberationSans SDF");
					}
					callback?.Invoke(<font>5__3);
					return false;
				}

				bool IEnumerator.MoveNext()
				{
					//ILSpy generated this explicit interface implementation from .override directive in MoveNext
					return this.MoveNext();
				}

				[DebuggerHidden]
				void IEnumerator.Reset()
				{
					throw new NotSupportedException();
				}
			}

			public int MAX_LOAD_FONT_RETRIES;

			public float BACKOFF_DELAY_MILLISECONDS;

			public FontLoader()
			{
				MAX_LOAD_FONT_RETRIES = 5;
				BACKOFF_DELAY_MILLISECONDS = 0.05f;
			}

			[IteratorStateMachine(typeof(<LoadFontCoroutine>d__3))]
			public IEnumerator LoadFontCoroutine(string fontname, Action<TMP_FontAsset> callback)
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <LoadFontCoroutine>d__3(0)
				{
					<>4__this = this,
					fontname = fontname,
					callback = callback
				};
			}
		}
	}
	internal class VerifierReportManager : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <Cycle>d__14 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public VerifierReportManager <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Cycle>d__14(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Expected O, but got Unknown
				int num = <>1__state;
				VerifierReportManager verifierReportManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					goto IL_002d;
				case 1:
					<>1__state = -1;
					<>2__current = verifierReportManager.Fade(1f, 0f);
					<>1__state = 2;
					return true;
				case 2:
				{
					<>1__state = -1;
					ModMetadata modMetadata = verifierReportManager.loadedMods[verifierReportManager.modIndex];
					((TMP_Text)verifierReportManager.modcycle_textblock).text = $"[{verifierReportManager.modIndex + 1}/{verifierReportManager.loadedMods.Count}] {modMetadata.Name} v{modMetadata.Version} ({modMetadata.SHA256.Substring(0, 8)}...)";
					verifierReportManager.modIndex = (verifierReportManager.modIndex + 1) % verifierReportManager.loadedMods.Count;
					<>2__current = verifierReportManager.Fade(0f, 1f);
					<>1__state = 3;
					return true;
				}
				case 3:
					{
						<>1__state = -1;
						goto IL_002d;
					}
					IL_002d:
					<>2__current = (object)new WaitForSecondsRealtime(2f);
					<>1__state = 1;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <Fade>d__15 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public VerifierReportManager <>4__this;

			public float from;

			public float to;

			private float <t>5__2;

			private Color <c>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Fade>d__15(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				VerifierReportManager verifierReportManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<t>5__2 = 0f;
					<c>5__3 = ((Graphic)verifierReportManager.modcycle_textblock).color;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (<t>5__2 < 0.3f)
				{
					<t>5__2 += Time.deltaTime;
					float num2 = Mathf.Lerp(from, to, <t>5__2 / 0.3f);
					((Graphic)verifierReportManager.modcycle_textblock).color = new Color(<c>5__3.r, <c>5__3.g, <c>5__3.b, num2);
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private readonly TextMeshProUGUI report_textblock;

		private readonly TextMeshProUGUI modcycle_textblock;

		internal List<ModMetadata> loadedMods;

		private int modIndex;

		private const float FADE_DURATION = 0.3f;

		private const float CYCLE_INTERVAL = 2f;

		internal DateTime timestamp;

		private static TMP_FontAsset? FONT_ASSET;

		public Utils.FontLoader fontLoader = new Utils.FontLoader();

		public VerifierReportManager()
		{
			//IL_004d: 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: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			Canvas val = ((Component)this).gameObject.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 1000;
			CanvasScaler val2 = ((Component)this).gameObject.AddComponent<CanvasScaler>();
			val2.uiScaleMode = (ScaleMode)1;
			val2.referenceResolution = new Vector2(1920f, 1080f);
			GameObject val3 = new GameObject("VerifierPanel");
			val3.transform.SetParent(((Component)this).gameObject.transform, false);
			val3.AddComponent<RectTransform>();
			PlaceInPosition(val3.GetComponent<RectTransform>(), VerifierReport.Position, new Vector2(VerifierReport.PaddingLeft, VerifierReport.PaddingBottom));
			VerticalLayoutGroup val4 = val3.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val4).spacing = 10f;
			((LayoutGroup)val4).childAlignment = PositionToTextAnchor(VerifierReport.Position);
			GameObject val5 = new GameObject("VerifierReport");
			val5.transform.SetParent(val3.transform, false);
			report_textblock = val5.AddComponent<TextMeshProUGUI>();
			((TMP_Text)report_textblock).text = "Loading report...";
			((TMP_Text)report_textblock).alignment = PositionToAlignment(VerifierReport.Position);
			GameObject val6 = new GameObject("ModCycle");
			val6.transform.SetParent(val3.transform, false);
			modcycle_textblock = val6.AddComponent<TextMeshProUGUI>();
			((TMP_Text)modcycle_textblock).text = "";
			((TMP_Text)modcycle_textblock).alignment = PositionToAlignment(VerifierReport.Position);
			loadedMods = new List<ModMetadata>();
			timestamp = DateTime.UtcNow;
		}

		private void Start()
		{
			LoadFont();
			((MonoBehaviour)this).StartCoroutine(Cycle());
		}

		private void LoadFont()
		{
			if ((Object)(object)FONT_ASSET != (Object)null)
			{
				SetFont(report_textblock, FONT_ASSET);
				SetFont(modcycle_textblock, FONT_ASSET);
				return;
			}
			((MonoBehaviour)this).StartCoroutine(fontLoader.LoadFontCoroutine("DarumaDropOne-Regular SDF", delegate(TMP_FontAsset font)
			{
				FONT_ASSET = font;
				SetFont(report_textblock, FONT_ASSET);
				SetFont(modcycle_textblock, FONT_ASSET);
			}));
		}

		public void SetReportText(int unauthorized)
		{
			((TMP_Text)report_textblock).text = $"Verification Time: {timestamp}\r\nMods: {loadedMods.Count - unauthorized}/{loadedMods.Count} allowed";
		}

		public void SetReportError(string error)
		{
			((TMP_Text)report_textblock).text = "Error during verification:\r\n" + error;
		}

		[IteratorStateMachine(typeof(<Cycle>d__14))]
		private IEnumerator Cycle()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Cycle>d__14(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<Fade>d__15))]
		private IEnumerator Fade(float from, float to)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Fade>d__15(0)
			{
				<>4__this = this,
				from = from,
				to = to
			};
		}

		public static TextAnchor PositionToTextAnchor(ReportPosition position)
		{
			return (TextAnchor)(position switch
			{
				ReportPosition.Top => 1, 
				ReportPosition.Bottom => 7, 
				ReportPosition.Left => 3, 
				ReportPosition.TopLeft => 0, 
				ReportPosition.BottomLeft => 6, 
				ReportPosition.Right => 5, 
				ReportPosition.TopRight => 2, 
				ReportPosition.BottomRight => 8, 
				_ => 3, 
			});
		}

		public static TextAlignmentOptions PositionToAlignment(ReportPosition position)
		{
			switch (position)
			{
			case ReportPosition.Top:
			case ReportPosition.Bottom:
				return (TextAlignmentOptions)514;
			case ReportPosition.Left:
			case ReportPosition.TopLeft:
			case ReportPosition.BottomLeft:
				return (TextAlignmentOptions)513;
			case ReportPosition.Right:
			case ReportPosition.TopRight:
			case ReportPosition.BottomRight:
				return (TextAlignmentOptions)516;
			default:
				return (TextAlignmentOptions)513;
			}
		}

		private static void SetFont(TextMeshProUGUI textMesh, TMP_FontAsset font)
		{
			//IL_0021: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)textMesh).font = font;
			((TMP_Text)textMesh).fontSize = 20f;
			((TMP_Text)textMesh).overflowMode = (TextOverflowModes)0;
			((TMP_Text)textMesh).textWrappingMode = (TextWrappingModes)0;
			((Graphic)textMesh).color = Color.white;
			((TMP_Text)textMesh).outlineWidth = 0.075f;
			((TMP_Text)textMesh).outlineColor = Color32.op_Implicit(Color.black);
		}

		private static void PlaceInPosition(RectTransform rect, ReportPosition pos, Vector2 padding)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			switch (pos)
			{
			case ReportPosition.TopLeft:
				((Vector2)(ref val))..ctor(0f, 1f);
				break;
			case ReportPosition.Top:
				((Vector2)(ref val))..ctor(0.5f, 1f);
				break;
			case ReportPosition.TopRight:
				((Vector2)(ref val))..ctor(1f, 1f);
				break;
			case ReportPosition.Left:
				((Vector2)(ref val))..ctor(0f, 0.5f);
				break;
			case ReportPosition.Right:
				((Vector2)(ref val))..ctor(1f, 0.5f);
				break;
			case ReportPosition.BottomLeft:
				((Vector2)(ref val))..ctor(0f, 0f);
				break;
			case ReportPosition.Bottom:
				((Vector2)(ref val))..ctor(0.5f, 0f);
				break;
			case ReportPosition.BottomRight:
				((Vector2)(ref val))..ctor(1f, 0f);
				break;
			default:
				((Vector2)(ref val))..ctor(0f, 1f);
				break;
			}
			rect.anchorMin = val;
			rect.anchorMax = val;
			rect.pivot = val;
			rect.anchoredPosition = padding;
		}
	}
}
namespace ModVerifier.Configuration
{
	internal static class VerifierReport
	{
		private static ConfigEntry<ReportPosition>? _reportPos;

		private static ConfigEntry<float>? _reportPaddingLeft;

		private static ConfigEntry<float>? _reportPaddingBottom;

		public static ReportPosition Position
		{
			get
			{
				if (_reportPos == null)
				{
					Plugin.Logger.LogError((object)"Requested config entry, but no config file was bound.");
					throw new InvalidOperationException("requesting config value before any config file was bound");
				}
				return _reportPos.Value;
			}
		}

		public static float PaddingLeft
		{
			get
			{
				if (_reportPaddingLeft == null)
				{
					Plugin.Logger.LogError((object)"Requested config entry, but no config file was bound.");
					throw new InvalidOperationException("requesting config value before any config file was bound");
				}
				return _reportPaddingLeft.Value;
			}
		}

		public static float PaddingBottom
		{
			get
			{
				if (_reportPaddingBottom == null)
				{
					Plugin.Logger.LogError((object)"Requested config entry, but no config file was bound.");
					throw new InvalidOperationException("requesting config value before any config file was bound");
				}
				return _reportPaddingBottom.Value;
			}
		}

		public static void BindConfig(ConfigFile config)
		{
			_reportPos = config.Bind<ReportPosition>("VerifierReport", "ReportPosition", ReportPosition.Right, "The position of the mod verifier report.\r\nUse ReportPadding to make sure its not obstructed by other text.");
			_reportPaddingLeft = config.Bind<float>("VerifierReport", "ReportMoveRight", -20f, "Moves report right from its position in pixels.\r\nSet to negative values to move left instead.");
			_reportPaddingBottom = config.Bind<float>("VerifierReport", "ReportMoveUp", 0f, "Moves report upwards from its position in pixels.\r\nSet to negative values to move downwards instead.");
		}
	}
}
namespace ModVerifier.Common
{
	public class ExceptionNotification : Exception
	{
		private readonly List<Exception> innerExceptions = new List<Exception>();

		public override string Message => base.Message + string.Format(", {0} inner exceptions: {1}", innerExceptions.Count, string.Join(", ", innerExceptions));

		public void AddException(Exception exception)
		{
			innerExceptions.Add(exception);
		}

		public bool HasErrors()
		{
			return innerExceptions.Count > 0;
		}
	}
	internal struct ModMetadata
	{
		public string Name;

		public string GUID;

		public string Version;

		public string SHA256;

		public ModMetadata()
		{
			Name = string.Empty;
			GUID = string.Empty;
			Version = string.Empty;
			SHA256 = string.Empty;
		}
	}
	public enum ReportPosition
	{
		Top,
		Bottom,
		Left,
		TopLeft,
		BottomLeft,
		Right,
		TopRight,
		BottomRight
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}