Decompiled source of MicMeter v1.1.0

CWMicMeter.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Voice.Unity;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using Zorro.Settings;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("U-FESNOS")]
[assembly: AssemblyProduct("MicMeter")]
[assembly: AssemblyTitle("MicMeter")]
[assembly: AssemblyCopyright("U-FESNOS")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 CWMicMeter
{
	public enum Corner
	{
		TopLeft,
		TopRight,
		BottomLeft,
		BottomRight
	}
	[ContentWarningPlugin("U-FESNOS.MicMeter", "1.1.0", true)]
	[BepInPlugin("U-FESNOS.MicMeter", "CWMicMeter", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "U-FESNOS.MicMeter";

		public const string Name = "CWMicMeter";

		public const string Version = "1.1.0";

		private static readonly FieldInfo? RecorderField = AccessTools.Field(typeof(PlayerVoiceHandler), "m_Recorder");

		private static readonly FieldInfo? ModeField = AccessTools.Field(typeof(PlayerVoiceHandler), "m_VoiceChatModeSetting");

		private static readonly FieldInfo? InputSourceField = AccessTools.Field(typeof(Recorder), "inputSource");

		private ConfigEntry<bool> visible;

		private ConfigEntry<Key> toggleKey;

		private ConfigEntry<Corner> corner;

		private ConfigEntry<int> offsetX;

		private ConfigEntry<int> offsetY;

		private ConfigEntry<float> scale;

		private ConfigEntry<float> floorDb;

		private ConfigEntry<bool> dimWhenOff;

		private bool inGame;

		private bool transmitting;

		private int mode = -1;

		private bool hasLevel;

		private float levelDb = -120f;

		private float holdDb = -120f;

		private float holdTimer;

		private bool clipped;

		private float clipTimer;

		private object? lastInput;

		private AudioClip? micClip;

		private string? micDevice;

		private float[] buffer = new float[0];

		private float resolveTimer;

		private VoiceChatModeSetting? modeSetting;

		private string modeText = string.Empty;

		private int modeTextFor = int.MinValue;

		private string modeTextLang = string.Empty;

		private float modeTextTime;

		private GUIStyle? labelStyle;

		private GUIStyle? smallStyle;

		private GUIStyle? rightStyle;

		private void Awake()
		{
			Lang.Bind(((BaseUnityPlugin)this).Config);
			visible = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Visible", true, "Show the meter (also toggled with ToggleKey) / 表示する (ToggleKey でも切り替え可能)");
			toggleKey = ((BaseUnityPlugin)this).Config.Bind<Key>("General", "ToggleKey", (Key)101, "Key to show / hide / 表示・非表示を切り替えるキー");
			corner = ((BaseUnityPlugin)this).Config.Bind<Corner>("Layout", "Corner", Corner.TopRight, "Screen corner / 表示する画面の隅");
			offsetX = ((BaseUnityPlugin)this).Config.Bind<int>("Layout", "OffsetX", 16, "Horizontal distance from the edge (px) / 画面端からの横方向の距離");
			offsetY = ((BaseUnityPlugin)this).Config.Bind<int>("Layout", "OffsetY", 16, "Vertical distance from the edge (px) / 画面端からの縦方向の距離");
			scale = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "Scale", 1f, "Size (1.0 = default) / 表示の大きさ");
			floorDb = ((BaseUnityPlugin)this).Config.Bind<float>("Meter", "FloorDb", -60f, "Level at the left end of the meter (dBFS) / メーター左端の音量");
			dimWhenOff = ((BaseUnityPlugin)this).Config.Bind<bool>("Meter", "DimWhenOff", true, "Dim the meter while not transmitting / 送信オフの間はメーターを薄く表示する");
			if (RecorderField == null || ModeField == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"PlayerVoiceHandler layout is different from what this mod expects (game update?).");
			}
		}

		private void Update()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if (current != null && (int)toggleKey.Value != 0 && ((ButtonControl)current[toggleKey.Value]).wasPressedThisFrame)
			{
				visible.Value = !visible.Value;
			}
			PlayerVoiceHandler instance = PlayerVoiceHandler.Instance;
			Recorder val = (Recorder)(((Object)(object)instance != (Object)null && RecorderField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			inGame = (Object)(object)val != (Object)null;
			if ((Object)(object)val == (Object)null)
			{
				micClip = null;
				lastInput = null;
				return;
			}
			transmitting = val.TransmitEnabled;
			mode = -1;
			modeSetting = null;
			if (ModeField != null)
			{
				object? value = ModeField.GetValue(instance);
				VoiceChatModeSetting val2 = (VoiceChatModeSetting)((value is VoiceChatModeSetting) ? value : null);
				if (val2 != null)
				{
					mode = ((IntSetting)val2).Value;
					modeSetting = val2;
				}
			}
			UpdateLevel(val);
		}

		private void UpdateLevel(Recorder recorder)
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			resolveTimer -= unscaledDeltaTime;
			if (resolveTimer <= 0f)
			{
				resolveTimer = 1f;
				ResolveMic(recorder);
			}
			if ((Object)(object)micClip != (Object)null && TryReadPeak(micClip, out var peak))
			{
				hasLevel = true;
			}
			else if (transmitting)
			{
				peak = recorder.LevelMeter.CurrentPeakAmp;
				hasLevel = true;
			}
			else
			{
				hasLevel = false;
				peak = 0f;
			}
			float num = ((peak > 1E-05f) ? (20f * Mathf.Log10(peak)) : (-120f));
			levelDb = ((num > levelDb) ? num : Mathf.Max(num, levelDb - 30f * unscaledDeltaTime));
			if (num >= holdDb)
			{
				holdDb = num;
				holdTimer = 1.5f;
			}
			else if ((holdTimer -= unscaledDeltaTime) <= 0f)
			{
				holdDb = Mathf.Max(num, holdDb - 20f * unscaledDeltaTime);
			}
			if (peak >= 0.99f)
			{
				clipped = true;
				clipTimer = 2f;
			}
			else if (clipped && (clipTimer -= unscaledDeltaTime) <= 0f)
			{
				clipped = false;
			}
		}

		private bool TryReadPeak(AudioClip clip, out float peak)
		{
			peak = 0f;
			try
			{
				int samples = clip.samples;
				int num = Math.Max(1, clip.channels);
				if (samples <= 0)
				{
					return false;
				}
				int position = Microphone.GetPosition(micDevice);
				int num2 = Mathf.Clamp(clip.frequency / 20, 256, samples - 1);
				int num3 = position - num2;
				if (num3 < 0)
				{
					num3 += samples;
				}
				if (buffer.Length != num2 * num)
				{
					buffer = new float[num2 * num];
				}
				if (!clip.GetData(buffer, num3))
				{
					return false;
				}
				for (int i = 0; i < buffer.Length; i++)
				{
					float num4 = Math.Abs(buffer[i]);
					if (num4 > peak)
					{
						peak = num4;
					}
				}
				return true;
			}
			catch
			{
				micClip = null;
				return false;
			}
		}

		private void ResolveMic(Recorder recorder)
		{
			object obj = InputSourceField?.GetValue(recorder);
			if (obj != lastInput || !((Object)(object)micClip != (Object)null))
			{
				lastInput = obj;
				micClip = null;
				micDevice = null;
				if (obj != null)
				{
					FindClip(obj, 0, new HashSet<object>());
				}
			}
		}

		private bool FindClip(object obj, int depth, HashSet<object> seen)
		{
			if (!seen.Add(obj))
			{
				return false;
			}
			List<FieldInfo> allFields = GetAllFields(obj.GetType());
			AudioClip val = null;
			string text = null;
			foreach (FieldInfo item in allFields)
			{
				if (typeof(AudioClip).IsAssignableFrom(item.FieldType))
				{
					object? value = item.GetValue(obj);
					val = (AudioClip)((value is AudioClip) ? value : null);
				}
				else if (item.FieldType == typeof(string) && item.Name.IndexOf("device", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					text = item.GetValue(obj) as string;
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				micClip = val;
				micDevice = text;
				return true;
			}
			if (depth >= 2)
			{
				return false;
			}
			foreach (FieldInfo item2 in allFields)
			{
				if (!item2.FieldType.IsValueType && !(item2.FieldType == typeof(string)) && !typeof(Delegate).IsAssignableFrom(item2.FieldType))
				{
					object value2 = item2.GetValue(obj);
					if (value2 != null && !(value2 is Object) && FindClip(value2, depth + 1, seen))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static List<FieldInfo> GetAllFields(Type type)
		{
			List<FieldInfo> list = new List<FieldInfo>();
			Type type2 = type;
			while (type2 != null && type2 != typeof(object))
			{
				list.AddRange(type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
				type2 = type2.BaseType;
			}
			return list;
		}

		private string ModeName()
		{
			string current = Lang.Current;
			if (mode == modeTextFor && current == modeTextLang && Time.unscaledTime - modeTextTime < 2f)
			{
				return modeText;
			}
			modeTextFor = mode;
			modeTextLang = current;
			modeTextTime = Time.unscaledTime;
			modeText = string.Empty;
			try
			{
				VoiceChatModeSetting? obj = modeSetting;
				List<string> list = ((obj != null) ? ((EnumSetting)obj).GetChoices() : null);
				if (list != null && mode >= 0 && mode < list.Count && !string.IsNullOrEmpty(list[mode]))
				{
					modeText = list[mode];
					return modeText;
				}
			}
			catch
			{
			}
			switch (mode)
			{
			case 0:
				modeText = Lang.T("常時オン", "Open mic", "自由麦", "自由麥", "항상 켜짐");
				break;
			case 1:
				modeText = Lang.T("押して話す", "Push-to-talk", "按键说话", "按鍵說話", "눌러서 말하기");
				break;
			case 2:
				modeText = Lang.T("切り替え", "Toggle", "切换", "切換", "전환");
				break;
			case 3:
				modeText = Lang.T("ボイスオフ", "Voice off", "关闭语音", "關閉語音", "음성 끔");
				break;
			}
			return modeText;
		}

		private void OnGUI()
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected O, but got Unknown
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_054f: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05db: Unknown result type (might be due to invalid IL or missing references)
			if (!visible.Value || !inGame)
			{
				return;
			}
			float num = Mathf.Clamp(scale.Value, 0.5f, 4f);
			float num2 = 300f * num;
			float num3 = 62f * num;
			float num4 = 8f * num;
			float num5 = ((corner.Value == Corner.TopLeft || corner.Value == Corner.BottomLeft) ? ((float)offsetX.Value) : ((float)Screen.width - num2 - (float)offsetX.Value));
			float num6 = ((corner.Value == Corner.TopLeft || corner.Value == Corner.TopRight) ? ((float)offsetY.Value) : ((float)Screen.height - num3 - (float)offsetY.Value));
			if (labelStyle == null || smallStyle == null || rightStyle == null)
			{
				labelStyle = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				smallStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)3
				};
				rightStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)5
				};
			}
			Font font = Lang.GetFont();
			labelStyle.font = font;
			smallStyle.font = font;
			rightStyle.font = font;
			labelStyle.fontSize = Mathf.RoundToInt(14f * num);
			smallStyle.fontSize = Mathf.RoundToInt(12f * num);
			rightStyle.fontSize = Mathf.RoundToInt(12f * num);
			labelStyle.normal.textColor = Color.white;
			smallStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f);
			rightStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f);
			Color color = GUI.color;
			Fill(new Rect(num5, num6, num2, num3), new Color(0f, 0f, 0f, 0.6f));
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(num5 + num4, num6 + num4, 104f * num, 22f * num);
			Fill(val, transmitting ? new Color(0.13f, 0.7f, 0.3f, 0.95f) : new Color(0.75f, 0.16f, 0.16f, 0.95f));
			GUI.Label(val, transmitting ? Lang.T("マイク ON", "MIC ON", "麦克风 开", "麥克風 開", "마이크 켜짐") : Lang.T("マイク OFF", "MIC OFF", "麦克风 关", "麥克風 關", "마이크 꺼짐"), labelStyle);
			GUI.Label(new Rect(((Rect)(ref val)).xMax + num4, ((Rect)(ref val)).y, 100f * num, ((Rect)(ref val)).height), ModeName(), smallStyle);
			string text = ((!hasLevel) ? "-- dB" : ((holdDb <= -100f) ? "-inf dB" : (holdDb.ToString("0") + " dB")));
			if (clipped)
			{
				text = "CLIP " + text;
			}
			GUI.Label(new Rect(num5 + num2 - num4 - 90f * num, ((Rect)(ref val)).y, 90f * num, ((Rect)(ref val)).height), text, rightStyle);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(num5 + num4, ((Rect)(ref val)).yMax + 8f * num, num2 - num4 * 2f, 16f * num);
			Fill(val2, new Color(0.15f, 0.15f, 0.15f, 0.9f));
			float num7 = Mathf.Min(floorDb.Value, -12f);
			float num8 = ((transmitting || !dimWhenOff.Value) ? 1f : 0.45f);
			if (hasLevel)
			{
				float num9 = Mathf.Clamp01((levelDb - num7) / (0f - num7));
				float num10 = Mathf.Clamp01((-18f - num7) / (0f - num7));
				float num11 = Mathf.Clamp01((-6f - num7) / (0f - num7));
				DrawSegment(val2, 0f, Mathf.Min(num9, num10), new Color(0.2f, 0.8f, 0.35f, num8));
				DrawSegment(val2, num10, Mathf.Min(num9, num11), new Color(0.95f, 0.8f, 0.2f, num8));
				DrawSegment(val2, num11, num9, new Color(0.95f, 0.25f, 0.2f, num8));
				float num12 = Mathf.Clamp01((holdDb - num7) / (0f - num7));
				if (num12 > 0f)
				{
					Fill(new Rect(((Rect)(ref val2)).x + ((Rect)(ref val2)).width * num12 - 1f * num, ((Rect)(ref val2)).y, 2f * num, ((Rect)(ref val2)).height), new Color(1f, 1f, 1f, 0.9f));
				}
			}
			float[] array = new float[5] { -48f, -36f, -24f, -12f, -6f };
			foreach (float num13 in array)
			{
				if (!(num13 <= num7))
				{
					float num14 = (num13 - num7) / (0f - num7);
					Fill(new Rect(((Rect)(ref val2)).x + ((Rect)(ref val2)).width * num14, ((Rect)(ref val2)).y + ((Rect)(ref val2)).height * 0.6f, 1f, ((Rect)(ref val2)).height * 0.4f), new Color(1f, 1f, 1f, 0.35f));
				}
			}
			GUI.color = color;
		}

		private static void DrawSegment(Rect bar, float from, float to, Color color)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (!(to <= from))
			{
				Fill(new Rect(((Rect)(ref bar)).x + ((Rect)(ref bar)).width * from, ((Rect)(ref bar)).y, ((Rect)(ref bar)).width * (to - from), ((Rect)(ref bar)).height), color);
			}
		}

		private static void Fill(Rect rect, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color2;
		}
	}
	internal static class Lang
	{
		internal const string Ja = "ja";

		internal const string En = "en";

		internal const string ZhHans = "zh-Hans";

		internal const string ZhHant = "zh-Hant";

		internal const string Ko = "ko";

		private static readonly string[] Choices = new string[6] { "Auto", "ja", "en", "zh-Hans", "zh-Hant", "ko" };

		private static readonly Dictionary<string, Font> Fonts = new Dictionary<string, Font>();

		private static ConfigEntry<string>? setting;

		private static string current = "en";

		private static float nextCheck = -1f;

		internal static string Current
		{
			get
			{
				if (Time.unscaledTime >= nextCheck)
				{
					nextCheck = Time.unscaledTime + 1f;
					current = Detect();
				}
				return current;
			}
		}

		internal static void Bind(ConfigFile config)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			setting = config.Bind<string>("General", "Language", "Auto", new ConfigDescription("Display language. Auto follows the game's language. / 表示言語。Auto はゲームの言語設定に合わせる", (AcceptableValueBase)(object)new AcceptableValueList<string>(Choices), Array.Empty<object>()));
		}

		internal static string T(string ja, string en, string zhHans, string zhHant, string ko)
		{
			return Current switch
			{
				"ja" => ja, 
				"zh-Hans" => zhHans, 
				"zh-Hant" => zhHant, 
				"ko" => ko, 
				_ => en, 
			};
		}

		internal static Font GetFont()
		{
			string text = Current;
			if (!Fonts.TryGetValue(text, out Font value) || (Object)(object)value == (Object)null)
			{
				value = Font.CreateDynamicFontFromOSFont(FontNames(text), 16);
				Fonts[text] = value;
			}
			return value;
		}

		private static string[] FontNames(string lang)
		{
			return lang switch
			{
				"ja" => new string[8] { "Yu Gothic UI", "Meiryo UI", "Meiryo", "MS UI Gothic", "Microsoft YaHei UI", "Malgun Gothic", "Segoe UI", "Arial" }, 
				"zh-Hans" => new string[8] { "Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "Microsoft JhengHei UI", "Yu Gothic UI", "Malgun Gothic", "Segoe UI", "Arial" }, 
				"zh-Hant" => new string[8] { "Microsoft JhengHei UI", "Microsoft JhengHei", "PMingLiU", "Microsoft YaHei UI", "Yu Gothic UI", "Malgun Gothic", "Segoe UI", "Arial" }, 
				"ko" => new string[6] { "Malgun Gothic", "Gulim", "Yu Gothic UI", "Microsoft YaHei UI", "Segoe UI", "Arial" }, 
				_ => new string[5] { "Segoe UI", "Arial", "Yu Gothic UI", "Microsoft YaHei UI", "Malgun Gothic" }, 
			};
		}

		private static string Detect()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			string text = setting?.Value ?? "Auto";
			if (string.IsNullOrEmpty(text) || text.Equals("Auto", StringComparison.OrdinalIgnoreCase))
			{
				text = string.Empty;
				try
				{
					Locale selectedLocale = LocalizationSettings.SelectedLocale;
					object obj;
					if (selectedLocale == null)
					{
						obj = null;
					}
					else
					{
						LocaleIdentifier identifier = selectedLocale.Identifier;
						obj = ((LocaleIdentifier)(ref identifier)).Code;
					}
					if (obj == null)
					{
						obj = string.Empty;
					}
					text = (string)obj;
				}
				catch
				{
				}
				if (string.IsNullOrEmpty(text))
				{
					text = FromSystem(Application.systemLanguage);
				}
			}
			return Normalize(text);
		}

		private static string Normalize(string code)
		{
			string text = code.Trim().ToLowerInvariant();
			if (text.StartsWith("ja"))
			{
				return "ja";
			}
			if (text.StartsWith("ko"))
			{
				return "ko";
			}
			if (text.StartsWith("zh"))
			{
				if (!text.Contains("hant") && !text.Contains("tw") && !text.Contains("hk") && !text.Contains("mo"))
				{
					return "zh-Hans";
				}
				return "zh-Hant";
			}
			return "en";
		}

		private static string FromSystem(SystemLanguage language)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			if ((int)language <= 22)
			{
				if ((int)language == 6)
				{
					goto IL_0033;
				}
				if ((int)language == 22)
				{
					return "ja";
				}
			}
			else
			{
				if ((int)language == 23)
				{
					return "ko";
				}
				if ((int)language == 40)
				{
					goto IL_0033;
				}
				if ((int)language == 41)
				{
					return "zh-Hant";
				}
			}
			return "en";
			IL_0033:
			return "zh-Hans";
		}
	}
}