using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BoneLib;
using BoneLib.BoneMenu;
using DeathBlackoutMod;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Preferences;
using UnityEngine;
using UnityEngine.Rendering;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Death Blackout & Mute")]
[assembly: AssemblyDescription("Blacks out screen and mutes audio instantly on local player death, Fusion compatible")]
[assembly: AssemblyCompany("imalwaysbored")]
[assembly: AssemblyProduct("DeathBlackoutMod")]
[assembly: AssemblyCopyright("Created by imalwaysbored")]
[assembly: AssemblyTrademark("imalwaysbored")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: MelonInfo(typeof(Main), "Death Blackout & Mute", "1.2.0", "imalwaysbored", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
namespace DeathBlackoutMod;
public class Main : MelonMod
{
private static GameObject _blackoutRig;
private static Material _blackoutMaterial;
private static Camera _cachedCamera;
private static float _savedVolume = 1f;
private static MelonPreferences_Category _prefsCategory;
private static MelonPreferences_Entry<bool> _prefsEnabled;
private const float QuadSize = 4f;
private const float NearPlaneMargin = 0.02f;
private static int _frameCounter = 0;
private static readonly Dictionary<RigManager, bool> _currentMuteStates = new Dictionary<RigManager, bool>();
private static readonly Dictionary<RigManager, float> _unmuteTimers = new Dictionary<RigManager, float>();
public static bool IsDead { get; private set; }
public static bool ModEnabled => _prefsEnabled?.Value ?? true;
public override void OnInitializeMelon()
{
_prefsCategory = MelonPreferences.CreateCategory("DeathBlackoutMod", "Death Blackout & Mute");
_prefsEnabled = _prefsCategory.CreateEntry<bool>("Enabled", true, "Enable Mod", (string)null, false, false, (ValueValidator)null, (string)null);
SetupBoneMenu();
MelonLogger.Msg("Death Blackout & Mute (Self-Healing Mic Mute) loaded!");
((MelonBase)this).HarmonyInstance.PatchAll();
}
private void SetupBoneMenu()
{
//IL_000a: 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)
Page.Root.CreatePage("Death Blackout", Color.red, 0, true).CreateBool("Mod Enabled", Color.white, _prefsEnabled.Value, (Action<bool>)delegate(bool val)
{
_prefsEnabled.Value = val;
_prefsCategory.SaveToFile(true);
if (!val && IsDead)
{
TriggerRespawn();
}
});
}
public override void OnUpdate()
{
if (IsDead && ModEnabled)
{
EnsureRigExists();
AttachRigToCamera();
}
if (ModEnabled)
{
_frameCounter++;
if (_frameCounter % 15 == 0)
{
UpdateRemotePlayerMuteStates();
}
}
}
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
_cachedCamera = null;
_blackoutRig = null;
IsDead = false;
_currentMuteStates.Clear();
_unmuteTimers.Clear();
}
public override void OnDeinitializeMelon()
{
if (IsDead)
{
AudioListener.volume = _savedVolume;
SetFusionLocalMicMute(mute: false);
}
if ((Object)(object)_blackoutRig != (Object)null)
{
Object.Destroy((Object)(object)_blackoutRig);
_blackoutRig = null;
}
if ((Object)(object)_blackoutMaterial != (Object)null)
{
Object.Destroy((Object)(object)_blackoutMaterial);
_blackoutMaterial = null;
}
_currentMuteStates.Clear();
_unmuteTimers.Clear();
}
public static void TriggerDeath()
{
if (!IsDead && ModEnabled)
{
IsDead = true;
_savedVolume = AudioListener.volume;
AudioListener.volume = 0f;
SetFusionLocalMicMute(mute: true);
EnsureRigExists();
AttachRigToCamera();
if ((Object)(object)_blackoutRig != (Object)null)
{
_blackoutRig.SetActive(true);
}
}
}
public static void TriggerRespawn()
{
if (IsDead)
{
IsDead = false;
AudioListener.volume = _savedVolume;
SetFusionLocalMicMute(mute: false);
if ((Object)(object)_blackoutRig != (Object)null)
{
_blackoutRig.SetActive(false);
}
}
}
private static void UpdateRemotePlayerMuteStates()
{
try
{
bool flag = IsLocalPlayerDeadState();
SetFusionLocalMicMute(flag);
Il2CppArrayBase<Player_Health> val = Object.FindObjectsOfType<Player_Health>();
if (val == null)
{
return;
}
foreach (Player_Health item in val)
{
if ((Object)(object)item == (Object)null || IsLocalPlayerHealth(item))
{
continue;
}
RigManager componentInParent = ((Component)item).GetComponentInParent<RigManager>();
if ((Object)(object)componentInParent == (Object)null)
{
continue;
}
bool num = flag || IsDeadState(item);
if (!_currentMuteStates.ContainsKey(componentInParent))
{
_currentMuteStates[componentInParent] = false;
}
if (num)
{
if (!_currentMuteStates[componentInParent])
{
SetRemotePlayerVoiceMute(componentInParent, mute: true);
_currentMuteStates[componentInParent] = true;
}
_unmuteTimers.Remove(componentInParent);
}
else if (_currentMuteStates[componentInParent])
{
if (!_unmuteTimers.ContainsKey(componentInParent))
{
_unmuteTimers[componentInParent] = Time.time + 2.2f;
}
else if (Time.time >= _unmuteTimers[componentInParent])
{
SetRemotePlayerVoiceMute(componentInParent, mute: false);
_currentMuteStates[componentInParent] = false;
_unmuteTimers.Remove(componentInParent);
}
}
}
}
catch
{
}
}
private static bool IsLocalPlayerDeadState()
{
try
{
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
return IsDead;
}
Player_Health componentInChildren = ((Component)rigManager).GetComponentInChildren<Player_Health>();
if ((Object)(object)componentInChildren != (Object)null)
{
return IsDeadState(componentInChildren);
}
}
catch
{
}
return IsDead;
}
private static bool IsDeadState(Player_Health health)
{
if ((Object)(object)health == (Object)null)
{
return false;
}
try
{
string[] array = new string[4] { "deathHandled", "_deathHandled", "isDead", "_isDead" };
foreach (string name in array)
{
FieldInfo field = typeof(Player_Health).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
return (bool)field.GetValue(health);
}
PropertyInfo property = typeof(Player_Health).GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return (bool)property.GetValue(health, null);
}
}
array = new string[4] { "health", "_health", "curr_Health", "_curr_Health" };
foreach (string name2 in array)
{
FieldInfo field2 = typeof(Player_Health).GetField(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field2 != null && Convert.ToSingle(field2.GetValue(health)) <= 0f)
{
return true;
}
PropertyInfo property2 = typeof(Player_Health).GetProperty(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property2 != null && Convert.ToSingle(property2.GetValue(health, null)) <= 0f)
{
return true;
}
}
}
catch
{
}
return false;
}
public static void SetRemotePlayerVoiceMute(RigManager rig, bool mute)
{
if ((Object)(object)rig == (Object)null)
{
return;
}
try
{
foreach (Component componentsInChild in ((Component)((Component)rig).transform.root).gameObject.GetComponentsInChildren<Component>(true))
{
if ((Object)(object)componentsInChild == (Object)null)
{
continue;
}
string text = ((Object)componentsInChild).ToString();
if (text.Contains("Voice") || text.Contains("AudioStream"))
{
AudioSource component = componentsInChild.GetComponent<AudioSource>();
if ((Object)(object)component != (Object)null)
{
component.mute = mute;
}
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("Could not toggle remote voice mute: " + ex.Message);
}
}
public static void SetCurrentMuteState(RigManager rig, bool mute)
{
if (!((Object)(object)rig == (Object)null))
{
_currentMuteStates[rig] = mute;
if (mute)
{
_unmuteTimers.Remove(rig);
}
}
}
private static void SetFusionLocalMicMute(bool mute)
{
try
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
if (!(assembly.GetName().Name == "LabFusion"))
{
continue;
}
Type type = assembly.GetType("LabFusion.Voice.VoiceManager") ?? assembly.GetType("LabFusion.Network.VoiceManager");
if (type != null)
{
PropertyInfo propertyInfo = type.GetProperty("IsMuted") ?? type.GetProperty("Muted") ?? type.GetProperty("VoiceMuted");
if (propertyInfo != null && propertyInfo.CanWrite)
{
propertyInfo.SetValue(null, mute);
break;
}
MethodInfo methodInfo = type.GetMethod("SetMuted") ?? type.GetMethod("MuteMicrophone");
if (methodInfo != null)
{
methodInfo.Invoke(null, new object[1] { mute });
break;
}
}
Type type2 = assembly.GetType("LabFusion.Preferences.ClientSettings");
if (type2 != null)
{
FieldInfo fieldInfo = type2.GetField("VoiceMuted") ?? type2.GetField("IsMuted");
if (fieldInfo != null)
{
fieldInfo.SetValue(null, mute);
break;
}
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("Could not toggle local Fusion mic mute: " + ex.Message);
}
}
public static bool IsLocalPlayerHealth(Player_Health health)
{
if ((Object)(object)health == (Object)null)
{
return false;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
return false;
}
RigManager componentInParent = ((Component)health).GetComponentInParent<RigManager>();
if ((Object)(object)componentInParent == (Object)null)
{
return false;
}
return (Object)(object)componentInParent == (Object)(object)rigManager;
}
private static void EnsureRigExists()
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_blackoutRig != (Object)null)
{
return;
}
if ((Object)(object)_blackoutMaterial == (Object)null)
{
Shader val = FindBlackoutShader();
if ((Object)(object)val == (Object)null)
{
MelonLogger.Error("No usable blackout shader found.");
return;
}
_blackoutMaterial = new Material(val);
if (_blackoutMaterial.HasProperty("_Color"))
{
_blackoutMaterial.color = Color.black;
}
_blackoutMaterial.renderQueue = 4100;
}
_blackoutRig = new GameObject("DeathBlackoutRig");
CreateQuadChild(_blackoutRig.transform, 0f);
CreateQuadChild(_blackoutRig.transform, 180f);
_blackoutRig.SetActive(false);
}
private static void CreateQuadChild(Transform parent, float yRotationDegrees)
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
((Object)obj).name = "DeathBlackoutQuad_" + yRotationDegrees;
Collider component = obj.GetComponent<Collider>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
if ((Object)(object)component2 != (Object)null)
{
((Renderer)component2).material = _blackoutMaterial;
((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
((Renderer)component2).receiveShadows = false;
}
obj.transform.SetParent(parent, false);
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.Euler(0f, yRotationDegrees, 0f);
obj.transform.localScale = new Vector3(4f, 4f, 1f);
}
private static Shader FindBlackoutShader()
{
string[] array = new string[3] { "Sprites/Default", "UI/Default", "Unlit/Color" };
for (int i = 0; i < array.Length; i++)
{
Shader val = Shader.Find(array[i]);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
return null;
}
private static void AttachRigToCamera()
{
//IL_006f: 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)
if ((Object)(object)_blackoutRig == (Object)null)
{
return;
}
Camera activeCamera = GetActiveCamera();
if (!((Object)(object)activeCamera == (Object)null))
{
Transform transform = ((Component)activeCamera).transform;
if ((Object)(object)_blackoutRig.transform.parent != (Object)(object)transform)
{
_blackoutRig.transform.SetParent(transform, false);
}
float num = activeCamera.nearClipPlane + 0.02f;
_blackoutRig.transform.localPosition = new Vector3(0f, 0f, num);
_blackoutRig.transform.localRotation = Quaternion.identity;
}
}
private static Camera GetActiveCamera()
{
if ((Object)(object)_cachedCamera != (Object)null)
{
return _cachedCamera;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null || (Object)(object)rigManager.physicsRig == (Object)null || (Object)(object)((Rig)rigManager.physicsRig).m_head == (Object)null)
{
return null;
}
Camera val = ((Component)((Rig)rigManager.physicsRig).m_head).GetComponentInChildren<Camera>();
if ((Object)(object)val == (Object)null)
{
val = Camera.main;
}
_cachedCamera = val;
return _cachedCamera;
}
}
[HarmonyPatch(typeof(Player_Health), "Dying")]
public static class DyingPatch
{
public static void Prefix(Player_Health __instance, float damage)
{
if (Main.ModEnabled)
{
if (Main.IsLocalPlayerHealth(__instance))
{
Main.TriggerDeath();
return;
}
RigManager componentInParent = ((Component)__instance).GetComponentInParent<RigManager>();
Main.SetRemotePlayerVoiceMute(componentInParent, mute: true);
Main.SetCurrentMuteState(componentInParent, mute: true);
}
}
}
[HarmonyPatch(typeof(Player_Health), "Death")]
public static class DeathPatch
{
public static void Prefix(Player_Health __instance)
{
if (Main.ModEnabled)
{
if (Main.IsLocalPlayerHealth(__instance))
{
Main.TriggerDeath();
return;
}
RigManager componentInParent = ((Component)__instance).GetComponentInParent<RigManager>();
Main.SetRemotePlayerVoiceMute(componentInParent, mute: true);
Main.SetCurrentMuteState(componentInParent, mute: true);
}
}
}
[HarmonyPatch(typeof(Player_Health), "SetFullHealth")]
public static class RespawnPatch
{
public static void Postfix(Player_Health __instance)
{
if (Main.ModEnabled && Main.IsLocalPlayerHealth(__instance))
{
Main.TriggerRespawn();
}
}
}