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 ByPlayerId = new Dictionary(); private static readonly HashSet AmplitudeAttached = new HashSet(); 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 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(); 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(); Speaker val3 = val.AddComponent(); 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 item in ByPlayerId) { if (item.Value.Speaker == speaker) { entry = item.Value; break; } } if (entry == null || !AmplitudeAttached.Add(speaker)) { return; } remoteVoice.FloatFrameDecoded += delegate(FrameOut 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 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 item in ByPlayerId) { if (item.Value.Actor == actorNumber) { return item.Value.Amplitude; } } return 0f; } internal static int[] SpeakingActors() { List list = new List(ByPlayerId.Count); foreach (KeyValuePair 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 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(); ((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(); 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 dictionary = (Dictionary)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 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(); 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() : 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(); 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, IDataReader, 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 FallbackPalette = (IReadOnlyList)(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 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, "Current #" + NameColors.ToHex(current) + ""); foreach (IReadOnlyList 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 colors, Action 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(); 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 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 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, "Or type a color as #RRGGBB and press enter."); } private static IEnumerable> Rows(IReadOnlyList colors) { for (int start = 0; start < colors.Count; start += 6) { yield return colors.Skip(start).Take(6).ToList(); } } private static IReadOnlyList Palette() { try { IReadOnlyList 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 GamePaletteRaw() { MetaManager instance = MetaManager.instance; if ((Object)(object)instance == (Object)null || instance.colors == null) { return Array.Empty(); } List 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("Private channel"); 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 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("Announcements"); 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)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: ON" : "Private channel: OFF"); if (((TMP_Text)privateToggle.labelTMP).text != text) { ((TMP_Text)privateToggle.labelTMP).text = text; } } } private void UpdateOffHint() { if (!((Object)(object)offHint == (Object)null)) { string text = "Off - the host opens the private channel."; 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 ? "live" : "muted") : "mic off", PrivateVoiceDriver.Health.Listening => "listening", PrivateVoiceDriver.Health.Provisioning => "connecting", PrivateVoiceDriver.Health.Failed => "failed", _ => "off", } + (flag2 ? " ●" : 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: MUTED" : "Microphone: LIVE"); if (text != micMuteCache) { micMuteCache = text; ((TMP_Text)micMuteButton.labelTMP).text = text; } } if ((Object)(object)soundMuteButton != (Object)null) { string text2 = (PrivateVoiceLocalPrefs.Muted ? "Sound: MUTED" : "Sound: ON"); 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 = "Mic mute: " + KeyName(value) + " Sound mute: " + KeyName(value2) + " Both are local and reset when the game closes."; ((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(); } 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(); if ((Object)(object)row != (Object)null) { playerName = row.playerName; head = row.playerHead; rowRect = ((Component)row).GetComponent(); if ((Object)(object)head != (Object)null) { headRect = ((Component)head).GetComponent(); } } } 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(); Transform val3 = val.Find("Eyes"); eyesTransform = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent() : 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 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.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.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.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().sharedMesh = mesh; ((Renderer)val.AddComponent()).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 entries; private readonly List view = new List(); private int pageIndex; private string searchText = ""; private int facetIndex; private int initiatorIndex; private readonly List initiators = new List { null }; private string?[] entryInitiators = Array.Empty(); private string[] entryStripped = Array.Empty(); private string[] entryStrippedLower = Array.Empty(); 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 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 = "Steam"; 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)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() : 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() : 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() : 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() : 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() : 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() : 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 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 BuildDetailLines(string raw) { int num = raw.IndexOf("] ", StringComparison.Ordinal); string text = ((num >= 0) ? raw.Substring(num + 2) : raw); List list = new List(); list.Add("● " + EventTitle(raw) + ""); List list2 = list; string text2 = TimeOf(raw); if (text2.Length > 0) { list2.Add("" + text2 + ""); } List<(string, string)> list3 = ParseFields(text); if (list3.Count > 0) { foreach (var (text3, text4) in list3) { list2.Add("" + text3 + " " + text4 + ""); } list2.Add("" + text + ""); } else { list2.Add("" + text + ""); } return list2; } private void CopyDetail() { if (!string.IsNullOrEmpty(detailRaw)) { GUIUtility.systemCopyBuffer = detailRaw; if ((Object)(object)copyBtn != (Object)null) { ((TMP_Text)copyBtn.labelTMP).text = "Copied"; } } } private void OpenSteam() { SteamUtils.OpenProfile(detailSteamId); } private static string? TargetSteamIdOf(string strippedEntry) { int num = strippedEntry.IndexOf("] ", StringComparison.Ordinal); string body = ((num >= 0) ? strippedEntry.Substring(num + 2) : strippedEntry); foreach (var (text, result) in CoreFieldsOf(body)) { if (text == "Steam ID") { return result; } } return null; } private void Prev() { if (pageIndex > 0) { pageIndex--; ShowList(); } } private void Next() { if (pageIndex < TotalPages - 1) { pageIndex++; ShowList(); } } private string EntryAt(int global) { return entries[view[view.Count - 1 - global]]; } private void OnSearchChanged(string value) { string text = (value ?? "").Trim().ToLowerInvariant(); if (!(text == searchText)) { searchText = text; pageIndex = 0; RebuildView(); ShowList(); } } private void CycleFacet() { facetIndex = (facetIndex + 1) % FacetLabels.Length; if ((Object)(object)facetBtn != (Object)null) { ((TMP_Text)facetBtn.labelTMP).text = FacetCaption(); } pageIndex = 0; RebuildView(); ShowList(); } private string FacetCaption() { string text = FacetLabels[facetIndex]; string arg = ((facetIndex == 0) ? text : ("" + text + "")); return string.Format("Filter: {0} ({2})", arg, "#6f7d88", ViewCount); } private static string FacetColor(int idx) { return idx switch { 1 => "#ef5350", 2 => "#ff7043", 3 => "#b57ae0", 4 => "#66bb6a", 5 => "#8aa0b0", _ => "#66b2ff", }; } private void CycleInitiator() { initiatorIndex = (initiatorIndex + 1) % initiators.Count; if ((Object)(object)initiatorBtn != (Object)null) { ((TMP_Text)initiatorBtn.labelTMP).text = InitiatorCaption(); } pageIndex = 0; RebuildView(); ShowList(); } private string InitiatorCaption() { if (initiatorIndex == 0) { return "By: All"; } string text = initiators[initiatorIndex] ?? "All"; int num = text.IndexOf(" (", StringComparison.Ordinal); string text2 = ((num > 0) ? text.Substring(0, num) : text); if (text2.Length > 18) { text2 = MenuUiHelpers.TruncateSafe(text2, 17) + "…"; } return "By: " + text2 + ""; } private void RebuildView() { view.Clear(); for (int i = 0; i < entries.Count; i++) { if ((facetIndex == 0 || FacetMatches(entryStripped[i])) && (initiatorIndex == 0 || string.Equals(entryInitiators[i], initiators[initiatorIndex], StringComparison.Ordinal)) && (searchText.Length <= 0 || entryStrippedLower[i].IndexOf(searchText, StringComparison.Ordinal) >= 0)) { view.Add(i); } } } private void BuildInitiatorIndex() { entryInitiators = new string[entries.Count]; entryStripped = new string[entries.Count]; entryStrippedLower = new string[entries.Count]; HashSet hashSet = new HashSet(StringComparer.Ordinal); for (int i = 0; i < entries.Count; i++) { string text = MenuUiHelpers.StripRichText(entries[i]); entryStripped[i] = text; entryStrippedLower[i] = text.ToLowerInvariant(); string text2 = InitiatorOf(text); entryInitiators[i] = text2; if (text2 != null && hashSet.Add(text2)) { initiators.Add(text2); } } } private static string? InitiatorOf(string strippedEntry) { int num = strippedEntry.IndexOf("] ", StringComparison.Ordinal); string body = ((num >= 0) ? strippedEntry.Substring(num + 2) : strippedEntry); foreach (var (text, result) in CoreFieldsOf(body)) { if (text == "By") { return result; } } return null; } private bool FacetMatches(string strippedEntry) { string text = HistoryPatterns.EventKind(strippedEntry).ToLowerInvariant(); return facetIndex switch { 1 => text.StartsWith("kick request", StringComparison.Ordinal) || text.StartsWith("ban request", StringComparison.Ordinal) || text.StartsWith("banning", StringComparison.Ordinal) || text.StartsWith("player kicked", StringComparison.Ordinal) || text.StartsWith("player banned", StringComparison.Ordinal) || text.StartsWith("ghost player", StringComparison.Ordinal), 2 => text.StartsWith("rpc flood", StringComparison.Ordinal), 3 => text.StartsWith("global voice", StringComparison.Ordinal), 4 => text.StartsWith("moderator ", StringComparison.Ordinal), 5 => !text.StartsWith("kick request", StringComparison.Ordinal) && !text.StartsWith("ban request", StringComparison.Ordinal) && !text.StartsWith("banning", StringComparison.Ordinal) && !text.StartsWith("player kicked", StringComparison.Ordinal) && !text.StartsWith("player banned", StringComparison.Ordinal) && !text.StartsWith("ghost player", StringComparison.Ordinal) && !text.StartsWith("rpc flood", StringComparison.Ordinal) && !text.StartsWith("global voice", StringComparison.Ordinal) && !text.StartsWith("moderator ", StringComparison.Ordinal), _ => true, }; } private static string RowCaption(string entry) { string text = MenuUiHelpers.StripRichText(entry); int num = text.IndexOf("] ", StringComparison.Ordinal); string text2 = ((num >= 0) ? text.Substring(0, num + 1) : ""); string body = ((num >= 0) ? text.Substring(num + 2) : text); string text3 = EventTitle(text); string text4 = CaptionSuffix(body); if (!string.IsNullOrEmpty(text4)) { text3 = text3 + " - " + text4; } if (text3.Length > 34) { text3 = MenuUiHelpers.TruncateSafe(text3, 33) + "…"; } string text5 = ((text2.Length > 0) ? ("" + text2 + " ") : ""); return "● " + text5 + text3; } private static string? CaptionSuffix(string body) { foreach (var (text, text2) in ParseFields(body)) { switch (text) { case "Player": return text2; case "By": case "Cancelled by": { int num = text2.IndexOf(" (", StringComparison.Ordinal); return "by " + ((num > 0) ? text2.Substring(0, num) : text2); } case "Duration": case "Reason": return text2; } } return null; } private static string SevColor(string strippedEntry) { string text = HistoryPatterns.EventKind(strippedEntry).ToLowerInvariant(); if (text.StartsWith("announcement", StringComparison.Ordinal)) { return "#4dd0e1"; } if (text.StartsWith("rpc flood", StringComparison.Ordinal)) { return "#ff7043"; } if (text.StartsWith("global voice", StringComparison.Ordinal)) { return "#b57ae0"; } if (text.StartsWith("moderator granted", StringComparison.Ordinal)) { return "#66bb6a"; } if (text.StartsWith("moderator revoked", StringComparison.Ordinal)) { return "#ffa726"; } if (text.StartsWith("moderator token revoked", StringComparison.Ordinal)) { return "#ffa726"; } if (text.StartsWith("banning", StringComparison.Ordinal) || text.StartsWith("ban request", StringComparison.Ordinal) || text.StartsWith("player banned", StringComparison.Ordinal) || text.StartsWith("ghost player banned", StringComparison.Ordinal)) { return "#ef5350"; } if (text.StartsWith("kick request", StringComparison.Ordinal) || text.StartsWith("player kicked", StringComparison.Ordinal) || text.StartsWith("ghost player kicked", StringComparison.Ordinal)) { return "#ff7043"; } if (text.StartsWith("run start countdown", StringComparison.Ordinal)) { return "#8aa0b0"; } if (text.StartsWith("private voice channel", StringComparison.Ordinal)) { return "#8aa0b0"; } if (text.Contains("ban")) { return "#ef5350"; } if (text.Contains("kick")) { return "#ff7043"; } return "#8aa0b0"; } private static string EventTitle(string strippedEntry) { string text = HistoryPatterns.EventKind(strippedEntry).ToLowerInvariant(); if (text.StartsWith("announcement", StringComparison.Ordinal)) { return "Announcement"; } if (text.StartsWith("rpc flood", StringComparison.Ordinal)) { return "RPC Flood"; } if (text.StartsWith("global voice unmute", StringComparison.Ordinal)) { return "Voice Unmute"; } if (text.StartsWith("global voice mute", StringComparison.Ordinal)) { return "Voice Mute"; } if (text.StartsWith("moderator granted", StringComparison.Ordinal)) { return "Mod Granted"; } if (text.StartsWith("moderator revoked", StringComparison.Ordinal)) { return "Mod Revoked"; } if (text.StartsWith("moderator token revoked", StringComparison.Ordinal)) { return "Token Revoked"; } if (text.StartsWith("ghost player banned", StringComparison.Ordinal)) { return "Ghost Banned"; } if (text.StartsWith("ghost player kicked", StringComparison.Ordinal)) { return "Ghost Kicked"; } if (text.StartsWith("ban request", StringComparison.Ordinal) || text.StartsWith("banning", StringComparison.Ordinal)) { return "Ban Request"; } if (text.StartsWith("kick request", StringComparison.Ordinal)) { return "Kick Request"; } if (text.StartsWith("player banned", StringComparison.Ordinal)) { return "Player Banned"; } if (text.StartsWith("player kicked", StringComparison.Ordinal)) { return "Player Kicked"; } if (text.StartsWith("run start countdown begun", StringComparison.Ordinal)) { return "Countdown Started"; } if (text.StartsWith("run start countdown cancelled", StringComparison.Ordinal)) { return "Countdown Cancelled"; } if (text.StartsWith("run started", StringComparison.Ordinal)) { return "Run Started"; } if (text.StartsWith("start game", StringComparison.Ordinal)) { return "Start Game"; } if (text.StartsWith("admin menu", StringComparison.Ordinal)) { return "Admin Menu"; } if (text.StartsWith("return to lobby", StringComparison.Ordinal)) { return "Back to Lobby"; } if (text.StartsWith("private voice channel opened", StringComparison.Ordinal)) { return "Private Voice On"; } if (text.StartsWith("private voice channel closed", StringComparison.Ordinal)) { return "Private Voice Off"; } if (text.StartsWith("private voice channel key rotated", StringComparison.Ordinal)) { return "Private Voice Key"; } return HistoryPatterns.EventKind(strippedEntry); } private static string TimeOf(string strippedEntry) { int num = strippedEntry.IndexOf(']'); if (num <= 1) { return ""; } return strippedEntry.Substring(1, num - 1); } private static List<(string Label, string Value)> ParseFields(string body) { List<(string, string)> list = new List<(string, string)>(); Match match = HistoryPatterns.MetaTailPattern.Match(body); if (match.Success) { string[] array = match.Groups["meta"].Value.Split('|'); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length != 0) { int num = text2.IndexOf(':'); if (num > 0) { list.Add((text2.Substring(0, num).Trim(), text2.Substring(num + 1).Trim())); } else { list.Add(("Info", text2)); } } } body = body.Substring(0, match.Index); } List<(string, string)> list2 = ParseCoreFields(body); list2.AddRange(list); return list2; } private static List<(string Label, string Value)> CoreFieldsOf(string body) { Match match = HistoryPatterns.MetaTailPattern.Match(body); if (match.Success) { body = body.Substring(0, match.Index); } return ParseCoreFields(body); } private static List<(string Label, string Value)> ParseCoreFields(string body) { List<(string, string)> list = new List<(string, string)>(); Match match = HistoryPatterns.FloodPattern.Match(body); if (match.Success) { list.Add(("Player", match.Groups["name"].Value.Trim())); list.Add(("Actor #", match.Groups["actor"].Value)); list.Add(("Steam ID", match.Groups["sid"].Value)); if (match.Groups["reason"].Value.Length > 0) { list.Add(("Reason", match.Groups["reason"].Value)); } list.Add(("Action", "Auto-kick")); return list; } match = HistoryPatterns.GhostPatternStrict.Match(body); if (!match.Success) { match = HistoryPatterns.GhostPattern.Match(body); } if (match.Success) { list.Add(("Player", match.Groups["name"].Value.Trim())); list.Add(("Actor #", match.Groups["actor"].Value)); if (match.Groups["sid"].Success) { list.Add(("Steam ID", match.Groups["sid"].Value)); } AddActionField(list, match.Groups["verb"].Value); AddByField(list, body); return list; } Regex[][] targetPatternTiers = HistoryPatterns.TargetPatternTiers; foreach (Regex[] array in targetPatternTiers) { Regex[] array2 = array; foreach (Regex regex in array2) { match = regex.Match(body); if (match.Success) { list.Add(("Player", match.Groups["name"].Value.Trim())); list.Add(("Steam ID", match.Groups["sid"].Value)); AddActionField(list, match.Groups["verb"].Value); AddByField(list, body); return list; } } } match = HistoryPatterns.CountdownBegunPattern.Match(body); if (match.Success) { list.Add(("Duration", match.Groups["dur"].Value)); return list; } match = HistoryPatterns.CountdownCancelPattern.Match(body); if (match.Success) { if (match.Groups["who"].Success) { string value = match.Groups["who"].Value; if (value.Equals("host", StringComparison.OrdinalIgnoreCase)) { list.Add(("By", "Host")); } else { list.Add(("Cancelled by", value)); } } else { string value2 = match.Groups["reason"].Value; list.Add(("Reason", char.ToUpperInvariant(value2[0]) + value2.Substring(1))); } return list; } AddByField(list, body); return list; } private static void AddActionField(List<(string, string)> fields, string verb) { string text; switch (verb.ToLowerInvariant()) { case "kick": case "kicked": text = "Kick"; break; case "banned": case "ban": case "banning": text = "Ban"; break; case "granted to": text = "Grant"; break; case "revoked from": text = "Revoke"; break; case "mute": text = "Mute"; break; case "unmute": text = "Unmute"; break; default: text = null; break; } string text2 = text; if (text2 != null) { fields.Add(("Action", text2)); } } private static void AddByField(List<(string, string)> fields, string body) { Match match = HistoryPatterns.ByPattern.Match(body); if (match.Success) { fields.Add(("By", match.Groups["name"].Value + " (" + match.Groups["sid"].Value + ")")); } else if (body.EndsWith("by host", StringComparison.OrdinalIgnoreCase)) { fields.Add(("By", "Host")); } } private static void CenterInColumn(REPOButton? btn, int col) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0035: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)btn == (Object)null)) { Vector2 labelSize = btn.GetLabelSize(); ((Transform)((REPOElement)btn).rectTransform).localPosition = new Vector3(ModStyle.ColumnCenter(col, 5) - labelSize.x / 2f, 20f, 0f); } } private static void SetActiveSafe(Component? c, bool active) { if ((Object)(object)c != (Object)null) { c.gameObject.SetActive(active); } } } internal static class HistoryPatterns { internal static readonly Regex[] StrictTargetPatterns = new Regex[4] { new Regex("^(?Kick|Ban|Banning) request\\s+(?.*)\\s*\\((?[^()]+?)\\)\\s*(?=from player:)", RegexOptions.Compiled), new Regex("^Player (?kicked|banned):\\s*(?.*)\\s*\\((?[^()]+?)\\)\\s*(?=by host\\s*$)", RegexOptions.Compiled), new Regex("^Moderator (?granted to|revoked from)\\s+(?.*)\\s*\\((?[^()]+?)\\)\\s*(?=by host\\s*$)", RegexOptions.Compiled), new Regex("^Global voice (?mute|unmute):\\s*(?.*)\\s*\\((?[^()]+?)\\)\\s*(?=by\\b)", RegexOptions.Compiled) }; internal static readonly Regex[] TargetPatterns = new Regex[4] { new Regex("^(?Kick|Ban|Banning) request\\s+(?.*?)\\s*\\((?[^()]+?)\\)", RegexOptions.Compiled), new Regex("^Player (?kicked|banned):\\s*(?.*?)\\s*\\((?[^()]+?)\\)", RegexOptions.Compiled), new Regex("^Moderator (?granted to|revoked from)\\s+(?.*?)\\s*\\((?[^()]+?)\\)", RegexOptions.Compiled), new Regex("^Global voice (?mute|unmute):\\s*(?.*?)\\s*\\((?[^()]+?)\\)", RegexOptions.Compiled) }; internal static readonly Regex[][] TargetPatternTiers = new Regex[2][] { StrictTargetPatterns, TargetPatterns }; internal static readonly Regex FloodPattern = new Regex("^RPC flood:\\s*(?.*)\\s*\\(actor\\s*(?-?\\d+),\\s*SteamID:\\s*(?[^()]+?)\\)\\s*(?.*?)\\s*-\\s*auto-kicked$", RegexOptions.Compiled); internal static readonly Regex GhostPatternStrict = new Regex("^Ghost player (?kicked|banned)\\s*\\(ActorNumber:\\s*(?-?\\d+),\\s*Name:\\s*(?.*?)(?:,\\s*SteamID:\\s*(?[^()]+?))?\\)\\s*(?:by host|by:\\s*.*\\([^()]*\\))\\s*$", RegexOptions.Compiled); internal static readonly Regex GhostPattern = new Regex("^Ghost player (?kicked|banned)\\s*\\(ActorNumber:\\s*(?-?\\d+),\\s*Name:\\s*(?.*?)(?:,\\s*SteamID:\\s*(?[^()]+?))?\\)", RegexOptions.Compiled); internal static readonly Regex CountdownBegunPattern = new Regex("^Run start countdown begun \\((?[^()]+)\\)$", RegexOptions.Compiled); internal static readonly Regex CountdownCancelPattern = new Regex("^Run start countdown cancelled(?: by (?.+)| \\((?[^()]+)\\))$", RegexOptions.Compiled); internal static readonly Regex ByPattern = new Regex("^.*(?:\\bby:?\\s*|\\bfrom player:\\s*)(?.*?)\\s*\\((?[^()]+)\\)\\s*$", RegexOptions.Compiled); internal static readonly Regex MetaTailPattern = new Regex("\\s*\\[(?[^\\[\\]]*)\\]\\s*$", RegexOptions.Compiled); private static readonly char[] KindCutChars = new char[2] { ':', '(' }; internal static string EventKind(string strippedEntry) { int num = strippedEntry.IndexOf("] ", StringComparison.Ordinal); string text = ((num >= 0) ? strippedEntry.Substring(num + 2) : strippedEntry); int num2 = text.IndexOfAny(KindCutChars); return ((num2 >= 0) ? text.Substring(0, num2) : text).Trim(); } } internal enum HudCorner { TopLeft, TopRight, BottomLeft, BottomRight } internal readonly struct HudPlacement { internal readonly float AnchorX; internal readonly float AnchorY; internal readonly float PivotX; internal readonly float PivotY; internal readonly float InsetX; internal readonly float InsetY; internal readonly float GrowSign; internal HudPlacement(float ax, float ay, float px, float py, float ix, float iy, float grow) { AnchorX = ax; AnchorY = ay; PivotX = px; PivotY = py; InsetX = ix; InsetY = iy; GrowSign = grow; } } internal static class HudLayout { internal const float Inset = 40f; internal static HudPlacement For(HudCorner corner) { return corner switch { HudCorner.TopLeft => new HudPlacement(0f, 1f, 0f, 1f, 40f, -40f, -1f), HudCorner.BottomLeft => new HudPlacement(0f, 0f, 0f, 0f, 40f, 40f, 1f), HudCorner.BottomRight => new HudPlacement(1f, 0f, 1f, 0f, -40f, 40f, 1f), _ => new HudPlacement(1f, 1f, 1f, 1f, -40f, -40f, -1f), }; } } internal static class MarkerMeshes { internal static Mesh Bipyramid(int sides, float radius, float topHeight, float bottomHeight) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) sides = Mathf.Max(3, sides); List verts = new List(sides * 6); List tris = new List(sides * 6); Vector3 a = default(Vector3); ((Vector3)(ref a))..ctor(0f, topHeight, 0f); Vector3 a2 = default(Vector3); ((Vector3)(ref a2))..ctor(0f, 0f - bottomHeight, 0f); for (int i = 0; i < sides; i++) { Vector3 val = Ring(i, sides, radius); Vector3 val2 = Ring(i + 1, sides, radius); AddTri(verts, tris, a, val2, val); AddTri(verts, tris, a2, val, val2); } return Build(verts, tris); } internal static Mesh Pyramid(float radius, float height, int sides) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_005d: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0070: Unknown result type (might be due to invalid IL or missing references) sides = Mathf.Max(3, sides); List verts = new List(sides * 6); List tris = new List(sides * 6); Vector3 a = default(Vector3); ((Vector3)(ref a))..ctor(0f, height, 0f); for (int i = 0; i < sides; i++) { Vector3 val = Ring(i, sides, radius); Vector3 val2 = Ring(i + 1, sides, radius); AddTri(verts, tris, a, val2, val); AddTri(verts, tris, Vector3.zero, val, val2); } return Build(verts, tris); } internal static Mesh GemCut(int sides, float girdleRadius, float tableRadius, float crownHeight, float pavilionDepth) { //IL_0059: 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_0070: 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) //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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00ad: 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_00b8: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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) sides = Mathf.Max(3, sides); List verts = new List(sides * 12); List tris = new List(sides * 12); Vector3 a = default(Vector3); ((Vector3)(ref a))..ctor(0f, crownHeight, 0f); Vector3 a2 = default(Vector3); ((Vector3)(ref a2))..ctor(0f, 0f - pavilionDepth, 0f); for (int i = 0; i < sides; i++) { Vector3 val = Ring(i, sides, girdleRadius); Vector3 val2 = Ring(i + 1, sides, girdleRadius); Vector3 val3 = Ring(i, sides, tableRadius, 0.5f, crownHeight); Vector3 val4 = Ring(i + 1, sides, tableRadius, 0.5f, crownHeight); AddTri(verts, tris, a, val4, val3); AddTri(verts, tris, val3, val2, val); AddTri(verts, tris, val2, val3, val4); AddTri(verts, tris, a2, val, val2); } return Build(verts, tris); } internal static Mesh Band(int sides, float outerRadius, float innerRadius, float height) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) sides = Mathf.Max(3, sides); float num = height * 0.5f; List verts = new List(sides * 24); List tris = new List(sides * 24); for (int i = 0; i < sides; i++) { Vector3 val = Ring(i, sides, outerRadius, 0f, num); Vector3 val2 = Ring(i + 1, sides, outerRadius, 0f, num); Vector3 val3 = Ring(i, sides, outerRadius, 0f, 0f - num); Vector3 val4 = Ring(i + 1, sides, outerRadius, 0f, 0f - num); Vector3 a = Ring(i, sides, innerRadius, 0f, num); Vector3 val5 = Ring(i + 1, sides, innerRadius, 0f, num); Vector3 val6 = Ring(i, sides, innerRadius, 0f, 0f - num); Vector3 val7 = Ring(i + 1, sides, innerRadius, 0f, 0f - num); AddTri(verts, tris, val, val2, val4); AddTri(verts, tris, val, val4, val3); AddTri(verts, tris, a, val7, val5); AddTri(verts, tris, a, val6, val7); AddTri(verts, tris, a, val2, val); AddTri(verts, tris, a, val5, val2); AddTri(verts, tris, val6, val3, val4); AddTri(verts, tris, val6, val4, val7); } return Build(verts, tris); } private static Vector3 Ring(int i, int sides, float radius, float halfStepOffset = 0f, float y = 0f) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) float num = ((float)i + halfStepOffset) / (float)sides * MathF.PI * 2f; return new Vector3(Mathf.Cos(num) * radius, y, Mathf.Sin(num) * radius); } private static void AddTri(List verts, List tris, Vector3 a, Vector3 b, Vector3 c) { //IL_0008: 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_0016: Unknown result type (might be due to invalid IL or missing references) int count = verts.Count; verts.Add(a); verts.Add(b); verts.Add(c); tris.Add(count); tris.Add(count + 1); tris.Add(count + 2); } private static Mesh Build(List verts, List tris) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Mesh val = new Mesh { name = "SharePermissions_MarkerMesh" }; val.SetVertices(verts); val.SetTriangles(tris, 0); val.RecalculateNormals(); val.RecalculateBounds(); return val; } } internal sealed class MembersPanelController { private const int MaxRows = 20; private readonly REPOPopupPage page; private readonly REPOButton?[] rows = (REPOButton?[])(object)new REPOButton[20]; private readonly REPOScrollViewElement?[] rowElems = (REPOScrollViewElement?[])(object)new REPOScrollViewElement[20]; private readonly int[] rowActors = new int[20]; private readonly string[] rowCaptionBase = new string[20]; private readonly bool[] rowTalking = new bool[20]; private readonly float[] rowTalkHoldUntil = new float[20]; private readonly HashSet actorsWithAvatars = new HashSet(); private REPOLabel? footer; private REPOScrollViewElement? footerElem; private string noteDraft = ""; private bool suspended; private bool tabVisible = true; private static readonly Color ConfirmHeaderColor = ModStyle.ConfirmDanger; internal MembersPanelController(REPOPopupPage page) { this.page = page; for (int i = 0; i < 20; i++) { rowActors[i] = -1; } } internal void Build() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown for (int i = 0; i < 20; i++) { int slot = i; 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 { OnRowClick(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[i] = (((Object)(object)rows[i] != (Object)null) ? ((Component)rows[i]).GetComponent() : null); } page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) string text = (SemiFunc.IsMasterClient() ? "Click a player to manage" : "Click a player for notes - the host manages roles"); string text2 = "" + text + ""; footer = MenuAPI.CreateREPOLabel(text2, sv, default(Vector2)); ((TMP_Text)footer.labelTMP).richText = true; ((TMP_Text)footer.labelTMP).fontSize = 14f; MenuUiHelpers.SizeWrappedLabel(footer, text2, 250f); return ((REPOElement)footer).rectTransform; }, 4f, 0f); footerElem = (((Object)(object)footer != (Object)null) ? ((Component)footer).GetComponent() : null); Refresh(); } internal void SetTabVisible(bool visible) { tabVisible = visible; if (visible) { Refresh(); return; } for (int i = 0; i < 20; i++) { if ((Object)(object)rowElems[i] != (Object)null) { rowElems[i].visibility = false; } } if ((Object)(object)footerElem != (Object)null) { footerElem.visibility = false; } } internal void Refresh() { if ((Object)(object)page == (Object)null || suspended || !tabVisible) { return; } Player[] array = PhotonNetwork.PlayerList ?? Array.Empty(); array = Array.FindAll(array, (Player p) => p.IsLocal || MenuUiHelpers.HasVisibleGlyph(p.NickName)); if (array.Length > 20) { Plugin.Logger.LogWarning((object)$"Members panel: {array.Length} players exceeds {20} rows; showing first {20}"); } BuildAvatarActorSet(); for (int num = 0; num < 20; num++) { bool flag = num < array.Length; if ((Object)(object)rowElems[num] != (Object)null) { rowElems[num].visibility = flag; } if (!flag) { rowActors[num] = -1; rowCaptionBase[num] = ""; rowTalking[num] = false; rowTalkHoldUntil[num] = 0f; continue; } Player val = array[num]; if (rowActors[num] != val.ActorNumber) { rowTalking[num] = false; rowTalkHoldUntil[num] = 0f; } rowActors[num] = val.ActorNumber; rowCaptionBase[num] = CaptionBase(val, !val.IsLocal && !actorsWithAvatars.Contains(val.ActorNumber)); ApplyCaption(num); } if ((Object)(object)footerElem != (Object)null) { footerElem.visibility = true; } } internal void TickTalking() { if ((Object)(object)page == (Object)null || suspended || !tabVisible) { return; } if (!ModConfig.ShowTalkDots.Value) { for (int i = 0; i < 20; i++) { if (rowTalking[i]) { rowTalking[i] = false; rowTalkHoldUntil[i] = 0f; ApplyCaption(i); } } return; } float unscaledTime = Time.unscaledTime; Player localPlayer = PhotonNetwork.LocalPlayer; int num = ((localPlayer != null) ? localPlayer.ActorNumber : (-1)); bool localActive = PrivateVoiceChannel.LocalActive; for (int j = 0; j < 20; j++) { int num2 = rowActors[j]; if (num2 >= 0 && num2 != num) { float num3 = ((localActive && PrivateVoiceChannel.IsMemberActor(num2)) ? PrivateSpeakers.AmplitudeFor(num2) : VoiceChatPatch.AmplitudeFor(num2)); if (num3 > 0.005f) { rowTalkHoldUntil[j] = unscaledTime + 0.18f; } bool flag = unscaledTime < rowTalkHoldUntil[j]; if (flag != rowTalking[j]) { rowTalking[j] = flag; ApplyCaption(j); } } } } private void ApplyCaption(int r) { if (!((Object)(object)rows[r] == (Object)null)) { ((TMP_Text)rows[r].labelTMP).text = (rowTalking[r] ? (rowCaptionBase[r] + " ●") : rowCaptionBase[r]); } } private void OnRowClick(int slot) { if (slot < 0 || slot >= 20) { return; } int num = rowActors[slot]; if (num < 0) { return; } Room currentRoom = PhotonNetwork.CurrentRoom; Player val = ((currentRoom != null) ? currentRoom.GetPlayer(num, false) : null); if (val == null) { return; } if (val.IsLocal) { if (ModerationActions.LocalCanModerate) { OpenNotesOnly(val); } } else if (SemiFunc.IsMasterClient()) { OpenActions(val); } else if (ModerationActions.LocalCanModerate) { OpenNotesOnly(val); } } private void OpenActions(Player player) { if (MenuUiHelpers.IsOpenPending) { return; } ModRole modRole = RoleResolver.ResolveByPlayer(player); if (modRole == ModRole.Host) { return; } string name = MenuUiHelpers.SanitizePlayerName(player.NickName, $"Player_{player.ActorNumber}"); string steamId = PlayerRegistry.Instance.Resolve(player.ActorNumber) ?? ""; int actor = player.ActorNumber; suspended = true; REPOPopupPage sub = MenuUiHelpers.CreatePage("Manage Member", Unsuspend); string text = (string.IsNullOrEmpty(steamId) ? "" : (" " + steamId + "")); MenuUiHelpers.AddLabel(sub, "" + name + "\n● " + ModStyle.RoleLabel(modRole) + "" + text + ""); if (modRole == ModRole.Moderator) { MenuUiHelpers.AddScrollViewButton(sub, "Demote moderator", delegate { CloseSub(); Confirm("Demote", "Remove moderator access from " + name + "?", delegate { ModerationActions.DemoteModerator(actor, steamId); }); }); } else if (modRole == ModRole.ModUser && !string.IsNullOrEmpty(steamId)) { MenuUiHelpers.AddScrollViewButton(sub, "Promote to moderator", delegate { CloseSub(); Confirm("Promote", "Grant moderator access to " + name + "?", delegate { ModerationActions.PromoteModerator(actor, steamId); }); }); } else { MenuUiHelpers.AddLabel(sub, "Promote requires the mod installed"); } if (!string.IsNullOrEmpty(steamId)) { BuildNameColorActions(sub, CloseSub, name, steamId, modRole); } BuildNotesSection(sub, CloseSub, name, steamId); MenuUiHelpers.OpenPage(sub); void CloseSub() { MenuUiHelpers.ClosePage(sub); Unsuspend(); } void Unsuspend() { suspended = false; Refresh(); } } private void OpenNotesOnly(Player player) { REPOPopupPage sub; if (!MenuUiHelpers.IsOpenPending) { string text = MenuUiHelpers.SanitizePlayerName(player.NickName, $"Player_{player.ActorNumber}"); string text2 = PlayerRegistry.Instance.Resolve(player.ActorNumber) ?? ""; suspended = true; sub = MenuUiHelpers.CreatePage("Player Notes", Unsuspend); string text3 = (string.IsNullOrEmpty(text2) ? "" : ("\n" + text2 + "")); MenuUiHelpers.AddLabel(sub, "" + text + "" + text3); BuildNotesSection(sub, CloseSub, text, text2); MenuUiHelpers.OpenPage(sub); } void CloseSub() { MenuUiHelpers.ClosePage(sub); Unsuspend(); } void Unsuspend() { suspended = false; Refresh(); } } private void BuildNameColorActions(REPOPopupPage sub, Action closeSub, string name, string steamId, ModRole role) { //IL_003d: 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_0042: Unknown result type (might be due to invalid IL or missing references) Color seed = (Color)(((??)NameColors.Resolve(steamId, role)) ?? Color.white); MenuUiHelpers.AddScrollViewButton(sub, "Set name color", delegate { //IL_0031: Unknown result type (might be due to invalid IL or missing references) closeSub(); ColorPickerPage.Open(name + "'s name color", "Color for " + name + " only. Overrides the host and moderator colors for them.", seed, delegate(Color picked) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) NameColors.SetOverride(steamId, picked); NameColorSync.Broadcast(); }, NameColors.GetOverride(steamId).HasValue ? "Clear name color" : null, NameColors.GetOverride(steamId).HasValue ? ((Action)delegate { NameColors.SetOverride(steamId, null); NameColorSync.Broadcast(); }) : null); }); } private void BuildNotesSection(REPOPopupPage sub, Action closeSub, string playerName, string steamId) { //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown noteDraft = ""; if (string.IsNullOrEmpty(steamId)) { MenuUiHelpers.AddLabel(sub, "Notes need a resolved Steam ID"); return; } List list = NotesStore.For(steamId); MenuUiHelpers.AddLabel(sub, $"Notes ({list.Count})"); string text = ModerationActions.LocalSteamId ?? ""; bool flag = SemiFunc.IsMasterClient(); foreach (PlayerNote item in list) { PlayerNote note = item; string text2 = DateTimeOffset.FromUnixTimeSeconds(note.CreatedUnix).ToLocalTime().ToString("yyyy-MM-dd"); string text3 = ((note.AuthorName.Length > 0) ? note.AuthorName : "unknown"); string text4 = ((note.LobbyName.Length > 0 && !PlayerNotesCore.LooksLikeRoomGuid(note.LobbyName)) ? (", " + note.LobbyName) : ""); string caption = note.Text + "\n" + text3 + text4 + ", " + text2 + ""; if (flag || (note.AuthorSteamId.Length > 0 && note.AuthorSteamId == text)) { MenuUiHelpers.AddScrollViewButton(sub, "", delegate { closeSub(); Confirm("Delete note", "Delete this note about " + playerName + "?", delegate { NotesStore.Delete(note.Id); if (SemiFunc.IsMasterClient()) { NotesSync.BroadcastTombstone(note.Id); } else { CommandSender.Send("NoteDelete", new object[1] { note.Id }, (ReceiverGroup)2); } }); }, delegate(REPOButton b) { ((TMP_Text)b.labelTMP).richText = true; ((TMP_Text)b.labelTMP).fontSize = 14f; ((TMP_Text)b.labelTMP).text = caption; MenuUiHelpers.SizeWrappedButton(b, caption, 250f); }); } else { MenuUiHelpers.AddLabel(sub, caption); } } sub.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) REPOInputField val = MenuAPI.CreateREPOInputField("Note", (Action)delegate(string v) { noteDraft = v ?? ""; }, sv, default(Vector2), false, "add a note", ""); ((TMP_Text)val.labelTMP).fontSize = 14f; return ((REPOElement)val).rectTransform; }, 4f, 0f); MenuUiHelpers.AddScrollViewButton(sub, "Add note", delegate { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Room currentRoom = PhotonNetwork.CurrentRoom; string text5 = PlayerNotesCore.SanitizeName((currentRoom != null) ? currentRoom.Name : null, 40); if (text5.Length == 0 || PlayerNotesCore.LooksLikeRoomGuid(text5)) { Player masterClient = PhotonNetwork.MasterClient; text5 = PlayerNotesCore.SanitizeName((masterClient != null) ? masterClient.NickName : null, 40); } Player localPlayer = PhotonNetwork.LocalPlayer; string authorName = MenuUiHelpers.SanitizePlayerName((localPlayer != null) ? localPlayer.NickName : null, "unknown"); if (NotesStore.TryAddLocal(steamId, noteDraft, ModerationActions.LocalSteamId ?? "0", authorName, text5, out PlayerNote note2, out string reason)) { if (SemiFunc.IsMasterClient()) { NotesSync.ForwardNew(new List { note2 }, new List(), -1); } else { NotesSync.SendOneToHost(note2); } } else if (reason == "target-full") { NotificationCenter.EnqueueDirect($"Note not added - {playerName} already has {20} notes", ModStyle.SevInfo); } noteDraft = ""; closeSub(); }); } private void BuildAvatarActorSet() { actorsWithAvatars.Clear(); foreach (PlayerAvatar item in SemiFunc.PlayerGetAll()) { if (!((Object)(object)item == (Object)null)) { PhotonView component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null && component.Owner != null) { actorsWithAvatars.Add(component.Owner.ActorNumber); } } } } private static void Confirm(string verb, string message, Action onConfirm) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MenuUiHelpers.ShowTwoOptionPopup(verb, ConfirmHeaderColor, message, onConfirm, null); } private static string CaptionBase(Player player, bool connecting) { ModRole role = RoleResolver.ResolveByPlayer(player); string text = ModStyle.RoleHex(role); string text2 = MenuUiHelpers.SanitizePlayerName(player.NickName, $"Player_{player.ActorNumber}"); if (text2.Length > 16) { text2 = text2.Substring(0, 15) + "…"; } if (player.IsLocal) { text2 += " (you)"; } string text3 = PlayerRegistry.Instance.Resolve(player.ActorNumber); int num = ((!string.IsNullOrEmpty(text3)) ? NotesStore.CountFor(text3) : 0); if (num > 0) { text2 += string.Format(" ({2})", "75%", "#9aa4ad", num); } string text4 = (connecting ? "connecting" : ("" + ModStyle.RoleLabel(role) + "")); return "● " + text2 + " " + text4 + ""; } } internal sealed class MembersRefresher : MonoBehaviour { internal Action? OnRefresh; internal Action? OnTick; private int lastCount = -1; private int lastAvatarCount = -1; private void OnEnable() { Moderators.Instance.Changed += Trigger; ModUsers.Instance.Changed += Trigger; } private void OnDisable() { Moderators.Instance.Changed -= Trigger; ModUsers.Instance.Changed -= Trigger; } private void Update() { Room currentRoom = PhotonNetwork.CurrentRoom; int num = ((currentRoom != null) ? currentRoom.PlayerCount : 0); int num2 = SemiFunc.PlayerGetAll()?.Count ?? 0; if (num != lastCount || num2 != lastAvatarCount) { lastCount = num; lastAvatarCount = num2; Trigger(); } OnTick?.Invoke(); } private void Trigger() { OnRefresh?.Invoke(); } } internal static class MenuUiHelpers { private static MenuButtonPopUp? menuButtonPopup; internal const int MaxPlayerNameLength = 32; private static int nextFakePageIndex = -2000; private static float openBlockedUntil; internal static bool IsOpenPending => Time.unscaledTime < openBlockedUntil; internal static string StripRichText(string? text) { if (string.IsNullOrEmpty(text)) { return ""; } string source = Regex.Replace(text, "<[^>]*>", string.Empty); return new string(source.Where((char c) => !char.IsControl(c)).ToArray()); } internal static string SanitizePlayerName(string? name, string? fallback = "Unknown") { if (string.IsNullOrWhiteSpace(name)) { return fallback ?? ""; } string text = StripRichText(name).Trim(); if (string.IsNullOrWhiteSpace(text)) { return fallback ?? ""; } if (text.Length > 32) { text = TruncateSafe(text, 32) + "..."; } return text; } internal static string TruncateSafe(string text, int max) { if (text.Length <= max) { return text; } int num = max; if (num > 0 && char.IsHighSurrogate(text[num - 1])) { num--; } return text.Substring(0, num); } internal static bool HasVisibleGlyph(string? name) { if (string.IsNullOrEmpty(name)) { return false; } for (int i = 0; i < name.Length; i++) { char c = name[i]; int cp; if (char.IsHighSurrogate(c) && i + 1 < name.Length && char.IsLowSurrogate(name[i + 1])) { cp = char.ConvertToUtf32(c, name[++i]); } else { if (char.IsSurrogate(c)) { continue; } cp = c; } if (IsVisibleCodePoint(cp)) { return true; } } return false; } private static bool IsKnownInvisibleCodePoint(int cp) { switch (cp) { case 4447: case 4448: case 6158: case 10240: case 12644: case 65440: return true; default: return false; } } private static bool IsVisibleCodePoint(int cp) { if (IsKnownInvisibleCodePoint(cp)) { return false; } UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(cp); if ((uint)(unicodeCategory - 5) <= 2u || (uint)(unicodeCategory - 11) <= 6u || unicodeCategory == UnicodeCategory.OtherNotAssigned) { return false; } return true; } internal static REPOPopupPage CreatePage(string title, Action onClose) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown REPOPopupPage page = MenuAPI.CreateREPOPopupPage(title, (PresetSide)0, false, true, 4f); AlignPopupToContentColumn(page); page.menuPage.menuPageIndex = (MenuPageIndex)(nextFakePageIndex--); MenuModalGatePatch.RegisterModalPage(page.menuPage); page.onEscapePressed = (ShouldCloseMenuDelegate)delegate { bool flag = (Object)(object)MenuManager.instance != (Object)null && (Object)(object)MenuManager.instance.currentMenuPage == (Object)(object)page.menuPage; if (flag) { onClose(); } return flag; }; page.AddElement((BuilderDelegate)delegate(Transform transform) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton("Close", (Action)delegate { ClosePage(page, onClose); }, transform, new Vector2(ModStyle.BandLeft, 20f)); ((Transform)((REPOElement)val).rectTransform).localPosition = new Vector3(ModStyle.ColumnCenter(4, 5) - val.GetLabelSize().x / 2f, 20f, 0f); }); return page; } private static void AlignPopupToContentColumn(REPOPopupPage page) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_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_0118: Unknown result type (might be due to invalid IL or missing references) try { Vector3[] array = (Vector3[])(object)new Vector3[4]; page.maskRectTransform.GetWorldCorners(array); float x = ((Component)page).transform.InverseTransformPoint(array[0]).x; float x2 = ((Component)page).transform.InverseTransformPoint(array[3]).x; if (x2 - x < 50f) { return; } ModStyle.BandLeft = x; ModStyle.BandRight = x2; TextMeshProUGUI headerTMP = page.headerTMP; if (!((Object)(object)headerTMP == (Object)null)) { ((TMP_Text)headerTMP).ForceMeshUpdate(false, false); Bounds textBounds = ((TMP_Text)headerTMP).textBounds; Vector3 val; if (!(((Bounds)(ref textBounds)).extents.x > 0f)) { RectTransform rectTransform = ((TMP_Text)headerTMP).rectTransform; Rect rect = ((TMP_Text)headerTMP).rectTransform.rect; val = ((Transform)rectTransform).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)); } else { val = ((TMP_Text)headerTMP).transform.TransformPoint(((Bounds)(ref textBounds)).center); } Vector3 val2 = val; float x3 = ((Component)page).transform.InverseTransformPoint(val2).x; float num = (x + x2) / 2f + 0f; Vector3 localPosition = ((Transform)((TMP_Text)headerTMP).rectTransform).localPosition; localPosition.x += num - x3; ((Transform)((TMP_Text)headerTMP).rectTransform).localPosition = localPosition; } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("[SharePermissions] Popup column alignment failed (using fallbacks): " + ex.Message)); } } internal static float LayoutScrollMask(REPOPopupPage page, float topBand) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_00ab: Unknown result type (might be due to invalid IL or missing references) try { Vector3[] array = (Vector3[])(object)new Vector3[4]; page.maskRectTransform.GetWorldCorners(array); float y = ((Component)page).transform.InverseTransformPoint(array[1]).y; float y2 = ((Component)page).transform.InverseTransformPoint(array[0]).y; float num = page.maskPadding.bottom + (56f - y2); page.maskPadding = new Padding(0f, topBand, 0f, Mathf.Max(0f, num)); return y; } catch (Exception ex) { Plugin.Logger.LogWarning((object)("[SharePermissions] Mask layout failed, using fallback: " + ex.Message)); page.maskPadding = new Padding(0f, topBand, 0f, 30f); return 300f; } } internal static void OpenPage(REPOPopupPage page) { openBlockedUntil = Time.unscaledTime + 0.1f; ((MonoBehaviour)MenuManager.instance).StartCoroutine(OpenPageDelayed(page)); } private static IEnumerator OpenPageDelayed(REPOPopupPage page) { yield return (object)new WaitForSeconds(0.05f); if ((Object)(object)page != (Object)null && (Object)(object)page.menuPage != (Object)null) { page.OpenPage(false); } } internal static void ClosePage(REPOPopupPage page, Action? onClose = null) { onClose?.Invoke(); if (!((Object)(object)page == (Object)null)) { page.ClosePage(true); MenuManager.instance.PageRemove(page.menuPage); } } internal static void AddLabel(REPOPopupPage parent, string text) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown parent.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //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(text, scrollView, default(Vector2)); ((TMP_Text)val.labelTMP).richText = true; ((TMP_Text)val.labelTMP).fontSize = 14f; SizeWrappedLabel(val, text, 250f); return ((REPOElement)val).rectTransform; }, 0f, 6f); } internal static void SizeWrappedLabel(REPOLabel label, string text, float width) { //IL_001e: 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_0043: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI labelTMP = label.labelTMP; ((TMP_Text)labelTMP).enableWordWrapping = true; ((TMP_Text)labelTMP).ForceMeshUpdate(false, false); float y = ((TMP_Text)labelTMP).GetPreferredValues(text, width, 0f).y; ((REPOElement)label).rectTransform.sizeDelta = new Vector2(width, y); ((TMP_Text)labelTMP).rectTransform.sizeDelta = new Vector2(width, y); } internal static void SizeWrappedButton(REPOButton button, string text, float width) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_001d: 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_002c: 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_0053: 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_008b: 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_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) TextMeshProUGUI labelTMP = button.labelTMP; RectTransform rectTransform = ((TMP_Text)labelTMP).rectTransform; Vector3 localPosition = ((Transform)rectTransform).localPosition; Vector2 anchorMin = (rectTransform.anchorMax = Vector2.zero); rectTransform.anchorMin = anchorMin; rectTransform.pivot = Vector2.zero; ((Transform)rectTransform).localPosition = localPosition; ((TMP_Text)labelTMP).enableAutoSizing = false; ((TMP_Text)labelTMP).enableWordWrapping = true; ((TMP_Text)labelTMP).overflowMode = (TextOverflowModes)0; ((TMP_Text)labelTMP).margin = Vector4.zero; ((TMP_Text)labelTMP).alignment = (TextAlignmentOptions)1025; float num = width - Mathf.Max(0f, localPosition.x); ((TMP_Text)labelTMP).ForceMeshUpdate(false, false); float y = ((TMP_Text)labelTMP).GetPreferredValues(text, num, 0f).y; rectTransform.sizeDelta = new Vector2(num, y); button.overrideButtonSize = new Vector2(width, y + Mathf.Max(0f, localPosition.y)); } internal static void AddScrollViewButton(REPOPopupPage parent, string text, Action onClick, Action? configure = null) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown parent.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton(text, onClick, scrollView, default(Vector2)); if (text.Length > 24) { Vector2 labelSize = val.GetLabelSize(); labelSize.x = 250f; val.overrideButtonSize = labelSize; REPOTextScroller val2 = ((Component)val.labelTMP).gameObject.AddComponent(); val2.maxCharacters = 24; } configure?.Invoke(val); return ((REPOElement)val).rectTransform; }, 0f, 0f); } internal static void ShowTwoOptionPopup(string title, Color headerColor, string message, Action? onLeftClicked, Action? onRightClicked, string leftTitle = "Yes", string rightTitle = "No") { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)menuButtonPopup)) { menuButtonPopup = ((Component)MenuManager.instance).gameObject.AddComponent(); } menuButtonPopup.option1Event = new UnityEvent(); menuButtonPopup.option2Event = new UnityEvent(); if (onLeftClicked != null) { menuButtonPopup.option1Event.AddListener(new UnityAction(onLeftClicked.Invoke)); } if (onRightClicked != null) { menuButtonPopup.option2Event.AddListener(new UnityAction(onRightClicked.Invoke)); } MenuManager.instance.PagePopUpTwoOptions(menuButtonPopup, title, (LocalizedAsset)null, headerColor, message, (LocalizedAsset)null, leftTitle, (LocalizedAsset)null, rightTitle, (LocalizedAsset)null, true); } } internal static class ModerationActions { internal readonly struct GhostInfo { internal readonly Player Player; internal readonly PlayerAvatar? UntrustedAvatar; internal GhostInfo(Player player, PlayerAvatar? untrustedAvatar) { Player = player; UntrustedAvatar = untrustedAvatar; } } private static readonly Color ConfirmHeaderColor = ModStyle.ConfirmDanger; private static string cachedLocalSteamId = ""; private const float AnnounceCooldownSeconds = 3f; private static float lastAnnounceSentAt; internal static string LocalSteamId { get { if ((Object)(object)PlayerAvatar.instance != (Object)null) { string value = SemiFunc.PlayerGetSteamID(PlayerAvatar.instance); if (!string.IsNullOrEmpty(value)) { cachedLocalSteamId = value; } } return cachedLocalSteamId; } } private static bool LocalIsHost => SemiFunc.IsMasterClient(); private static bool LocalIsModerator => Moderators.Instance.IsModerator(LocalSteamId); internal static bool LocalCanModerate { get { if (!LocalIsHost) { return LocalIsModerator; } return true; } } internal static bool PersistentBanAvailable { get { if (LocalCanModerate) { if (!LocalIsHost) { return HostCapabilities.PersistentBan; } return BanEnforcerBridge.IsAvailable; } return false; } } internal static void ClearSessionCache() { cachedLocalSteamId = ""; } internal static IEnumerable GetGhosts() { HashSet actorsWithAvatars = new HashSet(); Dictionary byActor = new Dictionary(); PlayerAvatar[] array = Object.FindObjectsOfType(); foreach (PlayerAvatar val in array) { if ((Object)(object)val == (Object)null) { continue; } PhotonView component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && component.Owner != null) { int actorNumber = component.Owner.ActorNumber; byActor[actorNumber] = val; if (PlayerValidator.Validate(val).IsValid) { actorsWithAvatars.Add(actorNumber); } } } Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val2 in playerList) { if (!val2.IsLocal && !actorsWithAvatars.Contains(val2.ActorNumber) && MenuUiHelpers.HasVisibleGlyph(val2.NickName)) { byActor.TryGetValue(val2.ActorNumber, out PlayerAvatar value); yield return new GhostInfo(val2, value); } } } internal static bool ShouldShowKickFor(PlayerAvatar target) { if ((Object)(object)target == (Object)null || target.isLocal) { return false; } if (!LocalCanModerate) { return false; } PhotonView component = ((Component)target).GetComponent(); if (component != null) { Player owner = component.Owner; if (((owner != null) ? new bool?(owner.IsMasterClient) : ((bool?)null)) == true) { return false; } } if (Moderators.Instance.IsModerator(target) && !LocalIsHost) { return false; } return true; } internal static bool ShouldShowKickForActor(Player target) { if (target == null || target.IsLocal) { return false; } if (!LocalCanModerate) { return false; } if (target.IsMasterClient) { return false; } string steamId = PlayerRegistry.Instance.Resolve(target.ActorNumber) ?? ""; if (Moderators.Instance.IsModerator(steamId) && !LocalIsHost) { return false; } return true; } internal static void HandlePlayerKick(PlayerAvatar target) { if (!ShouldShowKickFor(target)) { return; } string name = MenuUiHelpers.SanitizePlayerName(SemiFunc.PlayerGetName(target)); string steamId = SemiFunc.PlayerGetSteamID(target); PhotonView component = ((Component)target).GetComponent(); int? obj; if (component == null) { obj = null; } else { Player owner = component.Owner; obj = ((owner != null) ? new int?(owner.ActorNumber) : ((int?)null)); } int actor = obj ?? (-1); bool flag = Moderators.Instance.IsModerator(steamId); Action kick = delegate { DispatchPlayer(actor, steamId, ban: false); }; Action ban = delegate { DispatchPlayer(actor, steamId, ban: true); }; Action pban = (PersistentBanAvailable ? ((Action)delegate { DispatchPlayer(actor, steamId, ban: true, persistent: true); }) : null); if (flag) { ShowKickBanModal(name, delegate { Confirm(name, "Kick", kick); }, delegate { Confirm(name, "Ban", ban); }, (pban == null) ? null : ((Action)delegate { Confirm(name, "Ban (persistent)", pban); })); } else { ShowKickBanModal(name, kick, ban, pban); } } private static void DispatchPlayer(int actor, string steamId, bool ban, bool persistent = false) { if (LocalIsHost) { if (actor > 0) { string targetName = SteamName(steamId); bool targetIsModerator = Moderators.Instance.IsModerator(steamId); PBanOutcome pban = (persistent ? GameActions.RecordPersistentBan(steamId, targetName, null, null) : PBanOutcome.None); GameActions.KickByActorNumber(actor, ban); AuditEvents.PlayerKickBan(ban, targetName, steamId, actor, targetIsModerator, pban); } } else { CommandSender.Send("KickPlayer", new object[2] { steamId, persistent ? "pban" : (ban ? "ban" : "kick") }, (ReceiverGroup)2); } } internal static void HandleGhostKick(Player ghost) { if (ShouldShowKickForActor(ghost)) { string targetName = MenuUiHelpers.SanitizePlayerName(ghost.NickName, $"Unknown_{ghost.ActorNumber}"); ShowKickBanModal(targetName, delegate { DispatchGhost(ghost, ban: false); }, delegate { DispatchGhost(ghost, ban: true); }, PersistentBanAvailable ? ((Action)delegate { DispatchGhost(ghost, ban: true, persistent: true); }) : null); } } private static void DispatchGhost(Player ghost, bool ban, bool persistent = false) { if (LocalIsHost) { string text = PlayerRegistry.Instance.TryGetSteamId(ghost.ActorNumber) ?? ghost.UserId; string targetName = MenuUiHelpers.SanitizePlayerName(ghost.NickName, $"Unknown_{ghost.ActorNumber}"); PBanOutcome pban = (persistent ? GameActions.RecordPersistentBan(text, targetName, null, null) : PBanOutcome.None); GameActions.KickByActorNumber(ghost.ActorNumber, ban); AuditEvents.GhostKickBan(ban, ghost.ActorNumber, ghost.NickName, text, null, null, pban); } else { string text2 = $"{ghost.ActorNumber}"; CommandSender.Send("KickGhostPlayer", new object[2] { text2, persistent ? "pban" : (ban ? "ban" : "kick") }, (ReceiverGroup)2); } } internal static void KickPlayer(PlayerAvatar target, bool ban, bool persistent = false) { if (ShouldShowKickFor(target)) { string steamId = SemiFunc.PlayerGetSteamID(target); PhotonView component = ((Component)target).GetComponent(); int? obj; if (component == null) { obj = null; } else { Player owner = component.Owner; obj = ((owner != null) ? new int?(owner.ActorNumber) : ((int?)null)); } int actor = obj ?? (-1); DispatchPlayer(actor, steamId, ban, persistent); } } internal static void KickGhost(Player ghost, bool ban, bool persistent = false) { if (ShouldShowKickForActor(ghost)) { DispatchGhost(ghost, ban, persistent); } } internal static void PromoteModerator(int actor, string? steamId) { if (!LocalIsHost || string.IsNullOrEmpty(steamId) || actor <= 0) { return; } if (!ModUsers.Instance.Contains(steamId) && !Moderators.Instance.IsModerator(steamId)) { Plugin.Logger.LogWarning((object)("Promote refused: " + steamId + " is not running the mod")); return; } bool flag = false; foreach (IssuedToken item in from t in PromotedTokenStore.Entries() where t.SteamId == steamId select t) { foreach (int item2 in AuthorizedActors.ActorsHolding(item.Token)) { string text = PlayerRegistry.Instance.Resolve(item2); if (!string.IsNullOrEmpty(text) && !(text == steamId)) { Moderators.Instance.RemoveModerator(text); ModeratorSync.BroadcastRemoval(text); AuditEvents.ModeratorRevoked(SteamName(text), text); flag = true; } } PromotedTokenStore.Remove(item.Token); AuthorizedActors.RevokeToken(item.Token); } string text2 = TokenGenerator.NewToken(); PromotedTokenStore.Add(text2, steamId, SteamName(steamId)); AuthorizedActors.Authorize(actor, text2); CommandSender.SendToActors("GrantToken", new object[1] { text2 }, new int[1] { actor }); bool flag2 = Moderators.Instance.IsModerator(steamId); Moderators.Instance.AddModerator(steamId); ModeratorSync.BroadcastFullModeratorList(); if (!flag2) { AuditSync.SendBacklogTo(actor); NotesSync.SendFullTo(actor); } AuditEvents.ModeratorGranted(SteamName(steamId), steamId); if (flag) { PrivateVoiceSync.Rotate("credential reuse"); } else { PrivateVoiceSync.Resync(); } } internal static void DemoteModerator(int actor, string? steamId) { if (LocalIsHost && !string.IsNullOrEmpty(steamId) && !(steamId == LocalSteamId)) { string text = AuthorizedActors.TokenFor(actor); IssuedToken? label = (string.IsNullOrEmpty(text) ? ((IssuedToken?)null) : PromotedTokenStore.Find(text)); HashSet hashSet = new HashSet { steamId }; CollectTokenHolders(text, hashSet); if (!string.IsNullOrEmpty(text)) { PromotedTokenStore.Remove(text); AuthorizedActors.RevokeToken(text); } AuthorizedActors.RemoveActor(actor); RevokeAllCredentialsFor(hashSet); DemoteAndAudit(hashSet, label); } } private static void CollectTokenHolders(string? token, HashSet into) { if (string.IsNullOrEmpty(token)) { return; } foreach (int item in AuthorizedActors.ActorsHolding(token)) { string text = PlayerRegistry.Instance.Resolve(item); if (!string.IsNullOrEmpty(text)) { into.Add(text); } } } private static void DemoteAndAudit(HashSet steamIds, IssuedToken? label) { foreach (string steamId in steamIds) { Moderators.Instance.RemoveModerator(steamId); ModeratorSync.BroadcastRemoval(steamId); string name = ((label.HasValue && steamId == label.Value.SteamId && label.Value.Name.Length > 0) ? label.Value.Name : SteamName(steamId)); AuditEvents.ModeratorRevoked(name, steamId); } PrivateVoiceSync.Rotate("demotion"); } private static void RevokeAllCredentialsFor(HashSet steamIds) { foreach (IssuedToken item in PromotedTokenStore.Entries()) { if (item.SteamId.Length != 0 && steamIds.Contains(item.SteamId)) { CollectTokenHolders(item.Token, steamIds); PromotedTokenStore.Remove(item.Token); AuthorizedActors.RevokeToken(item.Token); } } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { return; } foreach (Player value in currentRoom.Players.Values) { if (value != null && AuthorizedActors.Contains(value.ActorNumber)) { string text = PlayerRegistry.Instance.Resolve(value.ActorNumber); if (!string.IsNullOrEmpty(text) && steamIds.Contains(text)) { string token = AuthorizedActors.TokenFor(value.ActorNumber); CollectTokenHolders(token, steamIds); PromotedTokenStore.Remove(token); AuthorizedActors.RevokeToken(token); AuthorizedActors.RemoveActor(value.ActorNumber); } } } } internal static void RevokeIssuedToken(string token) { if (!LocalIsHost) { return; } IssuedToken? label = PromotedTokenStore.Find(token); if (label.HasValue) { HashSet hashSet = new HashSet(); if (label.Value.SteamId.Length > 0) { hashSet.Add(label.Value.SteamId); } CollectTokenHolders(token, hashSet); PromotedTokenStore.Remove(token); AuthorizedActors.RevokeToken(token); RevokeAllCredentialsFor(hashSet); DemoteAndAudit(hashSet, label); if (hashSet.Count == 0) { AuditEvents.TokenRevoked(TokenPrefix(token)); } } } private static string TokenPrefix(string token) { return ((token.Length > 12) ? token.Substring(0, 12) : token) + "…"; } private static string SteamName(string? steamId) { PlayerAvatar val = (string.IsNullOrEmpty(steamId) ? null : SemiFunc.PlayerGetFromSteamID(steamId)); string text; if (!((Object)(object)val != (Object)null)) { text = steamId; if (text == null) { return ""; } } else { text = MenuUiHelpers.SanitizePlayerName(SemiFunc.PlayerGetName(val)); } return text; } internal static void StartGame() { if (LocalIsHost) { StartCountdown.BeginHostAuthoritative(ModConfig.StartCountdownSeconds.Value); } else { CommandSender.Send("StartGame", Array.Empty(), (ReceiverGroup)2); } } internal static void TogglePrivateVoice() { if (SemiFunc.IsMasterClient()) { if (PrivateVoiceChannel.Active) { PrivateVoiceSync.Close(); } else { PrivateVoiceSync.Open(); } } } internal static void BackToLobby() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ConfirmBackToLobby.Value) { DoBackToLobby(); } else { MenuUiHelpers.ShowTwoOptionPopup("Back to lobby", ConfirmHeaderColor, "Return everyone to the lobby?", DoBackToLobby, null); } } private static void DoBackToLobby() { if (LocalIsHost) { GameActions.ReturnToLobby(); } else { CommandSender.Send("BackToLobby", Array.Empty(), (ReceiverGroup)2); } } internal static bool SendAnnouncement(string? raw) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (!LocalIsHost) { return false; } string text = AnnounceText.Sanitize(raw); if (text.Length == 0) { return false; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (lastAnnounceSentAt > 0f && realtimeSinceStartup - lastAnnounceSentAt < 3f) { return false; } lastAnnounceSentAt = realtimeSinceStartup; CommandSender.Send("Announce", new object[1] { text }, (ReceiverGroup)0); NotificationCenter.EnqueueDirect("Announcement: " + text, ModStyle.SevAnnounce); AuditEvents.Announcement(text); return true; } private static void ShowKickBanModal(string targetName, Action onKick, Action onBan, Action? onPersistentBan = null) { REPOPopupPage popup = MenuUiHelpers.CreatePage("Player Actions", delegate { }); MenuUiHelpers.AddLabel(popup, "Player: " + targetName); MenuUiHelpers.AddScrollViewButton(popup, "Kick", delegate { MenuUiHelpers.ClosePage(popup); onKick(); }); MenuUiHelpers.AddScrollViewButton(popup, "Ban", delegate { MenuUiHelpers.ClosePage(popup); onBan(); }); if (onPersistentBan != null) { MenuUiHelpers.AddScrollViewButton(popup, "Ban (persistent)", delegate { MenuUiHelpers.ClosePage(popup); onPersistentBan(); }); } MenuUiHelpers.OpenPage(popup); } private static void Confirm(string name, string verb, Action onConfirm) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) MenuUiHelpers.ShowTwoOptionPopup("Moderator", ConfirmHeaderColor, name + " is a moderator.\n" + verb + " anyway?", onConfirm, null); } } internal static class ModPanel { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Action <>9__0_0; public static BuilderDelegate <>9__0_4; internal void b__0_0() { } internal void b__0_4(Transform t) { //IL_002b: 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_003c: 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_0061: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton("< Lobby", (Action)ModerationActions.BackToLobby, t, new Vector2(ModStyle.BandLeft, 20f)); Vector2 labelSize = val.GetLabelSize(); ((Transform)((REPOElement)val).rectTransform).localPosition = new Vector3(ModStyle.ColumnCenter(3, 5) - labelSize.x / 2f, 20f, 0f); } } internal static void Open() { //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown if (MenuUiHelpers.IsOpenPending) { return; } REPOPopupPage page = MenuUiHelpers.CreatePage("Moderation", delegate { }); float num = MenuUiHelpers.LayoutScrollMask(page, 42f); float tabY = num - 34f; IReadOnlyList entries = AuditLog.GetEntries(); IReadOnlyList readOnlyList = entries; if (ModConfig.PersistHistory.Value) { HashSet excludeKeys = new HashSet(entries); List list = AuditStore.PastEntries(ModConfig.PersistedHistoryCount.Value, excludeKeys); if (list.Count > 0) { List list2 = new List(list.Count + entries.Count); list2.AddRange(list); list2.AddRange(entries); readOnlyList = list2; } } int count = readOnlyList.Count; MembersPanelController members = new MembersPanelController(page); HistoryPageController history = new HistoryPageController(page, readOnlyList); TokensPanelController tokens = new TokensPanelController(page); SettingsPanelController settings = new SettingsPanelController(page); ExtrasPanelController extras = new ExtrasPanelController(page); string historyCaption = "History " + ModStyle.CountBadge(count, "0.12em"); int initialTokenCount = (SemiFunc.IsMasterClient() ? PromotedTokenStore.Entries().Count : ClientTokenStore.Entries().Count); REPOButton membersTab = null; REPOButton historyTab = null; REPOButton tokensTab = null; REPOButton settingsTab = null; REPOButton extrasTab = null; int active = 0; if (!SemiFunc.RunIsLobbyMenu()) { REPOPopupPage obj = page; object obj2 = <>c.<>9__0_4; if (obj2 == null) { BuilderDelegate val = delegate(Transform t) { //IL_002b: 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_003c: 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_0061: Unknown result type (might be due to invalid IL or missing references) REPOButton val2 = MenuAPI.CreateREPOButton("< Lobby", (Action)ModerationActions.BackToLobby, t, new Vector2(ModStyle.BandLeft, 20f)); Vector2 labelSize = val2.GetLabelSize(); ((Transform)((REPOElement)val2).rectTransform).localPosition = new Vector3(ModStyle.ColumnCenter(3, 5) - labelSize.x / 2f, 20f, 0f); }; <>c.<>9__0_4 = val; obj2 = (object)val; } obj.AddElement((BuilderDelegate)obj2); } page.AddElement((BuilderDelegate)delegate(Transform t) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01da: 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_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) membersTab = MenuAPI.CreateREPOButton("Members", (Action)delegate { Select(0); }, t, new Vector2(ModStyle.BandLeft, tabY)); historyTab = MenuAPI.CreateREPOButton(historyCaption, (Action)delegate { Select(1); }, t, new Vector2(ModStyle.BandLeft, tabY)); tokensTab = MenuAPI.CreateREPOButton(TokensCaption(initialTokenCount), (Action)delegate { Select(2); }, t, new Vector2(ModStyle.BandLeft, tabY)); settingsTab = MenuAPI.CreateREPOButton("Settings", (Action)delegate { Select(3); }, t, new Vector2(ModStyle.BandLeft, tabY)); extrasTab = MenuAPI.CreateREPOButton("+", (Action)delegate { Select(4); }, t, new Vector2(ModStyle.BandLeft, tabY)); REPOButton[] array = (REPOButton[])(object)new REPOButton[4] { membersTab, historyTab, tokensTab, settingsTab }; float num2 = TabBandLayout.TextColumnWidth(array.Length, ModStyle.BandLeft, ModStyle.BandRight); for (int num3 = 0; num3 < array.Length; num3++) { REPOButton val2 = array[num3]; ((TMP_Text)val2.labelTMP).richText = true; ((TMP_Text)val2.labelTMP).fontSize = 15f; Vector2 labelSize = val2.GetLabelSize(); float num4 = Mathf.Max(labelSize.x, num2 - 8f); val2.overrideButtonSize = new Vector2(num4, labelSize.y); ((Transform)((REPOElement)val2).rectTransform).localPosition = new Vector3(TabBandLayout.TextTabCenter(num3, array.Length, ModStyle.BandLeft, ModStyle.BandRight) - labelSize.x / 2f, tabY, 0f); } ((TMP_Text)extrasTab.labelTMP).richText = true; ((TMP_Text)extrasTab.labelTMP).fontSize = 15f; Vector2 labelSize2 = extrasTab.GetLabelSize(); extrasTab.overrideButtonSize = new Vector2(Mathf.Max(labelSize2.x, 18f), labelSize2.y); ((Transform)((REPOElement)extrasTab).rectTransform).localPosition = new Vector3(TabBandLayout.PlusTabCenter(ModStyle.BandRight) - labelSize2.x / 2f, tabY, 0f); }); members.Build(); history.Build(); tokens.Build(); settings.Build(); extras.Build(); tokens.CountChanged = StyleTabs; MembersRefresher membersRefresher = ((Component)page).gameObject.AddComponent(); membersRefresher.OnRefresh = (Action)Delegate.Combine(membersRefresher.OnRefresh, new Action(members.Refresh)); membersRefresher.OnTick = (Action)Delegate.Combine(membersRefresher.OnTick, new Action(members.TickTalking)); membersRefresher.OnTick = (Action)Delegate.Combine(membersRefresher.OnTick, new Action(extras.Tick)); Select(0); MenuUiHelpers.OpenPage(page); void Select(int which) { active = which; members.SetTabVisible(which == 0); history.SetTabVisible(which == 1); tokens.SetTabVisible(which == 2); settings.SetTabVisible(which == 3); extras.SetTabVisible(which == 4); StyleTabs(); page.scrollView.SetScrollPosition(0f); } void StyleTabs() { SetTabCaption(membersTab, "Members", active == 0); SetTabCaption(historyTab, historyCaption, active == 1); SetTabCaption(tokensTab, TokensCaption(tokens.TabCount), active == 2); SetTabCaption(settingsTab, "Settings", active == 3); SetTabCaption(extrasTab, "+", active == 4); } static string TokensCaption(int count2) { return "Access " + ModStyle.CountBadge(count2, "0.12em"); } } private static void SetTabCaption(REPOButton? tab, string text, bool activeTab) { if (!((Object)(object)tab == (Object)null)) { ((TMP_Text)tab.labelTMP).text = (activeTab ? ("" + text + "") : text); } } } internal static class ModStyle { internal const string RoleHostHex = "#ffd24a"; internal const string RoleModeratorHex = "#66b2ff"; internal const string RoleModUserHex = "#9bd17a"; internal const string RoleNoneHex = "#8aa0b0"; internal static readonly Color RoleHost = Hex(16765514); internal static readonly Color RoleModerator = Hex(6730495); internal static readonly Color RoleModUser = Hex(10211706); internal static readonly Color RoleNone = Hex(9085104); internal const string SevFloodHex = "#ff7043"; internal const string SevMuteHex = "#b57ae0"; internal const string SevKickHex = "#ef5350"; internal const string SevBanHex = "#ef5350"; internal const string SevGrantHex = "#66bb6a"; internal const string SevRevokeHex = "#ffa726"; internal const string SevInfoHex = "#8aa0b0"; internal const string SevAnnounceHex = "#4dd0e1"; internal static readonly Color SevFlood = Hex(16740419); internal static readonly Color SevBan = Hex(15684432); internal static readonly Color SevGrant = Hex(6732650); internal static readonly Color SevRevoke = Hex(16754470); internal static readonly Color SevInfo = Hex(9085104); internal static readonly Color SevAnnounce = Hex(5099745); internal static readonly Color SevMute = Hex(11893472); internal const string PrivateLiveHex = "#4dd07a"; internal const string PrivateWaitHex = "#e0b84d"; internal const string PrivateFailHex = "#ef5350"; internal const string MutedHex = "#ef5350"; internal static readonly Color ConfirmDanger = new Color(1f, 0.553f, 0f); internal static readonly Color ConfirmDestructive = new Color(0.94f, 0.45f, 0.42f); internal const string DetailLabelHex = "#8a94a0"; internal const string DetailValueHex = "#e6eaee"; internal const string DetailRawHex = "#69737d"; internal const string ExperimentalHex = "#ffb454"; internal const string SteamHex = "#66c0f4"; internal const string DimBodyHex = "#cdd2d8"; internal const string DimTimeHex = "#9aa4ad"; internal const string DimFaintHex = "#6f7d88"; internal static readonly Color NativeAccent = new Color(1f, 0.522f, 0f); internal const string NativeAccentHex = "#ff8500"; internal const float FontHeader = 15f; internal const float FontRow = 14f; internal const float FontDetail = 14f; internal const string SubTextScale = "85%"; internal const string BadgeScale = "75%"; internal const string BadgeLiftTab = "0.12em"; internal const string BadgeLiftHeader = "0.19em"; internal const float ContentWidth = 250f; internal const float PageSpacing = 4f; internal const float RowBottomPadding = 2f; internal const float LabelBottomPadding = 6f; internal const float ButtonPitch = 30f; internal const float RowHeight = 24f; internal const float MaskBottomY = 56f; internal const float TabBandCarve = 42f; internal const float TabRowDrop = 34f; internal const float TabHitboxGap = 8f; internal const float MaskTopFallbackY = 300f; internal static float BandLeft = 15f; internal static float BandRight = 285f; internal const float BandY = 20f; internal const int BandColumns = 5; internal const int BandColPrev = 0; internal const int BandColPage = 1; internal const int BandColNext = 2; internal const int BandColLobby = 3; internal const int BandColClose = 4; internal const float TitleAlignOffsetX = 0f; internal const float LobbyButtonX = 306f; internal const float LobbyButtonBaseY = 90f; internal const float EscapeButtonX = 250f; internal const float EscapeButtonBaseY = 66f; internal static readonly Vector2 ModTitleOffset = new Vector2(14f, 0f); internal static readonly Vector2 LobbyModFallback = new Vector2(306f, 120f); internal static readonly Vector2 LobbyStartFallback = new Vector2(306f, 90f); internal static readonly Vector2 EscapeModFallback = new Vector2(250f, 66f); internal static readonly Vector2 ToastPos = new Vector2(40f, 40f); internal const float ToastWidth = 560f; internal const float ToastRowHeight = 38f; internal const float ToastRowPitch = 46f; internal const int ToastStackMax = 3; internal const float ToastCascade = 0.15f; internal const int ToastSortingOrder = 100; internal const float ToastFontSize = 20f; internal const float ToastBarWidth = 6f; internal const float ToastBackingAlpha = 0.6f; internal const float ToastDimAlpha = 0.65f; internal static readonly Color ToastText = Hex(15133422); internal const int PrivateHudSortingOrder = 90; internal const float PrivateHudWidth = 240f; internal const float PrivateHudTitleHeight = 26f; internal const float PrivateHudRowHeight = 28f; internal const float PrivateHudRowPitch = 30f; internal const float PrivateHudFontSize = 18f; internal const float PrivateHudBackingAlpha = 0.55f; internal const float PrivateHudSelfBackingAlpha = 0.8f; internal const int PrivateHudMaxRows = 8; internal const float TalkThreshold = 0.005f; internal const float TalkHoldSeconds = 0.18f; internal const string TalkDot = " ●"; internal static string CountBadge(int count, string lift) { return string.Format("({2})", "75%", lift, count); } internal static float ColumnCenter(int index, int columns) { return BandLeft + ((float)index + 0.5f) * (BandRight - BandLeft) / (float)columns; } internal static void ConfigureSingleLineEllipsis(TextMeshProUGUI label) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)label).enableWordWrapping = false; ((TMP_Text)label).overflowMode = (TextOverflowModes)1; ((TMP_Text)label).margin = new Vector4(0f, 0f - ((TMP_Text)label).fontSize, 0f, 0f - ((TMP_Text)label).fontSize); } internal static string RoleHex(ModRole role) { return role switch { ModRole.Host => "#ffd24a", ModRole.Moderator => "#66b2ff", ModRole.ModUser => "#9bd17a", _ => "#8aa0b0", }; } internal static string RoleLabel(ModRole role) { return role switch { ModRole.Host => "Host", ModRole.Moderator => "Moderator", ModRole.ModUser => "Mod user", _ => "No mod", }; } internal static Color KindColor(string? kind) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ce: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) switch (kind) { case "flood": case "kick": case "ghostkick": return SevFlood; case "ban": case "ghostban": return SevBan; case "grant": return SevGrant; case "revoke": return SevRevoke; default: return SevInfo; } } private static Color Hex(int rgb) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) return new Color((float)((rgb >> 16) & 0xFF) / 255f, (float)((rgb >> 8) & 0xFF) / 255f, (float)(rgb & 0xFF) / 255f); } } internal static class ModUi { private sealed class ModButtonGate : MonoBehaviour { private readonly List<(GameObject go, Func show)> buttons = new List<(GameObject, Func)>(); private readonly List<(Transform page, REPOButton button, string seen)> anchors = new List<(Transform, REPOButton, string)>(); internal void Add(GameObject go, Func show) { buttons.Add((go, show)); go.SetActive(show()); } internal void ReAnchor(Transform page, REPOButton button) { anchors.Add((page, button, HeaderText(page))); } private static string HeaderText(Transform page) { MenuPage val = (((Object)(object)page != (Object)null) ? ((Component)page).GetComponent() : null); if (!((Object)(object)val != (Object)null) || !((Object)(object)val.menuHeader != (Object)null)) { return ""; } return ((TMP_Text)val.menuHeader).text; } private void Update() { for (int i = 0; i < buttons.Count; i++) { var (val, func) = buttons[i]; if (!((Object)(object)val == (Object)null)) { bool flag = func(); if (val.activeSelf != flag) { val.SetActive(flag); } } } for (int j = 0; j < anchors.Count; j++) { var (val2, val3, text) = anchors[j]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null)) { string text2 = HeaderText(val2); if (!(text2 == text)) { anchors[j] = (val2, val3, text2); AlignModButtonToTitle(val2, val3); } } } } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func <>9__0_2; public static Func <>9__0_3; public static Func <>9__0_4; public static BuilderDelegate <>9__0_0; public static Func <>9__0_5; public static BuilderDelegate <>9__0_1; internal void b__0_0(Transform parent) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) ModButtonGate modButtonGate = ((Component)parent).gameObject.GetComponent() ?? ((Component)parent).gameObject.AddComponent(); REPOButton val = MenuAPI.CreateREPOButton("Mod", (Action)ModPanel.Open, parent, ModStyle.LobbyModFallback); StyleModButton(val); AlignModButtonToTitle(parent, val); modButtonGate.Add(((Component)val).gameObject, () => CanModerate); modButtonGate.ReAnchor(parent, val); GameObject val2 = NativeStartGo(parent); if ((Object)(object)val2 != (Object)null) { modButtonGate.Add(val2, () => !SemiFunc.IsMultiplayer() || SemiFunc.IsMasterClient() || Moderators.Instance.IsModerator(ModerationActions.LocalSteamId)); } else { REPOButton val3 = MenuAPI.CreateREPOButton("Start game", (Action)ModerationActions.StartGame, parent, ModStyle.LobbyStartFallback); modButtonGate.Add(((Component)val3).gameObject, () => !SemiFunc.IsMasterClient() && Moderators.Instance.IsModerator(ModerationActions.LocalSteamId) && !StartCountdown.Active); } BuildCountdown(parent, val2); } internal bool b__0_2() { return CanModerate; } internal bool b__0_3() { if (SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClient()) { return Moderators.Instance.IsModerator(ModerationActions.LocalSteamId); } return true; } internal bool b__0_4() { if (!SemiFunc.IsMasterClient() && Moderators.Instance.IsModerator(ModerationActions.LocalSteamId)) { return !StartCountdown.Active; } return false; } internal void b__0_1(Transform parent) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) ModButtonGate modButtonGate = ((Component)parent).gameObject.GetComponent() ?? ((Component)parent).gameObject.AddComponent(); REPOButton val = MenuAPI.CreateREPOButton("Mod", (Action)ModPanel.Open, parent, ModStyle.EscapeModFallback); StyleModButton(val); AlignModButtonToTitle(parent, val); modButtonGate.Add(((Component)val).gameObject, () => CanModerate); modButtonGate.ReAnchor(parent, val); } internal bool b__0_5() { return CanModerate; } } private static bool CanModerate => ModerationActions.LocalCanModerate; internal static void Init() { //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: Expected O, but got Unknown //IL_0038: 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: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { BuilderDelegate val = delegate(Transform parent) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) ModButtonGate modButtonGate = ((Component)parent).gameObject.GetComponent() ?? ((Component)parent).gameObject.AddComponent(); REPOButton val3 = MenuAPI.CreateREPOButton("Mod", (Action)ModPanel.Open, parent, ModStyle.LobbyModFallback); StyleModButton(val3); AlignModButtonToTitle(parent, val3); modButtonGate.Add(((Component)val3).gameObject, () => CanModerate); modButtonGate.ReAnchor(parent, val3); GameObject val4 = NativeStartGo(parent); if ((Object)(object)val4 != (Object)null) { modButtonGate.Add(val4, () => !SemiFunc.IsMultiplayer() || SemiFunc.IsMasterClient() || Moderators.Instance.IsModerator(ModerationActions.LocalSteamId)); } else { REPOButton val5 = MenuAPI.CreateREPOButton("Start game", (Action)ModerationActions.StartGame, parent, ModStyle.LobbyStartFallback); modButtonGate.Add(((Component)val5).gameObject, () => !SemiFunc.IsMasterClient() && Moderators.Instance.IsModerator(ModerationActions.LocalSteamId) && !StartCountdown.Active); } BuildCountdown(parent, val4); }; <>c.<>9__0_0 = val; obj = (object)val; } MenuAPI.AddElementToLobbyMenu((BuilderDelegate)obj); object obj2 = <>c.<>9__0_1; if (obj2 == null) { BuilderDelegate val2 = delegate(Transform parent) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) ModButtonGate modButtonGate = ((Component)parent).gameObject.GetComponent() ?? ((Component)parent).gameObject.AddComponent(); REPOButton val3 = MenuAPI.CreateREPOButton("Mod", (Action)ModPanel.Open, parent, ModStyle.EscapeModFallback); StyleModButton(val3); AlignModButtonToTitle(parent, val3); modButtonGate.Add(((Component)val3).gameObject, () => CanModerate); modButtonGate.ReAnchor(parent, val3); }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } MenuAPI.AddElementToEscapeMenu((BuilderDelegate)obj2); Plugin.Logger.LogInfo((object)"Native moderation UI initialized"); } private static void AlignModButtonToTitle(Transform page, REPOButton button) { try { AlignToTitleRaw(page, button); } catch { } } [MethodImpl(MethodImplOptions.NoInlining)] private static void AlignToTitleRaw(Transform page, REPOButton button) { //IL_002f: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) MenuPage component = ((Component)page).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.menuHeader == (Object)null)) { TextMeshProUGUI menuHeader = component.menuHeader; ((TMP_Text)menuHeader).ForceMeshUpdate(false, false); Bounds textBounds = ((TMP_Text)menuHeader).textBounds; Vector3 val; if (((Bounds)(ref textBounds)).extents.x > 0f) { val = ((TMP_Text)menuHeader).transform.TransformPoint(new Vector3(((Bounds)(ref textBounds)).max.x, ((Bounds)(ref textBounds)).center.y, 0f)); } else { Rect rect = ((TMP_Text)menuHeader).rectTransform.rect; val = ((Transform)((TMP_Text)menuHeader).rectTransform).TransformPoint(new Vector3(((Rect)(ref rect)).xMax, ((Rect)(ref rect)).center.y, 0f)); } Vector3 val2 = page.InverseTransformPoint(val); Vector2 labelSize = button.GetLabelSize(); ((Transform)((REPOElement)button).rectTransform).localPosition = new Vector3(val2.x + ModStyle.ModTitleOffset.x, val2.y - labelSize.y / 2f + ModStyle.ModTitleOffset.y, 0f); } } private static void BuildCountdown(Transform page, GameObject? nativeStart) { //IL_0069: 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) GameObject val = null; CanvasGroup fade = null; TMP_Text val2 = null; if ((Object)(object)nativeStart != (Object)null) { try { (val, fade, val2) = BuildCountdownSlotRaw(nativeStart); } catch { val = null; fade = null; val2 = null; } } bool richAccent = false; if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { REPOButton val3 = MenuAPI.CreateREPOButton("Starts in 5", (Action)CancelCountdownIfAllowed, page, ModStyle.LobbyStartFallback); ((REPOElement)val3).rectTransform.pivot = new Vector2(0.5f, 0.5f); ((TMP_Text)val3.labelTMP).richText = true; val = ((Component)val3).gameObject; val2 = (TMP_Text)(object)val3.labelTMP; richAccent = true; } val.SetActive(false); ((Component)page).gameObject.AddComponent().Wire(val, fade, val2, richAccent, nativeStart); } [MethodImpl(MethodImplOptions.NoInlining)] private static (GameObject root, CanvasGroup fade, TMP_Text label) BuildCountdownSlotRaw(GameObject nativeStart) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0052: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)nativeStart.transform; GameObject val2 = new GameObject("SharePermissions Countdown", new Type[2] { typeof(RectTransform), typeof(CanvasGroup) }); RectTransform val3 = (RectTransform)val2.transform; ((Transform)val3).SetParent(((Transform)val).parent, false); val3.anchorMin = val.anchorMin; val3.anchorMax = val.anchorMax; val3.pivot = val.pivot; val3.anchoredPosition = val.anchoredPosition; val3.sizeDelta = val.sizeDelta; ((Transform)val3).localScale = ((Transform)val).localScale; ((Transform)val3).localRotation = ((Transform)val).localRotation; TextMeshProUGUI componentInChildren = nativeStart.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { throw new InvalidOperationException("native Start button has no label"); } GameObject val4 = Object.Instantiate(((Component)componentInChildren).gameObject, (Transform)(object)val3); ((Object)val4).name = "Countdown Label"; LocalizationChangedEvent[] componentsInChildren = val4.GetComponentsInChildren(true); foreach (LocalizationChangedEvent val5 in componentsInChildren) { val5.localizedAsset = null; } Component[] components = val4.GetComponents(); foreach (Component val6 in components) { if ((!(val6 is RectTransform) && !(val6 is CanvasRenderer) && !(val6 is TMP_Text)) || 1 == 0) { Object.Destroy((Object)(object)val6); } } foreach (Transform item in val4.transform) { Transform val7 = item; Object.Destroy((Object)(object)((Component)val7).gameObject); } TextMeshProUGUI component = val4.GetComponent(); ((TMP_Text)component).text = "Starts in 5"; ((Graphic)component).color = ModStyle.NativeAccent; return (root: val2, fade: val2.GetComponent(), label: (TMP_Text)(object)component); } private static GameObject? NativeStartGo(Transform page) { try { return NativeStartGoRaw(page); } catch { return null; } } [MethodImpl(MethodImplOptions.NoInlining)] private static GameObject? NativeStartGoRaw(Transform page) { MenuPageLobby component = ((Component)page).GetComponent(); if (!((Object)(object)component != (Object)null) || !((Object)(object)component.startButton != (Object)null)) { return null; } return ((Component)component.startButton).gameObject; } private static void CancelCountdownIfAllowed() { if (CanModerate) { StartCountdown.RequestCancelFromUi(); } } private static void StyleModButton(REPOButton button) { ((TMP_Text)button.labelTMP).richText = true; ((TMP_Text)button.labelTMP).text = "Mod"; } } internal static class NativeKickButton { internal static GameObject CreateX(GameObject nativeKickGo, Action onClick) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(nativeKickGo, nativeKickGo.transform.parent); ((Object)val).name = "SharePermissions_XKick"; val.SetActive(true); RectTransform val2 = null; MenuButtonKick component = val.GetComponent(); if (component != null) { val2 = component.backgroundRect; Object.Destroy((Object)(object)component); } MenuButtonPopUp componentInChildren = val.GetComponentInChildren(true); if (componentInChildren != null) { Object.Destroy((Object)(object)componentInChildren); } MenuButton componentInChildren2 = val.GetComponentInChildren(true); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.buttonTextString = "x"; if ((Object)(object)componentInChildren2.buttonText != (Object)null) { ((TMP_Text)componentInChildren2.buttonText).text = "x"; componentInChildren2.ResizeToText(); } } Button componentInChildren3 = val.GetComponentInChildren