Decompiled source of SharePermissions v2.4.2

SharePermissions.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using MenuLib.Structs;
using Microsoft.CodeAnalysis;
using POpusCodec.Enums;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice;
using Photon.Voice.Unity;
using SharePermissions.Core;
using SharePermissions.Net;
using SharePermissions.Net.Commands;
using SharePermissions.Patches;
using SharePermissions.Players;
using SharePermissions.UI;
using SharePermissions.Voice;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("RED")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.4.2.0")]
[assembly: AssemblyInformationalVersion("2.4.2+7581cc1fa5ca36b471ae197025cadb2d1e834ffe")]
[assembly: AssemblyProduct("SharePermissions")]
[assembly: AssemblyTitle("SharePermissions")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.4.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 SharePermissions.Voice
{
	internal sealed class MicRing
	{
		private readonly float[] buffer;

		private volatile int writeIndex;

		private volatile int readIndex;

		private volatile float level;

		internal float Level => level;

		internal int Available
		{
			get
			{
				int num = writeIndex;
				int num2 = readIndex;
				if (num < num2)
				{
					return buffer.Length - num2 + num;
				}
				return num - num2;
			}
		}

		internal MicRing(int capacity)
		{
			if (capacity < 2)
			{
				capacity = 2;
			}
			buffer = new float[capacity];
		}

		internal void Write(float[] data, int count)
		{
			if (data != null && count > 0)
			{
				if (count > data.Length)
				{
					count = data.Length;
				}
				float num = 0f;
				for (int i = 0; i < count; i++)
				{
					num += Math.Abs(data[i]);
				}
				level = num / (float)count;
				int num2 = writeIndex;
				int num3 = buffer.Length - 1 - Available;
				if (count > num3)
				{
					count = num3;
				}
				for (int j = 0; j < count; j++)
				{
					buffer[num2] = data[j];
					num2 = ((num2 + 1 != buffer.Length) ? (num2 + 1) : 0);
				}
				writeIndex = num2;
			}
		}

		internal bool Read(float[] destination)
		{
			if (destination == null || destination.Length == 0)
			{
				return false;
			}
			if (Available < destination.Length)
			{
				return false;
			}
			int num = readIndex;
			for (int i = 0; i < destination.Length; i++)
			{
				destination[i] = buffer[num];
				num = ((num + 1 != buffer.Length) ? (num + 1) : 0);
			}
			readIndex = num;
			return true;
		}

		internal void Reset()
		{
			readIndex = 0;
			writeIndex = 0;
			level = 0f;
		}
	}
	[HarmonyPatch(typeof(MicWrapper), "Read")]
	internal static class MicTee
	{
		private const int RingCapacity = 48000;

		internal static readonly MicRing Ring = new MicRing(48000);

		private static volatile int samplingRate;

		private static volatile int channels;

		internal static int SamplingRate => samplingRate;

		internal static int Channels => channels;

		internal static bool IsLive
		{
			get
			{
				if (SamplingRate > 0)
				{
					return Channels > 0;
				}
				return false;
			}
		}

		internal static float Level => Ring.Level;

		[HarmonyPostfix]
		[HarmonyWrapSafe]
		private static void Read_Postfix(MicWrapper __instance, float[] buffer, bool __result)
		{
			if (__result && buffer != null && PrivateVoiceGate.WantCapture)
			{
				channels = __instance.Channels;
				samplingRate = __instance.SamplingRate;
				Ring.Write(buffer, buffer.Length);
			}
		}

		internal static void Flush()
		{
			Ring.Reset();
			Plugin.Logger.LogDebug((object)"Private voice: mic tee flushed");
		}
	}
	internal static class PrivateVoiceGate
	{
		internal static volatile bool WantCapture;
	}
	internal static class PrivateSpeakers
	{
		private sealed class Entry
		{
			internal GameObject Go;

			internal Speaker Speaker;

			internal AudioSource Source;

			internal PrivateSpeakerGain Gain;

			internal int Actor;

			internal volatile float Amplitude;
		}

		private static readonly Dictionary<int, Entry> ByPlayerId = new Dictionary<int, Entry>();

		private static readonly HashSet<Speaker> AmplitudeAttached = new HashSet<Speaker>();

		private static float volume = 1f;

		internal static Speaker? Create(int playerId, object userData)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			if (!(userData is int num) || num <= 0)
			{
				Plugin.Logger.LogWarning((object)$"Private voice: stream {playerId} carried no usable actor claim - refusing");
				return null;
			}
			if (!PrivateVoiceChannel.IsMemberActor(num))
			{
				Plugin.Logger.LogWarning((object)$"Private voice: stream from non-member actor {num} - refusing to play");
				return null;
			}
			foreach (KeyValuePair<int, Entry> item in ByPlayerId)
			{
				if (item.Key != playerId && item.Value.Actor == num)
				{
					Plugin.Logger.LogWarning((object)$"Private voice: actor {num} already claimed by another stream - refusing");
					return null;
				}
			}
			if (ByPlayerId.TryGetValue(playerId, out Entry value))
			{
				return value.Speaker;
			}
			GameObject val = new GameObject($"SP_PrivSpeaker_a{num}");
			Object.DontDestroyOnLoad((Object)(object)val);
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.spatialBlend = 0f;
			val2.mute = false;
			val2.dopplerLevel = 0f;
			val2.priority = 0;
			val2.outputAudioMixerGroup = null;
			val2.bypassEffects = false;
			val2.bypassListenerEffects = true;
			val2.bypassReverbZones = true;
			PrivateSpeakerGain gain = val.AddComponent<PrivateSpeakerGain>();
			Speaker val3 = val.AddComponent<Speaker>();
			Entry entry = new Entry
			{
				Go = val,
				Speaker = val3,
				Source = val2,
				Gain = gain,
				Actor = num
			};
			ByPlayerId[playerId] = entry;
			Apply(entry, volume);
			val3.OnRemoteVoiceRemoveAction = delegate(Speaker s)
			{
				ByPlayerId.Remove(playerId);
				if ((Object)(object)s != (Object)null && (Object)(object)((Component)s).gameObject != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)s).gameObject);
				}
			};
			Plugin.Logger.LogInfo((object)$"Private voice: speaker for actor {num}");
			return val3;
		}

		internal static void AttachAmplitude(Speaker speaker)
		{
			if ((Object)(object)speaker == (Object)null)
			{
				return;
			}
			RemoteVoiceLink remoteVoice = speaker.RemoteVoice;
			if (remoteVoice == null)
			{
				return;
			}
			Entry entry = null;
			foreach (KeyValuePair<int, Entry> item in ByPlayerId)
			{
				if (item.Value.Speaker == speaker)
				{
					entry = item.Value;
					break;
				}
			}
			if (entry == null || !AmplitudeAttached.Add(speaker))
			{
				return;
			}
			remoteVoice.FloatFrameDecoded += delegate(FrameOut<float> frame)
			{
				float[] buf = frame.Buf;
				if (buf != null && buf.Length != 0)
				{
					float num = 0f;
					for (int i = 0; i < buf.Length; i++)
					{
						num += ((buf[i] < 0f) ? (0f - buf[i]) : buf[i]);
					}
					entry.Amplitude = num / (float)buf.Length;
				}
			};
		}

		internal static void DestroyAll()
		{
			foreach (KeyValuePair<int, Entry> item in ByPlayerId)
			{
				Entry value = item.Value;
				if ((Object)(object)value.Speaker != (Object)null)
				{
					value.Speaker.OnRemoteVoiceRemoveAction = null;
				}
				if ((Object)(object)value.Go != (Object)null)
				{
					Object.Destroy((Object)(object)value.Go);
				}
			}
			ByPlayerId.Clear();
			AmplitudeAttached.Clear();
		}

		internal static float AmplitudeFor(int actorNumber)
		{
			foreach (KeyValuePair<int, Entry> item in ByPlayerId)
			{
				if (item.Value.Actor == actorNumber)
				{
					return item.Value.Amplitude;
				}
			}
			return 0f;
		}

		internal static int[] SpeakingActors()
		{
			List<int> list = new List<int>(ByPlayerId.Count);
			foreach (KeyValuePair<int, Entry> item in ByPlayerId)
			{
				list.Add(item.Value.Actor);
			}
			return list.ToArray();
		}

		internal static void SetVolume(float value)
		{
			if (value < 0f)
			{
				value = 0f;
			}
			float num = 3f;
			if (value > num)
			{
				value = num;
			}
			volume = value;
			foreach (KeyValuePair<int, Entry> item in ByPlayerId)
			{
				Apply(item.Value, value);
			}
		}

		private static void Apply(Entry entry, float value)
		{
			if ((Object)(object)entry.Source != (Object)null)
			{
				entry.Source.volume = ((value > 1f) ? 1f : value);
			}
			if ((Object)(object)entry.Gain != (Object)null)
			{
				entry.Gain.Gain = ((value > 1f) ? value : 1f);
			}
		}
	}
	internal sealed class PrivateSpeakerGain : MonoBehaviour
	{
		private volatile float gain = 1f;

		internal float Gain
		{
			get
			{
				return gain;
			}
			set
			{
				gain = ((value < 1f) ? 1f : value);
			}
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			float num = gain;
			if (num != 1f)
			{
				for (int i = 0; i < data.Length; i++)
				{
					data[i] *= num;
				}
			}
		}
	}
	internal sealed class PrivateVoiceClient : VoiceFollowClient
	{
		private const float ConnectWarnCooldownSeconds = 5f;

		private const float ConnectRetryCooldownSeconds = 3f;

		private static bool quitting;

		private string token = string.Empty;

		private Recorder? recorder;

		private int userDataActor;

		private float nextConnectWarnAt;

		private float nextConnectAttemptAt;

		internal static PrivateVoiceClient? Instance { get; private set; }

		internal static bool EverCreated { get; private set; }

		internal Recorder? PrivateRecorder => recorder;

		protected override bool LeaderInRoom
		{
			get
			{
				if (PhotonNetwork.InRoom)
				{
					return PrivateVoiceChannel.IsValidRoomName(token);
				}
				return false;
			}
		}

		protected override bool LeaderOfflineMode => PhotonNetwork.OfflineMode;

		internal static void Init()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("SP_PrivateVoice")
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)(object)val);
				Instance = val.AddComponent<PrivateVoiceClient>();
				((VoiceConnection)Instance).SpeakerLinked += PrivateSpeakers.AttachAmplitude;
				EverCreated = true;
				Application.quitting += delegate
				{
					quitting = true;
				};
				Plugin.Logger.LogInfo((object)"Private voice client created");
			}
		}

		internal void Provision(string roomName)
		{
			if (!PrivateVoiceChannel.IsValidRoomName(roomName))
			{
				Plugin.Logger.LogWarning((object)"Private voice: refusing a malformed room name");
				return;
			}
			PrivateVoiceGate.WantCapture = true;
			bool flag = PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null && PhotonNetwork.LocalPlayer.ActorNumber > 0;
			if ((Object)(object)recorder == (Object)null)
			{
				if (flag && MicTee.IsLive)
				{
					CreateRecorder();
				}
			}
			else if (flag)
			{
				SyncUserData(recorder);
			}
			bool flag2 = ((VoiceConnection)this).Client != null && ((LoadBalancingClient)((VoiceConnection)this).Client).IsConnected;
			if (roomName == token && flag2)
			{
				return;
			}
			if (token.Length > 0 && roomName != token)
			{
				token = string.Empty;
				SafeDisconnect();
				return;
			}
			if (token.Length == 0)
			{
				if (flag2)
				{
					return;
				}
				token = roomName;
			}
			if (!(((VoiceConnection)this).Client == null || flag2) && PhotonNetwork.InRoom && !(Time.unscaledTime < nextConnectAttemptAt))
			{
				nextConnectAttemptAt = Time.unscaledTime + 3f;
				if (!((VoiceFollowClient)this).ConnectAndJoinRoom() && Time.unscaledTime >= nextConnectWarnAt)
				{
					nextConnectWarnAt = Time.unscaledTime + 5f;
					Plugin.Logger.LogWarning((object)("Private voice: connect/join refused for room " + PrivateVoiceChannel.Fingerprint(roomName)));
				}
			}
		}

		protected override void Start()
		{
			((VoiceFollowClient)this).Start();
			if (PhotonNetwork.NetworkingClient != null)
			{
				PhotonNetwork.NetworkingClient.StateChanged += OnLeaderStateChanged;
			}
		}

		private void OnLeaderStateChanged(ClientState fromState, ClientState toState)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			((VoiceFollowClient)this).LeaderStateChanged(toState);
		}

		protected override void OnDestroy()
		{
			if (Instance == this && !quitting)
			{
				Plugin.Logger.LogWarning((object)"Private voice: SP_PrivateVoice is being destroyed - the private channel cannot run again this session");
			}
			if (PhotonNetwork.NetworkingClient != null)
			{
				PhotonNetwork.NetworkingClient.StateChanged -= OnLeaderStateChanged;
			}
			((VoiceFollowClient)this).OnDestroy();
		}

		private void CreateRecorder()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SP_PrivateRecorder");
			val.transform.SetParent(((Component)this).transform, false);
			Recorder val2 = val.AddComponent<Recorder>();
			PrivateVoiceDsp.Mirror(val);
			val2.SourceType = (InputSourceType)2;
			val2.MicrophoneType = (MicType)1;
			val2.InputFactory = () => (IAudioDesc)(object)new TeeAudioReader();
			userDataActor = PhotonNetwork.LocalPlayer.ActorNumber;
			val2.UserData = userDataActor;
			val2.TransmitEnabled = false;
			val2.VoiceDetection = false;
			val2.Encrypt = true;
			val2.DebugEchoMode = false;
			val2.InterestGroup = 0;
			val2.TargetPlayers = null;
			val2.SamplingRate = NearestSupportedRate(MicTee.SamplingRate);
			((VoiceConnection)this).PrimaryRecorder = val2;
			if (!((VoiceConnection)this).AddRecorder(val2))
			{
				Plugin.Logger.LogWarning((object)"Private voice: AddRecorder refused - the recorder will never transmit");
				Object.Destroy((Object)(object)val);
			}
			else
			{
				recorder = val2;
				Plugin.Logger.LogInfo((object)$"Private voice recorder ready ({MicTee.SamplingRate} Hz, {MicTee.Channels} ch)");
			}
		}

		private void SyncUserData(Recorder rec)
		{
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			if (actorNumber != userDataActor)
			{
				userDataActor = actorNumber;
				rec.UserData = actorNumber;
				Plugin.Logger.LogInfo((object)"Private voice: local actor number changed, rebinding recorder identity");
			}
		}

		private static SamplingRate NearestSupportedRate(int hz)
		{
			//IL_0041: 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_004a: 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_0031: 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)
			if (hz <= 20000)
			{
				if (hz > 10000)
				{
					if (hz <= 14000)
					{
						return (SamplingRate)12000;
					}
					return (SamplingRate)16000;
				}
				return (SamplingRate)8000;
			}
			if (hz <= 36000)
			{
				return (SamplingRate)24000;
			}
			return (SamplingRate)48000;
		}

		internal bool ChannelLive(string expectedRoom)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			if (((VoiceConnection)this).Client == null || (int)((LoadBalancingClient)((VoiceConnection)this).Client).State != 9)
			{
				return false;
			}
			Room currentRoom = ((LoadBalancingClient)((VoiceConnection)this).Client).CurrentRoom;
			if (currentRoom != null && currentRoom.Name == expectedRoom)
			{
				return PrivateVoiceChannel.IsValidRoomName(currentRoom.Name);
			}
			return false;
		}

		private void SafeDisconnect()
		{
			if (((VoiceConnection)this).Client != null && ((LoadBalancingClient)((VoiceConnection)this).Client).IsConnected)
			{
				((VoiceFollowClient)this).Disconnect();
			}
		}

		internal void TearDown()
		{
			if ((Object)(object)recorder != (Object)null)
			{
				recorder.TransmitEnabled = false;
			}
			PrivateSpeakers.DestroyAll();
			SafeDisconnect();
			PrivateVoiceGate.WantCapture = false;
			MicTee.Flush();
			token = string.Empty;
			nextConnectWarnAt = 0f;
			nextConnectAttemptAt = 0f;
		}

		protected override string GetVoiceRoomName()
		{
			return token;
		}

		protected override bool ConnectVoice()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0026: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0076: Expected O, but got Unknown
			AppSettings val = null;
			((LoadBalancingClient)((VoiceConnection)this).Client).ServerPortOverrides = PhotonNetwork.ServerPortOverrides;
			val = PhotonNetwork.PhotonServerSettings.AppSettings.CopyTo(new AppSettings());
			if (!string.IsNullOrEmpty(PhotonNetwork.CloudRegion))
			{
				val.FixedRegion = PhotonNetwork.CloudRegion;
			}
			((LoadBalancingClient)((VoiceConnection)this).Client).SerializationProtocol = PhotonNetwork.NetworkingClient.SerializationProtocol;
			if (PhotonNetwork.AuthValues != null)
			{
				LoadBalancingTransport client = ((VoiceConnection)this).Client;
				if (((LoadBalancingClient)client).AuthValues == null)
				{
					AuthenticationValues val2 = new AuthenticationValues();
					AuthenticationValues val3 = val2;
					((LoadBalancingClient)client).AuthValues = val2;
				}
				((LoadBalancingClient)((VoiceConnection)this).Client).AuthValues = PhotonNetwork.AuthValues.CopyTo(((LoadBalancingClient)((VoiceConnection)this).Client).AuthValues);
			}
			((LoadBalancingClient)((VoiceConnection)this).Client).AuthMode = PhotonNetwork.NetworkingClient.AuthMode;
			((LoadBalancingClient)((VoiceConnection)this).Client).EncryptionMode = PhotonNetwork.NetworkingClient.EncryptionMode;
			return ((VoiceConnection)this).ConnectUsingSettings(val);
		}

		protected override bool JoinVoiceRoom(string voiceRoomName)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0046: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_006a: Expected O, but got Unknown
			//IL_006b: Expected O, but got Unknown
			if (!PrivateVoiceChannel.IsValidRoomName(voiceRoomName))
			{
				Plugin.Logger.LogWarning((object)"Private voice: join refused, malformed room name");
				return false;
			}
			RoomOptions roomOptions = new RoomOptions
			{
				IsVisible = false,
				IsOpen = true,
				MaxPlayers = 0,
				PlayerTtl = 2000,
				PublishUserId = true
			};
			EnterRoomParams val = new EnterRoomParams
			{
				RoomName = voiceRoomName,
				RoomOptions = roomOptions,
				Lobby = new TypedLobby("spv", (LobbyType)0)
			};
			Plugin.Logger.LogInfo((object)("Private voice: joining room " + PrivateVoiceChannel.Fingerprint(voiceRoomName)));
			return ((LoadBalancingClient)((VoiceConnection)this).Client).OpJoinOrCreateRoom(val);
		}

		protected override void OnOperationResponseReceived(OperationResponse operationResponse)
		{
			if (operationResponse.ReturnCode == 0)
			{
				((VoiceFollowClient)this).OnOperationResponseReceived(operationResponse);
				return;
			}
			Plugin.Logger.LogWarning((object)$"Private voice: op {operationResponse.OperationCode} failed ({operationResponse.ReturnCode})");
			if (operationResponse.OperationCode != 226)
			{
				((VoiceFollowClient)this).OnOperationResponseReceived(operationResponse);
				return;
			}
			string roomName = token;
			try
			{
				token = PrivateVoiceChannel.Fingerprint(roomName);
				((VoiceFollowClient)this).OnOperationResponseReceived(operationResponse);
			}
			finally
			{
				token = roomName;
			}
		}

		protected override Speaker? InstantiateSpeakerForRemoteVoice(int playerId, byte voiceId, object userData)
		{
			try
			{
				return PrivateSpeakers.Create(playerId, userData);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Private voice: speaker construction failed: {arg}");
				return null;
			}
		}
	}
	internal static class PrivateVoiceDriver
	{
		internal enum Health
		{
			Off,
			Provisioning,
			Live,
			Listening,
			Failed
		}

		private const float ReleaseGraceSeconds = 0.3f;

		private const float IntrusionConfirmSeconds = 2f;

		private const float MissingClientWarnCooldownSeconds = 5f;

		private static bool lastVoiceJoined;

		private static float releaseAt;

		private static float nextMissingClientWarnAt;

		private static string provisionedRoom = string.Empty;

		private static float unexpectedOccupantFirstSeenAt = -1f;

		internal static Health State { get; private set; } = Health.Off;

		internal static void Tick()
		{
			int num = ((PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0);
			PrivateVoiceChannel.SetLocalMembership(num > 0 && PrivateVoiceChannel.IsMemberActor(num));
			bool localActive = PrivateVoiceChannel.LocalActive;
			if (!localActive && provisionedRoom.Length > 0)
			{
				TearDown("mode off");
			}
			RecorderTransmitPatch.Suppress = localActive || Time.realtimeSinceStartup < releaseAt;
			if (!localActive)
			{
				if (Time.realtimeSinceStartup < releaseAt)
				{
					ForceGameRecorderOff();
				}
				State = Health.Off;
				return;
			}
			ForceGameRecorderOff();
			PrivateSpeakers.SetVolume(GameVolume() * PrivateVoiceLocalPrefs.Factor);
			PrivateVoiceClient instance = PrivateVoiceClient.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				if (Time.realtimeSinceStartup >= nextMissingClientWarnAt)
				{
					nextMissingClientWarnAt = Time.realtimeSinceStartup + 5f;
					Plugin.Logger.LogWarning((object)(PrivateVoiceClient.EverCreated ? "Private voice: the voice client was created at startup but no longer exists - something destroyed the SP_PrivateVoice object, so the channel cannot run" : "Private voice: the voice client was never created - PrivateVoiceClient.Init did not run or threw"));
				}
				State = Health.Failed;
				return;
			}
			string roomName = PrivateVoiceChannel.RoomName;
			if (provisionedRoom != roomName)
			{
				if (provisionedRoom.Length > 0)
				{
					TearDown("room rotated");
				}
				else
				{
					MicTee.Flush();
				}
				instance.Provision(roomName);
				provisionedRoom = roomName;
				State = Health.Provisioning;
				return;
			}
			if ((Object)(object)instance.PrivateRecorder == (Object)null)
			{
				instance.Provision(roomName);
				bool flag = instance.ChannelLive(roomName);
				if (!lastVoiceJoined && flag)
				{
					MicTee.Flush();
				}
				lastVoiceJoined = flag;
				State = ((!flag) ? Health.Provisioning : Health.Listening);
				return;
			}
			bool flag2 = instance.ChannelLive(roomName);
			if (!lastVoiceJoined && flag2)
			{
				MicTee.Flush();
			}
			if (lastVoiceJoined && !flag2)
			{
				Plugin.Logger.LogInfo((object)"Private voice: channel dropped, re-provisioning");
			}
			lastVoiceJoined = flag2;
			if (!flag2)
			{
				instance.Provision(roomName);
				SetPrivateTransmit(on: false);
				State = Health.Provisioning;
				return;
			}
			AuditOccupants();
			if (State == Health.Failed)
			{
				return;
			}
			Recorder privateRecorder = instance.PrivateRecorder;
			if ((Object)(object)privateRecorder != (Object)null && privateRecorder.RecordingEnabled)
			{
				if (privateRecorder.InterestGroup != 0)
				{
					privateRecorder.InterestGroup = 0;
				}
				if (privateRecorder.TargetPlayers != null)
				{
					privateRecorder.TargetPlayers = null;
				}
			}
			SetPrivateTransmit(GameMicAllows() && !PrivateVoiceLocalPrefs.MicMuted);
			State = Health.Live;
		}

		private static void AuditOccupants()
		{
			PrivateVoiceClient? instance = PrivateVoiceClient.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				LoadBalancingTransport client = ((VoiceConnection)instance).Client;
				if (client == null)
				{
					obj = null;
				}
				else
				{
					Room currentRoom = ((LoadBalancingClient)client).CurrentRoom;
					obj = ((currentRoom != null) ? currentRoom.Players : null);
				}
			}
			Dictionary<int, Player> dictionary = (Dictionary<int, Player>)obj;
			if (dictionary == null)
			{
				return;
			}
			PlayerRegistry instance2 = PlayerRegistry.Instance;
			if (instance2 == null)
			{
				return;
			}
			int[] array = PrivateVoiceChannel.MemberActors();
			for (int i = 0; i < array.Length; i++)
			{
				if (instance2.TryGetSteamId(array[i]) == null)
				{
					return;
				}
			}
			bool flag = false;
			foreach (KeyValuePair<int, Player> item in dictionary)
			{
				Player value = item.Value;
				if (value == null || value.IsLocal || value.IsInactive)
				{
					continue;
				}
				string userId = value.UserId;
				if (string.IsNullOrEmpty(userId))
				{
					continue;
				}
				bool flag2 = false;
				for (int j = 0; j < array.Length; j++)
				{
					if (instance2.TryGetSteamId(array[j]) == userId)
					{
						flag2 = true;
						break;
					}
				}
				if (!flag2)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				unexpectedOccupantFirstSeenAt = -1f;
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (unexpectedOccupantFirstSeenAt < 0f)
			{
				unexpectedOccupantFirstSeenAt = realtimeSinceStartup;
			}
			else if (!(realtimeSinceStartup - unexpectedOccupantFirstSeenAt < 2f))
			{
				Plugin.Logger.LogWarning((object)"Private voice: unexpected occupant persisted - muting the private channel");
				SetPrivateTransmit(on: false);
				State = Health.Failed;
			}
		}

		private static bool GameMicAllows()
		{
			PlayerVoiceChat instance = PlayerVoiceChat.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (!instance.microphoneEnabled)
			{
				return false;
			}
			if ((Object)(object)DataDirector.instance == (Object)null)
			{
				return false;
			}
			if (DataDirector.instance.toggleMute)
			{
				return false;
			}
			if ((Object)(object)AudioManager.instance == (Object)null)
			{
				return false;
			}
			if (AudioManager.instance.pushToTalk && !SemiFunc.InputHold((InputKey)25))
			{
				return false;
			}
			return true;
		}

		private static float GameVolume()
		{
			if ((Object)(object)DataDirector.instance == (Object)null)
			{
				return 1f;
			}
			float num = (float)DataDirector.instance.SettingValueFetch((Setting)13) * 0.01f;
			float num2 = (float)DataDirector.instance.SettingValueFetch((Setting)4) * 0.01f;
			float num3 = num * num2;
			if (num3 < 0f)
			{
				num3 = 0f;
			}
			if (num3 > 1f)
			{
				num3 = 1f;
			}
			return num3;
		}

		private static void SetPrivateTransmit(bool on)
		{
			Recorder val = PrivateVoiceClient.Instance?.PrivateRecorder;
			if ((Object)(object)val != (Object)null && val.TransmitEnabled != on)
			{
				val.TransmitEnabled = on;
			}
		}

		private static void ForceGameRecorderOff()
		{
			PlayerVoiceChat instance = PlayerVoiceChat.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				Recorder component = ((Component)instance).GetComponent<Recorder>();
				if ((Object)(object)component != (Object)null)
				{
					RecorderTransmitPatch.ForceOff(component);
				}
			}
		}

		internal static void TearDown(string reason)
		{
			if (provisionedRoom.Length != 0 || State != Health.Off)
			{
				Plugin.Logger.LogInfo((object)("Private voice: tearing down (" + reason + ")"));
				SetPrivateTransmit(on: false);
				PrivateVoiceClient.Instance?.TearDown();
				provisionedRoom = string.Empty;
				lastVoiceJoined = false;
				unexpectedOccupantFirstSeenAt = -1f;
				State = Health.Off;
				releaseAt = Time.realtimeSinceStartup + 0.3f;
			}
		}
	}
	internal static class PrivateVoiceLocalPrefs
	{
		internal const int MaxVolumePercent = 300;

		internal static int VolumePercent => ModConfig.PrivateChannelVolume.Value;

		internal static bool Muted { get; private set; }

		internal static bool MicMuted { get; private set; }

		internal static float Factor
		{
			get
			{
				if (!Muted)
				{
					return (float)VolumePercent * 0.01f;
				}
				return 0f;
			}
		}

		internal static void SetVolumePercent(int value)
		{
			int num = ((value >= 0) ? ((value > 300) ? 300 : value) : 0);
			if (ModConfig.PrivateChannelVolume.Value != num)
			{
				ModConfig.PrivateChannelVolume.Value = num;
			}
		}

		internal static void ToggleMuted()
		{
			Muted = !Muted;
		}

		internal static void ToggleMicMuted()
		{
			MicMuted = !MicMuted;
		}
	}
	internal static class PrivateVoiceDsp
	{
		internal static void Mirror(GameObject recorderObject)
		{
			PlayerVoiceChat instance = PlayerVoiceChat.instance;
			WebRtcAudioDsp val = (((Object)(object)instance != (Object)null) ? ((Component)instance).GetComponent<WebRtcAudioDsp>() : null);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Private voice: the game's recorder carries no WebRtcAudioDsp - the private stream keeps the raw microphone level and will stay quieter than the public channel");
				return;
			}
			if (MicTee.Channels != 1)
			{
				Plugin.Logger.LogWarning((object)$"Private voice: capture is {MicTee.Channels} ch and WebRtcAudioDsp is mono-only - the DSP mirror is skipped and the private stream keeps the raw microphone level");
				return;
			}
			WebRtcAudioDsp val2 = recorderObject.AddComponent<WebRtcAudioDsp>();
			val2.AEC = val.AEC;
			val2.AecHighPass = val.AecHighPass;
			val2.ReverseStreamDelayMs = val.ReverseStreamDelayMs;
			val2.HighPass = val.HighPass;
			val2.NoiseSuppression = val.NoiseSuppression;
			val2.AGC = val.AGC;
			val2.AgcCompressionGain = val.AgcCompressionGain;
			val2.AgcTargetLevel = val.AgcTargetLevel;
			val2.Bypass = val.Bypass;
			val2.VAD = false;
			Plugin.Logger.LogInfo((object)$"Private voice: DSP mirrored from the game's recorder (AGC {OnOff(val2.AGC)} target {val2.AgcTargetLevel} dBFS / compression {val2.AgcCompressionGain} dB, noise suppression {OnOff(val2.NoiseSuppression)}, high pass {OnOff(val2.HighPass)}, AEC {OnOff(val2.AEC)}, VAD off by design, bypass {OnOff(val2.Bypass)})");
		}

		private static string OnOff(bool value)
		{
			if (!value)
			{
				return "off";
			}
			return "on";
		}
	}
	internal sealed class TeeAudioReader : IAudioReader<float>, IDataReader<float>, IDisposable, IAudioDesc
	{
		public int SamplingRate => MicTee.SamplingRate;

		public int Channels => MicTee.Channels;

		public string? Error
		{
			get
			{
				if (!MicTee.IsLive)
				{
					return "mic tee not live";
				}
				return null;
			}
		}

		public bool Read(float[] buffer)
		{
			return MicTee.Ring.Read(buffer);
		}

		public void Dispose()
		{
		}
	}
}
namespace SharePermissions.UI
{
	internal static class ColorPickerPage
	{
		private const float ContentWidth = 250f;

