Decompiled source of SilksongFocusQoL v1.0.1

SilksongFocusQoL.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SilksongFocusQoL")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+8bbdc76b8b2ca802848b84675715a160716bb538")]
[assembly: AssemblyProduct("SilksongFocusQoL")]
[assembly: AssemblyTitle("SilksongFocusQoL")]
[assembly: AssemblyVersion("1.0.1.0")]
[BepInPlugin("com.zlq.silksongfocusqol", "Silksong Focus QoL", "1.0.1")]
public class SilksongFocusQoL : BaseUnityPlugin
{
	private class FocusQoLBehaviour : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <TimeoutTracking>d__20 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public FocusQoLBehaviour <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TimeoutTracking>d__20(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Expected O, but got Unknown
				int num = <>1__state;
				FocusQoLBehaviour focusQoLBehaviour = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSecondsRealtime(focusQoLBehaviour.autoUnpauseWindow.Value);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					focusQoLBehaviour.isTrackingTime = false;
					focusQoLBehaviour.timeoutCoroutine = null;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private bool wasPausedByMod;

		private bool wasAlreadyPaused;

		private float focusLostTime;

		private bool isTrackingTime;

		private Coroutine timeoutCoroutine;

		private bool wantsToPause;

		private ConfigEntry<bool> enableAutoPause;

		private ConfigEntry<bool> enableAutoUnpause;

		private ConfigEntry<float> autoUnpauseWindow;

		private ConfigEntry<bool> enableAutoMute;

		private Type gameManagerType;

		private PropertyInfo instanceProp;

		private MethodInfo isGamePausedMethod;

		private MethodInfo pauseGameToggle;

		private ParameterInfo[] pauseMethodParameters;

		public void SetConfig(ConfigEntry<bool> enableAutoPause, ConfigEntry<bool> enableAutoUnpause, ConfigEntry<float> autoUnpauseWindow, ConfigEntry<bool> enableAutoMute)
		{
			this.enableAutoPause = enableAutoPause;
			this.enableAutoUnpause = enableAutoUnpause;
			this.autoUnpauseWindow = autoUnpauseWindow;
			this.enableAutoMute = enableAutoMute;
			CacheGameManagerMethods();
		}

		private void CacheGameManagerMethods()
		{
			gameManagerType = Type.GetType("GameManager") ?? FindTypeByName("GameManager");
			if (gameManagerType != null)
			{
				instanceProp = gameManagerType.GetProperty("instance", BindingFlags.Static | BindingFlags.Public) ?? gameManagerType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
				isGamePausedMethod = gameManagerType.GetMethod("IsGamePaused", BindingFlags.Instance | BindingFlags.Public);
				pauseGameToggle = gameManagerType.GetMethod("PauseGameToggle", BindingFlags.Instance | BindingFlags.Public);
				if (pauseGameToggle != null)
				{
					pauseMethodParameters = pauseGameToggle.GetParameters();
				}
			}
		}

		private void Update()
		{
			if (wantsToPause && !IsGamePaused())
			{
				AttemptToPauseGame();
			}
		}

		private void OnApplicationFocus(bool hasFocus)
		{
			if (!((Behaviour)this).isActiveAndEnabled)
			{
				return;
			}
			try
			{
				if (!hasFocus)
				{
					focusLostTime = Time.unscaledTime;
					wasAlreadyPaused = IsGamePaused();
					if (enableAutoPause.Value)
					{
						wantsToPause = true;
						if (!wasAlreadyPaused)
						{
							AttemptToPauseGame();
						}
					}
					if (enableAutoUnpause.Value && autoUnpauseWindow.Value > 0f)
					{
						isTrackingTime = true;
						StopTrackingCoroutine();
						timeoutCoroutine = ((MonoBehaviour)this).StartCoroutine(TimeoutTracking());
					}
				}
				else
				{
					wantsToPause = false;
					StopTrackingCoroutine();
					if (enableAutoUnpause.Value && wasPausedByMod)
					{
						bool flag = true;
						if (autoUnpauseWindow.Value > 0f)
						{
							flag = isTrackingTime && Time.unscaledTime - focusLostTime <= autoUnpauseWindow.Value;
						}
						if (flag)
						{
							AttemptToUnpauseGame();
						}
					}
					wasPausedByMod = false;
					wasAlreadyPaused = false;
					isTrackingTime = false;
				}
				if (enableAutoMute.Value)
				{
					AudioListener.pause = !hasFocus;
				}
			}
			catch (Exception)
			{
			}
		}

		private void StopTrackingCoroutine()
		{
			if (timeoutCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(timeoutCoroutine);
				timeoutCoroutine = null;
			}
		}

		[IteratorStateMachine(typeof(<TimeoutTracking>d__20))]
		private IEnumerator TimeoutTracking()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TimeoutTracking>d__20(0)
			{
				<>4__this = this
			};
		}

