Decompiled source of ModKit v1.0.0

plugins/MycopunkModKit/MycopunkModKit.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MycopunkShared
{
	[BepInPlugin("doku_macaron.mycopunk.modkit", "Mycopunk Mod Kit", "1.0.0")]
	[MycoMod(/*Could not decode attribute arguments.*/)]
	public class ModKitPlugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			ModsMenu.Install(new Harmony("doku_macaron.mycopunk.modkit"), (BaseUnityPlugin)(object)this);
			Hotkeys.ReportConflicts((BaseUnityPlugin)(object)this);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Mycopunk Mod Kit 1.0.0 loaded.");
		}
	}
	public static class Hotkeys
	{
		private sealed class Binding
		{
			public string Guid;

			public string Owner;

			public Key Key;

			public string Modifiers;

			public bool FromConfig;

			public string KeyText
			{
				get
				{
					if (Modifiers.Length != 0)
					{
						return Modifiers + "+" + ((object)Unsafe.As<Key, Key>(ref Key)/*cast due to .constrained prefix*/).ToString();
					}
					return ((object)Unsafe.As<Key, Key>(ref Key)/*cast due to .constrained prefix*/).ToString();
				}
			}
		}

		private const string RegistryKey = "MycopunkShared.Hotkeys.v1.registry";

		private const string ReporterKey = "MycopunkShared.Hotkeys.v1.reporter";

		private const float GameInputTimeout = 120f;

		public unsafe static void Register(BaseUnityPlugin plugin, Key key, string purpose)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)key == 0)
			{
				return;
			}
			try
			{
				BepInPlugin metadata = plugin.Info.Metadata;
				string item = string.Join("\t", metadata.GUID, metadata.Name, ((object)(*(Key*)(&key))/*cast due to .constrained prefix*/).ToString(), "", purpose ?? "");
				if (!Registry().Contains(item))
				{
					Registry().Add(item);
				}
			}
			catch
			{
			}
		}

		public static void ReportConflicts(BaseUnityPlugin host)
		{
			try
			{
				AppDomain currentDomain = AppDomain.CurrentDomain;
				if (currentDomain.GetData("MycopunkShared.Hotkeys.v1.reporter") == null)
				{
					currentDomain.SetData("MycopunkShared.Hotkeys.v1.reporter", host.Info.Metadata.GUID);
					((MonoBehaviour)host).StartCoroutine(ReportWhenReady());
				}
			}
			catch
			{
			}
		}

		private static List<string> Registry()
		{
			AppDomain currentDomain = AppDomain.CurrentDomain;
			List<string> list = currentDomain.GetData("MycopunkShared.Hotkeys.v1.registry") as List<string>;
			if (list == null)
			{
				list = new List<string>();
				currentDomain.SetData("MycopunkShared.Hotkeys.v1.registry", list);
			}
			return list;
		}

		private static IEnumerator ReportWhenReady()
		{
			yield return null;
			FieldInfo controlsField = typeof(PlayerInput).GetField("_controls", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			float start = Time.realtimeSinceStartup;
			while (controlsField != null && controlsField.GetValue(null) == null && Time.realtimeSinceStartup - start < 120f)
			{
				yield return (object)new WaitForSecondsRealtime(1f);
			}
			ManualLogSource val = Logger.CreateLogSource("Hotkeys");
			try
			{
				Report(val, controlsField?.GetValue(null));
			}
			catch (Exception ex)
			{
				val.LogWarning((object)("Hotkey check failed: " + ex));
			}
		}

		private static void Report(ManualLogSource log, object controls)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			List<Binding> list = new List<Binding>();
			foreach (string item in Registry())
			{
				string[] array = item.Split('\t');
				if (array.Length >= 5 && Enum.TryParse<Key>(array[2], out Key result))
				{
					list.Add(new Binding
					{
						Guid = array[0],
						Owner = array[1] + ((array[4].Length > 0) ? (" (" + array[4] + ")") : ""),
						Key = result,
						Modifiers = array[3]
					});
				}
			}
			AddConfigEntries(list);
			string note;
			List<Binding> list2 = GameBindings(controls, out note);
			int count = list2.Count;
			IEnumerable<string> values = from b in list
				orderby ((object)Unsafe.As<Key, Key>(ref b.Key)/*cast due to .constrained prefix*/).ToString()
				select b.KeyText + " " + b.Owner;
			log.LogInfo((object)("Mod hotkeys: " + ((list.Count == 0) ? "none" : string.Join(", ", values)) + ". Game keyboard bindings checked: " + count + note + "."));
			int num = 0;
			foreach (IGrouping<Key, Binding> item2 in from b in list.Concat(list2)
				group b by b.Key)
			{
				List<Binding> list3 = item2.ToList();
				if (!list3.Any((Binding b) => b.Guid != null))
				{
					continue;
				}
				List<Binding> list4 = new List<Binding>();
				for (int num2 = 0; num2 < list3.Count; num2++)
				{
					for (int num3 = num2 + 1; num3 < list3.Count; num3++)
					{
						if (Clash(list3[num2], list3[num3]))
						{
							if (!list4.Contains(list3[num2]))
							{
								list4.Add(list3[num2]);
							}
							if (!list4.Contains(list3[num3]))
							{
								list4.Add(list3[num3]);
							}
						}
					}
				}
				if (list4.Count != 0)
				{
					num++;
					log.LogWarning((object)("Hotkey conflict on " + ((object)item2.Key/*cast due to .constrained prefix*/).ToString() + ": " + string.Join(", ", list4.Select((Binding b) => ((b.Modifiers.Length > 0) ? ("[" + b.KeyText + "] ") : "") + b.Owner))));
				}
			}
			if (num == 0)
			{
				log.LogInfo((object)"No hotkey conflicts found.");
			}
		}

		private static bool Clash(Binding a, Binding b)
		{
			if (a.Guid == null && b.Guid == null)
			{
				return false;
			}
			if (a.Guid != null && a.Guid == b.Guid && a.Owner == b.Owner)
			{
				return false;
			}
			if (a.Modifiers.Length != 0 && b.Modifiers.Length != 0)
			{
				return a.Modifiers == b.Modifiers;
			}
			return true;
		}

		private unsafe static void AddConfigEntries(List<Binding> into)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			foreach (PluginInfo value2 in Chainloader.PluginInfos.Values)
			{
				ConfigFile val;
				try
				{
					val = (((Object)(object)value2.Instance != (Object)null) ? value2.Instance.Config : null);
				}
				catch
				{
					continue;
				}
				if (val == null)
				{
					continue;
				}
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in val)
				{
					ConfigEntryBase value = item.Value;
					Key key = (Key)0;
					string modifiers = "";
					object boxedValue = value.BoxedValue;
					if (boxedValue is Key val2)
					{
						key = val2;
					}
					else if (boxedValue is KeyCode code)
					{
						key = FromKeyCode(code);
					}
					else if (boxedValue is KeyboardShortcut val3)
					{
						key = FromKeyCode(((KeyboardShortcut)(ref val3)).MainKey);
						modifiers = string.Join("+", (from m in ((KeyboardShortcut)(ref val3)).Modifiers.Select(FromKeyCode)
							where (int)m > 0
							select ((object)(*(Key*)(&m))/*cast due to .constrained prefix*/).ToString()).OrderBy<string, string>((string s) => s, StringComparer.Ordinal));
					}
					if ((int)key != 0)
					{
						string guid = value2.Metadata.GUID;
						if (!into.Any((Binding b) => b.Guid == guid && b.Key == key && b.Modifiers == modifiers))
						{
							into.Add(new Binding
							{
								Guid = guid,
								Owner = value2.Metadata.Name + " [" + item.Key.Section + "." + item.Key.Key + "]",
								Key = key,
								Modifiers = modifiers,
								FromConfig = true
							});
						}
					}
				}
			}
		}

		private static List<Binding> GameBindings(object controls, out string note)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			List<Binding> list = new List<Binding>();
			note = "";
			Keyboard current = Keyboard.current;
			if (controls == null)
			{
				note = " (the game's input was not created yet)";
				return list;
			}
			if (current == null)
			{
				note = " (no keyboard)";
				return list;
			}
			object? obj = controls.GetType().GetProperty("asset")?.GetValue(controls);
			InputActionAsset val = (InputActionAsset)((obj is InputActionAsset) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				note = " (PlayerControls.asset not found)";
				return list;
			}
			Enumerator<InputActionMap> enumerator = val.actionMaps.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					InputActionMap current2 = enumerator.Current;
					Enumerator<InputAction> enumerator2 = current2.actions.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							InputAction current3 = enumerator2.Current;
							Enumerator<InputBinding> enumerator3 = current3.bindings.GetEnumerator();
							try
							{
								while (enumerator3.MoveNext())
								{
									InputBinding current4 = enumerator3.Current;
									string effectivePath = ((InputBinding)(ref current4)).effectivePath;
									if (((InputBinding)(ref current4)).isComposite || string.IsNullOrEmpty(effectivePath) || !effectivePath.StartsWith("<Keyboard>", StringComparison.OrdinalIgnoreCase))
									{
										continue;
									}
									InputControl val2 = InputControlPath.TryFindControl((InputControl)(object)current, effectivePath, 0);
									KeyControl control = (KeyControl)(object)((val2 is KeyControl) ? val2 : null);
									if (control != null)
									{
										string owner = "game " + current2.name + "/" + current3.name;
										if (!list.Any((Binding b) => b.Key == control.keyCode && b.Owner == owner))
										{
											list.Add(new Binding
											{
												Owner = owner,
												Key = control.keyCode,
												Modifiers = ""
											});
										}
									}
								}
							}
							finally
							{
								((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
							}
						}
					}
					finally
					{
						((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
					}
				}
				return list;
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static Key FromKeyCode(KeyCode code)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected I4, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected I4, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			string text = ((object)(*(KeyCode*)(&code))/*cast due to .constrained prefix*/).ToString();
			if (text.StartsWith("Alpha"))
			{
				text = "Digit" + text.Substring(5);
			}
			else if (text.StartsWith("Keypad"))
			{
				text = "Numpad" + text.Substring(6);
			}
			if ((int)code <= 96)
			{
				if ((int)code == 13)
				{
					return (Key)2;
				}
				if ((int)code == 96)
				{
					return (Key)4;
				}
			}
			else
			{
				switch (code - 266)
				{
				case 5:
					return (Key)77;
				case 4:
					return (Key)80;
				case 3:
					return (Key)81;
				case 2:
					return (Key)79;
				case 1:
					return (Key)78;
				case 0:
					return (Key)82;
				}
				switch (code - 305)
				{
				case 1:
					return (Key)55;
				case 0:
					return (Key)56;
				case 5:
				case 6:
					return (Key)57;
				case 4:
				case 7:
					return (Key)58;
				}
			}
			if (!Enum.TryParse<Key>(text, ignoreCase: true, out Key result))
			{
				return (Key)0;
			}
			return result;
		}
	}
	public static class HudVisibility
	{
		public static bool ResultsOpen()
		{
			GameManager instance = GameManager.Instance;
			WindowSystem val = (((Object)(object)instance != (Object)null) ? instance.WindowSystem : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			for (int i = 0; i < val.Count; i++)
			{
				if (val[i] is MissionRewardsWindow || val[i] is MissionStatsWindow)
				{
					return true;
				}
			}
			return false;
		}
	}
	public interface IHudLine
	{
		string Name { get; set; }
	}
	public interface ITeammateHud
	{
		float NameFontSize { get; }

		bool HasPrevious { get; }

		float Offset { get; set; }

		string Marker { get; set; }

		IEnumerable<IHudLine> Siblings { get; }

		IHudLine CreateLine(string name);

		void DestroyLine(IHudLine line);

		void MoveLower(float dy);

		void MoveRoot(float dy);

		void PlaceLine(IHudLine line, float below);
	}
	public static class TeammateHudLines
	{
		private struct State
		{
			public float Lower;

			public float Offset;

			public float LineHeight;
		}

		public const string LinePrefix = "MycoLine|";

		public const string MarkerPrefix = "MycoHudLines|";

		public const string RemovedName = "MycoLine (removed)";

		public static IHudLine Add(ITeammateHud hud, string id, int order)
		{
			IHudLine hudLine = Find(hud, id);
			if (hudLine == null)
			{
				hudLine = hud.CreateLine("MycoLine|" + order.ToString("D4", CultureInfo.InvariantCulture) + "|" + id);
			}
			Layout(hud);
			return hudLine;
		}

		public static void Remove(ITeammateHud hud, string id)
		{
			IHudLine hudLine = Find(hud, id);
			if (hudLine != null)
			{
				hudLine.Name = "MycoLine (removed)";
				hud.DestroyLine(hudLine);
				Layout(hud);
			}
		}

		public static void Place(ITeammateHud hud)
		{
			if (TryParse(hud.Marker, out var state))
			{
				PlaceLines(hud, Lines(hud), state.LineHeight);
			}
		}

		public static List<T> TopLevel<T>(IList<T> candidates, T name, Func<T, T, bool> isInside) where T : class
		{
			List<T> list = new List<T>();
			foreach (T candidate in candidates)
			{
				if (candidate == null || candidate == name || isInside(name, candidate) || list.Contains(candidate))
				{
					continue;
				}
				bool flag = false;
				foreach (T candidate2 in candidates)
				{
					if (candidate2 != null && candidate2 != candidate && candidate2 != name && !isInside(name, candidate2) && isInside(candidate, candidate2))
					{
						flag = true;
					}
				}
				if (!flag)
				{
					list.Add(candidate);
				}
			}
			return list;
		}

		public static float LineHeight(float nameFontSize)
		{
			return Math.Max(nameFontSize * 1.15f, 18f);
		}

		private static IHudLine Find(ITeammateHud hud, string id)
		{
			foreach (IHudLine item in Lines(hud))
			{
				if (item.Name.EndsWith("|" + id, StringComparison.Ordinal))
				{
					return item;
				}
			}
			return null;
		}

		private static List<IHudLine> Lines(ITeammateHud hud)
		{
			List<IHudLine> list = new List<IHudLine>();
			foreach (IHudLine sibling in hud.Siblings)
			{
				if (sibling != null && sibling.Name != null && sibling.Name.StartsWith("MycoLine|", StringComparison.Ordinal))
				{
					list.Add(sibling);
				}
			}
			list.Sort((IHudLine a, IHudLine b) => string.CompareOrdinal(a.Name, b.Name));
			return list;
		}

		private static void PlaceLines(ITeammateHud hud, List<IHudLine> lines, float lineHeight)
		{
			for (int i = 0; i < lines.Count; i++)
			{
				hud.PlaceLine(lines[i], (float)(i + 1) * lineHeight);
			}
		}

		private static void Layout(ITeammateHud hud)
		{
			TryParse(hud.Marker, out var state);
			float offset = hud.Offset;
			hud.MoveLower(0f - state.Lower);
			offset -= state.Offset;
			if (hud.HasPrevious)
			{
				hud.MoveRoot(0f - state.Offset);
			}
			List<IHudLine> list = Lines(hud);
			float num = LineHeight(hud.NameFontSize);
			float num2 = (float)list.Count * num;
			PlaceLines(hud, list, num);
			state.Lower = 0f - num2;
			state.Offset = ((offset < 0f) ? (0f - num2) : num2);
			state.LineHeight = num;
			hud.MoveLower(state.Lower);
			hud.Offset = offset + state.Offset;
			if (hud.HasPrevious)
			{
				hud.MoveRoot(state.Offset);
			}
			hud.Marker = ((list.Count == 0) ? null : ("MycoHudLines|" + Format(state.Lower) + "|" + Format(state.Offset) + "|" + Format(state.LineHeight)));
		}

		private static bool TryParse(string marker, out State state)
		{
			state = default(State);
			if (marker == null || !marker.StartsWith("MycoHudLines|", StringComparison.Ordinal))
			{
				return false;
			}
			string[] array = marker.Split('|');
			if (array.Length < 4)
			{
				return false;
			}
			state.Lower = Parse(array[1]);
			state.Offset = Parse(array[2]);
			state.LineHeight = Parse(array[3]);
			return true;
		}

		private static string Format(float v)
		{
			return v.ToString("R", CultureInfo.InvariantCulture);
		}

		private static float Parse(string s)
		{
			if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return 0f;
			}
			return result;
		}
	}
	public sealed class UnityTeammateHud : ITeammateHud
	{
		private sealed class Line : IHudLine
		{
			public readonly TextMeshProUGUI Text;

			public string Name
			{
				get
				{
					return ((Object)Text).name;
				}
				set
				{
					((Object)Text).name = value;
				}
			}

			public Line(TextMeshProUGUI text)
			{
				Text = text;
			}
		}

		private const BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo NameField = typeof(TeammateHUD).GetField("nameText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo ClassField = typeof(TeammateHUD).GetField("classText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo TitleField = typeof(TeammateHUD).GetField("titleText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo LoadingField = typeof(TeammateHUD).GetField("loadingBarParent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo OffsetField = typeof(TeammateHUD).GetField("offset", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private readonly TeammateHUD hud;

		private readonly TextMeshProUGUI name;

		public static bool Available
		{
			get
			{
				if (NameField != null)
				{
					return OffsetField != null;
				}
				return false;
			}
		}

		public float NameFontSize => ((TMP_Text)name).fontSize;

		public bool HasPrevious
		{
			get
			{
				if ((Object)(object)hud.Previous != (Object)null)
				{
					return ((Component)hud).transform is RectTransform;
				}
				return false;
			}
		}

		public float Offset
		{
			get
			{
				return (float)OffsetField.GetValue(hud);
			}
			set
			{
				OffsetField.SetValue(hud, value);
			}
		}

		public string Marker
		{
			get
			{
				Transform val = FindMarker();
				if (!((Object)(object)val != (Object)null))
				{
					return null;
				}
				return ((Object)val).name;
			}
			set
			{
				//IL_0035: 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)
				Transform val = FindMarker();
				if (value == null)
				{
					if (!((Object)(object)val == (Object)null))
					{
						((Object)val).name = "MycoHudLines (removed)";
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
				else if ((Object)(object)val == (Object)null)
				{
					GameObject val2 = new GameObject(value);
					val2.transform.SetParent(((Component)hud).transform, false);
					val2.SetActive(false);
				}
				else
				{
					((Object)val).name = value;
				}
			}
		}

		public IEnumerable<IHudLine> Siblings
		{
			get
			{
				Transform parent = ((TMP_Text)name).transform.parent;
				for (int i = 0; i < parent.childCount; i++)
				{
					TextMeshProUGUI component = ((Component)parent.GetChild(i)).GetComponent<TextMeshProUGUI>();
					if ((Object)(object)component != (Object)null && (Object)(object)component != (Object)(object)name)
					{
						yield return new Line(component);
					}
				}
			}
		}

		public static TextMeshProUGUI AddText(TeammateHUD hud, string id, int order)
		{
			UnityTeammateHud unityTeammateHud = For(hud);
			if (unityTeammateHud == null)
			{
				return null;
			}
			return ((Line)TeammateHudLines.Add(unityTeammateHud, id, order)).Text;
		}

		public static void Remove(TeammateHUD hud, string id)
		{
			UnityTeammateHud unityTeammateHud = For(hud);
			if (unityTeammateHud != null)
			{
				TeammateHudLines.Remove(unityTeammateHud, id);
			}
		}

		public static void Place(TeammateHUD hud)
		{
			UnityTeammateHud unityTeammateHud = For(hud);
			if (unityTeammateHud != null)
			{
				TeammateHudLines.Place(unityTeammateHud);
			}
		}

		private static UnityTeammateHud For(TeammateHUD hud)
		{
			if (!Available || (Object)(object)hud == (Object)null)
			{
				return null;
			}
			object? value = NameField.GetValue(hud);
			TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return new UnityTeammateHud(hud, val);
		}

		private UnityTeammateHud(TeammateHUD hud, TextMeshProUGUI name)
		{
			this.hud = hud;
			this.name = name;
		}

		private Transform FindMarker()
		{
			Transform transform = ((Component)hud).transform;
			for (int i = 0; i < transform.childCount; i++)
			{
				Transform child = transform.GetChild(i);
				if (((Object)child).name.StartsWith("MycoHudLines|", StringComparison.Ordinal))
				{
					return child;
				}
			}
			return null;
		}

		public IHudLine CreateLine(string lineName)
		{
			TextMeshProUGUI obj = Object.Instantiate<TextMeshProUGUI>(name, ((TMP_Text)name).transform.parent, false);
			((Object)obj).name = lineName;
			((TMP_Text)obj).text = "";
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).richText = false;
			((TMP_Text)obj).enableAutoSizing = false;
			((TMP_Text)obj).fontSize = ((TMP_Text)name).fontSize;
			((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
			((TMP_Text)obj).rectTransform.SetSizeWithCurrentAnchors((Axis)0, 360f);
			return new Line(obj);
		}

		public void DestroyLine(IHudLine line)
		{
			TextMeshProUGUI text = ((Line)line).Text;
			((Component)text).gameObject.SetActive(false);
			Object.Destroy((Object)(object)((Component)text).gameObject);
		}

		public void MoveLower(float dy)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (dy == 0f)
			{
				return;
			}
			List<RectTransform> list = new List<RectTransform>();
			FieldInfo[] array = new FieldInfo[3] { ClassField, TitleField, LoadingField };
			foreach (FieldInfo fieldInfo in array)
			{
				if (fieldInfo != null)
				{
					object? value = fieldInfo.GetValue(hud);
					Graphic val = (Graphic)((value is Graphic) ? value : null);
					if (val != null && (Object)(object)val != (Object)null)
					{
						list.Add(val.rectTransform);
					}
				}
			}
			foreach (RectTransform item in TeammateHudLines.TopLevel(list, ((TMP_Text)name).rectTransform, (RectTransform a, RectTransform b) => ((Transform)a).IsChildOf((Transform)(object)b)))
			{
				item.anchoredPosition += new Vector2(0f, dy);
			}
		}

		public void MoveRoot(float dy)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)hud).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if (val != null)
			{
				val.anchoredPosition += new Vector2(0f, dy);
			}
		}

		public void PlaceLine(IHudLine line, float below)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)((Line)line).Text).rectTransform.anchoredPosition = ((TMP_Text)name).rectTransform.anchoredPosition + new Vector2(0f, 0f - below);
		}
	}
	public static class ModsMenu
	{
		private abstract class Row
		{
			public GameObject Go;

			public ConfigEntryBase Entry;

			public string Owner;

			public TextMeshProUGUI Name;

			public HoverInfoText Hover;

			public abstract void Refresh();
		}

		private sealed class ToggleRow : Row
		{
			public RectTransform Knob;

			public Image Icon;

			public float Thickness;

			public override void Refresh()
			{
				ShowToggle(this, (bool)Entry.BoxedValue);
			}
		}

		private sealed class ColorRow : Row
		{
			public ScrollBar Bar;

			public Graphic Fill;

			public override void Refresh()
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				ShowColor(this, (Color)Entry.BoxedValue);
			}
		}

		private sealed class Item
		{
			public ConfigEntryBase Entry;

			public string Label;

			public string Owner;
		}

		private sealed class Group
		{
			public string Mod;

			public readonly List<Item> Items = new List<Item>();
		}

		private const string BuilderKey = "MycopunkShared.ModsMenu.v1.builder";

		private const string TabName = "Mods";

		private const float Step = 70f;

		private static ManualLogSource _log;

		private static readonly List<Row> Rows = new List<Row>();

		private static readonly FieldInfo HoverText = AccessTools.Field(typeof(HoverInfoText), "text");

		public static void Install(Harmony harmony, BaseUnityPlugin host)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			try
			{
				AppDomain currentDomain = AppDomain.CurrentDomain;
				if (currentDomain.GetData("MycopunkShared.ModsMenu.v1.builder") != null)
				{
					return;
				}
				currentDomain.SetData("MycopunkShared.ModsMenu.v1.builder", host.Info.Metadata.GUID);
				_log = Logger.CreateLogSource("ModsMenu");
				MethodInfo methodInfo = AccessTools.Method(typeof(PlayerOptions), "Awake", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerOptions), "OnOpen", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(typeof(TextBlocks), "Initialize", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					_log.LogWarning((object)"PlayerOptions.Awake not found; no MODS tab.");
					return;
				}
				Harmony val = new Harmony("MycopunkShared.ModsMenu");
				val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ModsMenu), "AwakePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				if (methodInfo2 != null)
				{
					val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(ModsMenu), "OnOpenPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (methodInfo3 != null)
				{
					val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(ModsMenu), "RefreshLabels", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				(_log ?? (_log = Logger.CreateLogSource("ModsMenu"))).LogWarning((object)("MODS tab disabled: " + ex));
			}
		}

		private static void AwakePrefix(PlayerOptions __instance)
		{
			try
			{
				Build(__instance);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("MODS tab could not be built: " + ex));
			}
		}

		private static void OnOpenPostfix()
		{
			try
			{
				foreach (Row row in Rows)
				{
					if ((Object)(object)row.Go == (Object)null)
					{
						continue;
					}
					if (Chainloader.PluginInfos.TryGetValue(row.Owner, out var value) && (Object)(object)value.Instance != (Object)null)
					{
						ConfigEntryBase value2 = ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)value.Instance.Config).FirstOrDefault((KeyValuePair<ConfigDefinition, ConfigEntryBase> p) => p.Key.Equals(row.Entry.Definition)).Value;
						if (value2 != null)
						{
							row.Entry = value2;
						}
					}
					row.Refresh();
				}
				RefreshLabels();
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("MODS tab refresh failed: " + ex.Message));
			}
		}

		private static List<Group> CollectEntries()
		{
			List<Group> list = new List<Group>();
			foreach (PluginInfo item in Chainloader.PluginInfos.Values.OrderBy<PluginInfo, string>((PluginInfo i) => i.Metadata.Name, StringComparer.OrdinalIgnoreCase))
			{
				ConfigFile val;
				try
				{
					val = (((Object)(object)item.Instance != (Object)null) ? item.Instance.Config : null);
				}
				catch
				{
					continue;
				}
				if (val == null)
				{
					continue;
				}
				string mod = (item.Metadata.Name.StartsWith("Mycopunk ", StringComparison.Ordinal) ? item.Metadata.Name.Substring(9) : item.Metadata.Name);
				Group obj2 = new Group
				{
					Mod = mod
				};
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in val)
				{
					ConfigEntryBase value = item2.Value;
					if (!(value.SettingType != typeof(bool)) || !(value.SettingType != typeof(Color)))
					{
						ConfigDescription description = value.Description;
						string text = ModsMenuTag.Find((description != null) ? description.Tags : null);
						if (text != null)
						{
							obj2.Items.Add(new Item
							{
								Entry = value,
								Label = ((text.Length > 0) ? text : item2.Key.Key),
								Owner = item.Metadata.GUID
							});
						}
					}
				}
				if (obj2.Items.Count > 0)
				{
					list.Add(obj2);
				}
			}
			return list;
		}

		private static void Build(PlayerOptions po)
		{
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Expected O, but got Unknown
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Expected O, but got Unknown
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Expected O, but got Unknown
			//IL_05c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c6: Expected O, but got Unknown
			FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerOptions), "sections");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(PlayerOptions), "sectionButtons");
			RectTransform[] array = fieldInfo?.GetValue(po) as RectTransform[];
			Array array2 = fieldInfo2?.GetValue(po) as Array;
			if (array == null || array2 == null)
			{
				_log.LogWarning((object)"PlayerOptions.sections / sectionButtons not found; no MODS tab.");
			}
			else
			{
				if (array.Any((RectTransform s) => (Object)(object)s != (Object)null && ((Object)s).name == "Mods"))
				{
					return;
				}
				List<Group> list = CollectEntries();
				if (list.Count == 0)
				{
					_log.LogInfo((object)"No config entries are marked for the MODS tab.");
					return;
				}
				List<Component> list2 = array2.Cast<Component>().ToList();
				Component val = ((IEnumerable<Component>)list2).FirstOrDefault((Func<Component, bool>)((Component b) => (Object)(object)b != (Object)null && ((Object)b).name == "Graphics"));
				RectTransform val2 = ((IEnumerable<RectTransform>)array).FirstOrDefault((Func<RectTransform, bool>)((RectTransform s) => (Object)(object)s != (Object)null && ((Object)s).name == "Debug"));
				RectTransform val3 = ((IEnumerable<RectTransform>)array).FirstOrDefault((Func<RectTransform, bool>)((RectTransform s) => (Object)(object)s != (Object)null && ((Object)s).name == "Gameplay"));
				Transform val4 = (((Object)(object)val3 != (Object)null) ? ((Transform)val3).Find("Items/HideHUD") : null);
				Transform val5 = (((Object)(object)val3 != (Object)null) ? ((Transform)val3).Find("Items/UIColor") : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val4 == (Object)null)
				{
					_log.LogWarning((object)"MODS tab: Graphics button, Debug section or Gameplay/Items/HideHUD not found; no MODS tab.");
					return;
				}
				if ((Object)(object)val5 == (Object)null)
				{
					_log.LogWarning((object)"MODS tab: Gameplay/Items/UIColor not found; colour entries are left out.");
				}
				int index = array.Length;
				MethodInfo setSection = AccessTools.Method(typeof(PlayerOptions), "SetSection", new Type[1] { typeof(int) }, (Type[])null);
				if (setSection == null)
				{
					_log.LogWarning((object)"PlayerOptions.SetSection(int) not found; no MODS tab.");
					return;
				}
				RectTransform val6 = (RectTransform)val.transform;
				GameObject val7 = Object.Instantiate<GameObject>(val.gameObject, ((Transform)val6).parent, false);
				((Object)val7).name = "Mods";
				RectTransform val8 = (RectTransform)val7.transform;
				val8.anchoredPosition = val6.anchoredPosition + new Vector2(0f, -70f);
				foreach (Component item in list2)
				{
					if ((Object)(object)item != (Object)null && (Object)(object)item != (Object)(object)val)
					{
						Transform transform = item.transform;
						RectTransform val9 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
						if (val9 != null && val9.anchoredPosition.y <= val8.anchoredPosition.y + 0.5f)
						{
							val9.anchoredPosition += new Vector2(0f, -70f);
						}
					}
				}
				Component[] componentsInChildren = val7.GetComponentsInChildren<Component>(true);
				foreach (Component val10 in componentsInChildren)
				{
					if ((Object)(object)val10 != (Object)null && ((object)val10).GetType().Name == "SetTextBlock")
					{
						Object.DestroyImmediate((Object)(object)val10);
					}
				}
				TextMeshProUGUI componentInChildren = val7.GetComponentInChildren<TextMeshProUGUI>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					((TMP_Text)componentInChildren).text = "MODS";
				}
				Component component = val7.GetComponent(((object)val).GetType());
				ReplaceEvent(component, "OnClickUp", delegate
				{
					setSection.Invoke(po, new object[1] { index });
				});
				GameObject val11 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Transform)val2).parent, false);
				((Object)val11).name = "Mods";
				val11.SetActive(false);
				Transform val12 = val11.transform.Find("Items");
				if ((Object)(object)val12 == (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val11);
					Object.DestroyImmediate((Object)(object)val7);
					_log.LogWarning((object)"Debug/Items not found; no MODS tab.");
					return;
				}
				for (int num2 = val12.childCount - 1; num2 >= 0; num2--)
				{
					Object.DestroyImmediate((Object)(object)((Component)val12.GetChild(num2)).gameObject);
				}
				Rows.RemoveAll((Row r) => (Object)(object)r.Go == (Object)null);
				int num3 = 0;
				GameObject val13 = new GameObject("ModsMenu holder");
				val13.SetActive(false);
				try
				{
					foreach (Group item2 in list)
					{
						GameObject val14 = MakeHeading(((Component)val4).gameObject, val13.transform, item2.Mod);
						if ((Object)(object)val14 != (Object)null)
						{
							val14.transform.SetParent(val12, false);
						}
						foreach (Item item3 in item2.Items)
						{
							Row row = ((item3.Entry.SettingType == typeof(bool)) ? ((Row)MakeToggleRow(((Component)val4).gameObject, val13.transform, item3)) : ((Row)(((Object)(object)val5 != (Object)null) ? MakeColorRow(((Component)val5).gameObject, val13.transform, item3) : null)));
							if (row != null)
							{
								row.Go.transform.SetParent(val12, false);
								Rows.Add(row);
								num3++;
								row.Refresh();
							}
						}
					}
				}
				finally
				{
					Object.Destroy((Object)(object)val13);
				}
				fieldInfo.SetValue(po, array.Concat((IEnumerable<RectTransform>)(object)new RectTransform[1] { (RectTransform)val11.transform }).ToArray());
				Array array3 = Array.CreateInstance(array2.GetType().GetElementType(), array2.Length + 1);
				Array.Copy(array2, array3, array2.Length);
				array3.SetValue(component, array2.Length);
				fieldInfo2.SetValue(po, array3);
				_log.LogInfo((object)("MODS tab added with " + num3 + " entries in " + list.Count + " groups."));
			}
		}

		private static GameObject MakeHeading(GameObject template, Transform holder, string mod)
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(template, holder, false);
			((Object)val).name = "Mod heading " + mod;
			Transform val2 = val.transform.Find("Name");
			TextMeshProUGUI val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<TextMeshProUGUI>() : null);
			if ((Object)(object)val3 == (Object)null)
			{
				Object.DestroyImmediate((Object)(object)val);
				return null;
			}
			for (int num = val.transform.childCount - 1; num >= 0; num--)
			{
				if ((Object)(object)val.transform.GetChild(num) != (Object)(object)val2)
				{
					Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject);
				}
			}
			foreach (Component item in (from c in val.GetComponents<Component>()
				where c is MonoBehaviour && !(c is Graphic) && !(c is LayoutElement)
				select c).ToList())
			{
				Object.DestroyImmediate((Object)(object)item);
			}
			foreach (Graphic item2 in val.GetComponents<Graphic>().ToList())
			{
				Object.DestroyImmediate((Object)(object)item2);
			}
			CanvasRenderer component = val.GetComponent<CanvasRenderer>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			((TMP_Text)val3).text = mod.ToUpperInvariant();
			((TMP_Text)val3).fontStyle = (FontStyles)(((TMP_Text)val3).fontStyle | 1);
			((TMP_Text)val3).fontSize = ((TMP_Text)val3).fontSize * 1.15f;
			LayoutElement obj = val.GetComponent<LayoutElement>() ?? val.AddComponent<LayoutElement>();
			RectTransform val4 = (RectTransform)val.transform;
			float minHeight = (obj.preferredHeight = val4.sizeDelta.y + 20f);
			obj.minHeight = minHeight;
			return val;
		}

		private static ToggleRow MakeToggleRow(GameObject template, Transform holder, Item item)
		{
			GameObject val = Object.Instantiate<GameObject>(template, holder, false);
			((Object)val).name = "Mod " + item.Label;
			Component[] components = val.GetComponents<Component>();
			foreach (Component val2 in components)
			{
				if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "ToggleOption")
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			Component val3 = ((IEnumerable<Component>)val.GetComponents<Component>()).FirstOrDefault((Func<Component, bool>)((Component c) => (Object)(object)c != (Object)null && FindField(((object)c).GetType(), "OnClickUp") != null));
			Transform obj = val.transform.Find("Name");
			TextMeshProUGUI val4 = ((obj != null) ? ((Component)obj).GetComponent<TextMeshProUGUI>() : null);
			Graphic val5 = (Graphic)(((Object)(object)val3 != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			Transform obj2 = val.transform.Find("Button/Icon");
			Image val6 = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null);
			if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null)
			{
				_log.LogWarning((object)("MODS tab: the toggle row layout is not as expected; skipping " + item.Label));
				Object.DestroyImmediate((Object)(object)val);
				return null;
			}
			float thickness = 1.5f;
			components = val.GetComponents<Component>();
			foreach (Component val7 in components)
			{
				if ((Object)(object)val7 != (Object)null && FindField(((object)val7).GetType(), "thickness")?.GetValue(val7) is float num)
				{
					thickness = num;
					break;
				}
			}
			ToggleRow row = new ToggleRow
			{
				Go = val,
				Entry = item.Entry,
				Owner = item.Owner,
				Knob = val5.rectTransform,
				Icon = val6,
				Thickness = thickness,
				Name = val4
			};
			AddLabel(row);
			ReplaceEvent(val3, "OnClickUp", delegate
			{
				try
				{
					bool flag = !(bool)row.Entry.BoxedValue;
					row.Entry.BoxedValue = flag;
					ShowToggle(row, flag);
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("MODS tab: could not change " + item.Label + ": " + ex.Message));
				}
			});
			return row;
		}

		private static ColorRow MakeColorRow(GameObject template, Transform holder, Item item)
		{
			GameObject val = Object.Instantiate<GameObject>(template, holder, false);
			((Object)val).name = "Mod " + item.Label;
			Component[] components = val.GetComponents<Component>();
			foreach (Component val2 in components)
			{
				if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "ColorOption")
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			Transform obj = val.transform.Find("Name");
			TextMeshProUGUI val3 = ((obj != null) ? ((Component)obj).GetComponent<TextMeshProUGUI>() : null);
			ScrollBar componentInChildren = val.GetComponentInChildren<ScrollBar>(true);
			object obj2;
			if (!((Object)(object)componentInChildren != (Object)null))
			{
				obj2 = null;
			}
			else
			{
				Transform obj3 = ((Component)componentInChildren).transform.Find("F");
				obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<Graphic>() : null);
			}
			Graphic val4 = (Graphic)obj2;
			UnityEvent<Vector2> val5 = (((Object)(object)componentInChildren != (Object)null) ? (FindField(((object)componentInChildren).GetType(), "OnDrag")?.GetValue(componentInChildren) as UnityEvent<Vector2>) : null);
			if ((Object)(object)val3 == (Object)null || (Object)(object)componentInChildren == (Object)null || (Object)(object)val4 == (Object)null || val5 == null)
			{
				_log.LogWarning((object)("MODS tab: the colour row layout is not as expected; skipping " + item.Label));
				Object.DestroyImmediate((Object)(object)val);
				return null;
			}
			components = ((Component)val4).GetComponents<Component>();
			foreach (Component val6 in components)
			{
				if ((Object)(object)val6 != (Object)null && ((object)val6).GetType().Name == "CharacterGraphic")
				{
					Object.DestroyImmediate((Object)(object)val6);
				}
			}
			for (int j = 0; j < ((UnityEventBase)val5).GetPersistentEventCount(); j++)
			{
				((UnityEventBase)val5).SetPersistentListenerState(j, (UnityEventCallState)0);
			}
			ColorRow row = new ColorRow
			{
				Go = val,
				Entry = item.Entry,
				Owner = item.Owner,
				Bar = componentInChildren,
				Fill = val4,
				Name = val3
			};
			AddLabel(row);
			val5.AddListener((UnityAction<Vector2>)delegate(Vector2 v)
			{
				//IL_0010: 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_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: 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_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					Color val7 = (Color)row.Entry.BoxedValue;
					Color val8 = Color.HSVToRGB(Mathf.Clamp01(v.x), Mathf.Clamp01(v.y), 1f);
					val8.a = val7.a;
					row.Entry.BoxedValue = val8;
					row.Fill.color = new Color(val8.r, val8.g, val8.b, 1f);
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("MODS tab: could not change " + item.Label + ": " + ex.Message));
				}
			});
			return row;
		}

		private static void RefreshLabels()
		{
			foreach (Row row in Rows)
			{
				if ((Object)(object)row.Go != (Object)null)
				{
					SetLabel(row);
				}
			}
		}

		private static void AddLabel(Row row)
		{
			if (HoverText != null)
			{
				ConfigDescription description = row.Entry.Description;
				if (!string.IsNullOrEmpty((description != null) ? description.Description : null))
				{
					row.Hover = row.Go.AddComponent<HoverInfoText>();
				}
			}
			SetLabel(row);
		}

		private static void SetLabel(Row row)
		{
			string language = ModsMenuTag.Language(TextBlocks.LanguageIndex);
			ConfigDescription description = row.Entry.Description;
			string text = ModsMenuTag.Find((description != null) ? description.Tags : null, language);
			((TMP_Text)row.Name).text = (string.IsNullOrEmpty(text) ? row.Entry.Definition.Key : text);
			if ((Object)(object)row.Hover != (Object)null)
			{
				HoverText.SetValue(row.Hover, ModsMenuTag.Description(row.Entry.Description.Tags, language, row.Entry.Description.Description));
			}
		}

		private static void ShowToggle(ToggleRow row, bool on)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = ((Transform)row.Knob).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if (!((Object)(object)val == (Object)null))
			{
				Rect rect = val.rect;
				float num = ((Rect)(ref rect)).width * 0.5f;
				rect = row.Knob.rect;
				float num2 = num - ((Rect)(ref rect)).width * 0.5f - row.Thickness;
				row.Knob.anchoredPosition = new Vector2(on ? num2 : (0f - num2), row.Knob.anchoredPosition.y);
				object obj = AccessTools.Property(typeof(Global), "Instance")?.GetValue(null) ?? AccessTools.Field(typeof(Global), "Instance")?.GetValue(null);
				Sprite val2 = (Sprite)((obj != null) ? /*isinst with value type is only supported in some contexts*/: null);
				if ((Object)(object)val2 != (Object)null)
				{
					row.Icon.sprite = val2;
				}
			}
		}

		private static void ShowColor(ColorRow row, Color color)
		{
			//IL_0000: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(color, ref num, ref num2, ref num3);
			row.Bar.SetScrollNoInvoke(new Vector2(num, num2));
			row.Fill.color = new Color(color.r, color.g, color.b, 1f);
		}

		private static FieldInfo FindField(Type type, string name)
		{
			Type type2 = type;
			while (type2 != null && type2 != typeof(object))
			{
				FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field;
				}
				type2 = type2.BaseType;
			}
			return null;
		}

		private static void ReplaceEvent(Component target, string field, Action action)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			FieldInfo fieldInfo = FindField(((object)target).GetType(), field);
			if (fieldInfo == null || !typeof(UnityEvent).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new MissingFieldException(((object)target).GetType().Name, field);
			}
			UnityEvent val = new UnityEvent();
			val.AddListener(new UnityAction(action.Invoke));
			fieldInfo.SetValue(target, val);
		}
	}
	public static class ModChannels
	{
		public const string DpsStatsKey = "MycopunkShared.DpsChecker.Stats.v1";

		public static void Publish(string key, object value)
		{
			try
			{
				AppDomain.CurrentDomain.SetData(key, value);
			}
			catch
			{
			}
		}

		public static T Get<T>(string key) where T : class
		{
			try
			{
				return AppDomain.CurrentDomain.GetData(key) as T;
			}
			catch
			{
				return null;
			}
		}

		public static string FormatDps(float max, int kills, bool estimated)
		{
			return max.ToString("R", CultureInfo.InvariantCulture) + "\t" + kills.ToString(CultureInfo.InvariantCulture) + "\t" + (estimated ? "1" : "0");
		}

		public static bool TryParseDps(string text, out float max, out int kills, out bool estimated)
		{
			max = 0f;
			kills = 0;
			estimated = false;
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			string[] array = text.Split('\t');
			if (array.Length < 3)
			{
				return false;
			}
			estimated = array[2] == "1";
			if (float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out max))
			{
				return int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out kills);
			}
			return false;
		}
	}
	public static class ModKit
	{
		public const string Guid = "doku_macaron.mycopunk.modkit";

		public const string Name = "Mycopunk Mod Kit";

		public const string Version = "1.0.0";
	}
	public static class ModsMenuTag
	{
		public const string Tag = "MycopunkShared.ModsMenu";

		public static object[] Label(string key, IDictionary<string, Dictionary<string, string>> names, IDictionary<string, Dictionary<string, string>> descriptions = null)
		{
			if (names == null || !names.TryGetValue("en", out var value) || !value.TryGetValue(key, out var value2))
			{
				throw new ArgumentException("Missing English MODS menu text: " + key);
			}
			List<object> list = new List<object>
			{
				"MycopunkShared.ModsMenu",
				"MycopunkShared.ModsMenu:" + value2
			};
			foreach (KeyValuePair<string, Dictionary<string, string>> name in names)
			{
				if (name.Key != "en" && name.Value.TryGetValue(key, out var value3) && !string.IsNullOrEmpty(value3))
				{
					list.Add("MycopunkShared.ModsMenu." + name.Key + ":" + value3);
				}
			}
			if (descriptions != null)
			{
				foreach (KeyValuePair<string, Dictionary<string, string>> description in descriptions)
				{
					if (description.Value.TryGetValue(key, out var value4) && !string.IsNullOrEmpty(value4))
					{
						list.Add("MycopunkShared.ModsMenu.description." + description.Key + ":" + value4);
					}
				}
			}
			return list.ToArray();
		}

		public static string Language(int gameLanguageIndex)
		{
			if (gameLanguageIndex != 8)
			{
				return "en";
			}
			return "ja";
		}

		public static string Description(object[] tags, string language, string fallback)
		{
			string text = "MycopunkShared.ModsMenu.description." + language + ":";
			if (tags != null)
			{
				for (int i = 0; i < tags.Length; i++)
				{
					if (tags[i] is string text2 && text2.StartsWith(text, StringComparison.Ordinal) && text2.Length > text.Length)
					{
						return text2.Substring(text.Length);
					}
				}
			}
			return fallback;
		}

		public static string Find(object[] tags, string language = "en")
		{
			if (tags == null)
			{
				return null;
			}
			string text = null;
			string text2 = null;
			bool flag = false;
			for (int i = 0; i < tags.Length; i++)
			{
				if (tags[i] is string text3)
				{
					if (text3 == "MycopunkShared.ModsMenu")
					{
						flag = true;
					}
					else if (text3.StartsWith("MycopunkShared.ModsMenu:", StringComparison.Ordinal))
					{
						flag = true;
						text = text3.Substring("MycopunkShared.ModsMenu".Length + 1);
					}
					else if (text3.StartsWith("MycopunkShared.ModsMenu." + language + ":", StringComparison.Ordinal))
					{
						text2 = text3.Substring("MycopunkShared.ModsMenu".Length + language.Length + 2);
					}
				}
			}
			if (!flag)
			{
				return null;
			}
			string text4;
			if (string.IsNullOrEmpty(text2))
			{
				text4 = text;
				if (text4 == null)
				{
					return "";
				}
			}
			else
			{
				text4 = text2;
			}
			return text4;
		}
	}
	public sealed class SessionLogFile : IDisposable
	{
		private sealed class Listener : ILogListener, IDisposable
		{
			private readonly ManualLogSource _source;

			private readonly StreamWriter _writer;

			public Listener(ManualLogSource source, string path)
			{
				_source = source;
				_writer = new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				_writer.NewLine = "\n";
				_writer.AutoFlush = true;
			}

			public void LogEvent(object sender, LogEventArgs e)
			{
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				if ((object)e.Source != _source)
				{
					return;
				}
				try
				{
					_writer.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " [" + ((object)e.Level/*cast due to .constrained prefix*/).ToString() + "] " + e.Data);
				}
				catch
				{
				}
			}

			public void Dispose()
			{
				try
				{
					_writer.Dispose();
				}
				catch
				{
				}
			}
		}

		private Listener _listener;

		public string FilePath { get; }

		private SessionLogFile(Listener listener, string path)
		{
			_listener = listener;
			FilePath = path;
		}

		public static string LogDirectory(string folder)
		{
			string text = Path.Combine(Paths.BepInExRootPath, folder, "logs");
			Directory.CreateDirectory(text);
			return text;
		}

		public static SessionLogFile Open(ManualLogSource log, string folder, string prefix)
		{
			try
			{
				string path = Path.Combine(LogDirectory(folder), prefix + "-" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".log");
				Listener listener = new Listener(log, path);
				Logger.Listeners.Add((ILogListener)(object)listener);
				return new SessionLogFile(listener, path);
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Session log file disabled: " + ex.Message));
				return null;
			}
		}

		public void Dispose()
		{
			if (_listener != null)
			{
				Logger.Listeners.Remove((ILogListener)(object)_listener);
				_listener.Dispose();
				_listener = null;
			}
		}
	}
}