Decompiled source of BigAccessibility v0.1.0

BigAccessibility.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigAccessibility")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+cfb69f04ccbab6ca75c3ece21f34f96272245e60")]
[assembly: AssemblyProduct("BigAccessibility")]
[assembly: AssemblyTitle("BigAccessibility")]
[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 BigAccessibility
{
	internal static class ColorFilter
	{
		private static GameObject _go;

		private static Volume _volume;

		private static ChannelMixer _mixer;

		private static ColorMode _mode = (ColorMode)(-1);

		private static int _strength = -1;

		private static Camera _cam;

		private static readonly float[][] Sim = new float[4][]
		{
			null,
			new float[9] { 0.152286f, 1.052583f, -0.204868f, 0.114503f, 0.786281f, 0.099216f, -0.003882f, -0.048116f, 1.051998f },
			new float[9] { 0.367322f, 0.860646f, -0.227968f, 0.280085f, 0.672501f, 0.047413f, -0.01182f, 0.04294f, 0.968881f },
			new float[9] { 1.255528f, -0.076749f, -0.178779f, -0.078411f, 0.930809f, 0.147602f, 0.004733f, 0.691367f, 0.3039f }
		};

		private static readonly float[] ShiftRG = new float[9] { 0f, 0f, 0f, 0.7f, 1f, 0f, 0.7f, 0f, 1f };

		private static readonly float[] ShiftBY = new float[9] { 1f, 0f, 0.7f, 0f, 1f, 0.7f, 0f, 0f, 0f };

		public static void Tick()
		{
			ColorMode value = Plugin.Color.Value;
			int value2 = Plugin.ColorStrength.Value;
			if (value == ColorMode.Off)
			{
				if ((Object)(object)_volume != (Object)null && ((Behaviour)_volume).enabled)
				{
					((Behaviour)_volume).enabled = false;
				}
				_mode = value;
				return;
			}
			if ((Object)(object)_go == (Object)null)
			{
				Build();
			}
			if (!((Behaviour)_volume).enabled)
			{
				((Behaviour)_volume).enabled = true;
			}
			FitCamera();
			if (value != _mode || value2 != _strength)
			{
				_mode = value;
				_strength = value2;
				Apply(Matrix(value, (float)value2 / 100f));
			}
		}

		private static void Build()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			_go = new GameObject("BigAccessibility ColorFilter");
			Object.DontDestroyOnLoad((Object)(object)_go);
			((Object)_go).hideFlags = (HideFlags)61;
			_volume = _go.AddComponent<Volume>();
			_volume.isGlobal = true;
			_volume.priority = 10000f;
			_volume.weight = 1f;
			VolumeProfile val = ScriptableObject.CreateInstance<VolumeProfile>();
			_mixer = ScriptableObject.CreateInstance<ChannelMixer>();
			((VolumeComponent)_mixer).active = true;
			val.components.Add((VolumeComponent)(object)_mixer);
			_volume.sharedProfile = val;
			_mode = (ColorMode)(-1);
		}

		private static void FitCamera()
		{
			//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)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null || (Object)(object)main == (Object)(object)_cam)
			{
				return;
			}
			_cam = main;
			UniversalAdditionalCameraData component = ((Component)main).GetComponent<UniversalAdditionalCameraData>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			LayerMask volumeLayerMask = component.volumeLayerMask;
			int value = ((LayerMask)(ref volumeLayerMask)).value;
			int layer = 0;
			if ((value & 1) == 0)
			{
				for (int i = 0; i < 32; i++)
				{
					if ((value & (1 << i)) != 0)
					{
						layer = i;
						break;
					}
				}
			}
			_go.layer = layer;
			if (!component.renderPostProcessing)
			{
				component.renderPostProcessing = true;
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(64, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("post-processing was off on '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)main).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("', turned it on for the color filter");
				}
				l.LogInfo(val);
			}
		}

		private static float[] Matrix(ColorMode mode, float s)
		{
			float[] array = Sim[(int)mode];
			float[] array2 = ((mode == ColorMode.Tritanopia) ? ShiftBY : ShiftRG);
			float[] array3 = new float[9];
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					float num = 0f;
					for (int k = 0; k < 3; k++)
					{
						num += array2[i * 3 + k] * (((k == j) ? 1f : 0f) - array[k * 3 + j]);
					}
					array3[i * 3 + j] = ((i == j) ? 1f : 0f) + s * num;
				}
			}
			return array3;
		}

		private static void Apply(float[] m)
		{
			((VolumeParameter<float>)(object)_mixer.redOutRedIn).Override(m[0] * 100f);
			((VolumeParameter<float>)(object)_mixer.redOutGreenIn).Override(m[1] * 100f);
			((VolumeParameter<float>)(object)_mixer.redOutBlueIn).Override(m[2] * 100f);
			((VolumeParameter<float>)(object)_mixer.greenOutRedIn).Override(m[3] * 100f);
			((VolumeParameter<float>)(object)_mixer.greenOutGreenIn).Override(m[4] * 100f);
			((VolumeParameter<float>)(object)_mixer.greenOutBlueIn).Override(m[5] * 100f);
			((VolumeParameter<float>)(object)_mixer.blueOutRedIn).Override(m[6] * 100f);
			((VolumeParameter<float>)(object)_mixer.blueOutGreenIn).Override(m[7] * 100f);
			((VolumeParameter<float>)(object)_mixer.blueOutBlueIn).Override(m[8] * 100f);
		}
	}
	public enum ColorMode
	{
		Off,
		Protanopia,
		Deuteranopia,
		Tritanopia
	}
	public enum SubtitleSize
	{
		Small,
		Medium,
		Large
	}
	[BepInPlugin("wtf.raccoon.BigAccessibility", "Big Accessibility", "0.1.0")]
	public class Plugin : BasePlugin
	{
		internal static ManualLogSource L;

		internal static ConfigEntry<ColorMode> Color;

		internal static ConfigEntry<int> ColorStrength;

		internal static ConfigEntry<bool> Subtitles;

		internal static ConfigEntry<SubtitleSize> Size;

		internal static ConfigEntry<bool> Direction;

		internal static ConfigEntry<float> MinVolume;

		internal static ConfigEntry<float> Linger;

		internal static ConfigEntry<int> MaxLines;

		internal static ConfigEntry<float> BackgroundOpacity;

		internal static ConfigEntry<bool> IncludeMusic;

		internal static ConfigEntry<bool> IncludeUi;

		internal static ConfigEntry<bool> LogCues;

		public override void Load()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			L = ((BasePlugin)this).Log;
			Color = ((BasePlugin)this).Config.Bind<ColorMode>("Color", "Filter", ColorMode.Off, "Color-blind correction filter.");
			ColorStrength = ((BasePlugin)this).Config.Bind<int>("Color", "Strength", 100, new ConfigDescription("Filter strength in percent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			Subtitles = ((BasePlugin)this).Config.Bind<bool>("Subtitles", "Enabled", false, "Show captions for sounds you can hear.");
			Size = ((BasePlugin)this).Config.Bind<SubtitleSize>("Subtitles", "Size", SubtitleSize.Medium, "Caption text size.");
			Direction = ((BasePlugin)this).Config.Bind<bool>("Subtitles", "ShowDirection", true, "Show < and > arrows toward the sound.");
			MinVolume = ((BasePlugin)this).Config.Bind<float>("Subtitles", "MinVolume", 0.05f, new ConfigDescription("Quietest sound (after distance falloff) that gets a caption.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			Linger = ((BasePlugin)this).Config.Bind<float>("Subtitles", "Linger", 2.5f, new ConfigDescription("Seconds a caption stays after the sound stops.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			MaxLines = ((BasePlugin)this).Config.Bind<int>("Subtitles", "MaxLines", 8, new ConfigDescription("Most captions on screen at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			BackgroundOpacity = ((BasePlugin)this).Config.Bind<float>("Subtitles", "BackgroundOpacity", 0.6f, new ConfigDescription("Caption box opacity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			IncludeMusic = ((BasePlugin)this).Config.Bind<bool>("Subtitles", "IncludeMusic", false, "Caption the music bus too.");
			IncludeUi = ((BasePlugin)this).Config.Bind<bool>("Subtitles", "IncludeUi", false, "Caption menu and UI sounds too.");
			LogCues = ((BasePlugin)this).Config.Bind<bool>("Subtitles", "LogNewCues", true, "Append every new sound cue name to BigAccessibility.cues.txt, to help write captions.");
			Captions.Load();
			new Harmony("wtf.raccoon.BigAccessibility").PatchAll(typeof(Plugin).Assembly);
			((BasePlugin)this).AddComponent<Runner>();
			L.LogInfo((object)"Big Accessibility loaded");
		}
	}
	public class Runner : MonoBehaviour
	{
		private static readonly HashSet<string> Seen = new HashSet<string>();

		public Runner(IntPtr p)
			: base(p)
		{
		}

		private void Update()
		{
			try
			{
				ColorFilter.Tick();
			}
			catch (Exception e)
			{
				Once("color", e);
			}
			try
			{
				SubtitleOverlay.Tick();
			}
			catch (Exception e2)
			{
				Once("subs", e2);
			}
		}

		private static void Once(string k, Exception e)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			if (Seen.Add(k + e.GetType().Name + e.Message))
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(2, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(k);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(e);
				}
				l.LogError(val);
			}
		}
	}
	internal static class SettingsTab
	{
		private sealed class Tab
		{
			public Transform Centre;

			public GameObject Page;

			public Button Button;

			public Selectable First;

			public readonly List<GameObject> Restore = new List<GameObject>();

			public readonly List<Action> Refresh = new List<Action>();

			public bool Open
			{
				get
				{
					if ((Object)(object)Page != (Object)null)
					{
						return Page.activeSelf;
					}
					return false;
				}
			}
		}

		private static readonly Dictionary<IntPtr, Tab> Tabs = new Dictionary<IntPtr, Tab>();

		private static readonly HashSet<string> NativeScripts = new HashSet<string> { "SettingsRow", "SettingsCatagory", "SettingItemIdentifier", "SliderSounds", "NmouseSliderHandler", "BackNavigationHelper", "MenuScreenBack", "RebindRow" };

		public static void Build(SettingsMenu menu)
		{
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Expected O, but got Unknown
			//IL_0627: Unknown result type (might be due to invalid IL or missing references)
			//IL_062e: Expected O, but got Unknown
			if ((Object)(object)menu == (Object)null || Tabs.ContainsKey(((Il2CppObjectBase)menu).Pointer))
			{
				return;
			}
			Transform val = Find(((Component)menu).transform, "SettingsMenuContents") ?? menu.contents;
			Transform val2 = (((Object)(object)val != (Object)null) ? val.Find("Left") : null);
			Transform val3 = (((Object)(object)val != (Object)null) ? val.Find("Centre") : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				Plugin.L.LogError((object)"settings menu layout not found (Left/Centre)");
			}
			else
			{
				if ((Object)(object)val3.Find("Accessibility") != (Object)null)
				{
					return;
				}
				Transform val4 = FindDeep(val3, (string n) => n.StartsWith("SettingsRow_Array"));
				Transform val5 = FindDeep(val3, (string n) => n.StartsWith("SettingsRow_Slider"));
				Transform val6 = val3.Find("General") ?? ((val3.childCount > 0) ? val3.GetChild(0) : null);
				Transform val7 = EntryFor(val2, menu.catagoryAudio) ?? FindDeep(val2, (string n) => n.Contains("Audio"));
				bool flag = default(bool);
				if ((Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null)
				{
					ManualLogSource l = Plugin.L;
					BepInExErrorLogInterpolatedStringHandler val8 = new BepInExErrorLogInterpolatedStringHandler(55, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("settings templates missing: array=");
						((BepInExLogInterpolatedStringHandler)val8).AppendFormatted<bool>((Object)(object)val4 != (Object)null);
						((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(" slider=");
						((BepInExLogInterpolatedStringHandler)val8).AppendFormatted<bool>((Object)(object)val5 != (Object)null);
						((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(" page=");
						((BepInExLogInterpolatedStringHandler)val8).AppendFormatted<bool>((Object)(object)val6 != (Object)null);
						((BepInExLogInterpolatedStringHandler)val8).AppendLiteral(" entry=");
						((BepInExLogInterpolatedStringHandler)val8).AppendFormatted<bool>((Object)(object)val7 != (Object)null);
					}
					l.LogError(val8);
					return;
				}
				Tab tab = new Tab
				{
					Centre = val3
				};
				GameObject val9 = Object.Instantiate<GameObject>(((Component)val6).gameObject, val3);
				((Object)val9).name = "Accessibility";
				val9.SetActive(false);
				for (int num = val9.transform.childCount - 1; num >= 0; num--)
				{
					Object.Destroy((Object)(object)((Component)val9.transform.GetChild(num)).gameObject);
				}
				DisableNative(val9, rootOnly: true);
				tab.Page = val9;
				List<List<Selectable>> list = new List<List<Selectable>>();
				list.Add(ArrayRow(tab, val4, "Color filter", new string[4] { "Off", "Protanopia (red)", "Deuteranopia (green)", "Tritanopia (blue)" }, () => (int)Plugin.Color.Value, delegate(int v)
				{
					Plugin.Color.Value = (ColorMode)v;
				}));
				list.Add(SliderRow(tab, val5, "Filter strength", 0, 100, 5, () => Plugin.ColorStrength.Value, delegate(int v)
				{
					Plugin.ColorStrength.Value = v;
				}, (int v) => v + "%"));
				list.Add(ArrayRow(tab, val4, "Subtitles", new string[2] { "Off", "On" }, () => Plugin.Subtitles.Value ? 1 : 0, delegate(int v)
				{
					Plugin.Subtitles.Value = v == 1;
				}));
				list.Add(ArrayRow(tab, val4, "Subtitle size", new string[3] { "Small", "Medium", "Large" }, () => (int)Plugin.Size.Value, delegate(int v)
				{
					Plugin.Size.Value = (SubtitleSize)v;
				}));
				list.Add(ArrayRow(tab, val4, "Sound direction", new string[2] { "Off", "On" }, () => Plugin.Direction.Value ? 1 : 0, delegate(int v)
				{
					Plugin.Direction.Value = v == 1;
				}));
				list.RemoveAll((List<Selectable> r) => r == null || r.Count == 0);
				GameObject val10 = Object.Instantiate<GameObject>(((Component)val7).gameObject, val2);
				((Object)val10).name = "Accessibility";
				val10.transform.SetSiblingIndex(val7.GetSiblingIndex() + 1);
				DisableNative(val10, rootOnly: false);
				ResetManaged(val10);
				foreach (TMP_Text componentsInChild in val10.GetComponentsInChildren<TMP_Text>(true))
				{
					SetText(componentsInChild, "Accessibility");
				}
				Button val11 = val10.GetComponent<Button>() ?? val10.GetComponentInChildren<Button>(true);
				if ((Object)(object)val11 == (Object)null)
				{
					Plugin.L.LogError((object)"category entry has no Button");
					Object.Destroy((Object)(object)val10);
					Object.Destroy((Object)(object)val9);
					return;
				}
				Bind(val11, delegate
				{
					Show(menu);
				});
				tab.Button = val11;
				tab.First = ((list.Count > 0) ? list[0][0] : null);
				Wire(tab, list, ((Component)val7).GetComponent<Button>() ?? ((Component)val7).GetComponentInChildren<Button>(true));
				Tabs[((Il2CppObjectBase)menu).Pointer] = tab;
				ManualLogSource l2 = Plugin.L;
				BepInExInfoLogInterpolatedStringHandler val12 = new BepInExInfoLogInterpolatedStringHandler(37, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("Accessibility tab added to '");
					((BepInExLogInterpolatedStringHandler)val12).AppendFormatted<string>(((Object)menu).name);
					((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("' (");
					((BepInExLogInterpolatedStringHandler)val12).AppendFormatted<int>(list.Count);
					((BepInExLogInterpolatedStringHandler)val12).AppendLiteral(" rows)");
				}
				l2.LogInfo(val12);
			}
		}

		public static void Show(SettingsMenu menu)
		{
			if (!Tabs.TryGetValue(((Il2CppObjectBase)menu).Pointer, out var value) || (Object)(object)value.Page == (Object)null || value.Open)
			{
				return;
			}
			value.Restore.Clear();
			for (int i = 0; i < value.Centre.childCount; i++)
			{
				GameObject gameObject = ((Component)value.Centre.GetChild(i)).gameObject;
				if ((Object)(object)gameObject != (Object)(object)value.Page && gameObject.activeSelf)
				{
					value.Restore.Add(gameObject);
					gameObject.SetActive(false);
				}
			}
			foreach (Action item in value.Refresh)
			{
				item();
			}
			value.Page.SetActive(true);
			if ((Object)(object)value.First != (Object)null && (Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject(((Component)value.First).gameObject);
			}
		}

		public static void Hide(SettingsMenu menu)
		{
			if ((Object)(object)menu == (Object)null || !Tabs.TryGetValue(((Il2CppObjectBase)menu).Pointer, out var value) || !value.Open)
			{
				return;
			}
			value.Page.SetActive(false);
			foreach (GameObject item in value.Restore)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.SetActive(true);
				}
			}
			value.Restore.Clear();
		}

		public static bool HandleBack(SettingsMenu menu)
		{
			if ((Object)(object)menu == (Object)null || !Tabs.TryGetValue(((Il2CppObjectBase)menu).Pointer, out var value) || !value.Open)
			{
				return false;
			}
			GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
			bool num = (Object)(object)val != (Object)null && val.transform.IsChildOf(value.Page.transform);
			Hide(menu);
			if (!num)
			{
				return false;
			}
			if ((Object)(object)value.Button != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject(((Component)value.Button).gameObject);
			}
			return true;
		}

		private static List<Selectable> ArrayRow(Tab tab, Transform tpl, string title, string[] values, Func<int> get, Action<int> set)
		{
			GameObject val = NewRow(tab, tpl, title);
			Transform obj = val.transform.Find("LeftButton");
			Button val2 = ((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
			Transform obj2 = val.transform.Find("RightButton");
			Button val3 = ((obj2 != null) ? ((Component)obj2).GetComponent<Button>() : null);
			Transform val4 = val.transform.Find("Variable");
			TMP_Text label = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponentInChildren<TMP_Text>(true) : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)label == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			Button component = ((Component)val4).GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				((Selectable)component).interactable = false;
			}
			Action refresh = delegate
			{
				SetText(label, values[Mathf.Clamp(get(), 0, values.Length - 1)]);
			};
			Action<int> step = delegate(int d)
			{
				set((get() + d + values.Length) % values.Length);
				refresh();
			};
			Bind(val2, delegate
			{
				step(-1);
			});
			Bind(val3, delegate
			{
				step(1);
			});
			ManagedButton component2 = ((Component)val2).GetComponent<ManagedButton>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.onLeft = Ev(delegate
				{
					step(-1);
				});
				component2.onRight = Ev(delegate
				{
					step(1);
				});
			}
			ManagedButton component3 = ((Component)val3).GetComponent<ManagedButton>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.onLeft = Ev(delegate
				{
					step(-1);
				});
				component3.onRight = Ev(delegate
				{
					step(1);
				});
			}
			tab.Refresh.Add(refresh);
			refresh();
			return new List<Selectable>
			{
				(Selectable)(object)val2,
				(Selectable)(object)val3
			};
		}

		private static List<Selectable> SliderRow(Tab tab, Transform tpl, string title, int min, int max, int stepSize, Func<int> get, Action<int> set, Func<int, string> fmt)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			GameObject val = NewRow(tab, tpl, title);
			Transform obj = val.transform.Find("Slider");
			Slider slider = ((obj != null) ? ((Component)obj).GetComponent<Slider>() : null) ?? val.GetComponentInChildren<Slider>(true);
			Transform obj2 = val.transform.Find("VariableDisplay");
			TMP_Text shown = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null);
			if ((Object)(object)slider == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			int num = (max - min) / stepSize;
			slider.onValueChanged = new SliderEvent();
			slider.minValue = 0f;
			slider.maxValue = num;
			slider.wholeNumbers = true;
			Action refresh = delegate
			{
				slider.SetValueWithoutNotify((float)(get() - min) / (float)stepSize);
				if ((Object)(object)shown != (Object)null)
				{
					SetText(shown, fmt(get()));
				}
			};
			((UnityEvent<float>)(object)slider.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<float>>((Delegate)(Action<float>)delegate(float raw)
			{
				set(min + Mathf.RoundToInt(raw) * stepSize);
				refresh();
			}));
			tab.Refresh.Add(refresh);
			refresh();
			return new List<Selectable> { (Selectable)(object)slider };
		}

		private static GameObject NewRow(Tab tab, Transform tpl, string title)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)tpl).gameObject, tab.Page.transform);
			((Object)val).name = "SettingsRow_Accessibility " + title;
			val.SetActive(true);
			DisableNative(val, rootOnly: false);
			ResetManaged(val);
			Transform obj = val.transform.Find("Title");
			SetText(((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null) ?? val.GetComponentInChildren<TMP_Text>(true), title);
			return val;
		}

		private static void Wire(Tab tab, List<List<Selectable>> rows, Button above)
		{
			Button button = tab.Button;
			Selectable val = (((Object)(object)above != (Object)null) ? ((Selectable)above).navigation.selectOnDown : null);
			Nav((Selectable)(object)button, (Selectable)(object)above, val, null, tab.First);
			if ((Object)(object)above != (Object)null)
			{
				Navigation navigation = ((Selectable)above).navigation;
				Nav((Selectable)(object)above, navigation.selectOnUp, (Selectable)(object)button, navigation.selectOnLeft, navigation.selectOnRight);
			}
			if ((Object)(object)val != (Object)null)
			{
				Navigation navigation2 = val.navigation;
				Nav(val, (Selectable)(object)button, navigation2.selectOnDown, navigation2.selectOnLeft, navigation2.selectOnRight);
			}
			for (int i = 0; i < rows.Count; i++)
			{
				Selectable up = ((i > 0) ? rows[i - 1][0] : null);
				Selectable down = ((i + 1 < rows.Count) ? rows[i + 1][0] : null);
				for (int j = 0; j < rows[i].Count; j++)
				{
					Nav(rows[i][j], up, down, (Selectable)((j > 0) ? ((object)rows[i][j - 1]) : ((object)button)), (j + 1 < rows[i].Count) ? rows[i][j + 1] : null);
				}
			}
		}

		private static void Nav(Selectable s, Selectable up, Selectable down, Selectable left, Selectable right)
		{
			if (!((Object)(object)s == (Object)null))
			{
				Navigation navigation = s.navigation;
				navigation.mode = (Mode)4;
				navigation.selectOnUp = up;
				navigation.selectOnDown = down;
				navigation.selectOnLeft = left;
				navigation.selectOnRight = right;
				s.navigation = navigation;
				ManagedButton component = ((Component)s).GetComponent<ManagedButton>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetNavagitationTargets((up != null) ? ((Component)up).gameObject : null, (down != null) ? ((Component)down).gameObject : null, (left != null) ? ((Component)left).gameObject : null, (right != null) ? ((Component)right).gameObject : null);
				}
			}
		}

		private static void DisableNative(GameObject root, bool rootOnly)
		{
			foreach (MonoBehaviour item in rootOnly ? root.GetComponents<MonoBehaviour>() : root.GetComponentsInChildren<MonoBehaviour>(true))
			{
				if ((Object)(object)item != (Object)null && NativeScripts.Contains(((MemberInfo)((Object)item).GetIl2CppType()).Name))
				{
					((Behaviour)item).enabled = false;
				}
			}
		}

		private static void ResetManaged(GameObject root)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			foreach (ManagedButton componentsInChild in root.GetComponentsInChildren<ManagedButton>(true))
			{
				componentsInChild.onLeft = new UnityEvent();
				componentsInChild.onRight = new UnityEvent();
			}
		}

		private static UnityEvent Ev(Action a)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			UnityEvent val = new UnityEvent();
			val.AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)a));
			return val;
		}

		private static void Bind(Button b, Action a)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			b.onClick = new ButtonClickedEvent();
			((UnityEvent)b.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)a));
		}

		private static void SetText(TMP_Text t, string s)
		{
			if (!((Object)(object)t == (Object)null))
			{
				LocalizedText component = ((Component)t).GetComponent<LocalizedText>();
				if ((Object)(object)component != (Object)null)
				{
					component.Change(s, (DisplayType)1);
				}
				t.text = s;
			}
		}

		private static Transform EntryFor(Transform left, SettingsCatagory cat)
		{
			Selectable val = (((Object)(object)cat != (Object)null) ? cat.catagoryButton : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Transform val2 = ((Component)val).transform;
			while ((Object)(object)val2 != (Object)null && (Object)(object)val2.parent != (Object)(object)left)
			{
				val2 = val2.parent;
			}
			return val2;
		}

		private static Transform Find(Transform root, string name)
		{
			return FindDeep(root, (string n) => n == name);
		}

		private static Transform FindDeep(Transform t, Func<string, bool> match)
		{
			for (int i = 0; i < t.childCount; i++)
			{
				Transform child = t.GetChild(i);
				if (match(((Object)child).name))
				{
					return child;
				}
			}
			for (int j = 0; j < t.childCount; j++)
			{
				Transform val = FindDeep(t.GetChild(j), match);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(SettingsMenu))]
	internal static class SettingsMenuPatches
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void Start(SettingsMenu __instance)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			try
			{
				SettingsTab.Build(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(11, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("tab build: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				l.LogError(val);
			}
		}

		[HarmonyPatch("SwapToCatagory")]
		[HarmonyPrefix]
		private static void Swap(SettingsMenu __instance)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			try
			{
				SettingsTab.Hide(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(10, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("tab swap: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				l.LogError(val);
			}
		}

		[HarmonyPatch("SettingBackEvent")]
		[HarmonyPrefix]
		private static bool Back(SettingsMenu __instance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			try
			{
				return !SettingsTab.HandleBack(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(10, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("tab back: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				l.LogError(val);
				return true;
			}
		}

		[HarmonyPatch("OnDisable")]
		[HarmonyPostfix]
		private static void Disable(SettingsMenu __instance)
		{
			try
			{
				SettingsTab.Hide(__instance);
			}
			catch
			{
			}
		}
	}
	internal sealed class Caption
	{
		public string Text;

		public bool OthersOnly;
	}
	internal static class Captions
	{
		private sealed class Rule
		{
			public Regex Re;

			public string Text;

			public int Weight;
		}

		private static readonly Dictionary<string, string> Exact = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, string> Names = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly List<Rule> Rules = new List<Rule>();

		private static readonly Dictionary<string, Caption> Cache = new Dictionary<string, Caption>();

		private static readonly HashSet<string> Logged = new HashSet<string>();

		private static string _path;

		private static string _cuesPath;

		private static readonly Regex Suffix = new Regex("(_(\\d+|lp|int|head|middle|tail|distant|[a-z]))+$", RegexOptions.IgnoreCase);

		public static void Load()
		{
			_path = Path.Combine(Paths.ConfigPath, "BigAccessibility.captions.txt");
			_cuesPath = Path.Combine(Paths.ConfigPath, "BigAccessibility.cues.txt");
			if (!File.Exists(_path))
			{
				File.WriteAllText(_path, "# Your Big Accessibility captions. Same syntax as the built-in list, and these win.\n#   sfx_prop_cowbell_shake = Cowbell rings     sfx_prop_*_grab = {1} grabbed\n#   @cowbell = Cowbell     name = -  (hide)     name = ~Text  (not your own sounds)\n# Cue names you have heard are listed in BigAccessibility.cues.txt.\n");
			}
			Exact.Clear();
			Names.Clear();
			Rules.Clear();
			Cache.Clear();
			using (Stream stream = typeof(Captions).Assembly.GetManifestResourceStream("BigAccessibility.captions.default.txt"))
			{
				if (stream != null)
				{
					Parse(new StreamReader(stream).ReadToEnd());
				}
			}
			Parse(File.ReadAllText(_path));
			Rules.Sort((Rule x, Rule y) => y.Weight.CompareTo(x.Weight));
			if (File.Exists(_cuesPath))
			{
				string[] array = File.ReadAllLines(_cuesPath);
				foreach (string text in array)
				{
					Logged.Add(text.Trim());
				}
			}
		}

		private static void Parse(string all)
		{
			string[] array = all.Split('\n');
			foreach (string obj in array)
			{
				string text = obj.Trim();
				if (text.Length == 0 || text[0] == '#')
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num <= 0)
				{
					continue;
				}
				string key = text.Substring(0, num).Trim();
				string text2 = text.Substring(num + 1).Trim();
				if (key[0] == '@')
				{
					Names[key.Substring(1)] = text2;
					continue;
				}
				if (!key.Contains('*'))
				{
					Exact[Tidy(key)] = text2;
					continue;
				}
				Rules.RemoveAll((Rule r) => r.Re.ToString() == Glob(key));
				Rules.Add(new Rule
				{
					Re = new Regex(Glob(key), RegexOptions.IgnoreCase),
					Text = text2,
					Weight = key.Replace("*", "").Length
				});
			}
		}

		private static string Glob(string key)
		{
			return "^" + Regex.Escape(Tidy(key)).Replace("\\*", "(.+?)") + "$";
		}

		public static string Tidy(string cue)
		{
			string text = cue.Trim();
			int num = text.IndexOf(" cue", StringComparison.OrdinalIgnoreCase);
			if (num > 0)
			{
				text = text.Substring(0, num);
			}
			if (text.EndsWith("_cue", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - 4);
			}
			text = Suffix.Replace(text, "");
			text = Regex.Replace(text, "(?<=[a-z])\\d+$", "", RegexOptions.IgnoreCase);
			return Suffix.Replace(text, "");
		}

		public static Caption For(string cue)
		{
			if (Cache.TryGetValue(cue, out var value))
			{
				return value;
			}
			if (Plugin.LogCues.Value && Logged.Add(cue))
			{
				try
				{
					File.AppendAllText(_cuesPath, cue + "\n");
				}
				catch
				{
				}
			}
			return Cache[cue] = Resolve(Tidy(cue));
		}

		private static Caption Resolve(string key)
		{
			string text = null;
			if (Exact.TryGetValue(key, out var value))
			{
				text = value;
			}
			else
			{
				foreach (Rule rule in Rules)
				{
					Match match = rule.Re.Match(key);
					if (match.Success)
					{
						text = rule.Text;
						for (int i = 1; i < match.Groups.Count; i++)
						{
							text = text.Replace("{" + i + "}", Name(match.Groups[i].Value));
						}
						break;
					}
				}
				if (text == null)
				{
					text = Pretty(key);
				}
			}
			if (text == null || text == "-")
			{
				return null;
			}
			Caption caption = new Caption();
			if (text.StartsWith("~"))
			{
				caption.OthersOnly = true;
				text = text.Substring(1).Trim();
			}
			if (text.Length == 0)
			{
				return null;
			}
			caption.Text = char.ToUpperInvariant(text[0]) + text.Substring(1);
			return caption;
		}

		private static string Name(string part)
		{
			if (!Names.TryGetValue(part, out var value))
			{
				return (Pretty(part) ?? part).ToLowerInvariant();
			}
			return value;
		}

		private static string Pretty(string cue)
		{
			string input = Regex.Replace(cue, "^(sfx|fly|amb|ui|sc|snd|sound|cue|audio)[_\\- ]+", "", RegexOptions.IgnoreCase);
			input = Regex.Replace(input, "^(prop|lobby)[_\\- ]+", "", RegexOptions.IgnoreCase);
			input = Regex.Replace(input, "[_\\-]+", " ");
			input = Regex.Replace(input, "(?<=[a-z])(?=[A-Z])", " ");
			input = Regex.Replace(input, "\\s+", " ").Trim();
			if (input.Length == 0)
			{
				return null;
			}
			return char.ToUpperInvariant(input[0]) + input.Substring(1).ToLowerInvariant();
		}
	}
	internal static class SubtitleOverlay
	{
		private sealed class Entry
		{
			public string Text;

			public float Heard;

			public float Dir;

			public bool Spatial;
		}

		private const float PollEvery = 0.1f;

		private const float OwnRadius = 2.5f;

		private static readonly Dictionary<string, Entry> Live = new Dictionary<string, Entry>();

		private static readonly List<Entry> Order = new List<Entry>();

		private static GameObject _canvas;

		private static RectTransform _root;

		private static readonly List<(Image bg, TextMeshProUGUI text)> Lines = new List<(Image, TextMeshProUGUI)>();

		private static float _nextPoll;

		private const float RawScanEvery = 2f;

		private static readonly List<AudioSource> Raw = new List<AudioSource>();

		private static float _nextRawScan;

		private static TMP_FontAsset _font;

		public static void Tick()
		{
			if (!Plugin.Subtitles.Value)
			{
				if ((Object)(object)_canvas != (Object)null && _canvas.activeSelf)
				{
					_canvas.SetActive(false);
				}
				Live.Clear();
			}
			else if (!((Object)(object)_canvas == (Object)null) || Build())
			{
				if (!_canvas.activeSelf)
				{
					_canvas.SetActive(true);
				}
				if (Time.unscaledTime >= _nextPoll)
				{
					_nextPoll = Time.unscaledTime + 0.1f;
					Poll();
				}
				Draw();
			}
		}

		private static void Poll()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Invalid comparison between Unknown and I4
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			AudioManager instance = AudioManager.Instance;
			AudioPool val = (((Object)(object)instance != (Object)null) ? instance.AudioPool : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			List<AudioSourceController> allControllers = val._allControllers;
			if (allControllers == null)
			{
				return;
			}
			Transform val2 = null;
			AudioListenerController listenerController = instance.ListenerController;
			if ((Object)(object)listenerController != (Object)null && (Object)(object)listenerController.Listener != (Object)null)
			{
				val2 = ((Component)listenerController.Listener).transform;
			}
			if ((Object)(object)val2 == (Object)null && (Object)(object)Camera.main != (Object)null)
			{
				val2 = ((Component)Camera.main).transform;
			}
			float unscaledTime = Time.unscaledTime;
			float value = Plugin.MinVolume.Value;
			for (int i = 0; i < allControllers.Count; i++)
			{
				AudioSourceController val3 = allControllers[i];
				if (!((Object)(object)val3 == (Object)null) && (int)val3.State == 1)
				{
					SoundCue cue = val3.Cue;
					if (!((Object)(object)cue == (Object)null) && !(val3.FinalVolume < value) && BusAllowed(val3.Bus))
					{
						Touch(((Object)cue).name, val3.CachedTransform.position, val3.SpatialBlend > 0.5f, val2, unscaledTime);
					}
				}
			}
			PollRaw(val, val2, unscaledTime, value);
		}

		private static void PollRaw(AudioPool pool, Transform ear, float now, float min)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			if (now >= _nextRawScan)
			{
				_nextRawScan = now + 2f;
				Raw.Clear();
				Transform transform = ((Component)pool).transform;
				foreach (AudioSource item in Object.FindObjectsOfType<AudioSource>())
				{
					if (!((Object)(object)item == (Object)null) && !((Component)item).transform.IsChildOf(transform) && ((Object)((Component)item).gameObject).name.IndexOf("Dissonance", StringComparison.OrdinalIgnoreCase) < 0)
					{
						Raw.Add(item);
					}
				}
			}
			foreach (AudioSource item2 in Raw)
			{
				if ((Object)(object)item2 == (Object)null || !item2.isPlaying || !((Behaviour)item2).isActiveAndEnabled)
				{
					continue;
				}
				AudioClip clip = item2.clip;
				if ((Object)(object)clip == (Object)null || item2.volume < min)
				{
					continue;
				}
				Vector3 position = ((Component)item2).transform.position;
				bool flag = item2.spatialBlend > 0.5f;
				if (flag && (Object)(object)ear != (Object)null)
				{
					Vector3 val = position - ear.position;
					if (((Vector3)(ref val)).magnitude > item2.maxDistance)
					{
						continue;
					}
				}
				Touch(((Object)clip).name, position, flag, ear, now);
			}
		}

		private static void Touch(string cueName, Vector3 pos, bool spatial, Transform ear, float now)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Caption caption = Captions.For(cueName);
			if (caption == null)
			{
				return;
			}
			spatial &= (Object)(object)ear != (Object)null;
			if (caption.OthersOnly)
			{
				if (!spatial)
				{
					return;
				}
				Vector3 val = pos - ear.position;
				if (((Vector3)(ref val)).sqrMagnitude < 6.25f)
				{
					return;
				}
			}
			float dir = 0f;
			if (spatial)
			{
				Vector3 val2 = ear.InverseTransformPoint(pos);
				Vector2 val3 = new Vector2(val2.x, val2.z);
				float magnitude = ((Vector2)(ref val3)).magnitude;
				dir = ((magnitude > 0.01f) ? (val2.x / magnitude) : 0f);
			}
			if (!Live.TryGetValue(caption.Text, out var value))
			{
				value = new Entry
				{
					Text = caption.Text
				};
				Live[caption.Text] = value;
			}
			value.Heard = now;
			value.Dir = dir;
			value.Spatial = spatial;
		}

		private static bool BusAllowed(AudioBus bus)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			if ((Object)(object)bus == (Object)null)
			{
				return true;
			}
			AudioSettingsGroupType audioSettingsGroup = bus.AudioSettingsGroup;
			if ((int)audioSettingsGroup == 1)
			{
				return Plugin.IncludeMusic.Value;
			}
			if ((int)audioSettingsGroup == 3)
			{
				return Plugin.IncludeUi.Value;
			}
			return true;
		}

		private static void Draw()
		{
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			float unscaledTime = Time.unscaledTime;
			float value = Plugin.Linger.Value;
			Order.Clear();
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, Entry> item3 in Live)
			{
				if (unscaledTime - item3.Value.Heard > value)
				{
					list.Add(item3.Key);
				}
				else
				{
					Order.Add(item3.Value);
				}
			}
			foreach (string item4 in list)
			{
				Live.Remove(item4);
			}
			Order.Sort((Entry a, Entry b) => b.Heard.CompareTo(a.Heard));
			int num = Math.Min(Plugin.MaxLines.Value, Order.Count);
			while (Lines.Count < num)
			{
				Lines.Add(NewLine());
			}
			float num2 = Plugin.Size.Value switch
			{
				SubtitleSize.Small => 20f, 
				SubtitleSize.Large => 34f, 
				_ => 26f, 
			};
			float num3 = num2 * 0.35f;
			float num4 = num2 * 1.35f;
			float value2 = Plugin.BackgroundOpacity.Value;
			float num5 = 0f;
			for (int num6 = 0; num6 < Lines.Count; num6++)
			{
				(Image bg, TextMeshProUGUI text) tuple = Lines[num6];
				Image item = tuple.bg;
				TextMeshProUGUI item2 = tuple.text;
				bool flag = num6 < num;
				((Component)item).gameObject.SetActive(flag);
				if (flag)
				{
					Entry entry = Order[num6];
					float num7 = Mathf.Clamp01(1f - (unscaledTime - entry.Heard - 0.2f) / value);
					((TMP_Text)item2).fontSize = num2;
					((TMP_Text)item2).text = Label(entry);
					((Graphic)item2).color = new Color(1f, 1f, 1f, Mathf.Lerp(0.35f, 1f, num7));
					((Graphic)item).color = new Color(0f, 0f, 0f, value2);
					num5 = Mathf.Max(num5, ((TMP_Text)item2).preferredWidth);
				}
			}
			num5 += num3 * 2f;
			for (int num8 = 0; num8 < num; num8++)
			{
				RectTransform rectTransform = ((Graphic)Lines[num8].bg).rectTransform;
				rectTransform.sizeDelta = new Vector2(num5, num4);
				rectTransform.anchoredPosition = new Vector2(0f, (float)num8 * num4);
			}
		}

		private static string Label(Entry e)
		{
			if (!Plugin.Direction.Value || !e.Spatial)
			{
				return e.Text;
			}
			if (e.Dir < -0.35f)
			{
				return "<  " + e.Text + "   ";
			}
			if (e.Dir > 0.35f)
			{
				return "   " + e.Text + "  >";
			}
			return "   " + e.Text + "   ";
		}

		private static bool Build()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = Object.FindObjectOfType<TextMeshProUGUI>();
			_font = (((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null) ? ((TMP_Text)val).font : TMP_Settings.defaultFontAsset);
			_canvas = new GameObject("BigAccessibility Subtitles");
			Object.DontDestroyOnLoad((Object)(object)_canvas);
			Canvas obj = _canvas.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32000;
			CanvasScaler obj2 = _canvas.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 1f;
			GameObject val2 = new GameObject("Stack");
			val2.transform.SetParent(_canvas.transform, false);
			_root = val2.AddComponent<RectTransform>();
			RectTransform root = _root;
			RectTransform root2 = _root;
			RectTransform root3 = _root;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(1f, 0f);
			root3.pivot = val3;
			Vector2 anchorMin = (root2.anchorMax = val3);
			root.anchorMin = anchorMin;
			_root.anchoredPosition = new Vector2(-24f, 120f);
			_root.sizeDelta = Vector2.zero;
			return true;
		}

		private static (Image, TextMeshProUGUI) NewLine()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_00bb: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Line");
			val.transform.SetParent((Transform)(object)_root, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).raycastTarget = false;
			RectTransform rectTransform = ((Graphic)obj).rectTransform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1f, 0f);
			rectTransform.pivot = val2;
			Vector2 anchorMin = (rectTransform.anchorMax = val2);
			rectTransform.anchorMin = anchorMin;
			GameObject val4 = new GameObject("Text");
			val4.transform.SetParent(val.transform, false);
			TextMeshProUGUI val5 = val4.AddComponent<TextMeshProUGUI>();
			((Graphic)val5).raycastTarget = false;
			((TMP_Text)val5).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val5).enableWordWrapping = false;
			if ((Object)(object)_font != (Object)null)
			{
				((TMP_Text)val5).font = _font;
			}
			RectTransform rectTransform2 = ((TMP_Text)val5).rectTransform;
			rectTransform2.anchorMin = Vector2.zero;
			rectTransform2.anchorMax = Vector2.one;
			anchorMin = (rectTransform2.offsetMax = Vector2.zero);
			rectTransform2.offsetMin = anchorMin;
			return (obj, val5);
		}
	}
}