Decompiled source of SmoothContacts v0.3.12

plugins/SmoothContacts.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.NET.Common;
using BepInExResoniteShim;
using BepisResoniteWrapper;
using FrooxEngine;
using FrooxEngine.UIX;
using HarmonyLib;
using SkyFrost.Base;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: TargetFramework(".NETCoreApp,Version=v10.0", FrameworkDisplayName = ".NET 10.0")]
[assembly: AssemblyCompany("markn2000")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.12.0")]
[assembly: AssemblyInformationalVersion("0.3.12+b15942700584b31618d9bc7e21dff605fa824bbc")]
[assembly: AssemblyProduct("SmoothContacts")]
[assembly: AssemblyTitle("SmoothContacts")]
[assembly: InternalsVisibleTo("SmoothContacts.Checks")]
[assembly: AssemblyVersion("0.3.12.0")]
[module: RefSafetyRules(11)]
namespace SmoothContacts;

[ResonitePlugin("markn2000.SmoothContacts", "SmoothContacts", "0.3.12", "markn2000", "https://github.com/MarkN2000/SmoothContacts")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BasePlugin
{
	public override void Load()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		((BasePlugin)this).Config.SaveOnConfigSet = false;
		ResoniteHooks.OnEngineReady += new Action(OnEngineReady);
	}

	private void OnEngineReady()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected O, but got Unknown
		ResoniteHooks.OnEngineReady -= new Action(OnEngineReady);
		try
		{
			ContactsPatches.BindSettings(((BasePlugin)this).Config);
			if (!File.Exists(((BasePlugin)this).Config.ConfigFilePath))
			{
				((BasePlugin)this).Config.Save();
			}
			ContactsPatches.ReportError = [CompilerGenerated] (global::System.Exception error) =>
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				ManualLogSource log2 = ((BasePlugin)this).Log;
				bool flag2 = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(33, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Error while processing Contacts: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<global::System.Exception>(error);
				}
				log2.LogError(val2);
			};
			ContactsPatches.Apply(((BasePlugin)this).HarmonyInstance);
			((BasePlugin)this).Log.LogInfo((object)"SmoothContacts: Contact loading and search restoration are batched while Contacts is active.");
		}
		catch (global::System.Exception ex)
		{
			((BasePlugin)this).HarmonyInstance.UnpatchSelf();
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(63, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to apply SmoothContacts. Its patches have been removed: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<global::System.Exception>(ex);
			}
			log.LogError(val);
		}
	}

	public override bool Unload()
	{
		return false;
	}
}
internal static class ContactsPatches
{
	internal sealed class Loading(ContactManager manager, Action<ContactData> update)
	{
		internal readonly ContactManager Manager = manager;

		internal readonly Action<ContactData> Update = update;

		internal List<ContactData>? Contacts;

		internal Dictionary<string, int> Order = new Dictionary<string, int>();

		internal readonly Dictionary<string, ContactData> Deferred = new Dictionary<string, ContactData>();

		internal int Position;

		internal bool Creating;

		internal string? Selection;

		internal Slot? Spacer;

		internal int ReservedRows = -1;

		private long extraRows;

		internal long RowOrder(string id)
		{
			int num = default(int);
			return (Order.TryGetValue(id, ref num) ? num : (Contacts.Count + extraRows++)) * 100;
		}

		internal ValueTuple<int, int> TakeBatch(int remaining)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			int position = Position;
			Position += Math.Min(remaining, Contacts.Count - Position);
			return new ValueTuple<int, int>(position, Position);
		}

