using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace uiHide
{
internal static class BeepPlayer
{
private const float Frequency = 880f;
private const float Duration = 0.08f;
private const float Amplitude = 0.5f;
private static AudioClip _clip;
private static AudioSource _source;
private static bool _initFailed;
private static MethodInfo _setDataMethod;
internal static void Cleanup()
{
if ((Object)(object)_clip != (Object)null)
{
Object.Destroy((Object)(object)_clip);
_clip = null;
}
if ((Object)(object)_source != (Object)null)
{
Object.Destroy((Object)(object)_source);
_source = null;
}
_initFailed = false;
_setDataMethod = null;
}
internal static void Play(bool hidden)
{
if (!_initFailed)
{
EnsureInit();
if (!((Object)(object)_source == (Object)null) && !((Object)(object)_clip == (Object)null))
{
_source.pitch = (hidden ? 0.8f : 1.3f);
_source.PlayOneShot(_clip);
}
}
}
private static void EnsureInit()
{
if ((Object)(object)_clip == (Object)null)
{
_clip = CreateBeepClip();
}
if ((Object)(object)_source == (Object)null && (Object)(object)Plugin.Instance != (Object)null)
{
_source = ((Component)Plugin.Instance).GetComponent<AudioSource>();
if ((Object)(object)_source == (Object)null)
{
_source = ((Component)Plugin.Instance).gameObject.AddComponent<AudioSource>();
}
_source.playOnAwake = false;
_source.loop = false;
_source.volume = 0.5f;
_source.clip = _clip;
}
if ((Object)(object)_source == (Object)null)
{
_initFailed = true;
}
}
private static AudioClip CreateBeepClip()
{
int num = 44100;
int num2 = (int)((float)num * 0.08f);
float[] array = new float[num2];
for (int i = 0; i < num2; i++)
{
float num3 = (float)i / (float)num;
float num4 = 1f - num3 / 0.08f;
array[i] = Mathf.Sin((float)Math.PI * 1760f * num3) * num4 * 0.5f;
}
AudioClip obj = AudioClip.Create("uiHideBeep", num2, 1, num, false);
SetDataViaReflection(obj, array, 0);
return obj;
}
private static void SetDataViaReflection(AudioClip clip, float[] data, int offset)
{
if (_setDataMethod == null)
{
_setDataMethod = typeof(AudioClip).GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
{
typeof(float[]),
typeof(int)
}, null);
}
if (_setDataMethod != null)
{
_setDataMethod.Invoke(clip, new object[2] { data, offset });
}
else if (Plugin.Log != null)
{
Plugin.Log.LogWarning((object)"[uiHide] AudioClip.SetData(float[], int) 未找到,提示音将静默");
}
}
}
[BepInPlugin("uiHide", "uiHide", "1.2.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
internal static Plugin Instance;
internal static ConfigEntry<KeyboardShortcut> HideHotkey;
internal static ConfigEntry<bool> AggressiveSuppress;
internal static ConfigEntry<bool> KeepNamesAndDistance;
internal static ConfigEntry<string> KeepNamePatterns;
internal static ConfigEntry<bool> ReleaseCursor;
internal static ConfigEntry<bool> PlayBeep;
private void Awake()
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
Instance = this;
BindConfig();
SceneManager.sceneLoaded += OnSceneLoaded;
Log.LogInfo((object)string.Format("[uiHide] v{0} 已加载,热键 {1},每帧压制 {2}", "1.2.0", HideHotkey.Value, AggressiveSuppress.Value ? "开" : "关"));
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
if (UISuppressor.IsHidden)
{
Log.LogInfo((object)"[uiHide] 卸载中恢复 UI");
UISuppressor.Restore();
}
BeepPlayer.Cleanup();
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
UISuppressor.OnSceneLoaded();
}
private void BindConfig()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
HideHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "HideHotkey", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[1] { (KeyCode)305 }), "切换显示/隐藏所有 UI 的组合键。主键在前,修饰键在后;在配置文件中修改后保存重启生效");
AggressiveSuppress = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AggressiveSuppress", true, "每帧重新压制 Canvas,防止某些 mod 在 Update 里强制重开自己的 UI。开销极小,建议开启");
KeepNamesAndDistance = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KeepNamesAndDistance", false, "隐藏模式下保留队友名字和距离指示。默认 false 一并隐藏;设 true 用于合影时仍想看到队友身份");
KeepNamePatterns = ((BaseUnityPlugin)this).Config.Bind<string>("General", "KeepNamePatterns", "playername,playernames,nametag,playerlabel,distance,overheaddistance", "保留名单的 GameObject 名匹配模式(逗号分隔,不区分大小写,子串匹配)。仅当 KeepNamesAndDistance=true 时生效。可增删以适配你安装的 mod");
ReleaseCursor = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReleaseCursor", true, "隐藏 UI 时释放鼠标光标,方便移动视角截图");
PlayBeep = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PlayBeep", true, "切换时播放短促提示音。设 false 可完全静默");
KeepNamePatterns.SettingChanged += delegate
{
UISuppressor.MarkPatternsDirty();
};
}
private void Update()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
KeyboardShortcut value = HideHotkey.Value;
if (((KeyboardShortcut)(ref value)).IsDown())
{
UISuppressor.Toggle();
}
if (UISuppressor.IsHidden)
{
UISuppressor.MaintainSuppression();
}
}
}
internal static class PluginInfo
{
public const string Guid = "uiHide";
public const string Name = "uiHide";
public const string Version = "1.2.0";
}
internal static class UISuppressor
{
private struct CanvasEntry
{
public Canvas canvas;
public bool wasEnabled;
}
private struct RendererEntry
{
public Renderer renderer;
public bool wasEnabled;
}
private static readonly List<CanvasEntry> _canvases = new List<CanvasEntry>();
private static readonly List<MonoBehaviour> _onGuiBehaviours = new List<MonoBehaviour>();
private static readonly List<RendererEntry> _renderers = new List<RendererEntry>();
private static readonly HashSet<Type> _hasOnGuiCache = new HashSet<Type>();
private static readonly HashSet<Type> _noOnGuiCache = new HashSet<Type>();
private static readonly List<string> _namePatterns = new List<string>();
private static bool _patternsDirty = true;
private const int RescanInterval = 15;
private static int _rescanCounter;
internal static bool IsHidden { get; private set; }
internal static void Toggle()
{
if (IsHidden)
{
Restore();
}
else
{
Suppress();
}
if (Plugin.PlayBeep.Value)
{
BeepPlayer.Play(IsHidden);
}
}
internal static void OnSceneLoaded()
{
_canvases.Clear();
_onGuiBehaviours.Clear();
_renderers.Clear();
_rescanCounter = 0;
if (IsHidden)
{
SuppressCanvases(scanAll: true);
SuppressBehaviours();
if (Plugin.Log != null)
{
Plugin.Log.LogInfo((object)"[uiHide] 场景加载,已重新压制");
}
}
}
internal static void MarkPatternsDirty()
{
_patternsDirty = true;
}
private static void Suppress()
{
try
{
IsHidden = true;
_canvases.Clear();
_onGuiBehaviours.Clear();
_renderers.Clear();
_rescanCounter = 0;
RefreshPatternsIfNeeded();
SuppressCanvases(scanAll: true);
SuppressBehaviours();
if (Plugin.ReleaseCursor.Value)
{
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
}
}
catch (Exception ex)
{
if (Plugin.Log != null)
{
Plugin.Log.LogError((object)("[uiHide] Suppress 异常: " + ex.Message));
}
}
}
internal static void Restore()
{
try
{
IsHidden = false;
for (int i = 0; i < _canvases.Count; i++)
{
Canvas canvas = _canvases[i].canvas;
if ((Object)(object)canvas != (Object)null)
{
((Behaviour)canvas).enabled = _canvases[i].wasEnabled;
}
}
_canvases.Clear();
for (int j = 0; j < _onGuiBehaviours.Count; j++)
{
MonoBehaviour val = _onGuiBehaviours[j];
if ((Object)(object)val != (Object)null)
{
((Behaviour)val).enabled = true;
}
}
_onGuiBehaviours.Clear();
for (int k = 0; k < _renderers.Count; k++)
{
Renderer renderer = _renderers[k].renderer;
if ((Object)(object)renderer != (Object)null)
{
renderer.enabled = _renderers[k].wasEnabled;
}
}
_renderers.Clear();
}
catch (Exception ex)
{
if (Plugin.Log != null)
{
Plugin.Log.LogError((object)("[uiHide] Restore 异常: " + ex.Message));
}
}
}
internal static void MaintainSuppression()
{
if (++_rescanCounter >= 15)
{
_rescanCounter = 0;
SuppressCanvases(scanAll: false);
}
if (!Plugin.AggressiveSuppress.Value)
{
return;
}
for (int num = _canvases.Count - 1; num >= 0; num--)
{
Canvas canvas = _canvases[num].canvas;
if ((Object)(object)canvas == (Object)null)
{
_canvases.RemoveAt(num);
}
else if (((Behaviour)canvas).enabled)
{
((Behaviour)canvas).enabled = false;
}
}
for (int num2 = _onGuiBehaviours.Count - 1; num2 >= 0; num2--)
{
MonoBehaviour val = _onGuiBehaviours[num2];
if ((Object)(object)val == (Object)null)
{
_onGuiBehaviours.RemoveAt(num2);
}
else if (((Behaviour)val).enabled)
{
((Behaviour)val).enabled = false;
}
}
for (int num3 = _renderers.Count - 1; num3 >= 0; num3--)
{
Renderer renderer = _renderers[num3].renderer;
if ((Object)(object)renderer == (Object)null)
{
_renderers.RemoveAt(num3);
}
else if (renderer.enabled)
{
renderer.enabled = false;
}
}
}
private static void SuppressCanvases(bool scanAll)
{
bool value = Plugin.KeepNamesAndDistance.Value;
RefreshPatternsIfNeeded();
Canvas[] array = Object.FindObjectsByType<Canvas>((FindObjectsInactive)1, (FindObjectsSortMode)1);
foreach (Canvas val in array)
{
if (!((Object)(object)val == (Object)null) && ((Behaviour)val).enabled && (!value || !IsKeepTarget(((Component)val).gameObject)) && (scanAll || !ContainsCanvas(val)))
{
_canvases.Add(new CanvasEntry
{
canvas = val,
wasEnabled = true
});
((Behaviour)val).enabled = false;
}
}
}
private static void SuppressBehaviours()
{
bool value = Plugin.KeepNamesAndDistance.Value;
MonoBehaviour[] array = Object.FindObjectsByType<MonoBehaviour>((FindObjectsInactive)1, (FindObjectsSortMode)1);
Assembly assembly = typeof(Plugin).Assembly;
foreach (MonoBehaviour val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Type type = ((object)val).GetType();
if (type.Assembly == assembly)
{
continue;
}
if (HasOnGui(type))
{
if (((Behaviour)val).enabled)
{
_onGuiBehaviours.Add(val);
((Behaviour)val).enabled = false;
}
continue;
}
string name = type.Name;
if ((name == "TextMeshPro" || name == "TextMesh") && (!value || !IsKeepTarget(((Component)val).gameObject)))
{
Renderer component = ((Component)val).GetComponent<Renderer>();
if (!((Object)(object)component == (Object)null) && component.enabled)
{
_renderers.Add(new RendererEntry
{
renderer = component,
wasEnabled = true
});
component.enabled = false;
}
}
}
}
private static bool ContainsCanvas(Canvas c)
{
for (int i = 0; i < _canvases.Count; i++)
{
if ((Object)(object)_canvases[i].canvas == (Object)(object)c)
{
return true;
}
}
return false;
}
private static bool IsKeepTarget(GameObject go)
{
if ((Object)(object)go == (Object)null)
{
return false;
}
if (IsNameMatch(((Object)go).name.ToLowerInvariant()))
{
return true;
}
Transform parent = go.transform.parent;
int num = 0;
while ((Object)(object)parent != (Object)null && num < 4)
{
if (IsNameMatch(((Object)parent).name.ToLowerInvariant()))
{
return true;
}
parent = parent.parent;
num++;
}
return false;
}
private static bool IsNameMatch(string lower)
{
if (string.IsNullOrEmpty(lower))
{
return false;
}
for (int i = 0; i < _namePatterns.Count; i++)
{
if (lower.Contains(_namePatterns[i]))
{
return true;
}
}
return false;
}
private static void RefreshPatternsIfNeeded()
{
if (!_patternsDirty)
{
return;
}
_patternsDirty = false;
_namePatterns.Clear();
if (Plugin.KeepNamePatterns == null)
{
return;
}
string[] array = Plugin.KeepNamePatterns.Value.Split(new char[1] { ',' });
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim().ToLowerInvariant();
if (text.Length > 0)
{
_namePatterns.Add(text);
}
}
}
private static bool HasOnGui(Type type)
{
if (_hasOnGuiCache.Contains(type))
{
return true;
}
if (_noOnGuiCache.Contains(type))
{
return false;
}
bool num = type.GetMethod("OnGUI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null;
if (num)
{
_hasOnGuiCache.Add(type);
return num;
}
_noOnGuiCache.Add(type);
return num;
}
}
}