Decompiled source of BetterChat v1.4.11

BetterChat.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BetterChat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Crystal")]
[assembly: AssemblyProduct("BetterChat")]
[assembly: AssemblyCopyright("Copyright © 2023 Crystal")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a81c5907-42c8-48a8-a758-24fcacbfd3aa")]
[assembly: AssemblyFileVersion("1.4.11.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.4.11.0")]
namespace BetterChat;

[BepInPlugin("dev.crystal.betterchat", "Better Chat", "1.4.11.0")]
[BepInProcess("valheim.exe")]
[BepInProcess("valheim_server.exe")]
public class BetterChatPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Chat))]
	private static class Chat_Patches
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void Awake_Postfix(Chat __instance)
		{
			__instance.m_hideDelay = HideDelay.Value;
			sChat = __instance;
			Graphic[] componentsInChildren = ((Component)((Terminal)__instance).m_chatWindow).GetComponentsInChildren<Graphic>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].raycastTarget = false;
			}
		}
	}

	[HarmonyPatch(typeof(Player))]
	private static class Player_Patches
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void Awake_Postfix(Player __instance)
		{
			Talker component = ((Component)__instance).GetComponent<Talker>();
			ApplyChatDistances(component);
			sTalkers.Add(component);
		}

		[HarmonyPatch("OnDestroy")]
		[HarmonyPrefix]
		private static void OnDestroy_Prefix(Player __instance)
		{
			sTalkers.Remove(((Component)__instance).GetComponent<Talker>());
		}
	}

	[HarmonyPatch(typeof(Chat))]
	private static class Chat_AlwaysShow_Patch
	{
		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static bool Update_Prefix(Chat __instance)
		{
			sHideTimerField.SetValue(__instance, 0f);
			return true;
		}
	}

	[HarmonyPatch(typeof(Chat))]
	private static class Chat_Slash_Patches
	{
		private enum TranspilerState
		{
			Searching,
			Inserting,
			Searching2,
			Labeling,
			Finishing
		}

		[CompilerGenerated]
		private sealed class <Update_Transpiler>d__1 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private CodeInstruction <>2__current;

			private int <>l__initialThreadId;

			private ILGenerator generator;

			public ILGenerator <>3__generator;

			private IEnumerable<CodeInstruction> instructions;

			public IEnumerable<CodeInstruction> <>3__instructions;

			private LocalBuilder <isSlashPressed>5__2;

			private Label <label>5__3;

			private TranspilerState <state>5__4;

			private IEnumerator<CodeInstruction> <>7__wrap4;

			private CodeInstruction <instruction>5__6;

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

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

			[DebuggerHidden]
			public <Update_Transpiler>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 3) <= 13u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<isSlashPressed>5__2 = null;
				<>7__wrap4 = null;
				<instruction>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ac: Expected O, but got Unknown
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Expected O, but got Unknown
				//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b7: Expected O, but got Unknown
				//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_0204: Expected O, but got Unknown
				//IL_0230: Unknown result type (might be due to invalid IL or missing references)
				//IL_023a: Expected O, but got Unknown
				//IL_0266: Unknown result type (might be due to invalid IL or missing references)
				//IL_0270: Expected O, but got Unknown
				//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_03c2: Expected O, but got Unknown
				//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ea: Expected O, but got Unknown
				//IL_041b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0425: Expected O, but got Unknown
				//IL_0447: Unknown result type (might be due to invalid IL or missing references)
				//IL_0451: Expected O, but got Unknown
				//IL_0482: Unknown result type (might be due to invalid IL or missing references)
				//IL_048c: Expected O, but got Unknown
				//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_04b4: Expected O, but got Unknown
				//IL_04e7: Unknown result type (might be due to invalid IL or missing references)
				//IL_04f1: Expected O, but got Unknown
				//IL_0386: Unknown result type (might be due to invalid IL or missing references)
				//IL_0390: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<isSlashPressed>5__2 = generator.DeclareLocal(typeof(bool));
						<isSlashPressed>5__2.SetLocalSymInfo("isSlashPressed");
						<label>5__3 = generator.DefineLabel();
						<>2__current = new CodeInstruction(OpCodes.Ldc_I4_0, (object)null);
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						<>2__current = new CodeInstruction(OpCodes.Stloc, (object)<isSlashPressed>5__2.LocalIndex);
						<>1__state = 2;
						return true;
					case 2:
						<>1__state = -1;
						<state>5__4 = TranspilerState.Searching;
						<>7__wrap4 = instructions.GetEnumerator();
						<>1__state = -3;
						goto IL_0513;
					case 3:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Ldc_I4, (object)47);
						<>1__state = 4;
						return true;
					case 4:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Call, (object)typeof(Input).GetMethod("GetKeyDown", new Type[1] { typeof(KeyCode) }));
						<>1__state = 5;
						return true;
					case 5:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Stloc, (object)<isSlashPressed>5__2.LocalIndex);
						<>1__state = 6;
						return true;
					case 6:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Ldloc, (object)<isSlashPressed>5__2.LocalIndex);
						<>1__state = 7;
						return true;
					case 7:
						<>1__state = -3;
						<state>5__4 = TranspilerState.Searching2;
						goto IL_02b5;
					case 8:
						<>1__state = -3;
						if (<state>5__4 == TranspilerState.Searching && <instruction>5__6.opcode == OpCodes.Call)
						{
							if (((MethodBase)<instruction>5__6.operand).Name == "GetButtonDown")
							{
								<state>5__4 = TranspilerState.Inserting;
							}
						}
						else if (<state>5__4 == TranspilerState.Searching2 && <instruction>5__6.opcode == OpCodes.Callvirt && ((MethodBase)<instruction>5__6.operand).Name == "ActivateInputField")
						{
							<>2__current = new CodeInstruction(OpCodes.Ldloc, (object)<isSlashPressed>5__2.LocalIndex);
							<>1__state = 9;
							return true;
						}
						goto IL_050c;
					case 9:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Brfalse, (object)<label>5__3);
						<>1__state = 10;
						return true;
					case 10:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
						<>1__state = 11;
						return true;
					case 11:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Ldfld, (object)typeof(Terminal).GetField("m_input"));
						<>1__state = 12;
						return true;
					case 12:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Ldstr, (object)"/");
						<>1__state = 13;
						return true;
					case 13:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Call, (object)typeof(TMP_InputField).GetMethod("set_text"));
						<>1__state = 14;
						return true;
					case 14:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Ldc_I4_1, (object)null);
						<>1__state = 15;
						return true;
					case 15:
						<>1__state = -3;
						<>2__current = new CodeInstruction(OpCodes.Stsfld, (object)typeof(BetterChatPlugin).GetField("sMoveCaretToEnd", BindingFlags.Static | BindingFlags.NonPublic));
						<>1__state = 16;
						return true;
					case 16:
						{
							<>1__state = -3;
							<state>5__4 = TranspilerState.Labeling;
							goto IL_050c;
						}
						IL_0513:
						if (<>7__wrap4.MoveNext())
						{
							<instruction>5__6 = <>7__wrap4.Current;
							if (<state>5__4 == TranspilerState.Inserting)
							{
								if (<instruction>5__6.opcode != OpCodes.Brtrue)
								{
									throw new InvalidOperationException(string.Format("[BetterChat] {0} encountered unexpected IL code. Unable to patch. This is most likely due to a game update changing the target code. Disable {1} in the config as a workaround until the mod can be fixed. Details: Search failed, opcode={2}", "Chat_Slash_Patches", "SlashOpensChat", <instruction>5__6.opcode));
								}
								<>2__current = <instruction>5__6.Clone();
								<>1__state = 3;
								return true;
							}
							if (<state>5__4 == TranspilerState.Labeling)
							{
								<instruction>5__6.labels.Add(<label>5__3);
								<state>5__4 = TranspilerState.Finishing;
							}
							goto IL_02b5;
						}
						<>m__Finally1();
						<>7__wrap4 = null;
						if (<state>5__4 != TranspilerState.Finishing)
						{
							throw new InvalidOperationException("[BetterChat] Chat_Slash_Patches encountered unexpected IL code. Unable to patch. This is most likely due to a game update changing the target code. Disable SlashOpensChat in the config as a workaround until the mod can be fixed. Details: Never reached finishing state");
						}
						return false;
						IL_02b5:
						<>2__current = <instruction>5__6;
						<>1__state = 8;
						return true;
						IL_050c:
						<instruction>5__6 = null;
						goto IL_0513;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap4 != null)
				{
					<>7__wrap4.Dispose();
				}
			}

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

			[DebuggerHidden]
			IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
			{
				<Update_Transpiler>d__1 <Update_Transpiler>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<Update_Transpiler>d__ = this;
				}
				else
				{
					<Update_Transpiler>d__ = new <Update_Transpiler>d__1(0);
				}
				<Update_Transpiler>d__.instructions = <>3__instructions;
				<Update_Transpiler>d__.generator = <>3__generator;
				return <Update_Transpiler>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<CodeInstruction>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<Update_Transpiler>d__1))]
		[HarmonyPatch("Update")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Update_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Update_Transpiler>d__1(-2)
			{
				<>3__instructions = instructions,
				<>3__generator = generator
			};
		}

		[HarmonyPatch("LateUpdate")]
		[HarmonyPostfix]
		private static void LateUpdate_Postfix(Chat __instance)
		{
			if (sMoveCaretToEnd)
			{
				((TMP_InputField)((Terminal)__instance).m_input).MoveTextEnd(false);
				sMoveCaretToEnd = false;
			}
		}
	}

	[HarmonyPatch(typeof(Chat))]
	private static class Chat_Show_Patch
	{
		[HarmonyPatch("OnNewChatMessage")]
		[HarmonyPostfix]
		private static void OnNewChatMessage_Postfix(Chat __instance, GameObject go, long senderID, Vector3 pos, Type type, UserInfo sender, string text)
		{
			sHideTimerField.SetValue(__instance, 0f);
		}
	}

	[HarmonyPatch(typeof(Terminal))]
	private static class Chat_MixedCase_Terminal_Patch
	{
		[HarmonyPatch("AddString", new Type[]
		{
			typeof(string),
			typeof(string),
			typeof(Type),
			typeof(bool)
		})]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> AddString_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return StripForcedCase(instructions);
		}
	}

	[HarmonyPatch(typeof(Chat))]
	private static class Chat_MixedCase_Chat_Patch
	{
		[HarmonyPatch("AddInworldText")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> AddInworldText_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return StripForcedCase(instructions);
		}
	}

	[HarmonyPatch(typeof(Chat))]
	private static class Chat_Shout_Patch
	{
		[CompilerGenerated]
		private sealed class <InputText_Transpiler>d__0 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private CodeInstruction <>2__current;

			private int <>l__initialThreadId;

			private IEnumerable<CodeInstruction> instructions;

			public IEnumerable<CodeInstruction> <>3__instructions;

			private IEnumerator<CodeInstruction> <>7__wrap1;

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

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

			[DebuggerHidden]
			public <InputText_Transpiler>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = instructions.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap1.MoveNext())
					{
						CodeInstruction current = <>7__wrap1.Current;
						if (current.opcode == OpCodes.Ldstr && current.operand.Equals("say "))
						{
							current.operand = "s ";
						}
						<>2__current = current;
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap1 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap1 != null)
				{
					<>7__wrap1.Dispose();
				}
			}

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

			[DebuggerHidden]
			IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
			{
				<InputText_Transpiler>d__0 <InputText_Transpiler>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<InputText_Transpiler>d__ = this;
				}
				else
				{
					<InputText_Transpiler>d__ = new <InputText_Transpiler>d__0(0);
				}
				<InputText_Transpiler>d__.instructions = <>3__instructions;
				return <InputText_Transpiler>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<CodeInstruction>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<InputText_Transpiler>d__0))]
		[HarmonyPatch("InputText")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> InputText_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InputText_Transpiler>d__0(-2)
			{
				<>3__instructions = instructions
			};
		}
	}

	[HarmonyPatch(typeof(Minimap))]
	private static class Minimap_Patches
	{
		[HarmonyPatch("UpdateDynamicPins")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 0; i < list.Count - 1; i++)
			{
				if (list[i + 1].opcode == OpCodes.Call && ((MethodBase)list[i + 1].operand).Name == "UpdateShoutPins")
				{
					list.RemoveRange(i, 2);
					break;
				}
			}
			return list;
		}
	}

	public const string ModId = "dev.crystal.betterchat";

	public static ConfigEntry<bool> AlwaysVisible;

	public static ConfigEntry<float> HideDelay;

	public static ConfigEntry<bool> ForceCase;

	public static ConfigEntry<bool> SlashOpensChat;

	public static ConfigEntry<bool> DefaultShout;

	public static ConfigEntry<bool> ShowShoutPings;

	public static ConfigEntry<float> TalkDistance;

	public static ConfigEntry<float> WhisperDistance;

	private static Harmony sChatAwakeHarmony;

	private static Harmony sPlayerHarmony;

	private static Harmony sChatShowHarmony;

	private static Harmony sChatAlwaysShowHarmony;

	private static Harmony sChatMixedCaseHarmony;

	private static Harmony sChatShoutHarmony;

	private static Harmony sMinimapHarmony;

	private static Harmony sChatSlashHarmony;

	private static Chat sChat;

	private static List<Talker> sTalkers;

	private static readonly FieldInfo sHideTimerField;

	private static bool sMoveCaretToEnd;

	static BetterChatPlugin()
	{
		sTalkers = new List<Talker>();
		sHideTimerField = typeof(Chat).GetField("m_hideTimer", BindingFlags.Instance | BindingFlags.NonPublic);
	}

	private void Awake()
	{
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Expected O, but got Unknown
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Expected O, but got Unknown
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Expected O, but got Unknown
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Expected O, but got Unknown
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Expected O, but got Unknown
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Expected O, but got Unknown
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Expected O, but got Unknown
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Expected O, but got Unknown
		AlwaysVisible = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "AlwaysVisible", false, "If True, the chat window will remain visible at all times. If False, the chat window will appear when new messages are received.");
		AlwaysVisible.SettingChanged += AlwaysVisible_SettingChanged;
		HideDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "HideDelay", 10f, "The time, in seconds, to keep the chat window visible after sending or receiving a message. Minimum is 0.5. Has no effect if AlwaysVisible=true.");
		HideDelay.SettingChanged += HideDelay_SettingChanged;
		ForceCase = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "ForceCase", false, "If True, shout will be in all caps and whisper will be in all lowercase (game default). If False, messages will appear as they were originally entered.");
		ForceCase.SettingChanged += ForceCase_SettingChanged;
		SlashOpensChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "SlashOpensChat", true, "If True, pressing the slash key (/) will open the chat window and start a message.");
		SlashOpensChat.SettingChanged += SlashOpensChat_SettingChanged;
		DefaultShout = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "DefaultShout", false, "If True, text entered will shout by default - type /say for talk. If False, chat will be talk by default - type /s for shout.");
		DefaultShout.SettingChanged += DefaultShout_SettingChanged;
		ShowShoutPings = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "ShowShoutPings", true, "If True, pings will show on your map when players shout (game default). If False, the pings will not show. (Other players can still see your shout pings.)");
		ShowShoutPings.SettingChanged += ShowShoutPings_SettingChanged;
		TalkDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "TalkDistance", 15f, "The maximum distance from a player at which you will receive their normal chat messages (not whisper or shout). Game default is 15. Acceptable range is 1-100.");
		TalkDistance.SettingChanged += Distance_SettingChanged;
		WhisperDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "WhisperDistance", 4f, "The maximum distance from a player at which you will receive their whispered chat messages. Game default is 4. Acceptable range is 1-20");
		WhisperDistance.SettingChanged += Distance_SettingChanged;
		ClampConfig();
		sChatAwakeHarmony = new Harmony("dev.crystal.betterchat_ChatAwake");
		sPlayerHarmony = new Harmony("dev.crystal.betterchat_Player");
		sChatShowHarmony = new Harmony("dev.crystal.betterchat_ChatShow");
		sChatAlwaysShowHarmony = new Harmony("dev.crystal.betterchat_ChatAlwaysShow");
		sChatMixedCaseHarmony = new Harmony("dev.crystal.betterchat_ChatMixedCase");
		sChatShoutHarmony = new Harmony("dev.crystal.betterchat_ChatShout");
		sMinimapHarmony = new Harmony("dev.crystal.betterchat_Minimap");
		sChatSlashHarmony = new Harmony("dev.crystal.betterchat_ChatSlash");
		sChatAwakeHarmony.PatchAll(typeof(Chat_Patches));
		sPlayerHarmony.PatchAll(typeof(Player_Patches));
		if (AlwaysVisible.Value)
		{
			sChatAlwaysShowHarmony.PatchAll(typeof(Chat_AlwaysShow_Patch));
		}
		else
		{
			sChatShowHarmony.PatchAll(typeof(Chat_Show_Patch));
		}
		if (!ForceCase.Value)
		{
			sChatMixedCaseHarmony.PatchAll(typeof(Chat_MixedCase_Terminal_Patch));
			sChatMixedCaseHarmony.PatchAll(typeof(Chat_MixedCase_Chat_Patch));
		}
		if (DefaultShout.Value)
		{
			sChatShoutHarmony.PatchAll(typeof(Chat_Shout_Patch));
		}
		if (!ShowShoutPings.Value)
		{
			sMinimapHarmony.PatchAll(typeof(Minimap_Patches));
		}
		if (SlashOpensChat.Value)
		{
			sChatSlashHarmony.PatchAll(typeof(Chat_Slash_Patches));
		}
	}

	private void OnDestroy()
	{
		sChatAwakeHarmony.UnpatchSelf();
		sPlayerHarmony.UnpatchSelf();
		sChatShowHarmony.UnpatchSelf();
		sChatAlwaysShowHarmony.UnpatchSelf();
		sChatMixedCaseHarmony.UnpatchSelf();
		sChatShoutHarmony.UnpatchSelf();
		sMinimapHarmony.UnpatchSelf();
		sChatSlashHarmony.UnpatchSelf();
	}

	private static void ClampConfig()
	{
		if (HideDelay.Value < 0.5f)
		{
			HideDelay.Value = 0.5f;
		}
		if (HideDelay.Value > 3600f)
		{
			HideDelay.Value = 3600f;
		}
		if (TalkDistance.Value < 1f)
		{
			TalkDistance.Value = 1f;
		}
		if (TalkDistance.Value > 100f)
		{
			TalkDistance.Value = 100f;
		}
		if (WhisperDistance.Value < 1f)
		{
			WhisperDistance.Value = 1f;
		}
		if (WhisperDistance.Value > 20f)
		{
			WhisperDistance.Value = 20f;
		}
	}

	private void AlwaysVisible_SettingChanged(object sender, EventArgs e)
	{
		if (AlwaysVisible.Value)
		{
			sChatShowHarmony.UnpatchSelf();
			sChatAlwaysShowHarmony.PatchAll(typeof(Chat_AlwaysShow_Patch));
		}
		else
		{
			sChatAlwaysShowHarmony.UnpatchSelf();
			sChatShowHarmony.PatchAll(typeof(Chat_Show_Patch));
		}
	}

	private void HideDelay_SettingChanged(object sender, EventArgs e)
	{
		ClampConfig();
		if ((Object)(object)sChat != (Object)null)
		{
			sChat.m_hideDelay = HideDelay.Value;
		}
	}

	private void ForceCase_SettingChanged(object sender, EventArgs e)
	{
		if (ForceCase.Value)
		{
			sChatMixedCaseHarmony.UnpatchSelf();
			return;
		}
		sChatMixedCaseHarmony.PatchAll(typeof(Chat_MixedCase_Terminal_Patch));
		sChatMixedCaseHarmony.PatchAll(typeof(Chat_MixedCase_Chat_Patch));
	}

	private void SlashOpensChat_SettingChanged(object sender, EventArgs e)
	{
		if (SlashOpensChat.Value)
		{
			sChatSlashHarmony.PatchAll(typeof(Chat_Slash_Patches));
		}
		else
		{
			sChatSlashHarmony.UnpatchSelf();
		}
	}

	private void DefaultShout_SettingChanged(object sender, EventArgs e)
	{
		if (DefaultShout.Value)
		{
			sChatShoutHarmony.PatchAll(typeof(Chat_Shout_Patch));
		}
		else
		{
			sChatShoutHarmony.UnpatchSelf();
		}
	}

	private void ShowShoutPings_SettingChanged(object sender, EventArgs e)
	{
		if (ShowShoutPings.Value)
		{
			sMinimapHarmony.UnpatchSelf();
		}
		else
		{
			sMinimapHarmony.PatchAll(typeof(Minimap_Patches));
		}
	}

	private void Distance_SettingChanged(object sender, EventArgs e)
	{
		ClampConfig();
		foreach (Talker sTalker in sTalkers)
		{
			ApplyChatDistances(sTalker);
		}
	}

	private static void ApplyChatDistances(Talker talker)
	{
		talker.m_visperDistance = WhisperDistance.Value;
		talker.m_normalDistance = TalkDistance.Value;
	}

	private static IEnumerable<CodeInstruction> StripForcedCase(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		for (int i = 0; i < list.Count; i++)
		{
			if (list[i].opcode == OpCodes.Callvirt)
			{
				MethodBase methodBase = list[i].operand as MethodBase;
				if (methodBase != null && (methodBase.Name == "ToLowerInvariant" || methodBase.Name == "ToUpper"))
				{
					list.RemoveRange(i - 1, 3);
					i -= 2;
				}
			}
		}
		return list;
	}
}