		private const float SwatchSize = 34f;

		private const float SwatchPitch = 38f;

		private const int SwatchesPerRow = 6;

		private static readonly IReadOnlyList<Color> FallbackPalette = (IReadOnlyList<Color>)(object)new Color[16]
		{
			ModStyle.RoleHost,
			ModStyle.RoleModerator,
			ModStyle.RoleModUser,
			ModStyle.RoleNone,
			ModStyle.SevBan,
			ModStyle.SevRevoke,
			ModStyle.SevGrant,
			ModStyle.SevFlood,
			Color.white,
			Color.red,
			Color.green,
			Color.blue,
			Color.yellow,
			Color.cyan,
			Color.magenta,
			Color.gray
		};

		internal static void Open(string title, string description, Color current, Action<Color> onPicked, string? clearCaption = null, Action? onClear = null)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			REPOPopupPage page = MenuUiHelpers.CreatePage(title, delegate
			{
			});
			MenuUiHelpers.AddLabel(page, description);
			MenuUiHelpers.AddLabel(page, "<size=75%><color=#6f7d88>Current</color>  <color=#" + NameColors.ToHex(current) + ">#" + NameColors.ToHex(current) + "</color></size>");
			foreach (IReadOnlyList<Color> item in Rows(Palette()))
			{
				AddSwatchRow(page, item, Choose);
			}
			AddHexInput(page, current, Choose);
			if (onClear != null && clearCaption != null)
			{
				MenuUiHelpers.AddScrollViewButton(page, clearCaption, delegate
				{
					MenuUiHelpers.ClosePage(page);
					onClear();
				});
			}
			MenuUiHelpers.OpenPage(page);
			void Choose(Color color)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				MenuUiHelpers.ClosePage(page);
				onPicked(color);
			}
		}

		private static void AddSwatchRow(REPOPopupPage page, IReadOnlyList<Color> colors, Action<Color> onChoose)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Expected O, but got Unknown
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				//IL_0033: 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_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject("SharePermissions_SwatchRow", new Type[1] { typeof(RectTransform) });
				RectTransform val2 = (RectTransform)val.transform;
				((Transform)val2).SetParent(scrollView, false);
				val2.anchorMin = Vector2.zero;
				val2.anchorMax = Vector2.zero;
				val2.pivot = Vector2.zero;
				val2.sizeDelta = new Vector2(250f, 34f);
				for (int i = 0; i < colors.Count; i++)
				{
					Color color = colors[i];
					REPOButton val3 = MenuAPI.CreateREPOButton("", (Action)delegate
					{
						//IL_000c: Unknown result type (might be due to invalid IL or missing references)
						onChoose(color);
					}, (Transform)(object)val2, new Vector2((float)i * 38f, 0f));
					val3.overrideButtonSize = new Vector2(34f, 34f);
					StyleSwatch(val3, color);
				}
				return val2;
			}, 0f, 2f);
		}

		private static void StyleSwatch(REPOButton button, Color color)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0061: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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)
			Image component = ((Component)button).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				((Graphic)component).color = color;
				((Graphic)component).raycastTarget = true;
			}
			if (!((Object)(object)button.menuButton == (Object)null))
			{
				button.menuButton.resizeButton = false;
				button.menuButton.customColors = true;
				button.menuButton.colorNormal = NameColors.Dimmed(color, 0.75f);
				button.menuButton.colorHover = color;
				button.menuButton.colorClick = Color.Lerp(color, Color.white, 0.95f);
			}
		}

		private static void AddHexInput(REPOPopupPage page, Color current, Action<Color> onChoose)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0030: Expected O, but got Unknown
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: 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)
				Action<string> obj = delegate(string value)
				{
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					if (NameColors.TryParseHex(value, out var color))
					{
						onChoose(color);
					}
					else
					{
						Plugin.Logger.LogInfo((object)("Name color ignored: '" + value + "' is not a #RRGGBB value"));
					}
				};
				string text = "#" + NameColors.ToHex(current);
				REPOInputField val = MenuAPI.CreateREPOInputField("Hex", obj, scrollView, default(Vector2), true, text, "");
				((TMP_Text)val.labelTMP).fontSize = 14f;
				return ((REPOElement)val).rectTransform;
			}, 4f, 2f);
			MenuUiHelpers.AddLabel(page, "<size=75%><color=#6f7d88>Or type a color as #RRGGBB and press enter.</color></size>");
		}

		private static IEnumerable<IReadOnlyList<Color>> Rows(IReadOnlyList<Color> colors)
		{
			for (int start = 0; start < colors.Count; start += 6)
			{
				yield return colors.Skip(start).Take(6).ToList();
			}
		}

		private static IReadOnlyList<Color> Palette()
		{
			try
			{
				IReadOnlyList<Color> readOnlyList = GamePaletteRaw();
				if (readOnlyList.Count > 0)
				{
					return readOnlyList;
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("[SharePermissions] Game color palette unreadable, using the built-in one: " + ex.Message));
			}
			return FallbackPalette;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static IReadOnlyList<Color> GamePaletteRaw()
		{
			MetaManager instance = MetaManager.instance;
			if ((Object)(object)instance == (Object)null || instance.colors == null)
			{
				return Array.Empty<Color>();
			}
			List<SemiColor> order = instance.colorsUIOrder;
			return (from c in instance.colors
				where (Object)(object)c != (Object)null
				orderby (order != null) ? order.IndexOf(c) : 0
				select c.color).ToList();
		}
	}
	internal sealed class ExtrasPanelController
	{
		private readonly REPOPopupPage page;

		private REPOScrollViewElement? channelHeaderElem;

		private REPOLabel? offHint;

		private REPOScrollViewElement? offHintElem;

		private string offHintCache = string.Empty;

		private REPOScrollViewElement? announceHeaderElem;

		private REPOButton? privateToggle;

		private REPOScrollViewElement? privateToggleElem;

		private REPOLabel? privateStatus;

		private REPOScrollViewElement? privateStatusElem;

		private bool privateTalking;

		private float privateTalkHoldUntil;

		private PrivateVoiceDriver.Health lastStatusState = (PrivateVoiceDriver.Health)(-1);

		private bool lastStatusMicMuted;

		private bool lastStatusTransmitting;

		private bool lastStatusShowTalkDot;

		private REPOButton? micMuteButton;

		private REPOScrollViewElement? micMuteElem;

		private string micMuteCache = string.Empty;

		private REPOButton? soundMuteButton;

		private REPOScrollViewElement? soundMuteElem;

		private string soundMuteCache = string.Empty;

		private REPOSlider? privateVolumeSlider;

		private REPOScrollViewElement? privateVolumeSliderElem;

		private REPOLabel? hotkeyHint;

		private REPOScrollViewElement? hotkeyHintElem;

		private KeyCode lastHotkeyMicMuteKey = (KeyCode)(-1);

		private KeyCode lastHotkeyDeafenKey = (KeyCode)(-1);

		private REPOInputField? announceField;

		private REPOScrollViewElement? announceFieldElem;

		private REPOButton? announceBtn;

		private REPOScrollViewElement? announceBtnElem;

		private string announceDraft = "";

		private bool tabVisible;

		internal ExtrasPanelController(REPOPopupPage page)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			this.page = page;
		}

		internal void Build()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Expected O, but got Unknown
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			channelHeaderElem = AddLabel("<size=115%>Private channel</size>");
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				privateToggle = MenuAPI.CreateREPOButton("", (Action)ModerationActions.TogglePrivateVoice, sv, default(Vector2));
				((TMP_Text)privateToggle.labelTMP).richText = true;
				((TMP_Text)privateToggle.labelTMP).fontSize = 14f;
				privateToggle.overrideButtonSize = new Vector2(250f, 24f);
				return ((REPOElement)privateToggle).rectTransform;
			}, 0f, 2f);
			privateToggleElem = Elem((Component?)(object)privateToggle);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				offHint = MenuAPI.CreateREPOLabel("", sv, default(Vector2));
				((TMP_Text)offHint.labelTMP).richText = true;
				((TMP_Text)offHint.labelTMP).fontSize = 14f;
				return ((REPOElement)offHint).rectTransform;
			}, 0f, 6f);
			offHintElem = Elem((Component?)(object)offHint);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				privateStatus = MenuAPI.CreateREPOLabel("", sv, default(Vector2));
				((TMP_Text)privateStatus.labelTMP).richText = true;
				((TMP_Text)privateStatus.labelTMP).fontSize = 14f;
				return ((REPOElement)privateStatus).rectTransform;
			}, 0f, 2f);
			privateStatusElem = Elem((Component?)(object)privateStatus);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				micMuteButton = MenuAPI.CreateREPOButton("", (Action)OnMicMuteClicked, sv, default(Vector2));
				((TMP_Text)micMuteButton.labelTMP).richText = true;
				((TMP_Text)micMuteButton.labelTMP).fontSize = 14f;
				micMuteButton.overrideButtonSize = new Vector2(250f, 24f);
				return ((REPOElement)micMuteButton).rectTransform;
			}, 0f, 2f);
			micMuteElem = Elem((Component?)(object)micMuteButton);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				soundMuteButton = MenuAPI.CreateREPOButton("", (Action)OnSoundMuteClicked, sv, default(Vector2));
				((TMP_Text)soundMuteButton.labelTMP).richText = true;
				((TMP_Text)soundMuteButton.labelTMP).fontSize = 14f;
				soundMuteButton.overrideButtonSize = new Vector2(250f, 24f);
				return ((REPOElement)soundMuteButton).rectTransform;
			}, 0f, 2f);
			soundMuteElem = Elem((Component?)(object)soundMuteButton);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				Action<int> action = OnPrivateVolumeChanged;
				int volumePercent = PrivateVoiceLocalPrefs.VolumePercent;
				privateVolumeSlider = MenuAPI.CreateREPOSlider("Private volume", "", action, sv, default(Vector2), 0, 300, volumePercent, "", "%", (BarBehavior)0);
				return ((REPOElement)privateVolumeSlider).rectTransform;
			}, 0f, 2f);
			privateVolumeSliderElem = Elem((Component?)(object)privateVolumeSlider);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				hotkeyHint = MenuAPI.CreateREPOLabel("", sv, default(Vector2));
				((TMP_Text)hotkeyHint.labelTMP).richText = true;
				((TMP_Text)hotkeyHint.labelTMP).fontSize = 14f;
				return ((REPOElement)hotkeyHint).rectTransform;
			}, 0f, 6f);
			hotkeyHintElem = Elem((Component?)(object)hotkeyHint);
			announceHeaderElem = AddLabel("<size=115%>Announcements</size>");
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				announceField = MenuAPI.CreateREPOInputField("Announce", (Action<string>)delegate(string v)
				{
					announceDraft = v ?? "";
				}, sv, default(Vector2), false, "message to everyone", "");
				((TMP_Text)announceField.labelTMP).fontSize = 14f;
				return ((REPOElement)announceField).rectTransform;
			}, 4f, 0f);
			announceFieldElem = Elem((Component?)(object)announceField);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				announceBtn = MenuAPI.CreateREPOButton("Send announcement", (Action)delegate
				{
					ModerationActions.SendAnnouncement(announceDraft);
				}, sv, default(Vector2));
				((TMP_Text)announceBtn.labelTMP).fontSize = 14f;
				return ((REPOElement)announceBtn).rectTransform;
			}, 0f, 2f);
			announceBtnElem = Elem((Component?)(object)announceBtn);
		}

		internal void SetTabVisible(bool visible)
		{
			tabVisible = visible;
			if (!visible)
			{
				SetVisibility(channelHeaderElem, visible: false);
				SetVisibility(privateToggleElem, visible: false);
				SetVisibility(offHintElem, visible: false);
				SetVisibility(privateStatusElem, visible: false);
				SetVisibility(micMuteElem, visible: false);
				SetVisibility(soundMuteElem, visible: false);
				SetVisibility(privateVolumeSliderElem, visible: false);
				SetVisibility(hotkeyHintElem, visible: false);
				SetVisibility(announceHeaderElem, visible: false);
				UnfocusAnnounceField();
				SetVisibility(announceFieldElem, visible: false);
				SetVisibility(announceBtnElem, visible: false);
			}
			else
			{
				Tick();
			}
		}

		private void UnfocusAnnounceField()
		{
			if ((Object)(object)announceField != (Object)null && (Object)(object)announceField.inputStringSystem != (Object)null)
			{
				announceField.inputStringSystem.isFocused = false;
			}
		}

		internal void Tick()
		{
			if (!((Object)(object)page == (Object)null) && tabVisible)
			{
				bool flag = SemiFunc.IsMasterClient();
				bool localActive = PrivateVoiceChannel.LocalActive;
				SetVisibility(channelHeaderElem, visible: true);
				SetVisibility(privateToggleElem, flag);
				SetVisibility(offHintElem, !flag && !localActive);
				SetVisibility(privateStatusElem, localActive);
				SetVisibility(micMuteElem, localActive);
				SetVisibility(soundMuteElem, localActive);
				SetVisibility(privateVolumeSliderElem, localActive);
				SetVisibility(hotkeyHintElem, localActive);
				SetVisibility(announceHeaderElem, flag);
				SetVisibility(announceFieldElem, flag);
				SetVisibility(announceBtnElem, flag);
				if (flag)
				{
					UpdateChannelToggle();
				}
				if (!flag && !localActive)
				{
					UpdateOffHint();
				}
				if (localActive)
				{
					UpdateStatus();
					UpdateMuteCaptions();
					UpdateHotkeyHint();
				}
				else
				{
					lastStatusState = (PrivateVoiceDriver.Health)(-1);
				}
			}
		}

		private void UpdateChannelToggle()
		{
			if (!((Object)(object)privateToggle == (Object)null))
			{
				string text = (PrivateVoiceChannel.Active ? "Private channel: <color=#4dd07a>ON</color>" : "Private channel: <color=#6f7d88>OFF</color>");
				if (((TMP_Text)privateToggle.labelTMP).text != text)
				{
					((TMP_Text)privateToggle.labelTMP).text = text;
				}
			}
		}

		private void UpdateOffHint()
		{
			if (!((Object)(object)offHint == (Object)null))
			{
				string text = "<size=75%><color=#6f7d88>Off - the host opens the private channel.</color></size>";
				if (!(text == offHintCache))
				{
					offHintCache = text;
					((TMP_Text)offHint.labelTMP).text = text;
					MenuUiHelpers.SizeWrappedLabel(offHint, text, 250f);
				}
			}
		}

		private void UpdateStatus()
		{
			if (!((Object)(object)privateStatus == (Object)null))
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				PrivateVoiceClient instance = PrivateVoiceClient.Instance;
				bool flag = (Object)(object)instance != (Object)null && (Object)(object)instance.PrivateRecorder != (Object)null && instance.PrivateRecorder.TransmitEnabled;
				if (MicTee.Level > 0.005f)
				{
					privateTalking = true;
					privateTalkHoldUntil = realtimeSinceStartup + 0.18f;
				}
				else if (realtimeSinceStartup >= privateTalkHoldUntil)
				{
					privateTalking = false;
				}
				bool flag2 = privateTalking && flag && PrivateVoiceDriver.State == PrivateVoiceDriver.Health.Live;
				PrivateVoiceDriver.Health state = PrivateVoiceDriver.State;
				bool micMuted = PrivateVoiceLocalPrefs.MicMuted;
				if (state != lastStatusState || micMuted != lastStatusMicMuted || flag != lastStatusTransmitting || flag2 != lastStatusShowTalkDot)
				{
					lastStatusState = state;
					lastStatusMicMuted = micMuted;
					lastStatusTransmitting = flag;
					lastStatusShowTalkDot = flag2;
					string text = "Private voice: " + state switch
					{
						PrivateVoiceDriver.Health.Live => (!micMuted) ? (flag ? "<color=#4dd07a>live</color>" : "<color=#6f7d88>muted</color>") : "<color=#ef5350>mic off</color>", 
						PrivateVoiceDriver.Health.Listening => "<color=#4dd07a>listening</color>", 
						PrivateVoiceDriver.Health.Provisioning => "<color=#e0b84d>connecting</color>", 
						PrivateVoiceDriver.Health.Failed => "<color=#ef5350>failed</color>", 
						_ => "<color=#6f7d88>off</color>", 
					} + (flag2 ? "  <color=#d9e8a8>●</color>" : string.Empty);
					((TMP_Text)privateStatus.labelTMP).text = text;
					MenuUiHelpers.SizeWrappedLabel(privateStatus, text, 250f);
				}
			}
		}

		private void UpdateMuteCaptions()
		{
			if ((Object)(object)micMuteButton != (Object)null)
			{
				string text = (PrivateVoiceLocalPrefs.MicMuted ? "Microphone: <color=#ef5350>MUTED</color>" : "Microphone: <color=#4dd07a>LIVE</color>");
				if (text != micMuteCache)
				{
					micMuteCache = text;
					((TMP_Text)micMuteButton.labelTMP).text = text;
				}
			}
			if ((Object)(object)soundMuteButton != (Object)null)
			{
				string text2 = (PrivateVoiceLocalPrefs.Muted ? "Sound: <color=#ef5350>MUTED</color>" : "Sound: <color=#4dd07a>ON</color>");
				if (text2 != soundMuteCache)
				{
					soundMuteCache = text2;
					((TMP_Text)soundMuteButton.labelTMP).text = text2;
				}
			}
		}

		private void UpdateHotkeyHint()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0040: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)hotkeyHint == (Object)null))
			{
				KeyCode value = ModConfig.PrivateMicMuteKey.Value;
				KeyCode value2 = ModConfig.PrivateDeafenKey.Value;
				if (value != lastHotkeyMicMuteKey || value2 != lastHotkeyDeafenKey)
				{
					lastHotkeyMicMuteKey = value;
					lastHotkeyDeafenKey = value2;
					string text = "<size=75%><color=#6f7d88>Mic mute: " + KeyName(value) + "   Sound mute: " + KeyName(value2) + "   Both are local and reset when the game closes.</color></size>";
					((TMP_Text)hotkeyHint.labelTMP).text = text;
					MenuUiHelpers.SizeWrappedLabel(hotkeyHint, text, 250f);
				}
			}
		}

		private unsafe static string KeyName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)key != 0)
			{
				return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			}
			return "unbound";
		}

		private static void OnMicMuteClicked()
		{
			PrivateVoiceLocalPrefs.ToggleMicMuted();
		}

		private static void OnSoundMuteClicked()
		{
			PrivateVoiceLocalPrefs.ToggleMuted();
		}

		private static void OnPrivateVolumeChanged(int percent)
		{
			PrivateVoiceLocalPrefs.SetVolumePercent(percent);
		}

		private REPOScrollViewElement? AddLabel(string richText)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			REPOLabel made = null;
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				REPOLabel val = MenuAPI.CreateREPOLabel(richText, sv, default(Vector2));
				((TMP_Text)val.labelTMP).richText = true;
				((TMP_Text)val.labelTMP).fontSize = 14f;
				MenuUiHelpers.SizeWrappedLabel(val, richText, 250f);
				made = val;
				return ((REPOElement)val).rectTransform;
			}, 0f, 6f);
			return Elem((Component?)(object)made);
		}

		private static REPOScrollViewElement? Elem(Component? made)
		{
			if (!((Object)(object)made == (Object)null))
			{
				return made.GetComponent<REPOScrollViewElement>();
			}
			return null;
		}

		private static void SetVisibility(REPOScrollViewElement? elem, bool visible)
		{
			if ((Object)(object)elem != (Object)null)
			{
				elem.visibility = visible;
			}
		}
	}
	internal sealed class GhostRowDriver : MonoBehaviour
	{
		private static readonly Color TalkNameColor = new Color(0.6f, 0.6f, 0.4f);

		internal static readonly Color IdleNameColor = new Color(0.2f, 0.2f, 0.2f);

		private const float ColorLerpSpeed = 10f;

		private const float TalkThreshold = 0.005f;

		private const float HoldTime = 0.18f;

		private const float WobbleDegreesPerLoudness = 200f;

		private const float FocusPushAlong = 12.5f;

		private const float FocusPushPerp = 6f;

		private const float EyeRestX = 50f;

		private const float EyeRestY = 25f;

		private const float EyeNudge = 10f;

		private const float EyeLerpSpeed = 10f;

		private const float CursorFocusOffsetX = 18f;

		private const float CursorFocusOffsetY = 15f;

		private int actorNumber;

		private MenuPlayerListed? row;

		private TextMeshProUGUI? playerName;

		private MenuPlayerHead? head;

		private RectTransform? rowRect;

		private RectTransform? headRect;

		private RectTransform? headTransform;

		private RectTransform? eyesTransform;

		private bool facingRight = true;

		private int listSpotPrev = -1;

		private float talkUntil;

		internal void Initialize(int actor)
		{
			actorNumber = actor;
		}

		private void Awake()
		{
			row = ((Component)this).GetComponent<MenuPlayerListed>();
			if ((Object)(object)row != (Object)null)
			{
				playerName = row.playerName;
				head = row.playerHead;
				rowRect = ((Component)row).GetComponent<RectTransform>();
				if ((Object)(object)head != (Object)null)
				{
					headRect = ((Component)head).GetComponent<RectTransform>();
				}
			}
		}

		private void Update()
		{
			float loud = ReadLoudness();
			bool talking = UpdateTalkHold(loud);
			PublishTalkState(talking);
			if ((Object)(object)row != (Object)null)
			{
				ApplyFacing(row.listSpot);
			}
			ApplyWobble(loud);
			UpdateNameColor(talking);
			SyncEyeContact();
		}

		private void SyncEyeContact()
		{
			try
			{
				SyncFocusPoint();
				SyncCursorFocus();
				SyncEyes();
			}
			catch
			{
			}
		}

		private float ReadLoudness()
		{
			return VoiceChatPatch.AmplitudeFor(actorNumber);
		}

		private bool UpdateTalkHold(float loud)
		{
			if (loud > 0.005f)
			{
				talkUntil = Time.time + 0.18f;
			}
			return Time.time < talkUntil;
		}

		private void PublishTalkState(bool talking)
		{
			if (!((Object)(object)head == (Object)null))
			{
				if (ShouldStampTalkStart(talking, head.isTalking))
				{
					head.startedTalkingAtTime = Time.time;
				}
				head.isTalking = talking;
			}
		}

		private void ApplyWobble(float loud)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)headTransform == (Object)null))
			{
				((Transform)headTransform).localEulerAngles = new Vector3(0f, 0f, facingRight ? (loud * 200f) : ((0f - loud) * 200f));
			}
		}

		private void UpdateNameColor(bool talking)
		{
			//IL_001b: 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_0023: 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)
			if (!((Object)(object)playerName == (Object)null))
			{
				((Graphic)playerName).color = Color.Lerp(((Graphic)playerName).color, talking ? TalkNameColor : IdleNameColor, Time.deltaTime * 10f);
			}
		}

		private static bool ShouldStampTalkStart(bool talkingNow, bool wasTalking)
		{
			if (talkingNow)
			{
				return !wasTalking;
			}
			return false;
		}

		private static bool FacingIsRight(int listSpot)
		{
			return listSpot % 2 == 0;
		}

		private void ApplyFacing(int listSpot)
		{
			if (listSpot == listSpotPrev || (Object)(object)head == (Object)null)
			{
				return;
			}
			listSpotPrev = listSpot;
			facingRight = FacingIsRight(listSpot);
			Transform val = (facingRight ? head.headRight : head.headLeft);
			Transform val2 = (facingRight ? head.headLeft : head.headRight);
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)val2 != (Object)null)
				{
					((Component)val2).gameObject.SetActive(false);
				}
				((Component)val).gameObject.SetActive(true);
				headTransform = ((Component)val).GetComponent<RectTransform>();
				Transform val3 = val.Find("Eyes");
				eyesTransform = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<RectTransform>() : null);
			}
		}

		private void SyncFocusPoint()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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)
			//IL_00d3: 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_0105: 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)
			if (!((Object)(object)head == (Object)null) && !((Object)(object)head.focusPoint == (Object)null) && !((Object)(object)headTransform == (Object)null) && !((Object)(object)rowRect == (Object)null) && !((Object)(object)headRect == (Object)null))
			{
				Vector3 val = ((Transform)rowRect).localPosition + ((Transform)headRect).localPosition + ((Transform)headTransform).localPosition * ((Transform)headRect).localScale.x;
				float z = ((Transform)headTransform).localEulerAngles.z;
				float num = (facingRight ? 12.5f : (-12.5f));
				val += new Vector3(MenuPlayerHead.LengthDirX(num, z), MenuPlayerHead.LengthDirY(num, z), 0f);
				val += new Vector3(MenuPlayerHead.LengthDirX(6f, z + 90f), MenuPlayerHead.LengthDirY(6f, z + 90f), 0f);
				((Transform)head.focusPoint).localPosition = val;
			}
		}

		private void SyncEyes()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)head == (Object)null || (Object)(object)eyesTransform == (Object)null || (Object)(object)head.focusPoint == (Object)null || (Object)(object)head.myFocusPoint == (Object)null)
			{
				return;
			}
			MenuPlayerHead val = null;
			float num = 0f;
			List<MenuPlayerHead> list = (((Object)(object)MenuManager.instance != (Object)null) ? MenuManager.instance.playerHeads : null);
			if (list != null)
			{
				for (int i = 0; i < list.Count; i++)
				{
					MenuPlayerHead val2 = list[i];
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)head) && val2.isTalking && val2.startedTalkingAtTime > num)
					{
						num = val2.startedTalkingAtTime;
						val = val2;
					}
				}
			}
			Vector3 val3 = (((Object)(object)val != (Object)null && (Object)(object)val.focusPoint != (Object)null) ? ((Transform)val.focusPoint).localPosition : ((Transform)head.myFocusPoint).localPosition);
			Vector3 val4 = val3 - ((Transform)head.focusPoint).localPosition;
			val4.z = 0f;
			Vector3 val5 = new Vector3(facingRight ? 50f : (-50f), 25f, 0f) + ((Vector3)(ref val4)).normalized * 10f;
			((Transform)eyesTransform).localPosition = Vector3.Lerp(((Transform)eyesTransform).localPosition, val5, Time.deltaTime * 10f);
		}

		private void SyncCursorFocus()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)head == (Object)null) && !((Object)(object)head.myFocusPoint == (Object)null) && !((Object)(object)MenuManager.instance == (Object)null) && (int)MenuManager.instance.currentMenuPageIndex == 8 && !((Object)(object)MenuCursor.instance == (Object)null) && !((Object)(object)headRect == (Object)null) && !((Object)(object)((Transform)headRect).parent == (Object)null) && !((Object)(object)((Transform)headRect).parent.parent == (Object)null))
			{
				Vector3 val = ((Component)MenuCursor.instance).transform.localPosition - ((Transform)headRect).parent.parent.localPosition;
				((Transform)head.myFocusPoint).localPosition = new Vector3(val.x + 18f, val.y + 15f, 0f);
			}
		}
	}
	internal sealed class HeadMarkerComponent : MonoBehaviour
	{
		private const float AppearSeconds = 0.35f;

		private float spinDegreesPerSecond;

		private float pulsePeriodSeconds;

		private float bobAmplitude;

		private float bobPeriodSeconds;

		private Material? pulseMaterial;

		private Color baseColor;

		private bool emissionAvailable;

		private Vector3 basePosition;

		private float appearElapsed;

		private const float GlintSeconds = 0.25f;

		private Material? glintMaterial;

		private float glintPeriodSeconds;

		private float nextGlintAt;

		private float glintStartedAt = float.NegativeInfinity;

		private bool glintAvailable;

		private bool glintWasActive;

		private Color glintBaseEmission;

		private Material?[]? ownedMaterials;

		private bool materialsDestroyed;

		internal void Initialize(Material? material, Color color, float spinDps, float pulsePeriod, float bobAmp, float bobPeriod, Material? glintMat = null, float glintPeriod = 0f)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_00ab: 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)
			pulseMaterial = material;
			baseColor = color;
			spinDegreesPerSecond = spinDps;
			pulsePeriodSeconds = pulsePeriod;
			bobAmplitude = bobAmp;
			bobPeriodSeconds = bobPeriod;
			basePosition = ((Component)this).transform.localPosition;
			if ((Object)(object)material != (Object)null && material.HasProperty("_EmissionColor"))
			{
				material.EnableKeyword("_EMISSION");
				emissionAvailable = true;
			}
			glintMaterial = glintMat;
			glintPeriodSeconds = glintPeriod;
			if ((Object)(object)glintMat != (Object)null && glintPeriod > 0f && glintMat.HasProperty("_EmissionColor"))
			{
				glintMat.EnableKeyword("_EMISSION");
				glintBaseEmission = glintMat.GetColor("_EmissionColor");
				glintAvailable = true;
				nextGlintAt = Time.time + glintPeriod * Random.Range(0.7f, 1.3f);
			}
		}

		internal void TakeOwnership(params Material?[] mats)
		{
			ownedMaterials = mats;
		}

		internal void DestroyOwnedMaterials()
		{
			if (materialsDestroyed || ownedMaterials == null)
			{
				return;
			}
			materialsDestroyed = true;
			Material[] array = ownedMaterials;
			foreach (Material val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private void OnDestroy()
		{
			DestroyOwnedMaterials();
		}

		private void OnEnable()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			appearElapsed = 0f;
			((Component)this).transform.localScale = Vector3.zero;
			if (glintAvailable)
			{
				nextGlintAt = Time.time + glintPeriodSeconds * Random.Range(0.7f, 1.3f);
			}
		}

		private void Update()
		{
			//IL_003d: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			if (appearElapsed < 0.35f)
			{
				appearElapsed += Time.deltaTime;
				float num = Mathf.Clamp01(appearElapsed / 0.35f) - 1f;
				((Component)this).transform.localScale = Vector3.one * (1f + 2.70158f * num * num * num + 1.70158f * num * num);
			}
			if (spinDegreesPerSecond != 0f)
			{
				((Component)this).transform.Rotate(0f, spinDegreesPerSecond * Time.deltaTime, 0f, (Space)0);
			}
			if (bobAmplitude > 0f)
			{
				float num2 = bobAmplitude * Mathf.Sin(Time.time * (MathF.PI * 2f / bobPeriodSeconds));
				((Component)this).transform.localPosition = basePosition + new Vector3(0f, num2, 0f);
			}
			if (emissionAvailable && (Object)(object)pulseMaterial != (Object)null)
			{
				float num3 = 1.05f + 0.45f * Mathf.Sin(Time.time * (MathF.PI * 2f / pulsePeriodSeconds));
				pulseMaterial.SetColor("_EmissionColor", baseColor * num3);
			}
			if (glintAvailable && (Object)(object)glintMaterial != (Object)null)
			{
				if (Time.time >= nextGlintAt)
				{
					glintStartedAt = Time.time;
					nextGlintAt = Time.time + glintPeriodSeconds * Random.Range(0.7f, 1.3f);
				}
				float num4 = (Time.time - glintStartedAt) / 0.25f;
				if (num4 < 1f)
				{
					glintWasActive = true;
					float num5 = Mathf.SmoothStep(0f, 1f, (num4 < 0.5f) ? (num4 * 2f) : (2f - num4 * 2f));
					Color val = (((Object)(object)glintMaterial == (Object)(object)pulseMaterial && emissionAvailable) ? (baseColor * (1.05f + 0.45f * Mathf.Sin(Time.time * (MathF.PI * 2f / pulsePeriodSeconds)))) : glintBaseEmission);
					glintMaterial.SetColor("_EmissionColor", Color.Lerp(val, Color.white * 1.6f, num5));
				}
				else if (glintWasActive)
				{
					glintWasActive = false;
					if ((Object)(object)glintMaterial != (Object)(object)pulseMaterial)
					{
						glintMaterial.SetColor("_EmissionColor", glintBaseEmission);
					}
				}
			}
			if (appearElapsed >= 0.35f && spinDegreesPerSecond == 0f && bobAmplitude <= 0f && !emissionAvailable && !glintAvailable)
			{
				((Behaviour)this).enabled = false;
			}
		}
	}
	internal static class HeadMarkers
	{
		internal const string CrownName = "SharePermissions_HostCrown";

		internal const string GemName = "SharePermissions_ModGem";

		internal const string DiamondName = "SharePermissions_ModUserDiamond";

		private static readonly Color GoldColor = new Color(0.95f, 0.76f, 0.31f);

		private static readonly Color RubyColor = new Color(0.85f, 0.2f, 0.28f);

		private static readonly Color ModUserColor = new Color(0.5f, 0.54f, 0.63f);

		private const float BandOuterRadius = 0.075f;

		private const float BandInnerRadius = 0.058f;

		private const float BandHeight = 0.03f;

		private const int CrownPoints = 8;

		private static Mesh? bandMesh;

		private static Mesh? tallSpikeMesh;

		private static Mesh? shortSpikeMesh;

		private static Mesh? jewelMesh;

		private static Mesh? gemMesh;

		private static Mesh? diamondMesh;

		private static Mesh BandMesh => bandMesh ?? (bandMesh = MarkerMeshes.Band(16, 0.075f, 0.058f, 0.03f));

		private static Mesh TallSpikeMesh => tallSpikeMesh ?? (tallSpikeMesh = MarkerMeshes.Pyramid(0.016f, 0.075f, 6));

		private static Mesh ShortSpikeMesh => shortSpikeMesh ?? (shortSpikeMesh = MarkerMeshes.Pyramid(0.013f, 0.048f, 6));

		private static Mesh JewelMesh => jewelMesh ?? (jewelMesh = MarkerMeshes.Bipyramid(6, 0.01f, 0.01f, 0.01f));

		private static Mesh GemMesh => gemMesh ?? (gemMesh = MarkerMeshes.GemCut(10, 0.05f, 0.028f, 0.032f, 0.068f));

		private static Mesh DiamondMesh => diamondMesh ?? (diamondMesh = MarkerMeshes.GemCut(8, 0.032f, 0.018f, 0.02f, 0.042f));

		internal static Transform BuildCrown(Transform attach)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SharePermissions_HostCrown");
			val.transform.SetParent(attach, false);
			val.transform.localPosition = new Vector3(0f, 0.2f, 0f);
			Material val2 = NewMaterial(GoldColor, 0.9f, 0.78f);
			Material val3 = NewMaterial(RubyColor, 0.3f, 0.9f, 0.75f);
			AddMesh(val.transform, val2, BandMesh);
			float num = 0.0665f;
			Vector3 val4 = default(Vector3);
			for (int i = 0; i < 8; i++)
			{
				float num2 = (float)i / 8f * MathF.PI * 2f;
				((Vector3)(ref val4))..ctor(Mathf.Cos(num2), 0f, Mathf.Sin(num2));
				bool flag = (i & 1) == 0;
				AddMesh(val.transform, val2, flag ? TallSpikeMesh : ShortSpikeMesh, val4 * num + Vector3.up * 0.015f);
				if (flag)
				{
					AddMesh(val.transform, val3, JewelMesh, val4 * 0.075f);
				}
			}
			HeadMarkerComponent headMarkerComponent = val.AddComponent<HeadMarkerComponent>();
			headMarkerComponent.Initialize(val2, GoldColor, 40f, 1.6f, 0f, 0f, val3, 4.5f);
			headMarkerComponent.TakeOwnership(val2, val3);
			val.SetActive(false);
			return val.transform;
		}

		internal static Transform BuildGem(Transform attach)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SharePermissions_ModGem");
			val.transform.SetParent(attach, false);
			val.transform.localPosition = new Vector3(0f, 0.18f, 0f);
			Material val2 = NewMaterial(Moderators.ModeratorColor, 0.25f, 0.92f, 0.25f);
			AddMesh(val.transform, val2, GemMesh);
			HeadMarkerComponent headMarkerComponent = val.AddComponent<HeadMarkerComponent>();
			headMarkerComponent.Initialize(val2, Moderators.ModeratorColor, 60f, 1.8f, 0.012f, 2.6f, val2, 6f);
			headMarkerComponent.TakeOwnership(val2);
			val.SetActive(false);
			return val.transform;
		}

		internal static Transform BuildDiamond(Transform attach)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SharePermissions_ModUserDiamond");
			val.transform.SetParent(attach, false);
			val.transform.localPosition = new Vector3(0f, 0.16f, 0f);
			Material val2 = NewMaterial(ModUserColor, 0.1f, 0.65f, 0.12f);
			AddMesh(val.transform, val2, DiamondMesh);
			HeadMarkerComponent headMarkerComponent = val.AddComponent<HeadMarkerComponent>();
			headMarkerComponent.Initialize(null, ModUserColor, 0f, 0f, 0f, 0f);
			headMarkerComponent.TakeOwnership(val2);
			val.SetActive(false);
			return val.transform;
		}

		private static GameObject AddMesh(Transform parent, Material mat, Mesh mesh, Vector3 localPos = default(Vector3))
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("facet");
			val.transform.SetParent(parent, false);
			val.transform.localPosition = localPos;
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = mat;
			return val;
		}

		private static Material NewMaterial(Color color, float metallic, float smoothness, float staticGlow = 0f)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_002f: 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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Standard") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Hidden/InternalErrorShader");
			Material val2 = new Material(val);
			val2.color = color;
			if (val2.HasProperty("_Metallic"))
			{
				val2.SetFloat("_Metallic", metallic);
			}
			if (val2.HasProperty("_Glossiness"))
			{
				val2.SetFloat("_Glossiness", smoothness);
			}
			if (staticGlow > 0f && val2.HasProperty("_EmissionColor"))
			{
				val2.EnableKeyword("_EMISSION");
				val2.SetColor("_EmissionColor", color * staticGlow);
			}
			return val2;
		}
	}
	internal sealed class HistoryPageController
	{
		private const int PageSize = 10;

		private const int DetailRows = 20;

		private const float DetailWidth = 250f;

		private const int ColPrev = 0;

		private const int ColPage = 1;

		private const int ColNext = 2;

		private const int BandColumns = 5;

		private static readonly Vector2 BandPos = new Vector2(ModStyle.BandLeft, 20f);

		private static readonly string[] FacetLabels = new string[6] { "All", "Kicks & bans", "Flood", "Mute", "Moderator", "Info" };

		private readonly REPOPopupPage page;

		private readonly IReadOnlyList<string> entries;

		private readonly List<int> view = new List<int>();

		private int pageIndex;

		private string searchText = "";

		private int facetIndex;

		private int initiatorIndex;

		private readonly List<string?> initiators = new List<string> { null };

		private string?[] entryInitiators = Array.Empty<string>();

		private string[] entryStripped = Array.Empty<string>();

		private string[] entryStrippedLower = Array.Empty<string>();

		private readonly REPOButton?[] rows = (REPOButton?[])(object)new REPOButton[10];

		private readonly REPOScrollViewElement?[] rowElems = (REPOScrollViewElement?[])(object)new REPOScrollViewElement[10];

		private readonly REPOLabel?[] detailRows = (REPOLabel?[])(object)new REPOLabel[20];

		private readonly REPOScrollViewElement?[] detailRowElems = (REPOScrollViewElement?[])(object)new REPOScrollViewElement[20];

		private REPOLabel? emptyLabel;

		private REPOScrollViewElement? emptyElem;

		private REPOInputField? searchField;

		private REPOScrollViewElement? searchElem;

		private REPOButton? facetBtn;

		private REPOScrollViewElement? facetElem;

		private REPOButton? initiatorBtn;

		private REPOScrollViewElement? initiatorElem;

		private REPOButton? prevBtn;

		private REPOButton? nextBtn;

		private REPOButton? backBtn;

		private REPOButton? copyBtn;

		private REPOButton? steamBtn;

		private REPOLabel? pageLabel;

		private string? detailSteamId;

		private string? detailRaw;

		private bool tabVisible = true;

		private int ViewCount => view.Count;

		private int TotalPages => Math.Max(1, (ViewCount + 10 - 1) / 10);

		internal HistoryPageController(REPOPopupPage page, IReadOnlyList<string> entries)
		{
			this.page = page;
			this.entries = entries;
			BuildInitiatorIndex();
			RebuildView();
		}

		internal void Build()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Expected O, but got Unknown
			page.AddElement((BuilderDelegate)delegate(Transform t)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: 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_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0125: Unknown result type (might be due to invalid IL or missing references)
				//IL_0170: Unknown result type (might be due to invalid IL or missing references)
				//IL_0175: Unknown result type (might be due to invalid IL or missing references)
				//IL_017e: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
				prevBtn = MenuAPI.CreateREPOButton("< Prev", (Action)Prev, t, BandPos);
				nextBtn = MenuAPI.CreateREPOButton("Next >", (Action)Next, t, BandPos);
				backBtn = MenuAPI.CreateREPOButton("< Back", (Action)ShowList, t, BandPos);
				copyBtn = MenuAPI.CreateREPOButton("Copy", (Action)CopyDetail, t, BandPos);
				steamBtn = MenuAPI.CreateREPOButton("Steam", (Action)OpenSteam, t, BandPos);
				((TMP_Text)steamBtn.labelTMP).richText = true;
				CenterInColumn(prevBtn, 0);
				CenterInColumn(backBtn, 0);
				CenterInColumn(nextBtn, 2);
				CenterInColumn(copyBtn, 2);
				CenterInColumn(steamBtn, 1);
				((TMP_Text)steamBtn.labelTMP).text = "<color=#66c0f4>Steam</color>";
				float num3 = (ModStyle.BandRight - ModStyle.BandLeft) / 5f;
				pageLabel = MenuAPI.CreateREPOLabel("", t, BandPos);
				((TMP_Text)pageLabel.labelTMP).fontSize = 14f;
				((TMP_Text)pageLabel.labelTMP).horizontalAlignment = (HorizontalAlignmentOptions)2;
				RectTransform rectTransform = ((REPOElement)pageLabel).rectTransform;
				Vector2 sizeDelta = ((REPOElement)pageLabel).rectTransform.sizeDelta;
				sizeDelta.x = num3;
				rectTransform.sizeDelta = sizeDelta;
				RectTransform rectTransform2 = ((TMP_Text)pageLabel.labelTMP).rectTransform;
				sizeDelta = ((TMP_Text)pageLabel.labelTMP).rectTransform.sizeDelta;
				sizeDelta.x = num3;
				rectTransform2.sizeDelta = sizeDelta;
				((Transform)((REPOElement)pageLabel).rectTransform).localPosition = new Vector3(ModStyle.ColumnCenter(1, 5) - num3 / 2f, 20f, 0f);
			});
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				searchField = MenuAPI.CreateREPOInputField("Search", (Action<string>)OnSearchChanged, sv, default(Vector2), false, "name, id, action", "");
				((TMP_Text)searchField.labelTMP).fontSize = 14f;
				return ((REPOElement)searchField).rectTransform;
			}, 0f, 2f);
			searchElem = (((Object)(object)searchField != (Object)null) ? ((Component)searchField).GetComponent<REPOScrollViewElement>() : null);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0016: 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_005d: Unknown result type (might be due to invalid IL or missing references)
				facetBtn = MenuAPI.CreateREPOButton(FacetCaption(), (Action)CycleFacet, sv, default(Vector2));
				((TMP_Text)facetBtn.labelTMP).richText = true;
				((TMP_Text)facetBtn.labelTMP).fontSize = 14f;
				facetBtn.overrideButtonSize = new Vector2(250f, 24f);
				return ((REPOElement)facetBtn).rectTransform;
			}, 0f, 2f);
			facetElem = (((Object)(object)facetBtn != (Object)null) ? ((Component)facetBtn).GetComponent<REPOScrollViewElement>() : null);
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0016: 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_005d: Unknown result type (might be due to invalid IL or missing references)
				initiatorBtn = MenuAPI.CreateREPOButton(InitiatorCaption(), (Action)CycleInitiator, sv, default(Vector2));
				((TMP_Text)initiatorBtn.labelTMP).richText = true;
				((TMP_Text)initiatorBtn.labelTMP).fontSize = 14f;
				initiatorBtn.overrideButtonSize = new Vector2(250f, 24f);
				return ((REPOElement)initiatorBtn).rectTransform;
			}, 0f, 2f);
			initiatorElem = (((Object)(object)initiatorBtn != (Object)null) ? ((Component)initiatorBtn).GetComponent<REPOScrollViewElement>() : null);
			for (int num = 0; num < 10; num++)
			{
				int slot = num;
				page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
				{
					//IL_0038: 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_009f: Unknown result type (might be due to invalid IL or missing references)
					rows[slot] = MenuAPI.CreateREPOButton("", (Action)delegate
					{
						SelectSlot(slot);
					}, sv, default(Vector2));
					((TMP_Text)rows[slot].labelTMP).richText = true;
					((TMP_Text)rows[slot].labelTMP).fontSize = 14f;
					rows[slot].overrideButtonSize = new Vector2(250f, 24f);
					return ((REPOElement)rows[slot]).rectTransform;
				}, 0f, 2f);
				rowElems[num] = (((Object)(object)rows[num] != (Object)null) ? ((Component)rows[num]).GetComponent<REPOScrollViewElement>() : null);
			}
			for (int num2 = 0; num2 < 20; num2++)
			{
				int slot2 = num2;
				page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
				{
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					detailRows[slot2] = MenuAPI.CreateREPOLabel("", sv, default(Vector2));
					((TMP_Text)detailRows[slot2].labelTMP).enableWordWrapping = true;
					((TMP_Text)detailRows[slot2].labelTMP).richText = true;
					((TMP_Text)detailRows[slot2].labelTMP).fontSize = 14f;
					return ((REPOElement)detailRows[slot2]).rectTransform;
				}, 0f, 2f);
				detailRowElems[num2] = (((Object)(object)detailRows[num2] != (Object)null) ? ((Component)detailRows[num2]).GetComponent<REPOScrollViewElement>() : null);
			}
			page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				emptyLabel = MenuAPI.CreateREPOLabel("No moderation events yet.", sv, default(Vector2));
				((TMP_Text)emptyLabel.labelTMP).fontSize = 14f;
				return ((REPOElement)emptyLabel).rectTransform;
			}, 0f, 0f);
			emptyElem = (((Object)(object)emptyLabel != (Object)null) ? ((Component)emptyLabel).GetComponent<REPOScrollViewElement>() : null);
			ShowList();
		}

		internal void SetTabVisible(bool visible)
		{
			tabVisible = visible;
			if (visible)
			{
				ShowList();
				return;
			}
			for (int i = 0; i < 10; i++)
			{
				if ((Object)(object)rowElems[i] != (Object)null)
				{
					rowElems[i].visibility = false;
				}
			}
			HideDetail();
			if ((Object)(object)emptyElem != (Object)null)
			{
				emptyElem.visibility = false;
			}
			UnfocusSearch();
			if ((Object)(object)searchElem != (Object)null)
			{
				searchElem.visibility = false;
			}
			if ((Object)(object)facetElem != (Object)null)
			{
				facetElem.visibility = false;
			}
			if ((Object)(object)initiatorElem != (Object)null)
			{
				initiatorElem.visibility = false;
			}
			SetActiveSafe((Component?)(object)prevBtn, active: false);
			SetActiveSafe((Component?)(object)nextBtn, active: false);
			SetActiveSafe((Component?)(object)pageLabel, active: false);
			SetActiveSafe((Component?)(object)backBtn, active: false);
			SetActiveSafe((Component?)(object)copyBtn, active: false);
			SetActiveSafe((Component?)(object)steamBtn, active: false);
		}

		private void UnfocusSearch()
		{
			if ((Object)(object)searchField != (Object)null && (Object)(object)searchField.inputStringSystem != (Object)null)
			{
				searchField.inputStringSystem.isFocused = false;
			}
		}

		internal void ShowList()
		{
			if (!tabVisible)
			{
				return;
			}
			for (int i = 0; i < 10; i++)
			{
				int num = pageIndex * 10 + i;
				bool flag = num < ViewCount;
				if ((Object)(object)rowElems[i] != (Object)null)
				{
					rowElems[i].visibility = flag;
				}
				if (flag && (Object)(object)rows[i] != (Object)null)
				{
					((TMP_Text)rows[i].labelTMP).text = RowCaption(EntryAt(num));
				}
			}
			HideDetail();
			detailRaw = null;
			if ((Object)(object)searchElem != (Object)null)
			{
				searchElem.visibility = true;
			}
			if ((Object)(object)facetElem != (Object)null)
			{
				facetElem.visibility = true;
			}
			if ((Object)(object)initiatorElem != (Object)null)
			{
				initiatorElem.visibility = initiators.Count > 1;
			}
			if ((Object)(object)facetBtn != (Object)null)
			{
				((TMP_Text)facetBtn.labelTMP).text = FacetCaption();
			}
			if ((Object)(object)emptyElem != (Object)null)
			{
				emptyElem.visibility = ViewCount == 0;
			}
			if ((Object)(object)emptyLabel != (Object)null && ViewCount == 0)
			{
				((TMP_Text)emptyLabel.labelTMP).text = ((entries.Count == 0) ? "No moderation events yet." : "No matching events.");
			}
			SetActiveSafe((Component?)(object)prevBtn, ViewCount > 0 && pageIndex > 0);
			SetActiveSafe((Component?)(object)nextBtn, ViewCount > 0 && pageIndex < TotalPages - 1);
			SetActiveSafe((Component?)(object)pageLabel, ViewCount > 0);
			SetActiveSafe((Component?)(object)backBtn, active: false);
			SetActiveSafe((Component?)(object)copyBtn, active: false);
			SetActiveSafe((Component?)(object)steamBtn, active: false);
			if ((Object)(object)copyBtn != (Object)null)
			{
				((TMP_Text)copyBtn.labelTMP).text = "Copy";
			}
			if ((Object)(object)pageLabel != (Object)null)
			{
				((TMP_Text)pageLabel.labelTMP).text = $"Page {pageIndex + 1}/{TotalPages}";
			}
			page.scrollView.SetScrollPosition(0f);
		}

		private void SelectSlot(int slot)
		{
			if (!tabVisible)
			{
				return;
			}
			int num = pageIndex * 10 + slot;
			if (num >= ViewCount)
			{
				return;
			}
			string text = (detailRaw = MenuUiHelpers.StripRichText(EntryAt(num)));
			List<string> list = BuildDetailLines(text);
			for (int i = 0; i < 20; i++)
			{
				bool flag = i < list.Count;
				if ((Object)(object)detailRowElems[i] != (Object)null)
				{
					detailRowElems[i].visibility = flag;
				}
				if (flag && (Object)(object)detailRows[i] != (Object)null)
				{
					((TMP_Text)detailRows[i].labelTMP).text = list[i];
					MenuUiHelpers.SizeWrappedLabel(detailRows[i], list[i], 250f);
				}
			}
			for (int j = 0; j < 10; j++)
			{
				if ((Object)(object)rowElems[j] != (Object)null)
				{
					rowElems[j].visibility = false;
				}
			}
			if ((Object)(object)emptyElem != (Object)null)
			{
				emptyElem.visibility = false;
			}
			UnfocusSearch();
			if ((Object)(object)searchElem != (Object)null)
			{
				searchElem.visibility = false;
			}
			if ((Object)(object)facetElem != (Object)null)
			{
				facetElem.visibility = false;
			}
			if ((Object)(object)initiatorElem != (Object)null)
			{
				initiatorElem.visibility = false;
			}
			SetActiveSafe((Component?)(object)prevBtn, active: false);
			SetActiveSafe((Component?)(object)nextBtn, active: false);
			SetActiveSafe((Component?)(object)backBtn, active: true);
			SetActiveSafe((Component?)(object)copyBtn, active: true);
			if ((Object)(object)copyBtn != (Object)null)
			{
				((TMP_Text)copyBtn.labelTMP).text = "Copy";
			}
			SetActiveSafe((Component?)(object)pageLabel, active: false);
			detailSteamId = TargetSteamIdOf(text);
			SetActiveSafe((Component?)(object)steamBtn, SteamUtils.TryParseValidSteamId(detailSteamId, out var _));
			page.scrollView.SetScrollPosition(0f);
		}

		private void HideDetail()
		{
			for (int i = 0; i < 20; i++)
			{
				if ((Object)(object)detailRowElems[i] != (Object)null)
				{
					detailRowElems[i].visibility = false;
				}
			}
		}

		private static List<string> BuildDetailLines(string raw)
		{
			int num = raw.IndexOf("] ", StringComparison.Ordinal);
			string text = ((num >= 0) ? raw.Substring(num + 2) : raw);
			List<string> list = new List<string>();