		internal void ClearSpacer()
		{
			ReservedRows = 0;
			Slot spacer = Spacer;
			Spacer = null;
			if (spacer != null && !((Worker)spacer).IsRemoved)
			{
				spacer.Destroy();
			}
		}
	}

	[CompilerGenerated]
	private sealed class <>c__DisplayClass18_0
	{
		[StructLayout((LayoutKind)3)]
		private struct <<Start>b__0>d : IAsyncStateMachine
		{
			public int <>1__state;

			public AsyncTaskMethodBuilder <>t__builder;

			public <>c__DisplayClass18_0 <>4__this;

			private global::System.Exception <failure>5__2;

			private ValueTuple<List<ContactData>, Dictionary<string, int>> <prepared>5__3;

			private ToBackground <>u__1;

			private ToWorld <>u__2;

			private void MoveNext()
			{
				//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: 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_0115: Unknown result type (might be due to invalid IL or missing references)
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_0225: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_013d: 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_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: 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_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: 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_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				<>c__DisplayClass18_0 CS$<>8__locals9 = <>4__this;
				try
				{
					ToWorld val;
					if (num != 0)
					{
						if (num == 1)
						{
							val = <>u__2;
							<>u__2 = default(ToWorld);
							num = (<>1__state = -1);
							goto IL_014c;
						}
						<failure>5__2 = null;
						<prepared>5__3 = new ValueTuple<List<ContactData>, Dictionary<string, int>>(new List<ContactData>(), new Dictionary<string, int>());
					}
					try
					{
						ToBackground val3;
						if (num != 0)
						{
							ToBackground val2 = default(ToBackground);
							val3 = ((ToBackground)(ref val2)).GetAwaiter();
							if (!((ToBackground)(ref val3)).IsCompleted)
							{
								num = (<>1__state = 0);
								<>u__1 = val3;
								((AsyncTaskMethodBuilder)(ref <>t__builder)).AwaitOnCompleted<ToBackground, <<Start>b__0>d>(ref val3, ref this);
								return;
							}
						}
						else
						{
							val3 = <>u__1;
							<>u__1 = default(ToBackground);
							num = (<>1__state = -1);
						}
						((ToBackground)(ref val3)).GetResult();
						List<ContactData> val4 = new List<ContactData>();
						CS$<>8__locals9.manager.ForeachContactData((Action<ContactData>)val4.Add);
						<prepared>5__3 = Prepare(val4, delegate(ContactData data)
						{
							UserMessages userMessages = CS$<>8__locals9.messages.GetUserMessages(data.UserId);
							return (userMessages != null) ? userMessages.UnreadCount : 0;
						});
					}
					catch (global::System.Exception ex)
					{
						<failure>5__2 = ex;
					}
					ToWorld val5 = default(ToWorld);
					val = ((ToWorld)(ref val5)).GetAwaiter();
					if (!((ToWorld)(ref val)).IsCompleted)
					{
						num = (<>1__state = 1);
						<>u__2 = val;
						((AsyncTaskMethodBuilder)(ref <>t__builder)).AwaitOnCompleted<ToWorld, <<Start>b__0>d>(ref val, ref this);
						return;
					}
					goto IL_014c;
					IL_014c:
					((ToWorld)(ref val)).GetResult();
					Loading loading = default(Loading);
					if (!((Worker)CS$<>8__locals9.dialog).IsDisposed && !((ComponentBase<Component>)(object)CS$<>8__locals9.dialog).IsDestroyed && Pending.TryGetValue(CS$<>8__locals9.dialog, ref loading) && loading == CS$<>8__locals9.state)
					{
						try
						{
							if (<failure>5__2 != null)
							{
								throw <failure>5__2;
							}
							Loading loading2 = CS$<>8__locals9.state;
							Loading loading3 = CS$<>8__locals9.state;
							ValueTuple<List<ContactData>, Dictionary<string, int>> val6 = <prepared>5__3;
							loading2.Contacts = val6.Item1;
							loading3.Order = val6.Item2;
						}
						catch (global::System.Exception error)
						{
							Abort(CS$<>8__locals9.dialog, error);
						}
					}
				}
				catch (global::System.Exception exception)
				{
					<>1__state = -2;
					<failure>5__2 = null;
					<prepared>5__3 = default(ValueTuple<List<ContactData>, Dictionary<string, int>>);
					((AsyncTaskMethodBuilder)(ref <>t__builder)).SetException(exception);
					return;
				}
				<>1__state = -2;
				<failure>5__2 = null;
				<prepared>5__3 = default(ValueTuple<List<ContactData>, Dictionary<string, int>>);
				((AsyncTaskMethodBuilder)(ref <>t__builder)).SetResult();
			}

			[DebuggerHidden]
			private void SetStateMachine(IAsyncStateMachine stateMachine)
			{
				((AsyncTaskMethodBuilder)(ref <>t__builder)).SetStateMachine(stateMachine);
			}
		}

		public ContactManager manager;

		public MessageManager messages;

		public ContactsDialog dialog;

		public Loading state;

		public Func<ContactData, int> <>9__1;

		[AsyncStateMachine(typeof(<<Start>b__0>d))]
		internal global::System.Threading.Tasks.Task <Start>b__0()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			<<Start>b__0>d <<Start>b__0>d = default(<<Start>b__0>d);
			<<Start>b__0>d.<>t__builder = AsyncTaskMethodBuilder.Create();
			<<Start>b__0>d.<>4__this = this;
			<<Start>b__0>d.<>1__state = -1;
			((AsyncTaskMethodBuilder)(ref <<Start>b__0>d.<>t__builder)).Start<<<Start>b__0>d>(ref <<Start>b__0>d);
			return ((AsyncTaskMethodBuilder)(ref <<Start>b__0>d.<>t__builder)).Task;
		}

		internal int <Start>b__1(ContactData data)
		{
			UserMessages userMessages = messages.GetUserMessages(data.UserId);
			if (userMessages == null)
			{
				return 0;
			}
			return userMessages.UnreadCount;
		}
	}

	internal static ConfigEntry<int> BatchSize = null;

	internal static ConfigEntry<int> PauseUpdates = null;

	internal static Action<global::System.Exception>? ReportError;

	internal static readonly ConditionalWeakTable<ContactsDialog, Loading> Pending = new ConditionalWeakTable<ContactsDialog, Loading>();

	internal static readonly ConditionalWeakTable<ContactsDialog, PriorityQueue<ContactItem, long>> Restoring = new ConditionalWeakTable<ContactsDialog, PriorityQueue<ContactItem, long>>();

	private static readonly ConditionalWeakTable<ContactsDialog, StrongBox<int>> Pauses = new ConditionalWeakTable<ContactsDialog, StrongBox<int>>();

	internal static readonly FieldRef<ContactsDialog, Dictionary<string, ContactItem>> Items = AccessTools.FieldRefAccess<ContactsDialog, Dictionary<string, ContactItem>>("_contactItems");

	private static readonly FieldRef<ContactsDialog, List<ContactItem>> SearchResults = AccessTools.FieldRefAccess<ContactsDialog, List<ContactItem>>("_searchResultItems");

	internal static readonly FieldRef<ContactsDialog, bool> SortRequested = AccessTools.FieldRefAccess<ContactsDialog, bool>("sortList");

	private static readonly FieldRef<ContactsDialog, SyncRef<TextField>> Search = AccessTools.FieldRefAccess<ContactsDialog, SyncRef<TextField>>("_searchBar");

	private static readonly FieldRef<ContactsDialog, UIBuilder> ListUI = AccessTools.FieldRefAccess<ContactsDialog, UIBuilder>("listUi");

	internal static void BindSettings(ConfigFile config)
	{
		BatchSize = config.Bind<int>("Loading", "Batch size", 5, "Maximum contacts to create or restore per batch. Values below 1 are treated as 1. Applies to the next batch.");
		PauseUpdates = config.Bind<int>("Loading", "Updates to skip", 1, "Updates to skip between batches. 0 or less runs every update. Decreases shorten the current wait; increases apply after the next batch. No restart required.");
	}

	internal static void Apply(Harmony harmony)
	{
		MethodInfo val = Target("OnAttach", global::System.Array.Empty<global::System.Type>());
		MethodInfo val2 = Target("OnCommonUpdate", global::System.Array.Empty<global::System.Type>());
		MethodInfo val3 = Target("OnActivated", global::System.Array.Empty<global::System.Type>());
		MethodInfo val4 = Target("UpdateContactItem", new global::System.Type[1] { typeof(ContactData) });
		MethodInfo val5 = Target("OpenContactPage", new global::System.Type[1] { typeof(string) });
		MethodInfo val6 = Target("set_SelectedContactId", new global::System.Type[1] { typeof(string) });
		MethodInfo val7 = Target("SearchTextChanged", new global::System.Type[1] { typeof(TextEditor) });
		MethodInfo val8 = Target("OnDispose", global::System.Array.Empty<global::System.Type>());
		Enumerable.ToList<CodeInstruction>(TranspileAttach((global::System.Collections.Generic.IEnumerable<CodeInstruction>)PatchProcessor.GetOriginalInstructions((MethodBase)(object)val, (ILGenerator)null)));
		Enumerable.ToList<CodeInstruction>(TranspileSort((global::System.Collections.Generic.IEnumerable<CodeInstruction>)PatchProcessor.GetOriginalInstructions((MethodBase)(object)val2, (ILGenerator)null), (MethodBase)(object)val2));
		Enumerable.ToList<CodeInstruction>(TranspileSort((global::System.Collections.Generic.IEnumerable<CodeInstruction>)PatchProcessor.GetOriginalInstructions((MethodBase)(object)val3, (ILGenerator)null), (MethodBase)(object)val3));
		Enumerable.ToList<CodeInstruction>(TranspileSort((global::System.Collections.Generic.IEnumerable<CodeInstruction>)PatchProcessor.GetOriginalInstructions((MethodBase)(object)val4, (ILGenerator)null), (MethodBase)(object)val4));
		Enumerable.ToList<CodeInstruction>(TranspileSearch((global::System.Collections.Generic.IEnumerable<CodeInstruction>)PatchProcessor.GetOriginalInstructions((MethodBase)(object)val7, (ILGenerator)null)));
		harmony.Patch((MethodBase)(object)val, (HarmonyMethod)null, (HarmonyMethod)null, Patch("TranspileAttach"), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val2, (HarmonyMethod)null, (HarmonyMethod)null, Patch("TranspileSort"), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val3, (HarmonyMethod)null, (HarmonyMethod)null, Patch("TranspileSort"), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val4, Patch("BeforeItem"), (HarmonyMethod)null, Patch("TranspileSort"), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val5, Patch("BeforeSelect"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val6, Patch("BeforeSelect"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val7, Patch("BeforeSearch"), (HarmonyMethod)null, Patch("TranspileSearch"), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)(object)val8, Patch("OnDispose"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		[CompilerGenerated]
		static HarmonyMethod Patch(string name)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return new HarmonyMethod(typeof(ContactsPatches), name, (global::System.Type[])null);
		}
		[CompilerGenerated]
		static MethodInfo Target(string name, params global::System.Type[] parameters)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			return AccessTools.DeclaredMethod(typeof(ContactsDialog), name, parameters, (global::System.Type[])null) ?? throw new MissingMethodException(typeof(ContactsDialog).FullName, name);
		}
	}

	internal static global::System.Collections.Generic.IEnumerable<CodeInstruction> TranspileAttach(global::System.Collections.Generic.IEnumerable<CodeInstruction> instructions)
	{
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: 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_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: 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_0152: 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)
		List<CodeInstruction> val = Enumerable.ToList<CodeInstruction>(instructions);
		MethodInfo enumerate = AccessTools.Method(typeof(ContactManager), "ForeachContactData", (global::System.Type[])null, (global::System.Type[])null);
		ValueTuple<CodeInstruction, int>[] array = Enumerable.ToArray<ValueTuple<CodeInstruction, int>>(Enumerable.Where<ValueTuple<CodeInstruction, int>>(Enumerable.Select<CodeInstruction, ValueTuple<CodeInstruction, int>>((global::System.Collections.Generic.IEnumerable<CodeInstruction>)val, (Func<CodeInstruction, int, ValueTuple<CodeInstruction, int>>)((CodeInstruction op, int index) => new ValueTuple<CodeInstruction, int>(op, index))), (Func<ValueTuple<CodeInstruction, int>, bool>)((ValueTuple<CodeInstruction, int> p) => CodeInstructionExtensions.Calls(p.Item1, enumerate))));
		if (array.Length != 1)
		{
			throw new InvalidOperationException($"Expected one initial contact enumeration call; found {array.Length}.");
		}
		int item = array[0].Item2;
		if (item >= 3 && !(val[item - 3].opcode != OpCodes.Ldarg_0) && !(val[item - 2].opcode != OpCodes.Ldftn))
		{
			object operand = val[item - 2].operand;
			MethodInfo val2 = (MethodInfo)((operand is MethodInfo) ? operand : null);
			if (val2 != null && !((MethodBase)val2).IsStatic && !(((MemberInfo)val2).DeclaringType != typeof(ContactsDialog)) && !(val[item - 1].opcode != OpCodes.Newobj))
			{
				val[item].opcode = OpCodes.Call;
				val[item].operand = AccessTools.Method(typeof(ContactsPatches), "Start", (global::System.Type[])null, (global::System.Type[])null);
				return (global::System.Collections.Generic.IEnumerable<CodeInstruction>)val;
			}
		}
		throw new InvalidOperationException("The initial contact callback has an unexpected format.");
	}

	internal static global::System.Collections.Generic.IEnumerable<CodeInstruction> TranspileSort(global::System.Collections.Generic.IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
	{
		//IL_0096: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		List<CodeInstruction> obj = Enumerable.ToList<CodeInstruction>(instructions);
		FieldInfo field = AccessTools.Field(typeof(ContactsDialog), "sortList");
		bool writing = ((MemberInfo)__originalMethod).Name != "OnCommonUpdate";
		CodeInstruction[] array = Enumerable.ToArray<CodeInstruction>(Enumerable.Where<CodeInstruction>((global::System.Collections.Generic.IEnumerable<CodeInstruction>)obj, (Func<CodeInstruction, bool>)((CodeInstruction op) => op.opcode == (writing ? OpCodes.Stfld : OpCodes.Ldfld) && object.Equals(op.operand, (object)field))));
		if (array.Length != 1)
		{
			throw new InvalidOperationException($"Expected one sort flag access; found {array.Length}.");
		}
		array[0].opcode = OpCodes.Call;
		array[0].operand = AccessTools.Method(typeof(ContactsPatches), (!writing) ? "UpdateLoading" : ((((MemberInfo)__originalMethod).Name == "OnActivated") ? "RequestActivationSort" : "RequestItemSort"), (global::System.Type[])null, (global::System.Type[])null);
		return (global::System.Collections.Generic.IEnumerable<CodeInstruction>)obj;
	}

	internal static global::System.Collections.Generic.IEnumerable<CodeInstruction> TranspileSearch(global::System.Collections.Generic.IEnumerable<CodeInstruction> instructions)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//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_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		List<CodeInstruction> val = Enumerable.ToList<CodeInstruction>(instructions);
		MethodInfo target = AccessTools.PropertySetter(typeof(Slot), "ActiveSelf");
		ValueTuple<CodeInstruction, int>[] array = Enumerable.ToArray<ValueTuple<CodeInstruction, int>>(Enumerable.Where<ValueTuple<CodeInstruction, int>>(Enumerable.Select<CodeInstruction, ValueTuple<CodeInstruction, int>>((global::System.Collections.Generic.IEnumerable<CodeInstruction>)val, (Func<CodeInstruction, int, ValueTuple<CodeInstruction, int>>)((CodeInstruction op, int i) => new ValueTuple<CodeInstruction, int>(op, i))), (Func<ValueTuple<CodeInstruction, int>, bool>)((ValueTuple<CodeInstruction, int> p) => CodeInstructionExtensions.Calls(p.Item1, target))));
		if (array.Length != 2)
		{
			throw new InvalidOperationException("The search visibility updates have an unexpected format.");
		}
		ValueTuple<CodeInstruction, int> val2 = array[0];
		CodeInstruction item = val2.Item1;
		int item2 = val2.Item2;
		if (item2 == 0 || val[item2 - 1].opcode != OpCodes.Ldc_I4_1)
		{
			throw new InvalidOperationException("The search reset activation has an unexpected format.");
		}
		val[item2 - 1].opcode = OpCodes.Ldarg_0;
		item.opcode = OpCodes.Call;
		item.operand = AccessTools.Method(typeof(ContactsPatches), "QueueRestore", (global::System.Type[])null, (global::System.Type[])null);
		return (global::System.Collections.Generic.IEnumerable<CodeInstruction>)val;
	}

	internal static ValueTuple<int, int, long, string> SortKey(Contact contact, OnlineStatus status, bool unread)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Invalid comparison between Unknown and I4
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected I4, but got Unknown
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		int num;
		if (contact.IsPartiallyMigrated)
		{
			num = 10;
		}
		else
		{
			int num2 = (((int)contact.ContactStatus != 2) ? ((status - 2) switch
			{
				3 => 0, 
				2 => 1, 
				0 => 3, 
				1 => 4, 
				_ => 5, 
			}) : 2);
			num = num2;
		}
		int num3 = num;
		return new ValueTuple<int, int, long, string>((!unread) ? 1 : 0, num3, -contact.LatestMessageTime.Ticks, contact.ContactUsername);
	}

	internal static ValueTuple<List<ContactData>, Dictionary<string, int>> Prepare(List<ContactData> snapshot, Func<ContactData, int> unreadCount)
	{
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		ValueTuple<ContactData, ValueTuple<int, int, long, string>>[] array = Enumerable.ToArray<ValueTuple<ContactData, ValueTuple<int, int, long, string>>>((global::System.Collections.Generic.IEnumerable<ValueTuple<ContactData, ValueTuple<int, int, long, string>>>)Enumerable.OrderBy<ValueTuple<ContactData, ValueTuple<int, int, long, string>>, ValueTuple<int, int, long, string>>(Enumerable.Select<ContactData, ValueTuple<ContactData, ValueTuple<int, int, long, string>>>((global::System.Collections.Generic.IEnumerable<ContactData>)snapshot, (Func<ContactData, ValueTuple<ContactData, ValueTuple<int, int, long, string>>>)delegate(ContactData data)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Contact contact = data.Contact;
			UserStatus currentStatus = data.CurrentStatus;
			OnlineStatus valueOrDefault = ((currentStatus != null) ? currentStatus.OnlineStatus : ((OnlineStatus?)null)).GetValueOrDefault();
			int num = unreadCount.Invoke(data);
			return new ValueTuple<ContactData, ValueTuple<int, int, long, string>>(data, SortKey(contact, valueOrDefault, num > 0));
		}), (Func<ValueTuple<ContactData, ValueTuple<int, int, long, string>>, ValueTuple<int, int, long, string>>)((ValueTuple<ContactData, ValueTuple<int, int, long, string>> entry) => entry.Item2)));
		return new ValueTuple<List<ContactData>, Dictionary<string, int>>(Enumerable.ToList<ContactData>(Enumerable.Select<ValueTuple<ContactData, ValueTuple<int, int, long, string>>, ContactData>((global::System.Collections.Generic.IEnumerable<ValueTuple<ContactData, ValueTuple<int, int, long, string>>>)array, (Func<ValueTuple<ContactData, ValueTuple<int, int, long, string>>, ContactData>)((ValueTuple<ContactData, ValueTuple<int, int, long, string>> entry) => entry.Item1))), Enumerable.ToDictionary<ValueTuple<string, int>, string, int>(Enumerable.Select<ValueTuple<ContactData, ValueTuple<int, int, long, string>>, ValueTuple<string, int>>((global::System.Collections.Generic.IEnumerable<ValueTuple<ContactData, ValueTuple<int, int, long, string>>>)array, (Func<ValueTuple<ContactData, ValueTuple<int, int, long, string>>, int, ValueTuple<string, int>>)((ValueTuple<ContactData, ValueTuple<int, int, long, string>> entry, int index) => new ValueTuple<string, int>(entry.Item1.UserId, index))), (Func<ValueTuple<string, int>, string>)((ValueTuple<string, int> entry) => entry.Item1), (Func<ValueTuple<string, int>, int>)((ValueTuple<string, int> entry) => entry.Item2)));
	}

	private static void Start(ContactManager manager, Action<ContactData> update)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Expected O, but got Unknown
		<>c__DisplayClass18_0 CS$<>8__locals13 = new <>c__DisplayClass18_0();
		CS$<>8__locals13.manager = manager;
		object target = ((global::System.Delegate)(object)update).Target;
		CS$<>8__locals13.dialog = (ContactsDialog)((target is ContactsDialog) ? target : null);
		if (CS$<>8__locals13.dialog == null)
		{
			ReportError?.Invoke((global::System.Exception)new InvalidOperationException("Unexpected contact loading target; using the original enumeration."));
			CS$<>8__locals13.manager.ForeachContactData(update);
			return;
		}
		CS$<>8__locals13.state = new Loading(CS$<>8__locals13.manager, update);
		Pending.Add(CS$<>8__locals13.dialog, CS$<>8__locals13.state);
		SortRequested.Invoke(CS$<>8__locals13.dialog) = false;
		CS$<>8__locals13.messages = ((SkyFrostInterface)((Worker)CS$<>8__locals13.dialog).Cloud).Messages;
		((Worker)CS$<>8__locals13.dialog).StartTask((Func<global::System.Threading.Tasks.Task>)([AsyncStateMachine(typeof(<>c__DisplayClass18_0.<<Start>b__0>d))] () =>
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			<>c__DisplayClass18_0.<<Start>b__0>d <<Start>b__0>d = default(<>c__DisplayClass18_0.<<Start>b__0>d);
			<<Start>b__0>d.<>t__builder = AsyncTaskMethodBuilder.Create();
			<<Start>b__0>d.<>4__this = CS$<>8__locals13;
			<<Start>b__0>d.<>1__state = -1;
			((AsyncTaskMethodBuilder)(ref <<Start>b__0>d.<>t__builder)).Start<<>c__DisplayClass18_0.<<Start>b__0>d>(ref <<Start>b__0>d);
			return ((AsyncTaskMethodBuilder)(ref <<Start>b__0>d.<>t__builder)).Task;
		}));
	}

	private static void UpdateSpacer(ContactsDialog dialog, Loading state)
	{
		if (state.ReservedRows == 0)
		{
			return;
		}
		if (state.ReservedRows < 0)
		{
			state.ReservedRows = Enumerable.Count<ContactData>((global::System.Collections.Generic.IEnumerable<ContactData>)state.Contacts, (Func<ContactData, bool>)((ContactData data) => !data.Contact.ShouldBeHidden));
		}
		int num = state.ReservedRows - Items.Invoke(dialog).Count;
		Slot root = ListUI.Invoke(dialog).Root;
		VerticalLayout component = ((ContainerWorker<Component>)(object)root).GetComponent<VerticalLayout>((Predicate<VerticalLayout>)null, false);
		if (num <= 0 || component == null)
		{
			state.ClearSpacer();
			return;
		}
		if (state.Spacer == null)
		{
			state.Spacer = root.AddSlot("SmoothContacts Spacer", true);
			state.Spacer.OrderOffset = 9223372036854775807L;
			((ContainerWorker<Component>)(object)state.Spacer).AttachComponent<RectTransform>(true, (Action<RectTransform>)null);
			((ContainerWorker<Component>)(object)state.Spacer).AttachComponent<LayoutElement>(true, (Action<LayoutElement>)null);
		}
		float value = ((SyncField<float>)(object)((DirectionalLayout)component).Spacing).Value;
		float num2 = (float)num * (32f + value) - value;
		LayoutElement component2 = ((ContainerWorker<Component>)(object)state.Spacer).GetComponent<LayoutElement>((Predicate<LayoutElement>)null, false);
		Sync<float> minHeight = component2.MinHeight;
		float value2 = (((SyncField<float>)(object)component2.PreferredHeight).Value = num2);
		((SyncField<float>)(object)minHeight).Value = value2;
	}

	internal static bool UpdateLoading(ContactsDialog dialog)
	{
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		Loading loading = default(Loading);
		bool flag = Pending.TryGetValue(dialog, ref loading);
		PriorityQueue<ContactItem, long> val = default(PriorityQueue<ContactItem, long>);
		bool flag2 = Restoring.TryGetValue(dialog, ref val);
		if (!flag && !flag2)
		{
			return SortRequested.Invoke(dialog);
		}
		int num = Math.Max(1, BatchSize.Value);
		int num2 = num;
		StrongBox<int> value = Pauses.GetValue(dialog, (CreateValueCallback<ContactsDialog, StrongBox<int>>)((ContactsDialog _) => new StrongBox<int>()));
		try
		{
			if (loading?.Contacts != null)
			{
				string selection = loading.Selection;
				if (selection != null)
				{
					loading.Selection = null;
					dialog.OpenContactPage(selection);
				}
			}
			value.Value = Math.Min(value.Value, Math.Max(0, PauseUpdates.Value));
			if (value.Value > 0)
			{
				value.Value--;
				return !flag && SortRequested.Invoke(dialog);
			}
			if (flag2)
			{
				ContactItem val2 = default(ContactItem);
				long num3 = default(long);
				while (num2 > 0 && val.TryDequeue(ref val2, ref num3))
				{
					num2--;
					try
					{
						if (!((Worker)val2).IsRemoved && !((Component)val2).Slot.ActiveSelf)
						{
							((Component)val2).Slot.ActiveSelf = true;
						}
					}
					catch (global::System.Exception ex)
					{
						ReportError?.Invoke(ex);
					}
				}
				if (val.Count == 0)
				{
					Restoring.Remove(dialog);
				}
			}
			if (!flag)
			{
				return SortRequested.Invoke(dialog);
			}
			if (loading.Contacts == null)
			{
				return false;
			}
			string term = NormalizeQuery(Search.Invoke(dialog).Target.TargetString);
			if (loading.Position == loading.Contacts.Count)
			{
				Enumerator<string, ContactData> enumerator = loading.Deferred.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						KeyValuePair<string, ContactData> current = enumerator.Current;
						loading.Order[current.Key] = loading.Contacts.Count;
						loading.Contacts.Add(current.Value);
					}
				}
				finally
				{
					((global::System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
				loading.Deferred.Clear();
			}
			ValueTuple<int, int> val3 = loading.TakeBatch(num2);
			int item = val3.Item1;
			int item2 = val3.Item2;
			num2 -= item2 - item;
			for (int num4 = item; num4 < item2; num4++)
			{
				Generate(dialog, loading, loading.Contacts[num4], term);
			}
			if (loading.Position == loading.Contacts.Count && loading.Deferred.Count == 0)
			{
				EndLoading(dialog);
			}
			else
			{
				UpdateSpacer(dialog, loading);
			}
		}
		catch (global::System.Exception error)
		{
			Abort(dialog, error);
		}
		finally
		{
			if (num2 < num)
			{
				value.Value = Math.Max(0, PauseUpdates.Value);
			}
			Loading loading2 = default(Loading);
			PriorityQueue<ContactItem, long> val4 = default(PriorityQueue<ContactItem, long>);
			if (!Pending.TryGetValue(dialog, ref loading2) && !Restoring.TryGetValue(dialog, ref val4))
			{
				Pauses.Remove(dialog);
			}
		}
		return false;
	}

	internal static void Generate(ContactsDialog dialog, Loading state, ContactData data, string term)
	{
		ContactData val = default(ContactData);
		if (state.Deferred.Remove(data.UserId, ref val))
		{
			data = val;
		}
		if (Items.Invoke(dialog).ContainsKey(data.UserId) || state.manager.GetContact(data.UserId) != data.Contact)
		{
			return;
		}
		state.Creating = true;
		try
		{
			state.update.Invoke(data);
			ContactItem val2 = default(ContactItem);
			if (Items.Invoke(dialog).TryGetValue(data.UserId, ref val2))
			{
				((Component)val2).Slot.OrderOffset = state.RowOrder(data.UserId);
				if (term.Length > 0 && !MatchesSearch(val2.Username, val2.AlternateNames, term))
				{
					((Component)val2).Slot.ActiveSelf = false;
				}
			}
		}
		finally
		{
			state.Creating = false;
		}
	}

	internal static bool BeforeSelect(ContactsDialog __instance, string __0)
	{
		Loading loading = default(Loading);
		if (string.IsNullOrEmpty(__0) || !Pending.TryGetValue(__instance, ref loading))
		{
			return true;
		}
		loading.Selection = null;
		if (Items.Invoke(__instance).ContainsKey(__0) || Enumerable.Any<ContactItem>((global::System.Collections.Generic.IEnumerable<ContactItem>)SearchResults.Invoke(__instance), (Func<ContactItem, bool>)((ContactItem item) => item.Contact.ContactUserId == __0)))
		{
			return true;
		}
		if (loading.Contacts == null || !((Component)__instance).Slot.IsActive)
		{
			loading.Selection = __0;
			return false;
		}
		try
		{
			ContactData data = null;
			int num = default(int);
			if (loading.Order.TryGetValue(__0, ref num))
			{
				data = loading.Contacts[num];
			}
			else
			{
				loading.manager.ForeachContactData((Action<ContactData>)delegate(ContactData candidate)
				{
					if (candidate.UserId == __0)
					{
						data = candidate;
					}
				});
			}
			if (data != null)
			{
				Generate(__instance, loading, data, NormalizeQuery(Search.Invoke(__instance).Target.TargetString));
			}
			if (Items.Invoke(__instance).ContainsKey(__0))
			{
				UpdateSpacer(__instance, loading);
			}
			else
			{
				loading.ClearSpacer();
			}
		}
		catch (global::System.Exception error)
		{
			Abort(__instance, error);
			throw;
		}
		return true;
	}

	internal static bool BeforeItem(ContactsDialog __instance, ContactData __0)
	{
		Loading loading = default(Loading);
		if (Pending.TryGetValue(__instance, ref loading) && !loading.Creating && !Items.Invoke(__instance).ContainsKey(__0.UserId))
		{
			loading.Deferred[__0.UserId] = __0;
			SortRequested.Invoke(__instance) = true;
			return false;
		}
		return true;
	}

	internal static void BeforeSearch(ContactsDialog __instance)
	{
		Restoring.Remove(__instance);
		Pauses.Remove(__instance);
		Loading loading = default(Loading);
		if (Pending.TryGetValue(__instance, ref loading))
		{
			loading.ClearSpacer();
		}
	}

	internal static void QueueRestore(Slot slot, ContactsDialog dialog)
	{
		if (!slot.ActiveSelf)
		{
			Restoring.GetValue(dialog, (CreateValueCallback<ContactsDialog, PriorityQueue<ContactItem, long>>)((ContactsDialog _) => new PriorityQueue<ContactItem, long>())).Enqueue(((ContainerWorker<Component>)(object)slot).GetComponent<ContactItem>((Predicate<ContactItem>)null, false), slot.OrderOffset);
		}
	}

	internal static string NormalizeQuery(string? query)
	{
		return query?.Trim().ToLower() ?? "";
	}

	internal static bool MatchesSearch(string username, global::System.Collections.Generic.IEnumerable<string> alternateNames, string term)
	{
		if (term.Length == 0)
		{
			return true;
		}
		if (username.StartsWith(term, (StringComparison)3))
		{
			return true;
		}
		global::System.Collections.Generic.IEnumerator<string> enumerator = alternateNames.GetEnumerator();
		try
		{
			while (((global::System.Collections.IEnumerator)enumerator).MoveNext())
			{
				if (enumerator.Current.StartsWith(term, (StringComparison)2))
				{
					return true;
				}
			}
		}
		finally
		{
			((global::System.IDisposable)enumerator)?.Dispose();
		}
		return false;
	}

	internal static void RequestActivationSort(ContactsDialog dialog, bool requested)
	{
		Loading loading = default(Loading);
		if (!Pending.TryGetValue(dialog, ref loading))
		{
			SortRequested.Invoke(dialog) = requested;
		}
	}

	internal static void RequestItemSort(ContactsDialog dialog, bool requested)
	{
		Loading loading = default(Loading);
		if (!Pending.TryGetValue(dialog, ref loading) || !loading.Creating)
		{
			SortRequested.Invoke(dialog) = requested;
		}
	}

	private static void Abort(ContactsDialog dialog, global::System.Exception error)
	{
		EndLoading(dialog);
		SortRequested.Invoke(dialog) = true;
		ReportError?.Invoke(error);
	}

	private static void EndLoading(ContactsDialog dialog)
	{
		Loading loading = default(Loading);
		if (Pending.TryGetValue(dialog, ref loading))
		{
			loading.ClearSpacer();
		}
		Pending.Remove(dialog);
	}

	internal static void OnDispose(ContactsDialog __instance)
	{
		EndLoading(__instance);
		Restoring.Remove(__instance);
		Pauses.Remove(__instance);
	}
}