using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using FishySteamworks.Server;
using HarmonyLib;
using MelonLoader;
using Microsoft.CodeAnalysis;
using MorePlayersPlusStandalone;
using ReluProtocol.Enum;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "MorePlayersPlus_VC_UI", "3.0.0", "Arena+Kandru+NeoMimicry", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MorePlayersPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MorePlayersPlus")]
[assembly: AssemblyTitle("MorePlayersPlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 MorePlayersPlusStandalone
{
public class Mod : MelonMod
{
private sealed class OverlayBehaviour : MonoBehaviour
{
private void OnGUI()
{
DrawOverlay();
}
}
private static class DiscordRpc
{
private static int _loggedUnavailable;
public static void Update(int playerCount, bool loading)
{
try
{
for (int i = 0; i < 10; i++)
{
using NamedPipeClientStream namedPipeClientStream = new NamedPipeClientStream(".", "discord-ipc-" + i, PipeDirection.InOut);
try
{
namedPipeClientStream.Connect(100);
}
catch
{
goto end_IL_0024;
}
namedPipeClientStream.ReadTimeout = 1000;
namedPipeClientStream.WriteTimeout = 1000;
WriteFrame(namedPipeClientStream, 0, "{\"v\":1,\"client_id\":\"1551559380799856660\"}");
ReadFrame(namedPipeClientStream);
string text = (loading ? "Loading" : "In game");
string payload = $"{{\"cmd\":\"SET_ACTIVITY\",\"args\":{{\"pid\":{Process.GetCurrentProcess().Id},\"activity\":{{\"details\":\"MIMESIS\",\"state\":\"{text} - {playerCount}/{32} players\",\"party\":{{\"id\":\"mimesis-moreplayersplus\",\"size\":[{playerCount},{32}],\"privacy\":1}},\"instance\":true}}}},\"nonce\":\"moreplayersplus\"}}";
WriteFrame(namedPipeClientStream, 1, payload);
return;
end_IL_0024:;
}
if (Interlocked.Exchange(ref _loggedUnavailable, 1) == 0)
{
MelonLogger.Msg("[MorePlayersPlus] Discord Rich Presence is unavailable (Discord may not be running)");
}
}
catch (Exception ex)
{
if (Interlocked.Exchange(ref _loggedUnavailable, 1) == 0)
{
MelonLogger.Warning("[MorePlayersPlus] Discord Rich Presence unavailable: " + ex.Message);
}
}
}
private static void WriteFrame(Stream stream, int opcode, string payload)
{
byte[] bytes = Encoding.UTF8.GetBytes(payload);
byte[] array = new byte[8];
Buffer.BlockCopy(BitConverter.GetBytes(opcode), 0, array, 0, 4);
Buffer.BlockCopy(BitConverter.GetBytes(bytes.Length), 0, array, 4, 4);
stream.Write(array, 0, array.Length);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
private static void ReadFrame(Stream stream)
{
byte[] array = new byte[8];
if (stream.Read(array, 0, array.Length) < array.Length)
{
return;
}
int num = BitConverter.ToInt32(array, 4);
if (num <= 0 || num > 1048576)
{
return;
}
byte[] buffer = new byte[num];
int num2;
for (int i = 0; i < num; i += num2)
{
num2 = stream.Read(buffer, i, num - i);
if (num2 <= 0)
{
break;
}
}
}
}
[HarmonyPatch]
private class DeathMatchLateJoinPatch
{
private static MethodBase TargetMethod()
{
return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp")?.GetType("DeathMatchRoom")?.GetMethod("CanEnterChannel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
private static bool Prefix(object __instance, long playerUID, ref MsgErrorCode __result)
{
return !TryAllowLateJoin(__instance, playerUID, out __result);
}
}
[HarmonyPatch]
private class LogisticsLateJoinPatch
{
private static MethodBase TargetMethod()
{
return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp")?.GetType("LogisticsRoom")?.GetMethod("CanEnterChannel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
private static bool Prefix(object __instance, long playerUID, ref MsgErrorCode __result)
{
return !TryAllowLateJoin(__instance, playerUID, out __result);
}
}
[HarmonyPatch(typeof(ServerSocket), "GetMaximumClients")]
private class GetMaxPatch
{
private static bool Prefix(ref int __result)
{
__result = 32;
return false;
}
}
[HarmonyPatch(typeof(ServerSocket), "SetMaximumClients")]
private class SetMaxPatch
{
private static bool Prefix(ref int value)
{
value = 32;
return true;
}
}
[HarmonyPatch]
private class DissonancePersist
{
private static MethodBase TargetMethod()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
Type type = assemblies[i].GetType("Dissonance.DissonanceComms");
if (!(type == null))
{
return AccessTools.Method(type, "OnEnable", (Type[])null, (Type[])null) ?? AccessTools.Method(type, "Start", (Type[])null, (Type[])null);
}
}
return null;
}
private static void Postfix(object __instance)
{
try
{
MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null);
if (!((Object)(object)val == (Object)null))
{
Object.DontDestroyOnLoad((Object)(object)((Component)val).gameObject);
Transform parent = ((Component)val).transform.parent;
if ((Object)(object)parent != (Object)null)
{
Object.DontDestroyOnLoad((Object)(object)((Component)parent).gameObject);
}
MelonLogger.Msg("[MorePlayersPlus] Dissonance persisted for loading VC");
}
}
catch (Exception ex)
{
MelonLogger.Error(ex.Message);
}
}
}
[HarmonyPatch]
private class DissonanceOnDisableBlock
{
private static MethodBase TargetMethod()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
Type type = assemblies[i].GetType("Dissonance.DissonanceComms");
if (type != null)
{
return AccessTools.Method(type, "OnDisable", (Type[])null, (Type[])null);
}
}
return null;
}
private static bool Prefix()
{
if (IsLoadingScreenActive())
{
return false;
}
return true;
}
}
[HarmonyPatch]
private class GameSettingsVoiceVolume
{
private static MethodBase TargetMethod()
{
return (AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp")?.GetType("UIPrefab_GameSettings"))?.GetMethod("Start", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
private static bool Prepare()
{
return TargetMethod() != null;
}
private static void Postfix(object __instance)
{
CreateVoiceVolumeUi(__instance);
CreateFeatureToggleButtons(__instance);
}
}
[HarmonyPatch]
private class ResultArrayExpand
{
private static IEnumerable<MethodBase> TargetMethods()
{
Assembly asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp");
if (asm == null)
{
yield break;
}
string[] array = new string[3] { "UIPrefab_DeathMatchResult", "UIPrefab_SurvivalResult", "UIPrefab_CollectionResult" };
foreach (string name in array)
{
MethodInfo methodInfo = asm.GetType(name)?.GetMethod("PatchParameter", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (methodInfo?.GetMethodBody() != null)
{
yield return methodInfo;
}
}
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
{
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
List<CodeInstruction> list = ins.ToList();
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i].opcode == OpCodes.Ldc_I4_4 && list[i + 1].opcode == OpCodes.Newarr)
{
Type type = list[i + 1].operand as Type;
if (type != null && type.Name.Contains("DeathMatchPlayerResult"))
{
list[i] = new CodeInstruction(OpCodes.Ldc_I4, (object)32);
}
}
}
return list;
}
}
[HarmonyPatch]
private class InGameMenu_EnsureSlots
{
private static MethodBase TargetMethod()
{
Type type = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp")?.GetTypes().FirstOrDefault((Type t) => t.Name == "UIPrefab_InGameMenu");
if (type == null)
{
return null;
}
return AccessTools.Method(type, "Awake", (Type[])null, (Type[])null) ?? AccessTools.Method(type, "Start", (Type[])null, (Type[])null) ?? AccessTools.Method(type, "OnEnable", (Type[])null, (Type[])null);
}
private static void Postfix(object __instance)
{
try
{
FieldInfo field = __instance.GetType().GetField("playerUIElements", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field == null || !(field.GetValue(__instance) is IList { Count: >=4, Count: <32 } list))
{
return;
}
object obj = list[1];
Type type = obj.GetType();
FieldInfo field2 = type.GetField("container");
if (field2 == null)
{
return;
}
object? value = field2.GetValue(obj);
GameObject val = (GameObject)((value is GameObject) ? value : null);
if ((Object)(object)val == (Object)null)
{
return;
}
Transform parent = val.transform.parent;
for (int i = list.Count; i < 32; i++)
{
GameObject val2 = Object.Instantiate<GameObject>(val, parent);
((Object)val2).name = $"MorePlayersPlayer{i + 1}";
val2.SetActive(false);
object obj2 = Activator.CreateInstance(type);
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
object value2 = fieldInfo.GetValue(obj);
Component comp = (Component)((value2 is Component) ? value2 : null);
if (comp != null)
{
Component val3 = ((IEnumerable<Component>)val2.GetComponentsInChildren(((object)comp).GetType(), true)).FirstOrDefault((Func<Component, bool>)((Component c) => ((Object)c.gameObject).name == ((Object)comp.gameObject).name));
if ((Object)(object)val3 != (Object)null)
{
fieldInfo.SetValue(obj2, val3);
}
}
else
{
fieldInfo.SetValue(obj2, value2);
}
}
list.Add(obj2);
}
MelonLogger.Msg($"[MorePlayersPlus] InGameMenu extended to {32} slots");
}
catch (Exception arg)
{
MelonLogger.Error($"InGameMenu patch: {arg}");
}
}
}
[CompilerGenerated]
private static class <>O
{
public static UnityAction <0>__OnLoadingListButtonClicked;
public static UnityAction <1>__OnSpeakingIndicatorButtonClicked;
}
public const int MAX_PLAYERS = 32;
private const float DEFAULT_VOICE_VOLUME_MULTIPLIER = 1.5f;
private static object _voiceVolumeEntry;
private static object _showLoadingPlayerListEntry;
private static object _showSpeakingIndicatorEntry;
private static object _voiceVolumeLabel;
private static object _masterVolumeLabel;
private static object _micVolumeLabel;
private static object _gameSettingsInstance;
private static Transform _voiceSliderTransform;
private static bool _masterVolumeBound;
private static bool _micVolumeBound;
private static bool _showLoadingPlayerList;
private static bool _showSpeakingIndicator;
private static float _voiceVolumeMultiplier = 1.5f;
private static OverlayBehaviour _overlayBehaviour;
private static GameObject _loadingListButton;
private static GameObject _speakingIndicatorButton;
private static GameObject _loadingListLabel;
private static GameObject _speakingIndicatorLabel;
private static object _languageSelectedLabel;
private static bool _featureButtonsCreated;
private const float FEATURE_ROW_SPACING = 52f;
private static int _discordUpdatePending;
private static float _nextDiscordUpdate;
private static float _nextFeatureLabelRefresh;
private const string DISCORD_APPLICATION_ID = "1551559380799856660";
private float _nextVcCheck;
public override void OnInitializeMelon()
{
InitializePreferences();
EnsureOverlayBehaviour();
((MelonBase)this).LoggerInstance.Msg($"MorePlayersPlus Standalone v3.0.0 Loaded! Max={32} - VC during loading + UI fix enabled");
((MelonBase)this).LoggerInstance.Msg("This mod works with or without Kandru's mod. If Kandru's mod is present, this adds VC during loading.");
((MelonBase)this).LoggerInstance.Msg($"VC volume multiplier: {_voiceVolumeMultiplier:0.0}x (1.0x = normal)");
((MelonBase)this).LoggerInstance.Msg($"Loading player list: {_showLoadingPlayerList}; speaking indicator: {_showSpeakingIndicator}");
}
public override void OnUpdate()
{
if (!(Time.time < _nextVcCheck))
{
_nextVcCheck = Time.time + 1f;
ApplyVoiceVolume();
UpdateDiscordPresence();
if (Time.time >= _nextFeatureLabelRefresh)
{
_nextFeatureLabelRefresh = Time.time + 0.5f;
UpdateFeatureToggleLabels();
}
if (IsLoadingScreenActive())
{
UnmuteAllDissonance();
}
}
}
private static void EnsureOverlayBehaviour()
{
//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_0029: Expected O, but got Unknown
try
{
if (!((Object)(object)_overlayBehaviour != (Object)null))
{
GameObject val = new GameObject("MorePlayersPlus_Overlay");
_overlayBehaviour = val.AddComponent<OverlayBehaviour>();
Object.DontDestroyOnLoad((Object)val);
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not create overlay: " + ex.Message);
}
}
private static void GetVoicePlayers(List<string> players, List<string> speaking)
{
try
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
Type type = assemblies[i].GetType("Dissonance.DissonanceComms");
if (type == null)
{
continue;
}
Object[] array = Object.FindObjectsOfType(type);
PropertyInfo property = type.GetProperty("Players", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Object[] array2 = array;
foreach (Object obj in array2)
{
if (!(property?.GetValue(obj) is IEnumerable enumerable))
{
continue;
}
foreach (object item in enumerable)
{
if (item != null)
{
Type type2 = item.GetType();
string text = type2.GetProperty("Name")?.GetValue(item)?.ToString();
if (string.IsNullOrWhiteSpace(text))
{
text = "Unknown player";
}
if (!players.Contains(text))
{
players.Add(text);
}
if (type2.GetProperty("IsSpeaking")?.GetValue(item) as bool? == true && !speaking.Contains(text))
{
speaking.Add(text);
}
}
}
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not read VC player list: " + ex.Message);
}
}
private static void DrawOverlay()
{
if (!_showLoadingPlayerList && !_showSpeakingIndicator)
{
return;
}
bool flag = IsLoadingScreenActive();
List<string> list = new List<string>();
List<string> list2 = new List<string>();
GetVoicePlayers(list, list2);
List<string> list3 = new List<string>();
if (_showLoadingPlayerList && flag)
{
list3.Add($"MorePlayersPlus PLAYERS ({list.Count}/{32})");
foreach (string item in list)
{
list3.Add(" " + item);
}
}
if (_showSpeakingIndicator && list2.Count > 0)
{
list3.Add("Speaking: " + string.Join(", ", list2));
}
if (list3.Count == 0)
{
return;
}
try
{
Type type = FindLoadedType("UnityEngine.GUI");
Type rectType = FindLoadedType("UnityEngine.Rect");
ConstructorInfo constructorInfo = rectType?.GetConstructor(new Type[4]
{
typeof(float),
typeof(float),
typeof(float),
typeof(float)
});
MethodInfo methodInfo = type?.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "Label" && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == rectType && m.GetParameters()[1].ParameterType == typeof(string));
if (constructorInfo == null || methodInfo == null)
{
return;
}
float num = 24f;
foreach (string item2 in list3)
{
object obj = constructorInfo.Invoke(new object[4] { 24f, num, 900f, 26f });
methodInfo.Invoke(null, new object[2] { obj, item2 });
num += 24f;
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not draw overlay: " + ex.Message);
}
}
private static void InitializePreferences()
{
try
{
Type type = typeof(MelonMod).Assembly.GetType("MelonLoader.MelonPreferences");
if (type == null)
{
return;
}
MethodInfo methodInfo = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
where m.Name == "CreateCategory"
orderby m.GetParameters().Length
select m).FirstOrDefault();
if (methodInfo == null)
{
return;
}
object[] parameters = ((methodInfo.GetParameters().Length != 1) ? new object[2] { "MorePlayersPlus", "MorePlayersPlus" } : new object[1] { "MorePlayersPlus" });
object obj = methodInfo.Invoke(null, parameters);
if (obj == null)
{
return;
}
MethodInfo methodInfo2 = (from m in obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public)
where m.Name == "CreateEntry" && m.IsGenericMethodDefinition
orderby m.GetParameters().Length
select m).FirstOrDefault();
if (methodInfo2 == null)
{
return;
}
MethodInfo methodInfo3 = methodInfo2.MakeGenericMethod(typeof(float));
ParameterInfo[] parameters2 = methodInfo3.GetParameters();
object[] array = new object[parameters2.Length];
for (int num = 0; num < parameters2.Length; num++)
{
switch (num)
{
case 0:
array[num] = "VoiceVolumeMultiplier";
continue;
case 1:
array[num] = 1.5f;
continue;
}
if (parameters2[num].ParameterType == typeof(string))
{
array[num] = "VC volume multiplier (1.0 = normal)";
}
else if (parameters2[num].ParameterType == typeof(bool))
{
array[num] = false;
}
else
{
array[num] = null;
}
}
_voiceVolumeEntry = methodInfo3.Invoke(obj, array);
if ((_voiceVolumeEntry?.GetType().GetProperty("Value") ?? _voiceVolumeEntry?.GetType().GetProperty("EditedValue"))?.GetValue(_voiceVolumeEntry) is float val)
{
_voiceVolumeMultiplier = Math.Max(0f, Math.Min(4f, val));
}
MethodInfo methodInfo4 = methodInfo2.MakeGenericMethod(typeof(bool));
ParameterInfo[] parameters3 = methodInfo4.GetParameters();
object[] array2 = new object[parameters3.Length];
for (int num2 = 0; num2 < parameters3.Length; num2++)
{
switch (num2)
{
case 0:
array2[num2] = "ShowLoadingPlayerList";
continue;
case 1:
array2[num2] = false;
continue;
}
if (parameters3[num2].ParameterType == typeof(string))
{
array2[num2] = "Show player list during loading screens";
}
else if (parameters3[num2].ParameterType == typeof(bool))
{
array2[num2] = false;
}
else
{
array2[num2] = null;
}
}
_showLoadingPlayerListEntry = methodInfo4.Invoke(obj, array2);
object[] array3 = new object[parameters3.Length];
for (int num3 = 0; num3 < parameters3.Length; num3++)
{
switch (num3)
{
case 0:
array3[num3] = "ShowSpeakingIndicator";
continue;
case 1:
array3[num3] = false;
continue;
}
if (parameters3[num3].ParameterType == typeof(string))
{
array3[num3] = "Show who is speaking";
}
else if (parameters3[num3].ParameterType == typeof(bool))
{
array3[num3] = false;
}
else
{
array3[num3] = null;
}
}
_showSpeakingIndicatorEntry = methodInfo4.Invoke(obj, array3);
object obj2 = _showLoadingPlayerListEntry?.GetType().GetProperty("Value")?.GetValue(_showLoadingPlayerListEntry);
object obj3 = _showSpeakingIndicatorEntry?.GetType().GetProperty("Value")?.GetValue(_showSpeakingIndicatorEntry);
if (obj2 is bool showLoadingPlayerList)
{
_showLoadingPlayerList = showLoadingPlayerList;
}
if (obj3 is bool showSpeakingIndicator)
{
_showSpeakingIndicator = showSpeakingIndicator;
}
type.GetMethod("Save", Type.EmptyTypes)?.Invoke(null, null);
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not initialize VC volume setting: " + ex.Message);
}
}
private static void ApplyVoiceVolume()
{
if (_voiceVolumeMultiplier <= 0f)
{
return;
}
try
{
Type type = (from a in AppDomain.CurrentDomain.GetAssemblies()
select a.GetType("Dissonance.Audio.Playback.VoicePlayback")).FirstOrDefault((Type t) => t != null);
if (type == null)
{
return;
}
PropertyInfo property = type.GetProperty("AudioSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Object[] array = Object.FindObjectsOfType(type);
foreach (Object val in array)
{
if (val == (Object)null)
{
continue;
}
object obj = property?.GetValue(val);
if (obj != null)
{
PropertyInfo property2 = obj.GetType().GetProperty("volume", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if ((object)property2 != null && property2.CanWrite)
{
property2.SetValue(obj, _voiceVolumeMultiplier);
}
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not apply VC volume: " + ex.Message);
}
}
private static void SetVoiceVolumeMultiplier(float value)
{
_voiceVolumeMultiplier = Math.Max(0f, Math.Min(4f, value));
try
{
PropertyInfo propertyInfo = _voiceVolumeEntry?.GetType().GetProperty("Value") ?? _voiceVolumeEntry?.GetType().GetProperty("EditedValue");
if ((object)propertyInfo != null && propertyInfo.CanWrite)
{
propertyInfo.SetValue(_voiceVolumeEntry, _voiceVolumeMultiplier);
}
typeof(MelonMod).Assembly.GetType("MelonLoader.MelonPreferences")?.GetMethod("Save", Type.EmptyTypes)?.Invoke(null, null);
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not save VC volume setting: " + ex.Message);
}
UpdateVoiceVolumeLabel();
ApplyVoiceVolume();
}
private static void OnVoiceVolumeSliderChanged(float value)
{
SetVoiceVolumeMultiplier(value);
}
private static void UpdateVoiceVolumeLabel()
{
if (_voiceVolumeLabel != null)
{
SetLabelText(_voiceVolumeLabel, $"VC VOLUME {Math.Round(_voiceVolumeMultiplier * 100f):0}%");
}
}
private static void SetPreferenceValue(object entry, bool value)
{
try
{
PropertyInfo propertyInfo = entry?.GetType().GetProperty("Value") ?? entry?.GetType().GetProperty("EditedValue");
if ((object)propertyInfo != null && propertyInfo.CanWrite)
{
propertyInfo.SetValue(entry, value);
}
typeof(MelonMod).Assembly.GetType("MelonLoader.MelonPreferences")?.GetMethod("Save", Type.EmptyTypes)?.Invoke(null, null);
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not save feature setting: " + ex.Message);
}
}
private static void UpdateFeatureToggleLabels()
{
bool flag = IsJapaneseUi();
SetButtonText(_loadingListButton, flag ? "オフ" : "OFF");
SetButtonText(_speakingIndicatorButton, flag ? "オン" : "ON");
SetButtonText(_loadingListLabel, flag ? "ロード中プレイヤー表示" : "LOADING PLAYERS");
SetButtonText(_speakingIndicatorLabel, flag ? "発話インジケータ" : "SPEAKING INDICATOR");
SetButtonText(_loadingListButton, (!flag) ? (_showLoadingPlayerList ? "ON" : "OFF") : (_showLoadingPlayerList ? "オン" : "オフ"));
SetButtonText(_speakingIndicatorButton, (!flag) ? (_showSpeakingIndicator ? "ON" : "OFF") : (_showSpeakingIndicator ? "オン" : "オフ"));
}
private static bool IsJapaneseUi()
{
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Invalid comparison between Unknown and I4
try
{
string text = _languageSelectedLabel?.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(_languageSelectedLabel)?.ToString();
if (!string.IsNullOrWhiteSpace(text))
{
if (text.Contains("日本") || text.Contains("Japanese") || text.Equals("ja", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (text.Contains("English") || text.Equals("en", StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
string[] array = new string[4] { "Language", "language", "CurrentLanguage", "SelectedLanguage" };
foreach (string text2 in array)
{
if (PlayerPrefs.HasKey(text2))
{
string text3 = PlayerPrefs.GetString(text2, string.Empty);
if (text3.Contains("日本") || text3.Contains("Japanese") || text3.Equals("ja", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (text3.Contains("English") || text3.Equals("en", StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
}
}
catch
{
}
return (int)Application.systemLanguage == 22;
}
private static void SetButtonText(GameObject buttonObject, string text)
{
if ((Object)(object)buttonObject == (Object)null)
{
return;
}
Type type = FindLoadedType("TMPro.TMP_Text");
if (!(type == null))
{
Component[] componentsInChildren = buttonObject.GetComponentsInChildren(type, true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
SetLabelText(componentsInChildren[i], text);
}
}
}
private static void OnLoadingListButtonClicked()
{
_showLoadingPlayerList = !_showLoadingPlayerList;
SetPreferenceValue(_showLoadingPlayerListEntry, _showLoadingPlayerList);
UpdateFeatureToggleLabels();
}
private static void OnSpeakingIndicatorButtonClicked()
{
_showSpeakingIndicator = !_showSpeakingIndicator;
SetPreferenceValue(_showSpeakingIndicatorEntry, _showSpeakingIndicator);
UpdateFeatureToggleLabels();
}
private static void OnFeatureButtonMouseOver()
{
}
private static void OnFeatureButtonMouseExit()
{
}
private static void ConfigureFeatureButtonHighlight(object settingsInstance, GameObject buttonObject)
{
try
{
Type type = settingsInstance.GetType();
Type type2 = FindLoadedType("TMPro.TMP_Text");
if (!(type2 == null))
{
Component val = buttonObject.GetComponentsInChildren(type2, true).FirstOrDefault();
MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "AddMouseOverEnterEvent" && m.GetParameters().Length == 3);
MethodInfo methodInfo2 = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "AddMouseOverExitEvent" && m.GetParameters().Length == 3);
if (!((Object)(object)val == (Object)null) && !(methodInfo == null) && !(methodInfo2 == null))
{
Type parameterType = methodInfo.GetParameters()[2].ParameterType;
MethodInfo method = typeof(Mod).GetMethod("OnFeatureButtonMouseOver", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo method2 = typeof(Mod).GetMethod("OnFeatureButtonMouseExit", BindingFlags.Static | BindingFlags.NonPublic);
Delegate obj = Delegate.CreateDelegate(parameterType, method);
Delegate obj2 = Delegate.CreateDelegate(parameterType, method2);
methodInfo.Invoke(settingsInstance, new object[3] { buttonObject, val, obj });
methodInfo2.Invoke(settingsInstance, new object[3] { buttonObject, val, obj2 });
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not register feature-button highlight: " + ex.Message);
}
}
private static void CreateFeatureToggleButtons(object settingsInstance)
{
//IL_00bd: 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_00c8: Expected O, but got Unknown
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Expected O, but got Unknown
if (settingsInstance == null || (_featureButtonsCreated && (Object)(object)_loadingListButton != (Object)null && (Object)(object)_speakingIndicatorButton != (Object)null))
{
return;
}
try
{
Type type = settingsInstance.GetType();
_languageSelectedLabel = type.GetField("_UE_Dropdown_selectLanguage_Label", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(settingsInstance);
object obj = type.GetField("_UE_LANGUAGE", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(settingsInstance);
object languageSelectedLabel = _languageSelectedLabel;
if (obj != null && languageSelectedLabel != null)
{
_loadingListLabel = CreateFeatureLabelElement(obj, "MorePlayersPlus_LoadingPlayerListLabel", -0f);
_speakingIndicatorLabel = CreateFeatureLabelElement(obj, "MorePlayersPlus_SpeakingIndicatorLabel", -52f);
object obj2 = <>O.<0>__OnLoadingListButtonClicked;
if (obj2 == null)
{
UnityAction val = OnLoadingListButtonClicked;
<>O.<0>__OnLoadingListButtonClicked = val;
obj2 = (object)val;
}
_loadingListButton = CreateFeatureValueElement(languageSelectedLabel, "MorePlayersPlus_LoadingPlayerListValue", -0f, (UnityAction)obj2);
object obj3 = <>O.<1>__OnSpeakingIndicatorButtonClicked;
if (obj3 == null)
{
UnityAction val2 = OnSpeakingIndicatorButtonClicked;
<>O.<1>__OnSpeakingIndicatorButtonClicked = val2;
obj3 = (object)val2;
}
_speakingIndicatorButton = CreateFeatureValueElement(languageSelectedLabel, "MorePlayersPlus_SpeakingIndicatorValue", -52f, (UnityAction)obj3);
AlignValueToLabel(_loadingListButton, _loadingListLabel);
AlignValueToLabel(_speakingIndicatorButton, _speakingIndicatorLabel);
ConfigureFeatureButtonHighlight(settingsInstance, _loadingListButton);
ConfigureFeatureButtonHighlight(settingsInstance, _speakingIndicatorButton);
float offset = -104f;
MoveSettingRow(type, settingsInstance, "_UE_Dropdown_selectLanguage", offset);
MoveSettingRow(type, settingsInstance, "_UE_Dropdown_selectLanguage_Label", offset);
MoveSettingRow(type, settingsInstance, "_UE_LANGUAGE", offset);
MoveSettingRow(type, settingsInstance, "_UE_CreatorCode", offset);
MoveSettingRow(type, settingsInstance, "_UE_CreateCodeText", offset);
MoveSettingRow(type, settingsInstance, "_UE_lastInputedCreatorCode", offset);
_featureButtonsCreated = true;
UpdateFeatureToggleLabels();
MelonLogger.Msg("[MorePlayersPlus] Added display-style player-list and speaking-indicator rows to Game Settings");
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not add feature toggles: " + ex.Message);
}
}
private static GameObject CreateFeatureLabelElement(object template, string name, float offsetY)
{
//IL_0071: 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_0097: Unknown result type (might be due to invalid IL or missing references)
object? obj = template?.GetType().GetProperty("gameObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(template);
GameObject val = (GameObject)((obj is GameObject) ? obj : null);
Transform val2 = ((val != null) ? val.transform : null);
if ((Object)(object)val == (Object)null || (Object)(object)((val2 != null) ? val2.parent : null) == (Object)null)
{
return null;
}
GameObject obj2 = Object.Instantiate<GameObject>(val, val2.parent);
((Object)obj2).name = name;
obj2.transform.localPosition = val2.localPosition + new Vector3(0f, offsetY, 0f);
obj2.transform.localScale = val2.localScale;
return obj2;
}
private static GameObject CreateFeatureValueElement(object template, string name, float offsetY, UnityAction onClick)
{
GameObject val = CreateFeatureLabelElement(template, name, offsetY);
if ((Object)(object)val == (Object)null)
{
return null;
}
Button val2 = val.GetComponent<Button>() ?? val.AddComponent<Button>();
((Selectable)val2).transition = (Transition)0;
((UnityEventBase)val2.onClick).RemoveAllListeners();
((UnityEvent)val2.onClick).AddListener(onClick);
Type type = FindLoadedType("TMPro.TMP_Text");
Graphic val3 = (Graphic)((type == null) ? null : /*isinst with value type is only supported in some contexts*/);
if ((Object)(object)val3 != (Object)null)
{
((Selectable)val2).targetGraphic = val3;
}
return val;
}
private static void AlignValueToLabel(GameObject valueObject, GameObject labelObject)
{
//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_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)valueObject == (Object)null) && !((Object)(object)labelObject == (Object)null))
{
Vector3 position = valueObject.transform.position;
position.y = labelObject.transform.position.y;
valueObject.transform.position = position;
}
}
private static void MoveSettingRow(Type settingsType, object settingsInstance, string fieldName, float offset)
{
object obj = settingsType.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(settingsInstance);
Transform val = (Transform)((obj is Transform) ? obj : null);
if ((Object)(object)val != (Object)null)
{
SetLocalPositionY(val, offset);
return;
}
object? obj2 = obj?.GetType().GetProperty("gameObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
GameObject val2 = (GameObject)((obj2 is GameObject) ? obj2 : null);
if ((Object)(object)val2 != (Object)null)
{
SetLocalPositionY(val2.transform, offset);
}
}
private static void UpdateDiscordPresence()
{
if (Time.time < _nextDiscordUpdate)
{
return;
}
_nextDiscordUpdate = Time.time + 15f;
if (Interlocked.Exchange(ref _discordUpdatePending, 1) != 0)
{
return;
}
List<string> list = new List<string>();
List<string> speaking = new List<string>();
GetVoicePlayers(list, speaking);
int playerCount = Math.Max(1, Math.Min(32, list.Count + 1));
bool loading = IsLoadingScreenActive();
ThreadPool.QueueUserWorkItem(delegate
{
try
{
DiscordRpc.Update(playerCount, loading);
}
finally
{
Interlocked.Exchange(ref _discordUpdatePending, 0);
}
});
}
private static void SetLabelText(object label, string text)
{
(label?.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.SetValue(label, text);
}
private static float GetSliderPercent(object slider, Type sliderType)
{
float num = Convert.ToSingle(sliderType.GetProperty("value")?.GetValue(slider) ?? ((object)0f));
float num2 = Convert.ToSingle(sliderType.GetProperty("minValue")?.GetValue(slider) ?? ((object)0f));
float num3 = Convert.ToSingle(sliderType.GetProperty("maxValue")?.GetValue(slider) ?? ((object)1f));
if (num3 <= num2)
{
return 0f;
}
return Math.Max(0f, Math.Min(100f, (num - num2) / (num3 - num2) * 100f));
}
private static void UpdateMasterVolumeLabel(float value)
{
SetLabelText(_masterVolumeLabel, $"MASTER VOLUME {Math.Round(value):0}%");
}
private static void UpdateMicVolumeLabel(float value)
{
SetLabelText(_micVolumeLabel, $"MIC VOLUME {Math.Round(value):0}%");
}
private static void ConfigureExistingVolumeLabel(object settingsInstance, string sliderFieldName, string labelFieldName, bool master)
{
if (master ? _masterVolumeBound : _micVolumeBound)
{
return;
}
Type type = settingsInstance.GetType();
object? obj = type.GetField(sliderFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(settingsInstance);
Transform val = (Transform)((obj is Transform) ? obj : null);
object obj2 = type.GetField(labelFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(settingsInstance);
Type type2 = FindLoadedType("UnityEngine.UI.Slider");
if ((Object)(object)val == (Object)null || obj2 == null || type2 == null)
{
return;
}
Component val2 = ((Component)val).gameObject.GetComponentsInChildren(type2, true).FirstOrDefault();
if (!((Object)(object)val2 == (Object)null))
{
if (master)
{
_masterVolumeLabel = obj2;
}
else
{
_micVolumeLabel = obj2;
}
object obj3 = type2.GetProperty("onValueChanged")?.GetValue(val2);
MethodInfo methodInfo = obj3?.GetType().GetMethod("AddListener");
if (methodInfo != null)
{
Type parameterType = methodInfo.GetParameters()[0].ParameterType;
string name = (master ? "UpdateMasterVolumeLabel" : "UpdateMicVolumeLabel");
MethodInfo method = typeof(Mod).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic);
Delegate obj4 = Delegate.CreateDelegate(parameterType, method);
methodInfo.Invoke(obj3, new object[1] { obj4 });
}
float sliderPercent = GetSliderPercent(val2, type2);
if (master)
{
_masterVolumeBound = true;
UpdateMasterVolumeLabel(sliderPercent);
}
else
{
_micVolumeBound = true;
UpdateMicVolumeLabel(sliderPercent);
}
}
}
private static void SetLocalPositionY(Transform transform, float offset)
{
try
{
PropertyInfo property = ((object)transform).GetType().GetProperty("localPosition");
object obj = property?.GetValue(transform);
FieldInfo fieldInfo = obj?.GetType().GetField("y");
if (!(property == null) && obj != null && !(fieldInfo == null))
{
float num = (float)fieldInfo.GetValue(obj);
fieldInfo.SetValue(obj, num + offset);
property.SetValue(transform, obj);
}
}
catch
{
}
}
private static void SetVoiceSliderHighlight(bool highlighted)
{
try
{
(_gameSettingsInstance?.GetType().GetMethod("SliderMouseOverImage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.Invoke(_gameSettingsInstance, new object[3] { _voiceSliderTransform, highlighted, false });
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not update VC slider highlight: " + ex.Message);
}
}
private static void OnVoiceSliderMouseOver()
{
SetVoiceSliderHighlight(highlighted: true);
}
private static void OnVoiceSliderMouseExit()
{
SetVoiceSliderHighlight(highlighted: false);
}
private static void ConfigureVoiceSliderHighlight(object settingsInstance, GameObject sliderClone, GameObject labelClone)
{
try
{
Type type = settingsInstance.GetType();
MethodInfo method = type.GetMethod("AddMouseOverEnterEvent", BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo method2 = type.GetMethod("AddMouseOverExitEvent", BindingFlags.Instance | BindingFlags.NonPublic);
Type type2 = FindLoadedType("UnityEngine.UI.Image");
Type type3 = FindLoadedType("TMPro.TMP_Text");
if (method == null || method2 == null || type2 == null || type3 == null)
{
return;
}
object obj = Activator.CreateInstance(typeof(List<>).MakeGenericType(type2));
object obj2 = Activator.CreateInstance(typeof(List<>).MakeGenericType(type3));
Component[] componentsInChildren = sliderClone.GetComponentsInChildren(type2, true);
foreach (Component value in componentsInChildren)
{
((IList)obj).Add(value);
}
if ((Object)(object)labelClone != (Object)null)
{
componentsInChildren = labelClone.GetComponentsInChildren(type3, true);
foreach (Component value2 in componentsInChildren)
{
((IList)obj2).Add(value2);
}
}
Type parameterType = method.GetParameters()[3].ParameterType;
MethodInfo method3 = typeof(Mod).GetMethod("OnVoiceSliderMouseOver", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo method4 = typeof(Mod).GetMethod("OnVoiceSliderMouseExit", BindingFlags.Static | BindingFlags.NonPublic);
Delegate obj3 = Delegate.CreateDelegate(parameterType, method3);
Delegate obj4 = Delegate.CreateDelegate(parameterType, method4);
_gameSettingsInstance = settingsInstance;
_voiceSliderTransform = sliderClone.transform;
method.Invoke(settingsInstance, new object[4] { sliderClone, obj, obj2, obj3 });
method2.Invoke(settingsInstance, new object[4] { sliderClone, obj, obj2, obj4 });
SetVoiceSliderHighlight(highlighted: false);
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not register VC slider highlight: " + ex.Message);
}
}
private static Type FindLoadedType(string fullName)
{
return (from a in AppDomain.CurrentDomain.GetAssemblies()
select a.GetType(fullName)).FirstOrDefault((Type t) => t != null);
}
private static void CreateVoiceVolumeUi(object settingsInstance)
{
if (settingsInstance == null)
{
return;
}
try
{
Type type = settingsInstance.GetType();
ConfigureExistingVolumeLabel(settingsInstance, "_UE_MasterVolume_Slider", "_UE_MASTER_VOLUME", master: true);
ConfigureExistingVolumeLabel(settingsInstance, "_UE_MicVolume_Slider", "_UE_Mic_VOLUME", master: false);
if (_voiceVolumeLabel != null)
{
return;
}
FieldInfo field = type.GetField("_UE_MicVolume_Slider", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo? field2 = type.GetField("_UE_Mic_VOLUME", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
object? obj = field?.GetValue(settingsInstance);
Transform val = (Transform)((obj is Transform) ? obj : null);
object obj2 = field2?.GetValue(settingsInstance);
if ((Object)(object)val == (Object)null || obj2 == null)
{
return;
}
GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent);
((Object)val2).name = "MorePlayersPlus_VoiceVolumeSlider";
SetLocalPositionY(val2.transform, -52f);
Type type2 = FindLoadedType("UnityEngine.UI.Slider");
Component val3 = ((type2 == null) ? null : val2.GetComponentsInChildren(type2, true).FirstOrDefault());
if (!((Object)(object)val3 == (Object)null))
{
type2.GetProperty("minValue")?.SetValue(val3, 0f);
type2.GetProperty("maxValue")?.SetValue(val3, 4f);
object obj3 = type2.GetProperty("onValueChanged")?.GetValue(val3);
obj3?.GetType().GetMethod("RemoveAllListeners")?.Invoke(obj3, null);
MethodInfo methodInfo = obj3?.GetType().GetMethod("AddListener");
if (methodInfo != null)
{
Type parameterType = methodInfo.GetParameters()[0].ParameterType;
MethodInfo method = typeof(Mod).GetMethod("OnVoiceVolumeSliderChanged", BindingFlags.Static | BindingFlags.NonPublic);
Delegate obj4 = Delegate.CreateDelegate(parameterType, method);
methodInfo.Invoke(obj3, new object[1] { obj4 });
}
MethodInfo method2 = type2.GetMethod("SetValueWithoutNotify");
if (method2 != null)
{
method2.Invoke(val3, new object[1] { _voiceVolumeMultiplier });
}
else
{
type2.GetProperty("value")?.SetValue(val3, _voiceVolumeMultiplier);
}
object? obj5 = obj2.GetType().GetProperty("gameObject")?.GetValue(obj2);
GameObject val4 = (GameObject)((obj5 is GameObject) ? obj5 : null);
Transform val5 = ((val4 != null) ? val4.transform : null);
GameObject val6 = null;
if ((Object)(object)val4 != (Object)null && (Object)(object)((val5 != null) ? val5.parent : null) != (Object)null)
{
val6 = Object.Instantiate<GameObject>(val4, val5.parent);
((Object)val6).name = "MorePlayersPlus_VoiceVolumeLabel";
SetLocalPositionY(val6.transform, -52f);
Type type3 = FindLoadedType("TMPro.TMP_Text");
_voiceVolumeLabel = ((type3 == null) ? null : val6.GetComponentsInChildren(type3, true).FirstOrDefault());
UpdateVoiceVolumeLabel();
}
ConfigureVoiceSliderHighlight(settingsInstance, val2, val6);
MelonLogger.Msg("[MorePlayersPlus] Added VC volume control to Game Settings");
}
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Could not add VC volume control UI: " + ex.Message);
}
}
private static bool IsLoadingScreenActive()
{
//IL_005c: 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)
try
{
MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>();
foreach (MonoBehaviour val in array)
{
if (!((Object)(object)val == (Object)null))
{
string name = ((object)val).GetType().Name;
if ((name.Contains("Loading") || name.Contains("Transition")) && ((Component)val).gameObject.activeInHierarchy)
{
return true;
}
}
}
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).name.Contains("Loading"))
{
return true;
}
}
catch
{
}
return false;
}
private static void UnmuteAllDissonance()
{
try
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
Type type = assemblies[i].GetType("Dissonance.DissonanceComms");
if (type == null)
{
continue;
}
Object[] array = Object.FindObjectsOfType(type);
foreach (Object obj in array)
{
PropertyInfo propertyInfo = AccessTools.Property(type, "IsMuted");
if (propertyInfo != null && (bool)propertyInfo.GetValue(obj))
{
propertyInfo.SetValue(obj, false);
}
PropertyInfo propertyInfo2 = AccessTools.Property(type, "IsMicMuted");
if (propertyInfo2 != null && (bool)propertyInfo2.GetValue(obj))
{
propertyInfo2.SetValue(obj, false);
}
}
}
}
catch
{
}
}
private static bool TryAllowLateJoin(object room, long playerUID, out MsgErrorCode result)
{
result = (MsgErrorCode)0;
try
{
Type type = room.GetType();
object obj = (type.BaseType?.GetProperty("IsSessionEnding", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(room);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
if (((uint)num & (flag ? 1u : 0u)) != 0)
{
return false;
}
object obj2 = type.GetField("_state", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(room);
if (obj2 == null)
{
return false;
}
string text = obj2.ToString();
bool flag2 = type.Name == "DeathMatchRoom";
bool flag3 = type.Name == "LogisticsRoom";
bool num2;
if (!flag2)
{
if (!flag3 || !(text != "Invalid") || !(text != "Ready"))
{
goto IL_00f3;
}
num2 = text != "GameOver";
}
else
{
if (text == "OnPlaying")
{
goto IL_00fb;
}
num2 = text == "LastManStanding";
}
if (!num2)
{
goto IL_00f3;
}
goto IL_00fb;
IL_00f3:
return false;
IL_00fb:
if ((type.BaseType?.GetMethod("FindPlayerByUID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.Invoke(room, new object[1] { playerUID }) != null)
{
result = (MsgErrorCode)12;
return true;
}
object obj3 = (type.BaseType?.GetField("_vPlayerDict", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(room);
if (Convert.ToInt32(obj3?.GetType().GetProperty("Count")?.GetValue(obj3) ?? ((object)0)) >= 32)
{
result = (MsgErrorCode)18;
return true;
}
result = (MsgErrorCode)0;
return true;
}
catch (Exception ex)
{
MelonLogger.Warning("[MorePlayersPlus] Late-join check failed: " + ex.Message);
return false;
}
}
}
}