		private bool IsGamePaused()
		{
			try
			{
				if (gameManagerType == null || instanceProp == null || isGamePausedMethod == null)
				{
					return false;
				}
				object value = instanceProp.GetValue(null);
				if (value == null)
				{
					return false;
				}
				return (bool)isGamePausedMethod.Invoke(value, null);
			}
			catch
			{
				return false;
			}
		}

		private void AttemptToPauseGame()
		{
			try
			{
				if (gameManagerType == null || instanceProp == null || pauseGameToggle == null)
				{
					return;
				}
				object value = instanceProp.GetValue(null);
				if (value != null && !IsGamePaused())
				{
					object obj = null;
					if (pauseMethodParameters.Length == 1 && pauseMethodParameters[0].ParameterType == typeof(bool))
					{
						obj = pauseGameToggle.Invoke(value, new object[1] { true });
					}
					else if (pauseMethodParameters.Length == 0)
					{
						obj = pauseGameToggle.Invoke(value, null);
					}
					if (obj != null && obj is IEnumerator)
					{
						((MonoBehaviour)this).StartCoroutine((IEnumerator)obj);
						wasPausedByMod = true;
					}
				}
			}
			catch
			{
			}
		}

		private void AttemptToUnpauseGame()
		{
			try
			{
				if (gameManagerType == null || instanceProp == null || pauseGameToggle == null)
				{
					return;
				}
				object value = instanceProp.GetValue(null);
				if (value != null && IsGamePaused() && wasPausedByMod)
				{
					object obj = null;
					if (pauseMethodParameters.Length == 1 && pauseMethodParameters[0].ParameterType == typeof(bool))
					{
						obj = pauseGameToggle.Invoke(value, new object[1] { false });
					}
					else if (pauseMethodParameters.Length == 0)
					{
						obj = pauseGameToggle.Invoke(value, null);
					}
					if (obj != null && obj is IEnumerator)
					{
						((MonoBehaviour)this).StartCoroutine((IEnumerator)obj);
					}
				}
			}
			catch
			{
			}
		}

		private Type FindTypeByName(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type[] types = assembly.GetTypes();
					foreach (Type type in types)
					{
						if (type.Name == typeName)
						{
							return type;
						}
					}
				}
				catch (ReflectionTypeLoadException)
				{
				}
			}
			return null;
		}

		private void OnDisable()
		{
			StopTrackingCoroutine();
		}
	}

	private GameObject focusQoLBehaviourObject;

	private ConfigEntry<bool> configEnableAutoPause;

	private ConfigEntry<bool> configEnableAutoUnpause;

	private ConfigEntry<float> configAutoUnpauseWindow;

	private ConfigEntry<bool> configEnableAutoMute;

	private void Awake()
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected O, but got Unknown
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Expected O, but got Unknown
		ValidateConfig();
		configEnableAutoMute = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "EnableAutoMute", true, "Mute audio when window loses focus");
		configEnableAutoPause = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "EnableAutoPause", true, "Pause game when window loses focus");
		configEnableAutoUnpause = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "EnableAutoUnpause", true, "Unpause when focus returns");
		configAutoUnpauseWindow = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "AutoUnpauseWindow", 3f, new ConfigDescription("Time window to auto-unpause\n0 = always unpause when focus returns; >0 = only if refocus occurs within this many seconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
		((BaseUnityPlugin)this).Config.SettingChanged += OnConfigChanged;
		focusQoLBehaviourObject = new GameObject("SilksongFocusQoLBehaviour", new Type[1] { typeof(FocusQoLBehaviour) });
		Object.DontDestroyOnLoad((Object)(object)focusQoLBehaviourObject);
		focusQoLBehaviourObject.GetComponent<FocusQoLBehaviour>().SetConfig(configEnableAutoPause, configEnableAutoUnpause, configAutoUnpauseWindow, configEnableAutoMute);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Silksong Focus QoL loaded");
	}

	private void ValidateConfig()
	{
		ConfigEntry<float> obj = configAutoUnpauseWindow;
		if (obj != null && obj.Value < 0f)
		{
			configAutoUnpauseWindow.Value = 0f;
		}
	}

	private void OnConfigChanged(object sender, SettingChangedEventArgs e)
	{
		try
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Config updated: [" + e.ChangedSetting.Definition.Section + "] " + e.ChangedSetting.Definition.Key));
			GameObject obj = focusQoLBehaviourObject;
			FocusQoLBehaviour focusQoLBehaviour = ((obj != null) ? obj.GetComponent<FocusQoLBehaviour>() : null);
			if ((Object)(object)focusQoLBehaviour != (Object)null)
			{
				focusQoLBehaviour.SetConfig(configEnableAutoPause, configEnableAutoUnpause, configAutoUnpauseWindow, configEnableAutoMute);
			}
		}
		catch (Exception arg)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)$"Error applying config change: {arg}");
		}
	}

	private void OnDestroy()
	{
		((BaseUnityPlugin)this).Config.SettingChanged -= OnConfigChanged;
		if ((Object)(object)focusQoLBehaviourObject != (Object)null)
		{
			Object.Destroy((Object)(object)focusQoLBehaviourObject);
		}
	}
}