Decompiled source of DeathBlackoutAndMute v1.4.0

Mods/DeathBlackoutMod.dll

Decompiled 2 months ago
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();
		}
	}
}