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)val.Types).FirstOrDefault((Func)((TypeDefinition t) => ((IEnumerable)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)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(); ReportManager.loadedMods = GetLoadedMods(); ReportManager.timestamp = DateTime.UtcNow; Object.DontDestroyOnLoad((Object)(object)manager_go); } } private void UpdateText(int unauthorized) { ReportManager.SetReportText(unauthorized); } private async Task 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 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 FetchWhitelistAsync(string web_url) { using HttpClient client = new HttpClient(); return JsonConvert.DeserializeObject(await client.GetStringAsync(web_url)); } private async Task LoadWhitelistFileAsync(string filepath) { return JsonConvert.DeserializeObject(await File.ReadAllTextAsync(filepath)); } private List GetLoadedMods() { List list = new List(); 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 b__0(TMP_FontAsset asset) { return ((Object)asset).name == fontname; } } [CompilerGenerated] private sealed class d__3 : IEnumerator, 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 callback; private int 5__2; private TMP_FontAsset 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; 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; 5__2 = <>4__this.MAX_LOAD_FONT_RETRIES; 5__3 = null; break; case 1: <>1__state = -1; break; } if (5__2 > 0) { 5__3 = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((TMP_FontAsset asset) => ((Object)asset).name == <>8__1.fontname)); if (!((Object)(object)5__3 != (Object)null)) { 5__2--; Plugin.Logger.LogDebug((object)$"Failed to load {<>8__1.fontname} font, retrying after {(float)(<>4__this.MAX_LOAD_FONT_RETRIES - 5__2) * <>4__this.BACKOFF_DELAY_MILLISECONDS}s..."); <>2__current = (object)new WaitForSeconds((float)(<>4__this.MAX_LOAD_FONT_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)5__3 == (Object)null) { Plugin.Logger.LogWarning((object)("Failed to load " + <>8__1.fontname + " font, fallback to built in font...")); 5__3 = Resources.GetBuiltinResource("LiberationSans SDF"); } callback?.Invoke(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(d__3))] public IEnumerator LoadFontCoroutine(string fontname, Action callback) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0) { <>4__this = this, fontname = fontname, callback = callback }; } } } internal class VerifierReportManager : MonoBehaviour { [CompilerGenerated] private sealed class d__14 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public VerifierReportManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 d__15 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public VerifierReportManager <>4__this; public float from; public float to; private float 5__2; private Color 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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; 5__2 = 0f; 5__3 = ((Graphic)verifierReportManager.modcycle_textblock).color; break; case 1: <>1__state = -1; break; } if (5__2 < 0.3f) { 5__2 += Time.deltaTime; float num2 = Mathf.Lerp(from, to, 5__2 / 0.3f); ((Graphic)verifierReportManager.modcycle_textblock).color = new Color(5__3.r, 5__3.g, 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 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(); val.renderMode = (RenderMode)0; val.sortingOrder = 1000; CanvasScaler val2 = ((Component)this).gameObject.AddComponent(); 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(); PlaceInPosition(val3.GetComponent(), VerifierReport.Position, new Vector2(VerifierReport.PaddingLeft, VerifierReport.PaddingBottom)); VerticalLayoutGroup val4 = val3.AddComponent(); ((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(); ((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(); ((TMP_Text)modcycle_textblock).text = ""; ((TMP_Text)modcycle_textblock).alignment = PositionToAlignment(VerifierReport.Position); loadedMods = new List(); 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(d__14))] private IEnumerator Cycle() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__14(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__15))] private IEnumerator Fade(float from, float to) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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? _reportPos; private static ConfigEntry? _reportPaddingLeft; private static ConfigEntry? _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("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("VerifierReport", "ReportMoveRight", -20f, "Moves report right from its position in pixels.\r\nSet to negative values to move left instead."); _reportPaddingBottom = config.Bind("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 innerExceptions = new List(); 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) { } } }