Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SharePermissions v2.4.2
SharePermissions.dll
Decompiled 12 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using MenuLib.Structs; using Microsoft.CodeAnalysis; using POpusCodec.Enums; using Photon.Pun; using Photon.Realtime; using Photon.Voice; using Photon.Voice.Unity; using SharePermissions.Core; using SharePermissions.Net; using SharePermissions.Net.Commands; using SharePermissions.Patches; using SharePermissions.Players; using SharePermissions.UI; using SharePermissions.Voice; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.TextCore; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("RED")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.4.2.0")] [assembly: AssemblyInformationalVersion("2.4.2+7581cc1fa5ca36b471ae197025cadb2d1e834ffe")] [assembly: AssemblyProduct("SharePermissions")] [assembly: AssemblyTitle("SharePermissions")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.4.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SharePermissions.Voice { internal sealed class MicRing { private readonly float[] buffer; private volatile int writeIndex; private volatile int readIndex; private volatile float level; internal float Level => level; internal int Available { get { int num = writeIndex; int num2 = readIndex; if (num < num2) { return buffer.Length - num2 + num; } return num - num2; } } internal MicRing(int capacity) { if (capacity < 2) { capacity = 2; } buffer = new float[capacity]; } internal void Write(float[] data, int count) { if (data != null && count > 0) { if (count > data.Length) { count = data.Length; } float num = 0f; for (int i = 0; i < count; i++) { num += Math.Abs(data[i]); } level = num / (float)count; int num2 = writeIndex; int num3 = buffer.Length - 1 - Available; if (count > num3) { count = num3; } for (int j = 0; j < count; j++) { buffer[num2] = data[j]; num2 = ((num2 + 1 != buffer.Length) ? (num2 + 1) : 0); } writeIndex = num2; } } internal bool Read(float[] destination) { if (destination == null || destination.Length == 0) { return false; } if (Available < destination.Length) { return false; } int num = readIndex; for (int i = 0; i < destination.Length; i++) { destination[i] = buffer[num]; num = ((num + 1 != buffer.Length) ? (num + 1) : 0); } readIndex = num; return true; } internal void Reset() { readIndex = 0; writeIndex = 0; level = 0f; } } [HarmonyPatch(typeof(MicWrapper), "Read")] internal static class MicTee { private const int RingCapacity = 48000; internal static readonly MicRing Ring = new MicRing(48000); private static volatile int samplingRate; private static volatile int channels; internal static int SamplingRate => samplingRate; internal static int Channels => channels; internal static bool IsLive { get { if (SamplingRate > 0) { return Channels > 0; } return false; } } internal static float Level => Ring.Level; [HarmonyPostfix] [HarmonyWrapSafe] private static void Read_Postfix(MicWrapper __instance, float[] buffer, bool __result) { if (__result && buffer != null && PrivateVoiceGate.WantCapture) { channels = __instance.Channels; samplingRate = __instance.SamplingRate; Ring.Write(buffer, buffer.Length); } } internal static void Flush() { Ring.Reset(); Plugin.Logger.LogDebug((object)"Private voice: mic tee flushed"); } } internal static class PrivateVoiceGate { internal static volatile bool WantCapture; } internal static class PrivateSpeakers { private sealed class Entry { internal GameObject Go; internal Speaker Speaker; internal AudioSource Source; internal PrivateSpeakerGain Gain; internal int Actor; internal volatile float Amplitude; } private static readonly Dictionary<int, Entry> ByPlayerId = new Dictionary<int, Entry>(); private static readonly HashSet<Speaker> AmplitudeAttached = new HashSet<Speaker>(); private static float volume = 1f; internal static Speaker? Create(int playerId, object userData) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown if (!(userData is int num) || num <= 0) { Plugin.Logger.LogWarning((object)$"Private voice: stream {playerId} carried no usable actor claim - refusing"); return null; } if (!PrivateVoiceChannel.IsMemberActor(num)) { Plugin.Logger.LogWarning((object)$"Private voice: stream from non-member actor {num} - refusing to play"); return null; } foreach (KeyValuePair<int, Entry> item in ByPlayerId) { if (item.Key != playerId && item.Value.Actor == num) { Plugin.Logger.LogWarning((object)$"Private voice: actor {num} already claimed by another stream - refusing"); return null; } } if (ByPlayerId.TryGetValue(playerId, out Entry value)) { return value.Speaker; } GameObject val = new GameObject($"SP_PrivSpeaker_a{num}"); Object.DontDestroyOnLoad((Object)(object)val); AudioSource val2 = val.AddComponent<AudioSource>(); val2.spatialBlend = 0f; val2.mute = false; val2.dopplerLevel = 0f; val2.priority = 0; val2.outputAudioMixerGroup = null; val2.bypassEffects = false; val2.bypassListenerEffects = true; val2.bypassReverbZones = true; PrivateSpeakerGain gain = val.AddComponent<PrivateSpeakerGain>(); Speaker val3 = val.AddComponent<Speaker>(); Entry entry = new Entry { Go = val, Speaker = val3, Source = val2, Gain = gain, Actor = num }; ByPlayerId[playerId] = entry; Apply(entry, volume); val3.OnRemoteVoiceRemoveAction = delegate(Speaker s) { ByPlayerId.Remove(playerId); if ((Object)(object)s != (Object)null && (Object)(object)((Component)s).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)s).gameObject); } }; Plugin.Logger.LogInfo((object)$"Private voice: speaker for actor {num}"); return val3; } internal static void AttachAmplitude(Speaker speaker) { if ((Object)(object)speaker == (Object)null) { return; } RemoteVoiceLink remoteVoice = speaker.RemoteVoice; if (remoteVoice == null) { return; } Entry entry = null; foreach (KeyValuePair<int, Entry> item in ByPlayerId) { if (item.Value.Speaker == speaker) { entry = item.Value; break; } } if (entry == null || !AmplitudeAttached.Add(speaker)) { return; } remoteVoice.FloatFrameDecoded += delegate(FrameOut<float> frame) { float[] buf = frame.Buf; if (buf != null && buf.Length != 0) { float num = 0f; for (int i = 0; i < buf.Length; i++) { num += ((buf[i] < 0f) ? (0f - buf[i]) : buf[i]); } entry.Amplitude = num / (float)buf.Length; } }; } internal static void DestroyAll() { foreach (KeyValuePair<int, Entry> item in ByPlayerId) { Entry value = item.Value; if ((Object)(object)value.Speaker != (Object)null) { value.Speaker.OnRemoteVoiceRemoveAction = null; } if ((Object)(object)value.Go != (Object)null) { Object.Destroy((Object)(object)value.Go); } } ByPlayerId.Clear(); AmplitudeAttached.Clear(); } internal static float AmplitudeFor(int actorNumber) { foreach (KeyValuePair<int, Entry> item in ByPlayerId) { if (item.Value.Actor == actorNumber) { return item.Value.Amplitude; } } return 0f; } internal static int[] SpeakingActors() { List<int> list = new List<int>(ByPlayerId.Count); foreach (KeyValuePair<int, Entry> item in ByPlayerId) { list.Add(item.Value.Actor); } return list.ToArray(); } internal static void SetVolume(float value) { if (value < 0f) { value = 0f; } float num = 3f; if (value > num) { value = num; } volume = value; foreach (KeyValuePair<int, Entry> item in ByPlayerId) { Apply(item.Value, value); } } private static void Apply(Entry entry, float value) { if ((Object)(object)entry.Source != (Object)null) { entry.Source.volume = ((value > 1f) ? 1f : value); } if ((Object)(object)entry.Gain != (Object)null) { entry.Gain.Gain = ((value > 1f) ? value : 1f); } } } internal sealed class PrivateSpeakerGain : MonoBehaviour { private volatile float gain = 1f; internal float Gain { get { return gain; } set { gain = ((value < 1f) ? 1f : value); } } private void OnAudioFilterRead(float[] data, int channels) { float num = gain; if (num != 1f) { for (int i = 0; i < data.Length; i++) { data[i] *= num; } } } } internal sealed class PrivateVoiceClient : VoiceFollowClient { private const float ConnectWarnCooldownSeconds = 5f; private const float ConnectRetryCooldownSeconds = 3f; private static bool quitting; private string token = string.Empty; private Recorder? recorder; private int userDataActor; private float nextConnectWarnAt; private float nextConnectAttemptAt; internal static PrivateVoiceClient? Instance { get; private set; } internal static bool EverCreated { get; private set; } internal Recorder? PrivateRecorder => recorder; protected override bool LeaderInRoom { get { if (PhotonNetwork.InRoom) { return PrivateVoiceChannel.IsValidRoomName(token); } return false; } } protected override bool LeaderOfflineMode => PhotonNetwork.OfflineMode; internal static void Init() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("SP_PrivateVoice") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val); Instance = val.AddComponent<PrivateVoiceClient>(); ((VoiceConnection)Instance).SpeakerLinked += PrivateSpeakers.AttachAmplitude; EverCreated = true; Application.quitting += delegate { quitting = true; }; Plugin.Logger.LogInfo((object)"Private voice client created"); } } internal void Provision(string roomName) { if (!PrivateVoiceChannel.IsValidRoomName(roomName)) { Plugin.Logger.LogWarning((object)"Private voice: refusing a malformed room name"); return; } PrivateVoiceGate.WantCapture = true; bool flag = PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null && PhotonNetwork.LocalPlayer.ActorNumber > 0; if ((Object)(object)recorder == (Object)null) { if (flag && MicTee.IsLive) { CreateRecorder(); } } else if (flag) { SyncUserData(recorder); } bool flag2 = ((VoiceConnection)this).Client != null && ((LoadBalancingClient)((VoiceConnection)this).Client).IsConnected; if (roomName == token && flag2) { return; } if (token.Length > 0 && roomName != token) { token = string.Empty; SafeDisconnect(); return; } if (token.Length == 0) { if (flag2) { return; } token = roomName; } if (!(((VoiceConnection)this).Client == null || flag2) && PhotonNetwork.InRoom && !(Time.unscaledTime < nextConnectAttemptAt)) { nextConnectAttemptAt = Time.unscaledTime + 3f; if (!((VoiceFollowClient)this).ConnectAndJoinRoom() && Time.unscaledTime >= nextConnectWarnAt) { nextConnectWarnAt = Time.unscaledTime + 5f; Plugin.Logger.LogWarning((object)("Private voice: connect/join refused for room " + PrivateVoiceChannel.Fingerprint(roomName))); } } } protected override void Start() { ((VoiceFollowClient)this).Start(); if (PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.StateChanged += OnLeaderStateChanged; } } private void OnLeaderStateChanged(ClientState fromState, ClientState toState) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((VoiceFollowClient)this).LeaderStateChanged(toState); } protected override void OnDestroy() { if (Instance == this && !quitting) { Plugin.Logger.LogWarning((object)"Private voice: SP_PrivateVoice is being destroyed - the private channel cannot run again this session"); } if (PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.StateChanged -= OnLeaderStateChanged; } ((VoiceFollowClient)this).OnDestroy(); } private void CreateRecorder() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SP_PrivateRecorder"); val.transform.SetParent(((Component)this).transform, false); Recorder val2 = val.AddComponent<Recorder>(); PrivateVoiceDsp.Mirror(val); val2.SourceType = (InputSourceType)2; val2.MicrophoneType = (MicType)1; val2.InputFactory = () => (IAudioDesc)(object)new TeeAudioReader(); userDataActor = PhotonNetwork.LocalPlayer.ActorNumber; val2.UserData = userDataActor; val2.TransmitEnabled = false; val2.VoiceDetection = false; val2.Encrypt = true; val2.DebugEchoMode = false; val2.InterestGroup = 0; val2.TargetPlayers = null; val2.SamplingRate = NearestSupportedRate(MicTee.SamplingRate); ((VoiceConnection)this).PrimaryRecorder = val2; if (!((VoiceConnection)this).AddRecorder(val2)) { Plugin.Logger.LogWarning((object)"Private voice: AddRecorder refused - the recorder will never transmit"); Object.Destroy((Object)(object)val); } else { recorder = val2; Plugin.Logger.LogInfo((object)$"Private voice recorder ready ({MicTee.SamplingRate} Hz, {MicTee.Channels} ch)"); } } private void SyncUserData(Recorder rec) { int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber; if (actorNumber != userDataActor) { userDataActor = actorNumber; rec.UserData = actorNumber; Plugin.Logger.LogInfo((object)"Private voice: local actor number changed, rebinding recorder identity"); } } private static SamplingRate NearestSupportedRate(int hz) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (hz <= 20000) { if (hz > 10000) { if (hz <= 14000) { return (SamplingRate)12000; } return (SamplingRate)16000; } return (SamplingRate)8000; } if (hz <= 36000) { return (SamplingRate)24000; } return (SamplingRate)48000; } internal bool ChannelLive(string expectedRoom) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 if (((VoiceConnection)this).Client == null || (int)((LoadBalancingClient)((VoiceConnection)this).Client).State != 9) { return false; } Room currentRoom = ((LoadBalancingClient)((VoiceConnection)this).Client).CurrentRoom; if (currentRoom != null && currentRoom.Name == expectedRoom) { return PrivateVoiceChannel.IsValidRoomName(currentRoom.Name); } return false; } private void SafeDisconnect() { if (((VoiceConnection)this).Client != null && ((LoadBalancingClient)((VoiceConnection)this).Client).IsConnected) { ((VoiceFollowClient)this).Disconnect(); } } internal void TearDown() { if ((Object)(object)recorder != (Object)null) { recorder.TransmitEnabled = false; } PrivateSpeakers.DestroyAll(); SafeDisconnect(); PrivateVoiceGate.WantCapture = false; MicTee.Flush(); token = string.Empty; nextConnectWarnAt = 0f; nextConnectAttemptAt = 0f; } protected override string GetVoiceRoomName() { return token; } protected override bool ConnectVoice() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0076: Expected O, but got Unknown AppSettings val = null; ((LoadBalancingClient)((VoiceConnection)this).Client).ServerPortOverrides = PhotonNetwork.ServerPortOverrides; val = PhotonNetwork.PhotonServerSettings.AppSettings.CopyTo(new AppSettings()); if (!string.IsNullOrEmpty(PhotonNetwork.CloudRegion)) { val.FixedRegion = PhotonNetwork.CloudRegion; } ((LoadBalancingClient)((VoiceConnection)this).Client).SerializationProtocol = PhotonNetwork.NetworkingClient.SerializationProtocol; if (PhotonNetwork.AuthValues != null) { LoadBalancingTransport client = ((VoiceConnection)this).Client; if (((LoadBalancingClient)client).AuthValues == null) { AuthenticationValues val2 = new AuthenticationValues(); AuthenticationValues val3 = val2; ((LoadBalancingClient)client).AuthValues = val2; } ((LoadBalancingClient)((VoiceConnection)this).Client).AuthValues = PhotonNetwork.AuthValues.CopyTo(((LoadBalancingClient)((VoiceConnection)this).Client).AuthValues); } ((LoadBalancingClient)((VoiceConnection)this).Client).AuthMode = PhotonNetwork.NetworkingClient.AuthMode; ((LoadBalancingClient)((VoiceConnection)this).Client).EncryptionMode = PhotonNetwork.NetworkingClient.EncryptionMode; return ((VoiceConnection)this).ConnectUsingSettings(val); } protected override bool JoinVoiceRoom(string voiceRoomName) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006b: Expected O, but got Unknown if (!PrivateVoiceChannel.IsValidRoomName(voiceRoomName)) { Plugin.Logger.LogWarning((object)"Private voice: join refused, malformed room name"); return false; } RoomOptions roomOptions = new RoomOptions { IsVisible = false, IsOpen = true, MaxPlayers = 0, PlayerTtl = 2000, PublishUserId = true }; EnterRoomParams val = new EnterRoomParams { RoomName = voiceRoomName, RoomOptions = roomOptions, Lobby = new TypedLobby("spv", (LobbyType)0) }; Plugin.Logger.LogInfo((object)("Private voice: joining room " + PrivateVoiceChannel.Fingerprint(voiceRoomName))); return ((LoadBalancingClient)((VoiceConnection)this).Client).OpJoinOrCreateRoom(val); } protected override void OnOperationResponseReceived(OperationResponse operationResponse) { if (operationResponse.ReturnCode == 0) { ((VoiceFollowClient)this).OnOperationResponseReceived(operationResponse); return; } Plugin.Logger.LogWarning((object)$"Private voice: op {operationResponse.OperationCode} failed ({operationResponse.ReturnCode})"); if (operationResponse.OperationCode != 226) { ((VoiceFollowClient)this).OnOperationResponseReceived(operationResponse); return; } string roomName = token; try { token = PrivateVoiceChannel.Fingerprint(roomName); ((VoiceFollowClient)this).OnOperationResponseReceived(operationResponse); } finally { token = roomName; } } protected override Speaker? InstantiateSpeakerForRemoteVoice(int playerId, byte voiceId, object userData) { try { return PrivateSpeakers.Create(playerId, userData); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Private voice: speaker construction failed: {arg}"); return null; } } } internal static class PrivateVoiceDriver { internal enum Health { Off, Provisioning, Live, Listening, Failed } private const float ReleaseGraceSeconds = 0.3f; private const float IntrusionConfirmSeconds = 2f; private const float MissingClientWarnCooldownSeconds = 5f; private static bool lastVoiceJoined; private static float releaseAt; private static float nextMissingClientWarnAt; private static string provisionedRoom = string.Empty; private static float unexpectedOccupantFirstSeenAt = -1f; internal static Health State { get; private set; } = Health.Off; internal static void Tick() { int num = ((PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0); PrivateVoiceChannel.SetLocalMembership(num > 0 && PrivateVoiceChannel.IsMemberActor(num)); bool localActive = PrivateVoiceChannel.LocalActive; if (!localActive && provisionedRoom.Length > 0) { TearDown("mode off"); } RecorderTransmitPatch.Suppress = localActive || Time.realtimeSinceStartup < releaseAt; if (!localActive) { if (Time.realtimeSinceStartup < releaseAt) { ForceGameRecorderOff(); } State = Health.Off; return; } ForceGameRecorderOff(); PrivateSpeakers.SetVolume(GameVolume() * PrivateVoiceLocalPrefs.Factor); PrivateVoiceClient instance = PrivateVoiceClient.Instance; if ((Object)(object)instance == (Object)null) { if (Time.realtimeSinceStartup >= nextMissingClientWarnAt) { nextMissingClientWarnAt = Time.realtimeSinceStartup + 5f; Plugin.Logger.LogWarning((object)(PrivateVoiceClient.EverCreated ? "Private voice: the voice client was created at startup but no longer exists - something destroyed the SP_PrivateVoice object, so the channel cannot run" : "Private voice: the voice client was never created - PrivateVoiceClient.Init did not run or threw")); } State = Health.Failed; return; } string roomName = PrivateVoiceChannel.RoomName; if (provisionedRoom != roomName) { if (provisionedRoom.Length > 0) { TearDown("room rotated"); } else { MicTee.Flush(); } instance.Provision(roomName); provisionedRoom = roomName; State = Health.Provisioning; return; } if ((Object)(object)instance.PrivateRecorder == (Object)null) { instance.Provision(roomName); bool flag = instance.ChannelLive(roomName); if (!lastVoiceJoined && flag) { MicTee.Flush(); } lastVoiceJoined = flag; State = ((!flag) ? Health.Provisioning : Health.Listening); return; } bool flag2 = instance.ChannelLive(roomName); if (!lastVoiceJoined && flag2) { MicTee.Flush(); } if (lastVoiceJoined && !flag2) { Plugin.Logger.LogInfo((object)"Private voice: channel dropped, re-provisioning"); } lastVoiceJoined = flag2; if (!flag2) { instance.Provision(roomName); SetPrivateTransmit(on: false); State = Health.Provisioning; return; } AuditOccupants(); if (State == Health.Failed) { return; } Recorder privateRecorder = instance.PrivateRecorder; if ((Object)(object)privateRecorder != (Object)null && privateRecorder.RecordingEnabled) { if (privateRecorder.InterestGroup != 0) { privateRecorder.InterestGroup = 0; } if (privateRecorder.TargetPlayers != null) { privateRecorder.TargetPlayers = null; } } SetPrivateTransmit(GameMicAllows() && !PrivateVoiceLocalPrefs.MicMuted); State = Health.Live; } private static void AuditOccupants() { PrivateVoiceClient? instance = PrivateVoiceClient.Instance; object obj; if (instance == null) { obj = null; } else { LoadBalancingTransport client = ((VoiceConnection)instance).Client; if (client == null) { obj = null; } else { Room currentRoom = ((LoadBalancingClient)client).CurrentRoom; obj = ((currentRoom != null) ? currentRoom.Players : null); } } Dictionary<int, Player> dictionary = (Dictionary<int, Player>)obj; if (dictionary == null) { return; } PlayerRegistry instance2 = PlayerRegistry.Instance; if (instance2 == null) { return; } int[] array = PrivateVoiceChannel.MemberActors(); for (int i = 0; i < array.Length; i++) { if (instance2.TryGetSteamId(array[i]) == null) { return; } } bool flag = false; foreach (KeyValuePair<int, Player> item in dictionary) { Player value = item.Value; if (value == null || value.IsLocal || value.IsInactive) { continue; } string userId = value.UserId; if (string.IsNullOrEmpty(userId)) { continue; } bool flag2 = false; for (int j = 0; j < array.Length; j++) { if (instance2.TryGetSteamId(array[j]) == userId) { flag2 = true; break; } } if (!flag2) { flag = true; break; } } if (!flag) { unexpectedOccupantFirstSeenAt = -1f; return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (unexpectedOccupantFirstSeenAt < 0f) { unexpectedOccupantFirstSeenAt = realtimeSinceStartup; } else if (!(realtimeSinceStartup - unexpectedOccupantFirstSeenAt < 2f)) { Plugin.Logger.LogWarning((object)"Private voice: unexpected occupant persisted - muting the private channel"); SetPrivateTransmit(on: false); State = Health.Failed; } } private static bool GameMicAllows() { PlayerVoiceChat instance = PlayerVoiceChat.instance; if ((Object)(object)instance == (Object)null) { return false; } if (!instance.microphoneEnabled) { return false; } if ((Object)(object)DataDirector.instance == (Object)null) { return false; } if (DataDirector.instance.toggleMute) { return false; } if ((Object)(object)AudioManager.instance == (Object)null) { return false; } if (AudioManager.instance.pushToTalk && !SemiFunc.InputHold((InputKey)25)) { return false; } return true; } private static float GameVolume() { if ((Object)(object)DataDirector.instance == (Object)null) { return 1f; } float num = (float)DataDirector.instance.SettingValueFetch((Setting)13) * 0.01f; float num2 = (float)DataDirector.instance.SettingValueFetch((Setting)4) * 0.01f; float num3 = num * num2; if (num3 < 0f) { num3 = 0f; } if (num3 > 1f) { num3 = 1f; } return num3; } private static void SetPrivateTransmit(bool on) { Recorder val = PrivateVoiceClient.Instance?.PrivateRecorder; if ((Object)(object)val != (Object)null && val.TransmitEnabled != on) { val.TransmitEnabled = on; } } private static void ForceGameRecorderOff() { PlayerVoiceChat instance = PlayerVoiceChat.instance; if (!((Object)(object)instance == (Object)null)) { Recorder component = ((Component)instance).GetComponent<Recorder>(); if ((Object)(object)component != (Object)null) { RecorderTransmitPatch.ForceOff(component); } } } internal static void TearDown(string reason) { if (provisionedRoom.Length != 0 || State != Health.Off) { Plugin.Logger.LogInfo((object)("Private voice: tearing down (" + reason + ")")); SetPrivateTransmit(on: false); PrivateVoiceClient.Instance?.TearDown(); provisionedRoom = string.Empty; lastVoiceJoined = false; unexpectedOccupantFirstSeenAt = -1f; State = Health.Off; releaseAt = Time.realtimeSinceStartup + 0.3f; } } } internal static class PrivateVoiceLocalPrefs { internal const int MaxVolumePercent = 300; internal static int VolumePercent => ModConfig.PrivateChannelVolume.Value; internal static bool Muted { get; private set; } internal static bool MicMuted { get; private set; } internal static float Factor { get { if (!Muted) { return (float)VolumePercent * 0.01f; } return 0f; } } internal static void SetVolumePercent(int value) { int num = ((value >= 0) ? ((value > 300) ? 300 : value) : 0); if (ModConfig.PrivateChannelVolume.Value != num) { ModConfig.PrivateChannelVolume.Value = num; } } internal static void ToggleMuted() { Muted = !Muted; } internal static void ToggleMicMuted() { MicMuted = !MicMuted; } } internal static class PrivateVoiceDsp { internal static void Mirror(GameObject recorderObject) { PlayerVoiceChat instance = PlayerVoiceChat.instance; WebRtcAudioDsp val = (((Object)(object)instance != (Object)null) ? ((Component)instance).GetComponent<WebRtcAudioDsp>() : null); if ((Object)(object)val == (Object)null) { Plugin.Logger.LogWarning((object)"Private voice: the game's recorder carries no WebRtcAudioDsp - the private stream keeps the raw microphone level and will stay quieter than the public channel"); return; } if (MicTee.Channels != 1) { Plugin.Logger.LogWarning((object)$"Private voice: capture is {MicTee.Channels} ch and WebRtcAudioDsp is mono-only - the DSP mirror is skipped and the private stream keeps the raw microphone level"); return; } WebRtcAudioDsp val2 = recorderObject.AddComponent<WebRtcAudioDsp>(); val2.AEC = val.AEC; val2.AecHighPass = val.AecHighPass; val2.ReverseStreamDelayMs = val.ReverseStreamDelayMs; val2.HighPass = val.HighPass; val2.NoiseSuppression = val.NoiseSuppression; val2.AGC = val.AGC; val2.AgcCompressionGain = val.AgcCompressionGain; val2.AgcTargetLevel = val.AgcTargetLevel; val2.Bypass = val.Bypass; val2.VAD = false; Plugin.Logger.LogInfo((object)$"Private voice: DSP mirrored from the game's recorder (AGC {OnOff(val2.AGC)} target {val2.AgcTargetLevel} dBFS / compression {val2.AgcCompressionGain} dB, noise suppression {OnOff(val2.NoiseSuppression)}, high pass {OnOff(val2.HighPass)}, AEC {OnOff(val2.AEC)}, VAD off by design, bypass {OnOff(val2.Bypass)})"); } private static string OnOff(bool value) { if (!value) { return "off"; } return "on"; } } internal sealed class TeeAudioReader : IAudioReader<float>, IDataReader<float>, IDisposable, IAudioDesc { public int SamplingRate => MicTee.SamplingRate; public int Channels => MicTee.Channels; public string? Error { get { if (!MicTee.IsLive) { return "mic tee not live"; } return null; } } public bool Read(float[] buffer) { return MicTee.Ring.Read(buffer); } public void Dispose() { } } } namespace SharePermissions.UI { internal static class ColorPickerPage { private const float ContentWidth = 250f; private const float SwatchSize = 34f; private const float SwatchPitch = 38f; private const int SwatchesPerRow = 6; private static readonly IReadOnlyList<Color> FallbackPalette = (IReadOnlyList<Color>)(object)new Color[16] { ModStyle.RoleHost, ModStyle.RoleModerator, ModStyle.RoleModUser, ModStyle.RoleNone, ModStyle.SevBan, ModStyle.SevRevoke, ModStyle.SevGrant, ModStyle.SevFlood, Color.white, Color.red, Color.green, Color.blue, Color.yellow, Color.cyan, Color.magenta, Color.gray }; internal static void Open(string title, string description, Color current, Action<Color> onPicked, string? clearCaption = null, Action? onClear = null) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) REPOPopupPage page = MenuUiHelpers.CreatePage(title, delegate { }); MenuUiHelpers.AddLabel(page, description); MenuUiHelpers.AddLabel(page, "<size=75%><color=#6f7d88>Current</color> <color=#" + NameColors.ToHex(current) + ">#" + NameColors.ToHex(current) + "</color></size>"); foreach (IReadOnlyList<Color> item in Rows(Palette())) { AddSwatchRow(page, item, Choose); } AddHexInput(page, current, Choose); if (onClear != null && clearCaption != null) { MenuUiHelpers.AddScrollViewButton(page, clearCaption, delegate { MenuUiHelpers.ClosePage(page); onClear(); }); } MenuUiHelpers.OpenPage(page); void Choose(Color color) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) MenuUiHelpers.ClosePage(page); onPicked(color); } } private static void AddSwatchRow(REPOPopupPage page, IReadOnlyList<Color> colors, Action<Color> onChoose) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SharePermissions_SwatchRow", new Type[1] { typeof(RectTransform) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(scrollView, false); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.zero; val2.pivot = Vector2.zero; val2.sizeDelta = new Vector2(250f, 34f); for (int i = 0; i < colors.Count; i++) { Color color = colors[i]; REPOButton val3 = MenuAPI.CreateREPOButton("", (Action)delegate { //IL_000c: Unknown result type (might be due to invalid IL or missing references) onChoose(color); }, (Transform)(object)val2, new Vector2((float)i * 38f, 0f)); val3.overrideButtonSize = new Vector2(34f, 34f); StyleSwatch(val3, color); } return val2; }, 0f, 2f); } private static void StyleSwatch(REPOButton button, Color color) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) Image component = ((Component)button).GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = color; ((Graphic)component).raycastTarget = true; } if (!((Object)(object)button.menuButton == (Object)null)) { button.menuButton.resizeButton = false; button.menuButton.customColors = true; button.menuButton.colorNormal = NameColors.Dimmed(color, 0.75f); button.menuButton.colorHover = color; button.menuButton.colorClick = Color.Lerp(color, Color.white, 0.95f); } } private static void AddHexInput(REPOPopupPage page, Color current, Action<Color> onChoose) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Action<string> obj = delegate(string value) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (NameColors.TryParseHex(value, out var color)) { onChoose(color); } else { Plugin.Logger.LogInfo((object)("Name color ignored: '" + value + "' is not a #RRGGBB value")); } }; string text = "#" + NameColors.ToHex(current); REPOInputField val = MenuAPI.CreateREPOInputField("Hex", obj, scrollView, default(Vector2), true, text, ""); ((TMP_Text)val.labelTMP).fontSize = 14f; return ((REPOElement)val).rectTransform; }, 4f, 2f); MenuUiHelpers.AddLabel(page, "<size=75%><color=#6f7d88>Or type a color as #RRGGBB and press enter.</color></size>"); } private static IEnumerable<IReadOnlyList<Color>> Rows(IReadOnlyList<Color> colors) { for (int start = 0; start < colors.Count; start += 6) { yield return colors.Skip(start).Take(6).ToList(); } } private static IReadOnlyList<Color> Palette() { try { IReadOnlyList<Color> readOnlyList = GamePaletteRaw(); if (readOnlyList.Count > 0) { return readOnlyList; } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("[SharePermissions] Game color palette unreadable, using the built-in one: " + ex.Message)); } return FallbackPalette; } [MethodImpl(MethodImplOptions.NoInlining)] private static IReadOnlyList<Color> GamePaletteRaw() { MetaManager instance = MetaManager.instance; if ((Object)(object)instance == (Object)null || instance.colors == null) { return Array.Empty<Color>(); } List<SemiColor> order = instance.colorsUIOrder; return (from c in instance.colors where (Object)(object)c != (Object)null orderby (order != null) ? order.IndexOf(c) : 0 select c.color).ToList(); } } internal sealed class ExtrasPanelController { private readonly REPOPopupPage page; private REPOScrollViewElement? channelHeaderElem; private REPOLabel? offHint; private REPOScrollViewElement? offHintElem; private string offHintCache = string.Empty; private REPOScrollViewElement? announceHeaderElem; private REPOButton? privateToggle; private REPOScrollViewElement? privateToggleElem; private REPOLabel? privateStatus; private REPOScrollViewElement? privateStatusElem; private bool privateTalking; private float privateTalkHoldUntil; private PrivateVoiceDriver.Health lastStatusState = (PrivateVoiceDriver.Health)(-1); private bool lastStatusMicMuted; private bool lastStatusTransmitting; private bool lastStatusShowTalkDot; private REPOButton? micMuteButton; private REPOScrollViewElement? micMuteElem; private string micMuteCache = string.Empty; private REPOButton? soundMuteButton; private REPOScrollViewElement? soundMuteElem; private string soundMuteCache = string.Empty; private REPOSlider? privateVolumeSlider; private REPOScrollViewElement? privateVolumeSliderElem; private REPOLabel? hotkeyHint; private REPOScrollViewElement? hotkeyHintElem; private KeyCode lastHotkeyMicMuteKey = (KeyCode)(-1); private KeyCode lastHotkeyDeafenKey = (KeyCode)(-1); private REPOInputField? announceField; private REPOScrollViewElement? announceFieldElem; private REPOButton? announceBtn; private REPOScrollViewElement? announceBtnElem; private string announceDraft = ""; private bool tabVisible; internal ExtrasPanelController(REPOPopupPage page) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) this.page = page; } internal void Build() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Expected O, but got Unknown //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown channelHeaderElem = AddLabel("<size=115%>Private channel</size>"); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) privateToggle = MenuAPI.CreateREPOButton("", (Action)ModerationActions.TogglePrivateVoice, sv, default(Vector2)); ((TMP_Text)privateToggle.labelTMP).richText = true; ((TMP_Text)privateToggle.labelTMP).fontSize = 14f; privateToggle.overrideButtonSize = new Vector2(250f, 24f); return ((REPOElement)privateToggle).rectTransform; }, 0f, 2f); privateToggleElem = Elem((Component?)(object)privateToggle); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) offHint = MenuAPI.CreateREPOLabel("", sv, default(Vector2)); ((TMP_Text)offHint.labelTMP).richText = true; ((TMP_Text)offHint.labelTMP).fontSize = 14f; return ((REPOElement)offHint).rectTransform; }, 0f, 6f); offHintElem = Elem((Component?)(object)offHint); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) privateStatus = MenuAPI.CreateREPOLabel("", sv, default(Vector2)); ((TMP_Text)privateStatus.labelTMP).richText = true; ((TMP_Text)privateStatus.labelTMP).fontSize = 14f; return ((REPOElement)privateStatus).rectTransform; }, 0f, 2f); privateStatusElem = Elem((Component?)(object)privateStatus); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) micMuteButton = MenuAPI.CreateREPOButton("", (Action)OnMicMuteClicked, sv, default(Vector2)); ((TMP_Text)micMuteButton.labelTMP).richText = true; ((TMP_Text)micMuteButton.labelTMP).fontSize = 14f; micMuteButton.overrideButtonSize = new Vector2(250f, 24f); return ((REPOElement)micMuteButton).rectTransform; }, 0f, 2f); micMuteElem = Elem((Component?)(object)micMuteButton); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) soundMuteButton = MenuAPI.CreateREPOButton("", (Action)OnSoundMuteClicked, sv, default(Vector2)); ((TMP_Text)soundMuteButton.labelTMP).richText = true; ((TMP_Text)soundMuteButton.labelTMP).fontSize = 14f; soundMuteButton.overrideButtonSize = new Vector2(250f, 24f); return ((REPOElement)soundMuteButton).rectTransform; }, 0f, 2f); soundMuteElem = Elem((Component?)(object)soundMuteButton); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Action<int> action = OnPrivateVolumeChanged; int volumePercent = PrivateVoiceLocalPrefs.VolumePercent; privateVolumeSlider = MenuAPI.CreateREPOSlider("Private volume", "", action, sv, default(Vector2), 0, 300, volumePercent, "", "%", (BarBehavior)0); return ((REPOElement)privateVolumeSlider).rectTransform; }, 0f, 2f); privateVolumeSliderElem = Elem((Component?)(object)privateVolumeSlider); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) hotkeyHint = MenuAPI.CreateREPOLabel("", sv, default(Vector2)); ((TMP_Text)hotkeyHint.labelTMP).richText = true; ((TMP_Text)hotkeyHint.labelTMP).fontSize = 14f; return ((REPOElement)hotkeyHint).rectTransform; }, 0f, 6f); hotkeyHintElem = Elem((Component?)(object)hotkeyHint); announceHeaderElem = AddLabel("<size=115%>Announcements</size>"); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) announceField = MenuAPI.CreateREPOInputField("Announce", (Action<string>)delegate(string v) { announceDraft = v ?? ""; }, sv, default(Vector2), false, "message to everyone", ""); ((TMP_Text)announceField.labelTMP).fontSize = 14f; return ((REPOElement)announceField).rectTransform; }, 4f, 0f); announceFieldElem = Elem((Component?)(object)announceField); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) announceBtn = MenuAPI.CreateREPOButton("Send announcement", (Action)delegate { ModerationActions.SendAnnouncement(announceDraft); }, sv, default(Vector2)); ((TMP_Text)announceBtn.labelTMP).fontSize = 14f; return ((REPOElement)announceBtn).rectTransform; }, 0f, 2f); announceBtnElem = Elem((Component?)(object)announceBtn); } internal void SetTabVisible(bool visible) { tabVisible = visible; if (!visible) { SetVisibility(channelHeaderElem, visible: false); SetVisibility(privateToggleElem, visible: false); SetVisibility(offHintElem, visible: false); SetVisibility(privateStatusElem, visible: false); SetVisibility(micMuteElem, visible: false); SetVisibility(soundMuteElem, visible: false); SetVisibility(privateVolumeSliderElem, visible: false); SetVisibility(hotkeyHintElem, visible: false); SetVisibility(announceHeaderElem, visible: false); UnfocusAnnounceField(); SetVisibility(announceFieldElem, visible: false); SetVisibility(announceBtnElem, visible: false); } else { Tick(); } } private void UnfocusAnnounceField() { if ((Object)(object)announceField != (Object)null && (Object)(object)announceField.inputStringSystem != (Object)null) { announceField.inputStringSystem.isFocused = false; } } internal void Tick() { if (!((Object)(object)page == (Object)null) && tabVisible) { bool flag = SemiFunc.IsMasterClient(); bool localActive = PrivateVoiceChannel.LocalActive; SetVisibility(channelHeaderElem, visible: true); SetVisibility(privateToggleElem, flag); SetVisibility(offHintElem, !flag && !localActive); SetVisibility(privateStatusElem, localActive); SetVisibility(micMuteElem, localActive); SetVisibility(soundMuteElem, localActive); SetVisibility(privateVolumeSliderElem, localActive); SetVisibility(hotkeyHintElem, localActive); SetVisibility(announceHeaderElem, flag); SetVisibility(announceFieldElem, flag); SetVisibility(announceBtnElem, flag); if (flag) { UpdateChannelToggle(); } if (!flag && !localActive) { UpdateOffHint(); } if (localActive) { UpdateStatus(); UpdateMuteCaptions(); UpdateHotkeyHint(); } else { lastStatusState = (PrivateVoiceDriver.Health)(-1); } } } private void UpdateChannelToggle() { if (!((Object)(object)privateToggle == (Object)null)) { string text = (PrivateVoiceChannel.Active ? "Private channel: <color=#4dd07a>ON</color>" : "Private channel: <color=#6f7d88>OFF</color>"); if (((TMP_Text)privateToggle.labelTMP).text != text) { ((TMP_Text)privateToggle.labelTMP).text = text; } } } private void UpdateOffHint() { if (!((Object)(object)offHint == (Object)null)) { string text = "<size=75%><color=#6f7d88>Off - the host opens the private channel.</color></size>"; if (!(text == offHintCache)) { offHintCache = text; ((TMP_Text)offHint.labelTMP).text = text; MenuUiHelpers.SizeWrappedLabel(offHint, text, 250f); } } } private void UpdateStatus() { if (!((Object)(object)privateStatus == (Object)null)) { float realtimeSinceStartup = Time.realtimeSinceStartup; PrivateVoiceClient instance = PrivateVoiceClient.Instance; bool flag = (Object)(object)instance != (Object)null && (Object)(object)instance.PrivateRecorder != (Object)null && instance.PrivateRecorder.TransmitEnabled; if (MicTee.Level > 0.005f) { privateTalking = true; privateTalkHoldUntil = realtimeSinceStartup + 0.18f; } else if (realtimeSinceStartup >= privateTalkHoldUntil) { privateTalking = false; } bool flag2 = privateTalking && flag && PrivateVoiceDriver.State == PrivateVoiceDriver.Health.Live; PrivateVoiceDriver.Health state = PrivateVoiceDriver.State; bool micMuted = PrivateVoiceLocalPrefs.MicMuted; if (state != lastStatusState || micMuted != lastStatusMicMuted || flag != lastStatusTransmitting || flag2 != lastStatusShowTalkDot) { lastStatusState = state; lastStatusMicMuted = micMuted; lastStatusTransmitting = flag; lastStatusShowTalkDot = flag2; string text = "Private voice: " + state switch { PrivateVoiceDriver.Health.Live => (!micMuted) ? (flag ? "<color=#4dd07a>live</color>" : "<color=#6f7d88>muted</color>") : "<color=#ef5350>mic off</color>", PrivateVoiceDriver.Health.Listening => "<color=#4dd07a>listening</color>", PrivateVoiceDriver.Health.Provisioning => "<color=#e0b84d>connecting</color>", PrivateVoiceDriver.Health.Failed => "<color=#ef5350>failed</color>", _ => "<color=#6f7d88>off</color>", } + (flag2 ? " <color=#d9e8a8>●</color>" : string.Empty); ((TMP_Text)privateStatus.labelTMP).text = text; MenuUiHelpers.SizeWrappedLabel(privateStatus, text, 250f); } } } private void UpdateMuteCaptions() { if ((Object)(object)micMuteButton != (Object)null) { string text = (PrivateVoiceLocalPrefs.MicMuted ? "Microphone: <color=#ef5350>MUTED</color>" : "Microphone: <color=#4dd07a>LIVE</color>"); if (text != micMuteCache) { micMuteCache = text; ((TMP_Text)micMuteButton.labelTMP).text = text; } } if ((Object)(object)soundMuteButton != (Object)null) { string text2 = (PrivateVoiceLocalPrefs.Muted ? "Sound: <color=#ef5350>MUTED</color>" : "Sound: <color=#4dd07a>ON</color>"); if (text2 != soundMuteCache) { soundMuteCache = text2; ((TMP_Text)soundMuteButton.labelTMP).text = text2; } } } private void UpdateHotkeyHint() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)hotkeyHint == (Object)null)) { KeyCode value = ModConfig.PrivateMicMuteKey.Value; KeyCode value2 = ModConfig.PrivateDeafenKey.Value; if (value != lastHotkeyMicMuteKey || value2 != lastHotkeyDeafenKey) { lastHotkeyMicMuteKey = value; lastHotkeyDeafenKey = value2; string text = "<size=75%><color=#6f7d88>Mic mute: " + KeyName(value) + " Sound mute: " + KeyName(value2) + " Both are local and reset when the game closes.</color></size>"; ((TMP_Text)hotkeyHint.labelTMP).text = text; MenuUiHelpers.SizeWrappedLabel(hotkeyHint, text, 250f); } } } private unsafe static string KeyName(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)key != 0) { return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); } return "unbound"; } private static void OnMicMuteClicked() { PrivateVoiceLocalPrefs.ToggleMicMuted(); } private static void OnSoundMuteClicked() { PrivateVoiceLocalPrefs.ToggleMuted(); } private static void OnPrivateVolumeChanged(int percent) { PrivateVoiceLocalPrefs.SetVolumePercent(percent); } private REPOScrollViewElement? AddLabel(string richText) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown REPOLabel made = null; page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) REPOLabel val = MenuAPI.CreateREPOLabel(richText, sv, default(Vector2)); ((TMP_Text)val.labelTMP).richText = true; ((TMP_Text)val.labelTMP).fontSize = 14f; MenuUiHelpers.SizeWrappedLabel(val, richText, 250f); made = val; return ((REPOElement)val).rectTransform; }, 0f, 6f); return Elem((Component?)(object)made); } private static REPOScrollViewElement? Elem(Component? made) { if (!((Object)(object)made == (Object)null)) { return made.GetComponent<REPOScrollViewElement>(); } return null; } private static void SetVisibility(REPOScrollViewElement? elem, bool visible) { if ((Object)(object)elem != (Object)null) { elem.visibility = visible; } } } internal sealed class GhostRowDriver : MonoBehaviour { private static readonly Color TalkNameColor = new Color(0.6f, 0.6f, 0.4f); internal static readonly Color IdleNameColor = new Color(0.2f, 0.2f, 0.2f); private const float ColorLerpSpeed = 10f; private const float TalkThreshold = 0.005f; private const float HoldTime = 0.18f; private const float WobbleDegreesPerLoudness = 200f; private const float FocusPushAlong = 12.5f; private const float FocusPushPerp = 6f; private const float EyeRestX = 50f; private const float EyeRestY = 25f; private const float EyeNudge = 10f; private const float EyeLerpSpeed = 10f; private const float CursorFocusOffsetX = 18f; private const float CursorFocusOffsetY = 15f; private int actorNumber; private MenuPlayerListed? row; private TextMeshProUGUI? playerName; private MenuPlayerHead? head; private RectTransform? rowRect; private RectTransform? headRect; private RectTransform? headTransform; private RectTransform? eyesTransform; private bool facingRight = true; private int listSpotPrev = -1; private float talkUntil; internal void Initialize(int actor) { actorNumber = actor; } private void Awake() { row = ((Component)this).GetComponent<MenuPlayerListed>(); if ((Object)(object)row != (Object)null) { playerName = row.playerName; head = row.playerHead; rowRect = ((Component)row).GetComponent<RectTransform>(); if ((Object)(object)head != (Object)null) { headRect = ((Component)head).GetComponent<RectTransform>(); } } } private void Update() { float loud = ReadLoudness(); bool talking = UpdateTalkHold(loud); PublishTalkState(talking); if ((Object)(object)row != (Object)null) { ApplyFacing(row.listSpot); } ApplyWobble(loud); UpdateNameColor(talking); SyncEyeContact(); } private void SyncEyeContact() { try { SyncFocusPoint(); SyncCursorFocus(); SyncEyes(); } catch { } } private float ReadLoudness() { return VoiceChatPatch.AmplitudeFor(actorNumber); } private bool UpdateTalkHold(float loud) { if (loud > 0.005f) { talkUntil = Time.time + 0.18f; } return Time.time < talkUntil; } private void PublishTalkState(bool talking) { if (!((Object)(object)head == (Object)null)) { if (ShouldStampTalkStart(talking, head.isTalking)) { head.startedTalkingAtTime = Time.time; } head.isTalking = talking; } } private void ApplyWobble(float loud) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)headTransform == (Object)null)) { ((Transform)headTransform).localEulerAngles = new Vector3(0f, 0f, facingRight ? (loud * 200f) : ((0f - loud) * 200f)); } } private void UpdateNameColor(bool talking) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)playerName == (Object)null)) { ((Graphic)playerName).color = Color.Lerp(((Graphic)playerName).color, talking ? TalkNameColor : IdleNameColor, Time.deltaTime * 10f); } } private static bool ShouldStampTalkStart(bool talkingNow, bool wasTalking) { if (talkingNow) { return !wasTalking; } return false; } private static bool FacingIsRight(int listSpot) { return listSpot % 2 == 0; } private void ApplyFacing(int listSpot) { if (listSpot == listSpotPrev || (Object)(object)head == (Object)null) { return; } listSpotPrev = listSpot; facingRight = FacingIsRight(listSpot); Transform val = (facingRight ? head.headRight : head.headLeft); Transform val2 = (facingRight ? head.headLeft : head.headRight); if (!((Object)(object)val == (Object)null)) { if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(false); } ((Component)val).gameObject.SetActive(true); headTransform = ((Component)val).GetComponent<RectTransform>(); Transform val3 = val.Find("Eyes"); eyesTransform = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<RectTransform>() : null); } } private void SyncFocusPoint() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)head == (Object)null) && !((Object)(object)head.focusPoint == (Object)null) && !((Object)(object)headTransform == (Object)null) && !((Object)(object)rowRect == (Object)null) && !((Object)(object)headRect == (Object)null)) { Vector3 val = ((Transform)rowRect).localPosition + ((Transform)headRect).localPosition + ((Transform)headTransform).localPosition * ((Transform)headRect).localScale.x; float z = ((Transform)headTransform).localEulerAngles.z; float num = (facingRight ? 12.5f : (-12.5f)); val += new Vector3(MenuPlayerHead.LengthDirX(num, z), MenuPlayerHead.LengthDirY(num, z), 0f); val += new Vector3(MenuPlayerHead.LengthDirX(6f, z + 90f), MenuPlayerHead.LengthDirY(6f, z + 90f), 0f); ((Transform)head.focusPoint).localPosition = val; } } private void SyncEyes() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)head == (Object)null || (Object)(object)eyesTransform == (Object)null || (Object)(object)head.focusPoint == (Object)null || (Object)(object)head.myFocusPoint == (Object)null) { return; } MenuPlayerHead val = null; float num = 0f; List<MenuPlayerHead> list = (((Object)(object)MenuManager.instance != (Object)null) ? MenuManager.instance.playerHeads : null); if (list != null) { for (int i = 0; i < list.Count; i++) { MenuPlayerHead val2 = list[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)head) && val2.isTalking && val2.startedTalkingAtTime > num) { num = val2.startedTalkingAtTime; val = val2; } } } Vector3 val3 = (((Object)(object)val != (Object)null && (Object)(object)val.focusPoint != (Object)null) ? ((Transform)val.focusPoint).localPosition : ((Transform)head.myFocusPoint).localPosition); Vector3 val4 = val3 - ((Transform)head.focusPoint).localPosition; val4.z = 0f; Vector3 val5 = new Vector3(facingRight ? 50f : (-50f), 25f, 0f) + ((Vector3)(ref val4)).normalized * 10f; ((Transform)eyesTransform).localPosition = Vector3.Lerp(((Transform)eyesTransform).localPosition, val5, Time.deltaTime * 10f); } private void SyncCursorFocus() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)head == (Object)null) && !((Object)(object)head.myFocusPoint == (Object)null) && !((Object)(object)MenuManager.instance == (Object)null) && (int)MenuManager.instance.currentMenuPageIndex == 8 && !((Object)(object)MenuCursor.instance == (Object)null) && !((Object)(object)headRect == (Object)null) && !((Object)(object)((Transform)headRect).parent == (Object)null) && !((Object)(object)((Transform)headRect).parent.parent == (Object)null)) { Vector3 val = ((Component)MenuCursor.instance).transform.localPosition - ((Transform)headRect).parent.parent.localPosition; ((Transform)head.myFocusPoint).localPosition = new Vector3(val.x + 18f, val.y + 15f, 0f); } } } internal sealed class HeadMarkerComponent : MonoBehaviour { private const float AppearSeconds = 0.35f; private float spinDegreesPerSecond; private float pulsePeriodSeconds; private float bobAmplitude; private float bobPeriodSeconds; private Material? pulseMaterial; private Color baseColor; private bool emissionAvailable; private Vector3 basePosition; private float appearElapsed; private const float GlintSeconds = 0.25f; private Material? glintMaterial; private float glintPeriodSeconds; private float nextGlintAt; private float glintStartedAt = float.NegativeInfinity; private bool glintAvailable; private bool glintWasActive; private Color glintBaseEmission; private Material?[]? ownedMaterials; private bool materialsDestroyed; internal void Initialize(Material? material, Color color, float spinDps, float pulsePeriod, float bobAmp, float bobPeriod, Material? glintMat = null, float glintPeriod = 0f) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) pulseMaterial = material; baseColor = color; spinDegreesPerSecond = spinDps; pulsePeriodSeconds = pulsePeriod; bobAmplitude = bobAmp; bobPeriodSeconds = bobPeriod; basePosition = ((Component)this).transform.localPosition; if ((Object)(object)material != (Object)null && material.HasProperty("_EmissionColor")) { material.EnableKeyword("_EMISSION"); emissionAvailable = true; } glintMaterial = glintMat; glintPeriodSeconds = glintPeriod; if ((Object)(object)glintMat != (Object)null && glintPeriod > 0f && glintMat.HasProperty("_EmissionColor")) { glintMat.EnableKeyword("_EMISSION"); glintBaseEmission = glintMat.GetColor("_EmissionColor"); glintAvailable = true; nextGlintAt = Time.time + glintPeriod * Random.Range(0.7f, 1.3f); } } internal void TakeOwnership(params Material?[] mats) { ownedMaterials = mats; } internal void DestroyOwnedMaterials() { if (materialsDestroyed || ownedMaterials == null) { return; } materialsDestroyed = true; Material[] array = ownedMaterials; foreach (Material val in array) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } private void OnDestroy() { DestroyOwnedMaterials(); } private void OnEnable() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) appearElapsed = 0f; ((Component)this).transform.localScale = Vector3.zero; if (glintAvailable) { nextGlintAt = Time.time + glintPeriodSeconds * Random.Range(0.7f, 1.3f); } } private void Update() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) if (appearElapsed < 0.35f) { appearElapsed += Time.deltaTime; float num = Mathf.Clamp01(appearElapsed / 0.35f) - 1f; ((Component)this).transform.localScale = Vector3.one * (1f + 2.70158f * num * num * num + 1.70158f * num * num); } if (spinDegreesPerSecond != 0f) { ((Component)this).transform.Rotate(0f, spinDegreesPerSecond * Time.deltaTime, 0f, (Space)0); } if (bobAmplitude > 0f) { float num2 = bobAmplitude * Mathf.Sin(Time.time * (MathF.PI * 2f / bobPeriodSeconds)); ((Component)this).transform.localPosition = basePosition + new Vector3(0f, num2, 0f); } if (emissionAvailable && (Object)(object)pulseMaterial != (Object)null) { float num3 = 1.05f + 0.45f * Mathf.Sin(Time.time * (MathF.PI * 2f / pulsePeriodSeconds)); pulseMaterial.SetColor("_EmissionColor", baseColor * num3); } if (glintAvailable && (Object)(object)glintMaterial != (Object)null) { if (Time.time >= nextGlintAt) { glintStartedAt = Time.time; nextGlintAt = Time.time + glintPeriodSeconds * Random.Range(0.7f, 1.3f); } float num4 = (Time.time - glintStartedAt) / 0.25f; if (num4 < 1f) { glintWasActive = true; float num5 = Mathf.SmoothStep(0f, 1f, (num4 < 0.5f) ? (num4 * 2f) : (2f - num4 * 2f)); Color val = (((Object)(object)glintMaterial == (Object)(object)pulseMaterial && emissionAvailable) ? (baseColor * (1.05f + 0.45f * Mathf.Sin(Time.time * (MathF.PI * 2f / pulsePeriodSeconds)))) : glintBaseEmission); glintMaterial.SetColor("_EmissionColor", Color.Lerp(val, Color.white * 1.6f, num5)); } else if (glintWasActive) { glintWasActive = false; if ((Object)(object)glintMaterial != (Object)(object)pulseMaterial) { glintMaterial.SetColor("_EmissionColor", glintBaseEmission); } } } if (appearElapsed >= 0.35f && spinDegreesPerSecond == 0f && bobAmplitude <= 0f && !emissionAvailable && !glintAvailable) { ((Behaviour)this).enabled = false; } } } internal static class HeadMarkers { internal const string CrownName = "SharePermissions_HostCrown"; internal const string GemName = "SharePermissions_ModGem"; internal const string DiamondName = "SharePermissions_ModUserDiamond"; private static readonly Color GoldColor = new Color(0.95f, 0.76f, 0.31f); private static readonly Color RubyColor = new Color(0.85f, 0.2f, 0.28f); private static readonly Color ModUserColor = new Color(0.5f, 0.54f, 0.63f); private const float BandOuterRadius = 0.075f; private const float BandInnerRadius = 0.058f; private const float BandHeight = 0.03f; private const int CrownPoints = 8; private static Mesh? bandMesh; private static Mesh? tallSpikeMesh; private static Mesh? shortSpikeMesh; private static Mesh? jewelMesh; private static Mesh? gemMesh; private static Mesh? diamondMesh; private static Mesh BandMesh => bandMesh ?? (bandMesh = MarkerMeshes.Band(16, 0.075f, 0.058f, 0.03f)); private static Mesh TallSpikeMesh => tallSpikeMesh ?? (tallSpikeMesh = MarkerMeshes.Pyramid(0.016f, 0.075f, 6)); private static Mesh ShortSpikeMesh => shortSpikeMesh ?? (shortSpikeMesh = MarkerMeshes.Pyramid(0.013f, 0.048f, 6)); private static Mesh JewelMesh => jewelMesh ?? (jewelMesh = MarkerMeshes.Bipyramid(6, 0.01f, 0.01f, 0.01f)); private static Mesh GemMesh => gemMesh ?? (gemMesh = MarkerMeshes.GemCut(10, 0.05f, 0.028f, 0.032f, 0.068f)); private static Mesh DiamondMesh => diamondMesh ?? (diamondMesh = MarkerMeshes.GemCut(8, 0.032f, 0.018f, 0.02f, 0.042f)); internal static Transform BuildCrown(Transform attach) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SharePermissions_HostCrown"); val.transform.SetParent(attach, false); val.transform.localPosition = new Vector3(0f, 0.2f, 0f); Material val2 = NewMaterial(GoldColor, 0.9f, 0.78f); Material val3 = NewMaterial(RubyColor, 0.3f, 0.9f, 0.75f); AddMesh(val.transform, val2, BandMesh); float num = 0.0665f; Vector3 val4 = default(Vector3); for (int i = 0; i < 8; i++) { float num2 = (float)i / 8f * MathF.PI * 2f; ((Vector3)(ref val4))..ctor(Mathf.Cos(num2), 0f, Mathf.Sin(num2)); bool flag = (i & 1) == 0; AddMesh(val.transform, val2, flag ? TallSpikeMesh : ShortSpikeMesh, val4 * num + Vector3.up * 0.015f); if (flag) { AddMesh(val.transform, val3, JewelMesh, val4 * 0.075f); } } HeadMarkerComponent headMarkerComponent = val.AddComponent<HeadMarkerComponent>(); headMarkerComponent.Initialize(val2, GoldColor, 40f, 1.6f, 0f, 0f, val3, 4.5f); headMarkerComponent.TakeOwnership(val2, val3); val.SetActive(false); return val.transform; } internal static Transform BuildGem(Transform attach) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SharePermissions_ModGem"); val.transform.SetParent(attach, false); val.transform.localPosition = new Vector3(0f, 0.18f, 0f); Material val2 = NewMaterial(Moderators.ModeratorColor, 0.25f, 0.92f, 0.25f); AddMesh(val.transform, val2, GemMesh); HeadMarkerComponent headMarkerComponent = val.AddComponent<HeadMarkerComponent>(); headMarkerComponent.Initialize(val2, Moderators.ModeratorColor, 60f, 1.8f, 0.012f, 2.6f, val2, 6f); headMarkerComponent.TakeOwnership(val2); val.SetActive(false); return val.transform; } internal static Transform BuildDiamond(Transform attach) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SharePermissions_ModUserDiamond"); val.transform.SetParent(attach, false); val.transform.localPosition = new Vector3(0f, 0.16f, 0f); Material val2 = NewMaterial(ModUserColor, 0.1f, 0.65f, 0.12f); AddMesh(val.transform, val2, DiamondMesh); HeadMarkerComponent headMarkerComponent = val.AddComponent<HeadMarkerComponent>(); headMarkerComponent.Initialize(null, ModUserColor, 0f, 0f, 0f, 0f); headMarkerComponent.TakeOwnership(val2); val.SetActive(false); return val.transform; } private static GameObject AddMesh(Transform parent, Material mat, Mesh mesh, Vector3 localPos = default(Vector3)) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("facet"); val.transform.SetParent(parent, false); val.transform.localPosition = localPos; val.AddComponent<MeshFilter>().sharedMesh = mesh; ((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = mat; return val; } private static Material NewMaterial(Color color, float metallic, float smoothness, float staticGlow = 0f) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Standard") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Hidden/InternalErrorShader"); Material val2 = new Material(val); val2.color = color; if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", metallic); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", smoothness); } if (staticGlow > 0f && val2.HasProperty("_EmissionColor")) { val2.EnableKeyword("_EMISSION"); val2.SetColor("_EmissionColor", color * staticGlow); } return val2; } } internal sealed class HistoryPageController { private const int PageSize = 10; private const int DetailRows = 20; private const float DetailWidth = 250f; private const int ColPrev = 0; private const int ColPage = 1; private const int ColNext = 2; private const int BandColumns = 5; private static readonly Vector2 BandPos = new Vector2(ModStyle.BandLeft, 20f); private static readonly string[] FacetLabels = new string[6] { "All", "Kicks & bans", "Flood", "Mute", "Moderator", "Info" }; private readonly REPOPopupPage page; private readonly IReadOnlyList<string> entries; private readonly List<int> view = new List<int>(); private int pageIndex; private string searchText = ""; private int facetIndex; private int initiatorIndex; private readonly List<string?> initiators = new List<string> { null }; private string?[] entryInitiators = Array.Empty<string>(); private string[] entryStripped = Array.Empty<string>(); private string[] entryStrippedLower = Array.Empty<string>(); private readonly REPOButton?[] rows = (REPOButton?[])(object)new REPOButton[10]; private readonly REPOScrollViewElement?[] rowElems = (REPOScrollViewElement?[])(object)new REPOScrollViewElement[10]; private readonly REPOLabel?[] detailRows = (REPOLabel?[])(object)new REPOLabel[20]; private readonly REPOScrollViewElement?[] detailRowElems = (REPOScrollViewElement?[])(object)new REPOScrollViewElement[20]; private REPOLabel? emptyLabel; private REPOScrollViewElement? emptyElem; private REPOInputField? searchField; private REPOScrollViewElement? searchElem; private REPOButton? facetBtn; private REPOScrollViewElement? facetElem; private REPOButton? initiatorBtn; private REPOScrollViewElement? initiatorElem; private REPOButton? prevBtn; private REPOButton? nextBtn; private REPOButton? backBtn; private REPOButton? copyBtn; private REPOButton? steamBtn; private REPOLabel? pageLabel; private string? detailSteamId; private string? detailRaw; private bool tabVisible = true; private int ViewCount => view.Count; private int TotalPages => Math.Max(1, (ViewCount + 10 - 1) / 10); internal HistoryPageController(REPOPopupPage page, IReadOnlyList<string> entries) { this.page = page; this.entries = entries; BuildInitiatorIndex(); RebuildView(); } internal void Build() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown page.AddElement((BuilderDelegate)delegate(Transform t) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) prevBtn = MenuAPI.CreateREPOButton("< Prev", (Action)Prev, t, BandPos); nextBtn = MenuAPI.CreateREPOButton("Next >", (Action)Next, t, BandPos); backBtn = MenuAPI.CreateREPOButton("< Back", (Action)ShowList, t, BandPos); copyBtn = MenuAPI.CreateREPOButton("Copy", (Action)CopyDetail, t, BandPos); steamBtn = MenuAPI.CreateREPOButton("Steam", (Action)OpenSteam, t, BandPos); ((TMP_Text)steamBtn.labelTMP).richText = true; CenterInColumn(prevBtn, 0); CenterInColumn(backBtn, 0); CenterInColumn(nextBtn, 2); CenterInColumn(copyBtn, 2); CenterInColumn(steamBtn, 1); ((TMP_Text)steamBtn.labelTMP).text = "<color=#66c0f4>Steam</color>"; float num3 = (ModStyle.BandRight - ModStyle.BandLeft) / 5f; pageLabel = MenuAPI.CreateREPOLabel("", t, BandPos); ((TMP_Text)pageLabel.labelTMP).fontSize = 14f; ((TMP_Text)pageLabel.labelTMP).horizontalAlignment = (HorizontalAlignmentOptions)2; RectTransform rectTransform = ((REPOElement)pageLabel).rectTransform; Vector2 sizeDelta = ((REPOElement)pageLabel).rectTransform.sizeDelta; sizeDelta.x = num3; rectTransform.sizeDelta = sizeDelta; RectTransform rectTransform2 = ((TMP_Text)pageLabel.labelTMP).rectTransform; sizeDelta = ((TMP_Text)pageLabel.labelTMP).rectTransform.sizeDelta; sizeDelta.x = num3; rectTransform2.sizeDelta = sizeDelta; ((Transform)((REPOElement)pageLabel).rectTransform).localPosition = new Vector3(ModStyle.ColumnCenter(1, 5) - num3 / 2f, 20f, 0f); }); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) searchField = MenuAPI.CreateREPOInputField("Search", (Action<string>)OnSearchChanged, sv, default(Vector2), false, "name, id, action", ""); ((TMP_Text)searchField.labelTMP).fontSize = 14f; return ((REPOElement)searchField).rectTransform; }, 0f, 2f); searchElem = (((Object)(object)searchField != (Object)null) ? ((Component)searchField).GetComponent<REPOScrollViewElement>() : null); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) facetBtn = MenuAPI.CreateREPOButton(FacetCaption(), (Action)CycleFacet, sv, default(Vector2)); ((TMP_Text)facetBtn.labelTMP).richText = true; ((TMP_Text)facetBtn.labelTMP).fontSize = 14f; facetBtn.overrideButtonSize = new Vector2(250f, 24f); return ((REPOElement)facetBtn).rectTransform; }, 0f, 2f); facetElem = (((Object)(object)facetBtn != (Object)null) ? ((Component)facetBtn).GetComponent<REPOScrollViewElement>() : null); page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) initiatorBtn = MenuAPI.CreateREPOButton(InitiatorCaption(), (Action)CycleInitiator, sv, default(Vector2)); ((TMP_Text)initiatorBtn.labelTMP).richText = true; ((TMP_Text)initiatorBtn.labelTMP).fontSize = 14f; initiatorBtn.overrideButtonSize = new Vector2(250f, 24f); return ((REPOElement)initiatorBtn).rectTransform; }, 0f, 2f); initiatorElem = (((Object)(object)initiatorBtn != (Object)null) ? ((Component)initiatorBtn).GetComponent<REPOScrollViewElement>() : null); for (int num = 0; num < 10; num++) { int slot = num; page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) rows[slot] = MenuAPI.CreateREPOButton("", (Action)delegate { SelectSlot(slot); }, sv, default(Vector2)); ((TMP_Text)rows[slot].labelTMP).richText = true; ((TMP_Text)rows[slot].labelTMP).fontSize = 14f; rows[slot].overrideButtonSize = new Vector2(250f, 24f); return ((REPOElement)rows[slot]).rectTransform; }, 0f, 2f); rowElems[num] = (((Object)(object)rows[num] != (Object)null) ? ((Component)rows[num]).GetComponent<REPOScrollViewElement>() : null); } for (int num2 = 0; num2 < 20; num2++) { int slot2 = num2; page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) detailRows[slot2] = MenuAPI.CreateREPOLabel("", sv, default(Vector2)); ((TMP_Text)detailRows[slot2].labelTMP).enableWordWrapping = true; ((TMP_Text)detailRows[slot2].labelTMP).richText = true; ((TMP_Text)detailRows[slot2].labelTMP).fontSize = 14f; return ((REPOElement)detailRows[slot2]).rectTransform; }, 0f, 2f); detailRowElems[num2] = (((Object)(object)detailRows[num2] != (Object)null) ? ((Component)detailRows[num2]).GetComponent<REPOScrollViewElement>() : null); } page.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform sv) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) emptyLabel = MenuAPI.CreateREPOLabel("No moderation events yet.", sv, default(Vector2)); ((TMP_Text)emptyLabel.labelTMP).fontSize = 14f; return ((REPOElement)emptyLabel).rectTransform; }, 0f, 0f); emptyElem = (((Object)(object)emptyLabel != (Object)null) ? ((Component)emptyLabel).GetComponent<REPOScrollViewElement>() : null); ShowList(); } internal void SetTabVisible(bool visible) { tabVisible = visible; if (visible) { ShowList(); return; } for (int i = 0; i < 10; i++) { if ((Object)(object)rowElems[i] != (Object)null) { rowElems[i].visibility = false; } } HideDetail(); if ((Object)(object)emptyElem != (Object)null) { emptyElem.visibility = false; } UnfocusSearch(); if ((Object)(object)searchElem != (Object)null) { searchElem.visibility = false; } if ((Object)(object)facetElem != (Object)null) { facetElem.visibility = false; } if ((Object)(object)initiatorElem != (Object)null) { initiatorElem.visibility = false; } SetActiveSafe((Component?)(object)prevBtn, active: false); SetActiveSafe((Component?)(object)nextBtn, active: false); SetActiveSafe((Component?)(object)pageLabel, active: false); SetActiveSafe((Component?)(object)backBtn, active: false); SetActiveSafe((Component?)(object)copyBtn, active: false); SetActiveSafe((Component?)(object)steamBtn, active: false); } private void UnfocusSearch() { if ((Object)(object)searchField != (Object)null && (Object)(object)searchField.inputStringSystem != (Object)null) { searchField.inputStringSystem.isFocused = false; } } internal void ShowList() { if (!tabVisible) { return; } for (int i = 0; i < 10; i++) { int num = pageIndex * 10 + i; bool flag = num < ViewCount; if ((Object)(object)rowElems[i] != (Object)null) { rowElems[i].visibility = flag; } if (flag && (Object)(object)rows[i] != (Object)null) { ((TMP_Text)rows[i].labelTMP).text = RowCaption(EntryAt(num)); } } HideDetail(); detailRaw = null; if ((Object)(object)searchElem != (Object)null) { searchElem.visibility = true; } if ((Object)(object)facetElem != (Object)null) { facetElem.visibility = true; } if ((Object)(object)initiatorElem != (Object)null) { initiatorElem.visibility = initiators.Count > 1; } if ((Object)(object)facetBtn != (Object)null) { ((TMP_Text)facetBtn.labelTMP).text = FacetCaption(); } if ((Object)(object)emptyElem != (Object)null) { emptyElem.visibility = ViewCount == 0; } if ((Object)(object)emptyLabel != (Object)null && ViewCount == 0) { ((TMP_Text)emptyLabel.labelTMP).text = ((entries.Count == 0) ? "No moderation events yet." : "No matching events."); } SetActiveSafe((Component?)(object)prevBtn, ViewCount > 0 && pageIndex > 0); SetActiveSafe((Component?)(object)nextBtn, ViewCount > 0 && pageIndex < TotalPages - 1); SetActiveSafe((Component?)(object)pageLabel, ViewCount > 0); SetActiveSafe((Component?)(object)backBtn, active: false); SetActiveSafe((Component?)(object)copyBtn, active: false); SetActiveSafe((Component?)(object)steamBtn, active: false); if ((Object)(object)copyBtn != (Object)null) { ((TMP_Text)copyBtn.labelTMP).text = "Copy"; } if ((Object)(object)pageLabel != (Object)null) { ((TMP_Text)pageLabel.labelTMP).text = $"Page {pageIndex + 1}/{TotalPages}"; } page.scrollView.SetScrollPosition(0f); } private void SelectSlot(int slot) { if (!tabVisible) { return; } int num = pageIndex * 10 + slot; if (num >= ViewCount) { return; } string text = (detailRaw = MenuUiHelpers.StripRichText(EntryAt(num))); List<string> list = BuildDetailLines(text); for (int i = 0; i < 20; i++) { bool flag = i < list.Count; if ((Object)(object)detailRowElems[i] != (Object)null) { detailRowElems[i].visibility = flag; } if (flag && (Object)(object)detailRows[i] != (Object)null) { ((TMP_Text)detailRows[i].labelTMP).text = list[i]; MenuUiHelpers.SizeWrappedLabel(detailRows[i], list[i], 250f); } } for (int j = 0; j < 10; j++) { if ((Object)(object)rowElems[j] != (Object)null) { rowElems[j].visibility = false; } } if ((Object)(object)emptyElem != (Object)null) { emptyElem.visibility = false; } UnfocusSearch(); if ((Object)(object)searchElem != (Object)null) { searchElem.visibility = false; } if ((Object)(object)facetElem != (Object)null) { facetElem.visibility = false; } if ((Object)(object)initiatorElem != (Object)null) { initiatorElem.visibility = false; } SetActiveSafe((Component?)(object)prevBtn, active: false); SetActiveSafe((Component?)(object)nextBtn, active: false); SetActiveSafe((Component?)(object)backBtn, active: true); SetActiveSafe((Component?)(object)copyBtn, active: true); if ((Object)(object)copyBtn != (Object)null) { ((TMP_Text)copyBtn.labelTMP).text = "Copy"; } SetActiveSafe((Component?)(object)pageLabel, active: false); detailSteamId = TargetSteamIdOf(text); SetActiveSafe((Component?)(object)steamBtn, SteamUtils.TryParseValidSteamId(detailSteamId, out var _)); page.scrollView.SetScrollPosition(0f); } private void HideDetail() { for (int i = 0; i < 20; i++) { if ((Object)(object)detailRowElems[i] != (Object)null) { detailRowElems[i].visibility = false; } } } private static List<string> BuildDetailLines(string raw) { int num = raw.IndexOf("] ", StringComparison.Ordinal); string text = ((num >= 0) ? raw.Substring(num + 2) : raw); List<string> list = new List<string>();