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);
}
}
}