using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Photon.Voice.Fusion;
using Photon.Voice.Unity;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace PerPlayerVoiceVolume;
public class NativeRowRefs
{
public GameObject Root;
public Text LabelText;
public TMP_Text LabelTmp;
public Text ValueText;
public TMP_Text ValueTmp;
}
[BepInPlugin("com.Sh4de.perplayervoicevolume", "PerPlayerVoiceVolume", "1.2.0")]
[BepInProcess("ShiftAtMidnight.exe")]
public class Mod : BasePlugin
{
internal const string GUID = "com.Sh4de.perplayervoicevolume";
internal static Mod Instance;
private static Harmony harmony;
private readonly Dictionary<string, float> volumes = new Dictionary<string, float>();
private readonly Dictionary<string, AudioSource> sources = new Dictionary<string, AudioSource>();
private readonly Dictionary<string, string> lastLabels = new Dictionary<string, string>();
private float refreshTimer;
private const float RefreshInterval = 1.5f;
private KeybindsManager keybindsManager;
private GameObject nativeRowTemplateSource;
private Transform nativeRowContainer;
private int nativeRowInsertBaseIndex;
private readonly Dictionary<string, NativeRowRefs> nativeRows = new Dictionary<string, NativeRowRefs>();
private float nativeSyncTimer;
private const float NativeSyncInterval = 1f;
public override void Load()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Expected O, but got Unknown
Instance = this;
try
{
harmony = new Harmony("com.Sh4de.perplayervoicevolume");
harmony.PatchAll();
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("Harmony PatchAll a echoue: " + ex));
}
try
{
((BasePlugin)this).AddComponent<UpdateDriver>();
}
catch (Exception ex2)
{
((BasePlugin)this).Log.LogError((object)("Failed to add UpdateDriver component: " + ex2));
}
}
public override bool Unload()
{
try
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("Harmony UnpatchSelf a echoue: " + ex));
}
return true;
}
internal void OnKeybindsManagerReady(KeybindsManager instance)
{
try
{
keybindsManager = instance;
Slider playerVolSlider = instance.playerVolSlider;
if (!((Object)(object)playerVolSlider == (Object)null))
{
Transform parent = ((Component)playerVolSlider).transform.parent;
if (!((Object)(object)parent == (Object)null))
{
nativeRowTemplateSource = ((Component)parent).gameObject;
nativeRowContainer = parent.parent;
nativeRowInsertBaseIndex = parent.GetSiblingIndex() + 1;
nativeRows.Clear();
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("OnKeybindsManagerReady failed: " + ex));
}
}
internal void OnUpdate()
{
refreshTimer += Time.unscaledDeltaTime;
if (refreshTimer >= 1.5f)
{
refreshTimer = 0f;
RefreshEntries();
}
foreach (KeyValuePair<string, AudioSource> source in sources)
{
if (!((Object)(object)source.Value == (Object)null))
{
float value;
float volume = (volumes.TryGetValue(source.Key, out value) ? value : 1f);
source.Value.volume = volume;
}
}
nativeSyncTimer += Time.unscaledDeltaTime;
if (nativeSyncTimer >= 1f)
{
nativeSyncTimer = 0f;
SyncNativeRows();
}
}
private void SyncNativeRows()
{
try
{
if ((Object)(object)keybindsManager == (Object)null || (Object)(object)nativeRowTemplateSource == (Object)null || (Object)(object)nativeRowContainer == (Object)null || !((Component)keybindsManager).gameObject.activeInHierarchy)
{
return;
}
bool flag = false;
foreach (string key in sources.Keys)
{
if (!nativeRows.ContainsKey(key))
{
CreateNativeRow(key);
flag = true;
}
}
List<string> list = new List<string>();
foreach (string key2 in nativeRows.Keys)
{
if (!sources.ContainsKey(key2))
{
list.Add(key2);
}
}
foreach (string item in list)
{
RemoveNativeRow(item);
flag = true;
}
if (flag)
{
try
{
RectTransform component = ((Component)nativeRowContainer).GetComponent<RectTransform>();
if ((Object)(object)component != (Object)null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(component);
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("ForceRebuildLayoutImmediate failed: " + ex.Message));
}
}
foreach (KeyValuePair<string, NativeRowRefs> nativeRow in nativeRows)
{
string displayLabel = GetDisplayLabel(nativeRow.Key);
if ((Object)(object)nativeRow.Value.LabelText != (Object)null)
{
nativeRow.Value.LabelText.text = displayLabel;
}
if ((Object)(object)nativeRow.Value.LabelTmp != (Object)null)
{
nativeRow.Value.LabelTmp.text = displayLabel;
}
float value2;
float value = (volumes.TryGetValue(nativeRow.Key, out value2) ? value2 : 1f);
UpdateValueDisplay(nativeRow.Value.ValueText, nativeRow.Value.ValueTmp, value);
}
}
catch (Exception ex2)
{
((BasePlugin)this).Log.LogError((object)("SyncNativeRows failed: " + ex2));
}
}
private static bool LooksNumeric(string s)
{
if (string.IsNullOrWhiteSpace(s))
{
return true;
}
return Regex.IsMatch(s.Trim().TrimEnd('%'), "^-?\\d+([.,]\\d+)?$");
}
private void DisableLocalizers(GameObject go)
{
if ((Object)(object)go == (Object)null)
{
return;
}
try
{
foreach (Behaviour component in go.GetComponents<Behaviour>())
{
if (!((Object)(object)component == (Object)null) && ((object)component).GetType().Name.IndexOf("Localiz", StringComparison.OrdinalIgnoreCase) >= 0)
{
component.enabled = false;
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("DisableLocalizers failed: " + ex.Message));
}
}
private void CreateNativeRow(string key)
{
try
{
GameObject val = Object.Instantiate<GameObject>(nativeRowTemplateSource, nativeRowContainer);
((Object)val).name = "PPVV_Row_" + key;
val.transform.SetSiblingIndex(nativeRowInsertBaseIndex + nativeRows.Count);
val.SetActive(true);
Slider componentInChildren = val.GetComponentInChildren<Slider>(true);
if ((Object)(object)componentInChildren == (Object)null)
{
Object.Destroy((Object)(object)val);
return;
}
((UnityEventBase)componentInChildren.onValueChanged).RemoveAllListeners();
componentInChildren.minValue = 0f;
componentInChildren.maxValue = 2f;
float value;
float num = (volumes.TryGetValue(key, out value) ? Mathf.Clamp(value, 0f, 2f) : 1f);
componentInChildren.SetValueWithoutNotify(num);
Text val2 = null;
Text val3 = null;
TMP_Text val4 = null;
TMP_Text val5 = null;
foreach (Text componentsInChild in val.GetComponentsInChildren<Text>(true))
{
if (!((Component)componentsInChild).transform.IsChildOf(((Component)componentInChildren).transform))
{
if (LooksNumeric(componentsInChild.text) && (Object)(object)val3 == (Object)null)
{
val3 = componentsInChild;
}
else if ((Object)(object)val2 == (Object)null)
{
val2 = componentsInChild;
}
}
}
try
{
foreach (TMP_Text componentsInChild2 in val.GetComponentsInChildren<TMP_Text>(true))
{
if (!componentsInChild2.transform.IsChildOf(((Component)componentInChildren).transform))
{
if (LooksNumeric(componentsInChild2.text) && (Object)(object)val5 == (Object)null)
{
val5 = componentsInChild2;
}
else if ((Object)(object)val4 == (Object)null)
{
val4 = componentsInChild2;
}
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("TMP_Text lookup failed: " + ex.Message));
}
if ((Object)(object)val2 != (Object)null)
{
DisableLocalizers(((Component)val2).gameObject);
}
if ((Object)(object)val4 != (Object)null)
{
DisableLocalizers(((Component)val4).gameObject);
}
string displayLabel = GetDisplayLabel(key);
if ((Object)(object)val2 != (Object)null)
{
val2.text = displayLabel;
}
if ((Object)(object)val4 != (Object)null)
{
val4.text = displayLabel;
}
UpdateValueDisplay(val3, val5, num);
string capturedKey = key;
Text capturedValueText = val3;
TMP_Text capturedValueTmp = val5;
Action<float> action = delegate(float newVal)
{
volumes[capturedKey] = newVal;
UpdateValueDisplay(capturedValueText, capturedValueTmp, newVal);
};
((UnityEvent<float>)(object)componentInChildren.onValueChanged).AddListener(UnityAction<float>.op_Implicit(action));
nativeRows[key] = new NativeRowRefs
{
Root = val,
LabelText = val2,
LabelTmp = val4,
ValueText = val3,
ValueTmp = val5
};
}
catch (Exception ex2)
{
((BasePlugin)this).Log.LogError((object)("CreateNativeRow failed for '" + key + "': " + ex2));
}
}
private void RemoveNativeRow(string key)
{
if (nativeRows.TryGetValue(key, out var value))
{
if ((Object)(object)value.Root != (Object)null)
{
Object.Destroy((Object)(object)value.Root);
}
nativeRows.Remove(key);
}
}
private void UpdateValueDisplay(Text valueText, TMP_Text valueTmp, float value)
{
string text = Mathf.RoundToInt(value * 100f) + "%";
if ((Object)(object)valueText != (Object)null)
{
valueText.text = text;
}
if ((Object)(object)valueTmp != (Object)null)
{
valueTmp.text = text;
}
}
private string GetDisplayLabel(string key)
{
if (!lastLabels.TryGetValue(key, out var value))
{
return key;
}
return value;
}
private void RefreshEntries()
{
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
NetworkRunner val = null;
try
{
foreach (NetworkRunner item in Resources.FindObjectsOfTypeAll<NetworkRunner>())
{
if (!((Object)(object)item == (Object)null))
{
val = item;
break;
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("NetworkRunner lookup failed: " + ex.Message));
}
VoiceNetworkObject[] array;
try
{
array = Il2CppArrayBase<VoiceNetworkObject>.op_Implicit(Resources.FindObjectsOfTypeAll<VoiceNetworkObject>());
}
catch (Exception ex2)
{
((BasePlugin)this).Log.LogError((object)("VoiceNetworkObject lookup failed: " + ex2.Message));
return;
}
HashSet<string> hashSet = new HashSet<string>();
VoiceNetworkObject[] array2 = array;
foreach (VoiceNetworkObject val2 in array2)
{
if ((Object)(object)val2 == (Object)null)
{
continue;
}
try
{
Speaker speakerInUse;
try
{
speakerInUse = val2.SpeakerInUse;
}
catch
{
goto end_IL_00b8;
}
if ((Object)(object)speakerInUse == (Object)null)
{
continue;
}
AudioSource component;
try
{
component = ((Component)speakerInUse).GetComponent<AudioSource>();
}
catch
{
goto end_IL_00b8;
}
if ((Object)(object)component == (Object)null)
{
continue;
}
NetworkObject val3 = null;
try
{
val3 = ((Component)val2).GetComponent<NetworkObject>();
}
catch
{
}
if ((Object)(object)val3 != (Object)null && (Object)(object)val != (Object)null)
{
try
{
PlayerRef inputAuthority = val3.InputAuthority;
if (((PlayerRef)(ref inputAuthority)).Equals(val.LocalPlayer))
{
continue;
}
}
catch
{
}
}
string key = GetKey(val3, val);
string label = GetLabel(val3, val2, val);
lastLabels[key] = label;
hashSet.Add(key);
sources[key] = component;
if (!volumes.ContainsKey(key))
{
volumes[key] = ((component.volume > 0f) ? component.volume : 1f);
}
end_IL_00b8:;
}
catch (Exception ex3)
{
((BasePlugin)this).Log.LogError((object)("Failed to process a VoiceNetworkObject: " + ex3.Message));
}
}
List<string> list = new List<string>();
foreach (string key2 in sources.Keys)
{
if (!hashSet.Contains(key2))
{
list.Add(key2);
}
}
foreach (string item2 in list)
{
sources.Remove(item2);
}
}
private string GetKey(NetworkObject no, NetworkRunner runner)
{
//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_001a: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)no != (Object)null && (Object)(object)runner != (Object)null)
{
PlayerRef inputAuthority = no.InputAuthority;
string playerUserId = runner.GetPlayerUserId(inputAuthority);
if (!string.IsNullOrEmpty(playerUserId))
{
return playerUserId;
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("GetKey failed: " + ex.Message));
}
if (!((Object)(object)no != (Object)null))
{
return "obj_unknown";
}
return "obj_" + ((Object)no).GetInstanceID();
}
private string GetLabel(NetworkObject no, VoiceNetworkObject vno, NetworkRunner runner)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: 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_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
try
{
PlayerManager val = null;
NetworkObject val2 = null;
if ((Object)(object)no != (Object)null && (Object)(object)runner != (Object)null)
{
try
{
PlayerRef inputAuthority = no.InputAuthority;
val2 = runner.GetPlayerObject(inputAuthority);
if ((Object)(object)val2 != (Object)null)
{
val = ((Component)val2).GetComponent<PlayerManager>();
if ((Object)(object)val == (Object)null)
{
val = ((Component)val2).GetComponentInChildren<PlayerManager>();
}
}
}
catch
{
}
}
if ((Object)(object)val == (Object)null)
{
try
{
if ((Object)(object)no != (Object)null)
{
val = ((Component)no).GetComponent<PlayerManager>();
}
}
catch
{
}
}
if ((Object)(object)val == (Object)null)
{
try
{
val = ((Component)vno).GetComponent<PlayerManager>();
}
catch
{
}
}
if ((Object)(object)val == (Object)null && (Object)(object)no != (Object)null)
{
try
{
val = ((Component)no).GetComponentInChildren<PlayerManager>();
}
catch
{
}
}
if ((Object)(object)val == (Object)null && (Object)(object)no != (Object)null)
{
try
{
val = ((Component)no).GetComponentInParent<PlayerManager>();
}
catch
{
}
}
if ((Object)(object)val == (Object)null && (Object)(object)no != (Object)null)
{
try
{
PlayerRef inputAuthority2 = no.InputAuthority;
foreach (PlayerManager item in Resources.FindObjectsOfTypeAll<PlayerManager>())
{
if ((Object)(object)item == (Object)null)
{
continue;
}
NetworkObject val3 = null;
try
{
val3 = ((Component)item).GetComponent<NetworkObject>();
}
catch
{
}
if ((Object)(object)val3 == (Object)null)
{
try
{
val3 = ((Component)item).GetComponentInParent<NetworkObject>();
}
catch
{
}
}
if (!((Object)(object)val3 == (Object)null))
{
PlayerRef inputAuthority3 = val3.InputAuthority;
if (((PlayerRef)(ref inputAuthority3)).Equals(inputAuthority2))
{
val = item;
break;
}
}
}
}
catch
{
}
}
if ((Object)(object)val != (Object)null)
{
string text = null;
try
{
text = val.playerName;
}
catch
{
}
if (!string.IsNullOrEmpty(text))
{
return text;
}
}
if ((Object)(object)val2 != (Object)null)
{
string text2 = TryExtractNameFromObject(((Component)val2).gameObject);
if (!string.IsNullOrEmpty(text2))
{
return text2;
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("GetLabel failed: " + ex));
}
return GetLabelSteamFallback(no, runner);
}
private string TryExtractNameFromObject(GameObject go)
{
try
{
if ((Object)(object)go == (Object)null)
{
return null;
}
List<string> list = new List<string>();
foreach (Text componentsInChild in go.GetComponentsInChildren<Text>(true))
{
if ((Object)(object)componentsInChild != (Object)null && !string.IsNullOrWhiteSpace(componentsInChild.text))
{
list.Add(componentsInChild.text);
}
}
try
{
foreach (TMP_Text componentsInChild2 in go.GetComponentsInChildren<TMP_Text>(true))
{
if ((Object)(object)componentsInChild2 != (Object)null && !string.IsNullOrWhiteSpace(componentsInChild2.text))
{
list.Add(componentsInChild2.text);
}
}
}
catch
{
}
foreach (string item in list)
{
string text = item.Trim();
if (text.Length >= 2 && !LooksNumeric(text))
{
return text;
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("TryExtractNameFromObject failed: " + ex.Message));
}
return null;
}
private string GetLabelSteamFallback(NetworkObject no, NetworkRunner runner)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)no != (Object)null && (Object)(object)runner != (Object)null && ulong.TryParse(runner.GetPlayerUserId(no.InputAuthority), out var result) && result != 0)
{
string friendPersonaName = SteamFriends.GetFriendPersonaName(new CSteamID(result));
if (!string.IsNullOrEmpty(friendPersonaName) && friendPersonaName != "[unknown]")
{
return friendPersonaName;
}
}
}
catch (Exception ex)
{
((BasePlugin)this).Log.LogError((object)("GetLabelSteamFallback failed: " + ex));
}
return "Player";
}
}
public class UpdateDriver : MonoBehaviour
{
public UpdateDriver(IntPtr ptr)
: base(ptr)
{
}
private void Update()
{
if (Mod.Instance == null)
{
return;
}
try
{
Mod.Instance.OnUpdate();
}
catch (Exception ex)
{
((BasePlugin)Mod.Instance).Log.LogError((object)("UpdateDriver.Update failed: " + ex));
}
}
}
[HarmonyPatch(typeof(KeybindsManager), "Start")]
internal static class KeybindsManager_Start_Patch
{
private static void Postfix(KeybindsManager __instance)
{
try
{
if (Mod.Instance != null)
{
Mod.Instance.OnKeybindsManagerReady(__instance);
}
}
catch (Exception ex)
{
Mod instance = Mod.Instance;
if (instance != null)
{
((BasePlugin)instance).Log.LogError((object)("KeybindsManager_Start_Patch postfix failed: " + ex));
}
}
}
}