Decompiled source of TabMapZoom v1.1.1

Zichen-TabMapZoom-1.1.1.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using Zichen_TabMapZoom.I18N;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Zichen-TabMapZoom-1.1.1")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+39dc04d9da07ed5cb1d34c6e90488b5fe8478f5b")]
[assembly: AssemblyProduct("Zichen-TabMapZoom-1.1.1")]
[assembly: AssemblyTitle("Zichen-TabMapZoom-1.1.1")]
[assembly: AssemblyVersion("1.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;
		}
	}
}
[BepInPlugin("zichen.tabmapzoom", "A.Tab Map Zoom", "1.1.1")]
public sealed class ZichenTabMapZoomPlugin : BaseUnityPlugin
{
	private static ZichenTabMapZoomPlugin Instance;

	public const string PluginGuid = "zichen.tabmapzoom";

	public const string PluginVersion = "1.1.1";

	public const string PluginName = "A.Tab Map Zoom";

	private const string ContactConfigSection = "模组信息";

	private const string TabMapConfigSection = "A.Tab地图缩放";

	private const string MinimapPluginGuid = "Minimap";

	private const string MinimapPackageFolder = "dig-Minimap";

	private static readonly string[] KnownTabMapConflictPluginIds = new string[2] { "Minimap", "dig-Minimap" };

	private static readonly string[] TabMapConflictKeywords = new string[12]
	{
		"minimap", "mini map", "mapzoom", "map zoom", "tabmapzoom", "tab map zoom", "mapscale", "map scale", "mapresize", "map resize",
		"地图缩放", "小地图"
	};

	private ConfigEntry<string> moduleNameInfo;

	private ConfigEntry<string> moduleVersionInfo;

	private ConfigEntry<string> contactInfo;

	private ConfigEntry<bool> tabMapZoomEnabled;

	private ConfigEntry<bool> tabMapZoomForceEnabled;

	private ConfigEntry<bool> tabMapRestoreOfficialOnOpen;

	private ConfigEntry<float> tabMapDefaultZoom;

	private ConfigEntry<float> tabMapMinZoom;

	private ConfigEntry<float> tabMapMaxZoom;

	private ConfigEntry<float> tabMapScrollSpeed;

	private float tabMapZoomMultiplier = 1f;

	private bool tabMapWasActive;

	private bool tabMapZoomBlockedByConflict;

	private bool tabMapConflictCompatibilityChecked;

	private Transform tabMapZoomTarget;

	private Vector3 tabMapOriginalScale = Vector3.one;

	private Vector3 tabMapOriginalLocalPosition = Vector3.zero;

	private Vector3 tabMapOriginalCenterLocal = Vector3.zero;

	private float tabMapOriginalMapScale = 1f;

	private bool tabMapHasOriginalCenter;

	private bool tabMapZoomDirty = true;

	private float tabMapLastAppliedZoom = float.MinValue;

	private int tabMapKnownLayerCount = -1;

	private int tabMapKnownModuleCount = -1;

	private Transform tabMapOverLayerTransform;

	private Vector3 tabMapOverLayerOffset = Vector3.zero;

	private readonly List<TabMapTransformSnapshot> tabMapLayerSnapshots = new List<TabMapTransformSnapshot>();

	private readonly List<TabMapModuleRuntimeSnapshot> tabMapModuleSnapshots = new List<TabMapModuleRuntimeSnapshot>();

	private readonly List<TabMapTransformSnapshot> tabMapModuleChildSnapshots = new List<TabMapTransformSnapshot>();

	private Harmony harmony;

	private I18NRegistry _i18n;

	private I18NSwitcher _i18nSwitcher;

	private bool _autoLocaleChecked;

	public static bool UseChinese()
	{
		return Instance?._i18n?.UseChinese == true;
	}

	private void Awake()
	{
		Instance = this;
		DetachFromManager();
		MakePluginHostPersistent();
		ResetConfigIfVersionChanged();
		bool defaultChinese = LanguageDetector.DetectDefault();
		_i18n = new I18NRegistry(((BaseUnityPlugin)this).Config);
		_i18n.BindLanguage(defaultChinese);
		moduleNameInfo = _i18n.BindReadOnly("Mod Info", "模组信息", "Mod Name", "模组名称", "Tab Map Zoom", "地图缩放");
		moduleVersionInfo = _i18n.BindReadOnly("Mod Info", "模组信息", "Mod Version", "模组版本号", "1.1.1", "1.1.1");
		contactInfo = _i18n.BindReadOnly("Mod Info", "模组信息", "Contact QQ", "REPO交流QQ群", "824639225", "824639225");
		tabMapZoomEnabled = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Enabled", "启用", "When enabled, you can use the mouse wheel to zoom the map content when opening the vanilla map with Tab.", "开启后,按 Tab 打开原版地图时可以用鼠标滚轮缩放地图内容。", defaultValue: true);
		tabMapZoomForceEnabled = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Force Enable", "强制生效", "Enabled by default. When enabled, ignores Minimap, mini-map, map zoom and other potentially conflicting mods detected at startup, forcing Tab map zoom to work.", "默认开启。开启后会忽略启动时检测到的 Minimap、小地图、地图缩放等可能冲突的模组,强制让 Tab 地图缩放生效。", defaultValue: true);
		tabMapRestoreOfficialOnOpen = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Restore Official State On Open", "每次打开地图强制恢复官方状态", "When enabled, every time the Tab map is closed/reopened it restores the official default map state, then applies the default zoom. When disabled, the map keeps the state from the last wheel zoom.", "开启后,每次关闭/重新打开 Tab 地图都会恢复官方默认地图状态,再应用默认缩放。关闭后,地图会保留上一次滚轮缩放后的状态。", defaultValue: true);
		tabMapDefaultZoom = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Default Zoom", "默认缩放/倍率", "Default zoom multiplier each time the Tab map opens. Below 1 shows a larger area, above 1 zooms into details.", "每次打开 Tab 地图时的默认缩放倍率。小于 1 可以看到更大范围,大于 1 会放大细节。", 0.75f, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f));
		tabMapMinZoom = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Min Zoom", "最小缩放/倍率", "The minimum the map can zoom out to. Smaller values show a larger area at once; lower it further if some rooms are still not visible.", "地图最多缩小到多少。数值越小,一次看到的范围越大;如果还有房间看不到,就继续调低这个值。", 0.3f, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f));
		tabMapMaxZoom = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Max Zoom", "最大缩放/倍率", "The maximum the map can zoom in to. This controls zooming into details, not seeing more rooms; lower the min zoom to see more rooms.", "地图最多放大到多少。这个控制的是放大看细节,不控制看到更多房间;要看到更多房间请调低最小缩放倍率。", 2f, (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f));
		tabMapScrollSpeed = _i18n.Bind("A.Tab地图缩放", "A.Tab地图缩放", "Scroll Speed", "滚轮缩放速度/倍率", "Zoom speed adjustment per mouse wheel notch.", "鼠标滚轮每格调整的缩放速度。", 0.18f, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 0.5f));
		tabMapZoomEnabled.SettingChanged += OnTabMapCompatibilitySettingChanged;
		tabMapZoomForceEnabled.SettingChanged += OnTabMapCompatibilitySettingChanged;
		ApplyHarmonyPatches();
		_i18nSwitcher = new I18NSwitcher(_i18n, harmony, "A.Tab Map Zoom", ((BaseUnityPlugin)this).Logger);
		_i18nSwitcher.InstallRepoConfigHook();
		TryBootstrapUpdateLoopFromCurrentMap();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"zichen-tab-map-zoom loaded.");
		if (!_autoLocaleChecked)
		{
			((MonoBehaviour)this).StartCoroutine(AutoFollowGameLocaleOnce());
		}
	}

	private IEnumerator AutoFollowGameLocaleOnce()
	{
		float waited = 0f;
		while (waited < 20f)
		{
			waited += 0.2f;
			yield return (object)new WaitForSecondsRealtime(0.2f);
			if (LanguageDetector.TryReadGameLocaleCode(out var code))
			{
				if (LanguageDetector.IsChineseCode(code) && _i18n?.LanguageEntry != null && _i18n.LanguageEntry.Value != I18NRegistry.DisplayLanguage.中文)
				{
					_i18n.LanguageEntry.Value = I18NRegistry.DisplayLanguage.中文;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"已根据游戏内语言设置自动切换为中文。");
				}
				_autoLocaleChecked = true;
				yield break;
			}
		}
		_autoLocaleChecked = true;
	}

	private void LateUpdate()
	{
		UpdateTabMapZoom();
	}

	private void DetachFromManager()
	{
		((Component)this).gameObject.transform.parent = null;
		((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
		Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
	}

	private void OnDestroy()
	{
		if (Instance == this)
		{
			Instance = null;
		}
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		if ((Object)(object)tabMapZoomTarget != (Object)null)
		{
			RestoreTabMapZoomTarget();
		}
	}

	private void OnTabMapCompatibilitySettingChanged(object sender, EventArgs e)
	{
		if (!IsTabMapZoomEnabledEffective())
		{
			ResetTabMapZoom();
			SetUpdateLoopActive(active: false);
		}
		else
		{
			tabMapZoomDirty = true;
			TryBootstrapUpdateLoopFromCurrentMap();
		}
	}

	private void ApplyTabMapConflictCompatibility()
	{
		if (TryDetectTabMapConflictPlugin(out var detectedPlugin))
		{
			tabMapZoomBlockedByConflict = true;
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Detected possible map zoom/minimap conflict plugin '" + detectedPlugin + "'. Tab map zoom will stay inactive unless 强制生效 is enabled."));
		}
	}

	private bool IsTabMapZoomEnabledEffective()
	{
		if (tabMapZoomEnabled == null || !tabMapZoomEnabled.Value)
		{
			return false;
		}
		EnsureTabMapConflictCompatibilityChecked();
		if (!tabMapZoomBlockedByConflict)
		{
			return true;
		}
		if (tabMapZoomForceEnabled != null)
		{
			return tabMapZoomForceEnabled.Value;
		}
		return false;
	}

	private void EnsureTabMapConflictCompatibilityChecked()
	{
		if (!tabMapConflictCompatibilityChecked)
		{
			tabMapConflictCompatibilityChecked = true;
			ApplyTabMapConflictCompatibility();
		}
	}

	private static bool TryDetectTabMapConflictPlugin(out string detectedPlugin)
	{
		detectedPlugin = string.Empty;
		try
		{
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				PluginInfo value = pluginInfo.Value;
				object obj;
				if (value == null)
				{
					obj = null;
				}
				else
				{
					BepInPlugin metadata = value.Metadata;
					obj = ((metadata != null) ? metadata.GUID : null);
				}
				if (obj == null)
				{
					obj = pluginInfo.Key;
				}
				string text = (string)obj;
				object obj2;
				if (value == null)
				{
					obj2 = null;
				}
				else
				{
					BepInPlugin metadata2 = value.Metadata;
					obj2 = ((metadata2 != null) ? metadata2.Name : null);
				}
				if (obj2 == null)
				{
					obj2 = string.Empty;
				}
				string text2 = (string)obj2;
				string text3 = ((value != null) ? value.Location : null) ?? string.Empty;
				if (!IsSelfPlugin(text, text2, text3) && (IsKnownTabMapConflict(text) || IsKnownTabMapConflict(text2) || LooksLikeTabMapConflictPlugin(text) || LooksLikeTabMapConflictPlugin(text2) || LooksLikeTabMapConflictPlugin(text3) || LooksLikeTabMapConflictPlugin(Path.GetFileNameWithoutExtension(text3)) || LooksLikeTabMapConflictPlugin(Path.GetFileName(Path.GetDirectoryName(text3) ?? string.Empty))))
				{
					detectedPlugin = (string.IsNullOrWhiteSpace(text2) ? text : (text2 + " (" + text + ")"));
					return true;
				}
			}
		}
		catch
		{
		}
		try
		{
			string pluginPath = Paths.PluginPath;
			if (string.IsNullOrWhiteSpace(pluginPath) || !Directory.Exists(pluginPath))
			{
				return false;
			}
			if (Directory.Exists(Path.Combine(pluginPath, "dig-Minimap")))
			{
				detectedPlugin = "dig-Minimap";
				return true;
			}
			foreach (string item in Directory.EnumerateFiles(pluginPath, "*.dll", SearchOption.AllDirectories))
			{
				if (!IsSelfPlugin(string.Empty, string.Empty, item))
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item);
					string fileName = Path.GetFileName(Path.GetDirectoryName(item) ?? string.Empty);
					if (IsKnownTabMapConflict(fileNameWithoutExtension) || IsKnownTabMapConflict(fileName) || LooksLikeTabMapConflictPlugin(fileNameWithoutExtension) || LooksLikeTabMapConflictPlugin(fileName) || LooksLikeTabMapConflictPlugin(item))
					{
						detectedPlugin = (string.IsNullOrWhiteSpace(fileName) ? fileNameWithoutExtension : (fileName + "/" + fileNameWithoutExtension + ".dll"));
						return true;
					}
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static bool IsSelfPlugin(string guid, string name, string location)
	{
		if (!string.Equals(guid, "zichen.tabmapzoom", StringComparison.OrdinalIgnoreCase) && !string.Equals(name, "A.Tab Map Zoom", StringComparison.OrdinalIgnoreCase))
		{
			return string.Equals(Path.GetFileNameWithoutExtension(location ?? string.Empty), "Zichen-TabMapZoom", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static bool IsKnownTabMapConflict(string text)
	{
		if (string.IsNullOrWhiteSpace(text))
		{
			return false;
		}
		string[] knownTabMapConflictPluginIds = KnownTabMapConflictPluginIds;
		foreach (string text2 in knownTabMapConflictPluginIds)
		{
			if (string.Equals(text.Trim(), text2, StringComparison.OrdinalIgnoreCase) || text.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
		}
		return false;
	}

	private static bool LooksLikeTabMapConflictPlugin(string text)
	{
		if (string.IsNullOrWhiteSpace(text))
		{
			return false;
		}
		string text2 = NormalizePluginSearchText(text);
		string[] tabMapConflictKeywords = TabMapConflictKeywords;
		for (int i = 0; i < tabMapConflictKeywords.Length; i++)
		{
			string value = NormalizePluginSearchText(tabMapConflictKeywords[i]);
			if (text2.Contains(value))
			{
				return true;
			}
		}
		return false;
	}

	private static string NormalizePluginSearchText(string text)
	{
		if (string.IsNullOrWhiteSpace(text))
		{
			return string.Empty;
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length);
		foreach (char c in text)
		{
			if (char.IsLetterOrDigit(c) || c > '\u007f')
			{
				stringBuilder.Append(char.ToLowerInvariant(c));
			}
		}
		return stringBuilder.ToString();
	}

	private void UpdateTabMapZoom()
	{
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		if (!IsTabMapZoomEnabledEffective() || !IsRunLevelActive())
		{
			ResetTabMapZoom();
			SetUpdateLoopActive(active: false);
			return;
		}
		Map instance = Map.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			ResetTabMapZoom();
			SetUpdateLoopActive(active: false);
			return;
		}
		if (!instance.Active)
		{
			if (tabMapRestoreOfficialOnOpen.Value)
			{
				ResetTabMapZoom();
			}
			SetUpdateLoopActive(active: false);
			return;
		}
		Transform transform = ((Component)instance).transform;
		if ((Object)(object)transform == (Object)null)
		{
			ResetTabMapZoom();
			return;
		}
		if ((Object)(object)tabMapZoomTarget != (Object)(object)transform || !tabMapWasActive)
		{
			if ((Object)(object)tabMapZoomTarget != (Object)(object)transform)
			{
				RestoreTabMapZoomTarget();
			}
			tabMapZoomTarget = transform;
			tabMapOriginalScale = transform.localScale;
			tabMapOriginalLocalPosition = transform.localPosition;
			tabMapOriginalMapScale = instance.Scale;
			RestoreTabMapModulePositions(instance);
			tabMapZoomMultiplier = ClampTabMapZoom(tabMapDefaultZoom.Value);
			RefreshTabMapSnapshots(instance, transform);
			tabMapWasActive = true;
		}
		else if (HasTabMapStructureChanged(instance))
		{
			RestoreTabMapZoomTarget();
			RefreshTabMapSnapshots(instance, transform);
		}
		float axis = Input.GetAxis("Mouse ScrollWheel");
		if (Mathf.Abs(axis) > 0.001f)
		{
			float num = ClampTabMapZoom(tabMapZoomMultiplier + axis * tabMapScrollSpeed.Value * 10f);
			if (!Mathf.Approximately(num, tabMapZoomMultiplier))
			{
				tabMapZoomMultiplier = num;
				tabMapZoomDirty = true;
			}
		}
		if (tabMapZoomDirty || !Mathf.Approximately(tabMapLastAppliedZoom, tabMapZoomMultiplier))
		{
			ApplyTabMapZoom(instance, transform);
			tabMapLastAppliedZoom = tabMapZoomMultiplier;
			tabMapZoomDirty = false;
		}
	}

	private void ResetTabMapZoom()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		RestoreTabMapZoomTarget();
		tabMapWasActive = false;
		tabMapZoomMultiplier = ClampTabMapZoom(tabMapDefaultZoom.Value);
		tabMapZoomTarget = null;
		tabMapOriginalScale = Vector3.one;
		tabMapOriginalLocalPosition = Vector3.zero;
		tabMapOriginalCenterLocal = Vector3.zero;
		tabMapOriginalMapScale = 1f;
		tabMapHasOriginalCenter = false;
		tabMapZoomDirty = true;
		tabMapLastAppliedZoom = float.MinValue;
		tabMapKnownLayerCount = -1;
		tabMapKnownModuleCount = -1;
		tabMapOverLayerTransform = null;
		tabMapOverLayerOffset = Vector3.zero;
		tabMapLayerSnapshots.Clear();
		tabMapModuleSnapshots.Clear();
		tabMapModuleChildSnapshots.Clear();
	}

	private void RestoreTabMapZoomTarget()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)tabMapZoomTarget == (Object)null))
		{
			tabMapZoomTarget.localScale = tabMapOriginalScale;
			tabMapZoomTarget.localPosition = tabMapOriginalLocalPosition;
			Map instance = Map.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.Scale = tabMapOriginalMapScale;
				RestoreTabMapLayerSnapshots();
				RestoreTabMapModuleChildSnapshots();
				RestoreTabMapModulePositions(instance);
			}
		}
	}

	private void ApplyTabMapZoom(Map map, Transform target)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: 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)
		target.localPosition = tabMapOriginalLocalPosition;
		target.localScale = tabMapOriginalScale;
		map.Scale = tabMapOriginalMapScale * tabMapZoomMultiplier;
		ApplyTabMapLayerZoom();
		ApplyTabMapModuleZoom(map);
		if (tabMapHasOriginalCenter)
		{
			Vector3 val = ScaleTabMapLocalVector(tabMapOriginalCenterLocal, tabMapZoomMultiplier);
			Vector3 val2 = ToParentSpace(target, target.TransformPoint(val));
			Vector3 val3 = GetTabMapAnchorInParentSpace(map, target) - val2;
			val3.y = 0f;
			target.localPosition += val3;
		}
	}

	private void CaptureTabMapLayerSnapshots(Map map)
	{
		if ((Object)(object)map == (Object)null || map.Layers == null)
		{
			return;
		}
		List<MapLayer> layers = map.Layers;
		for (int i = 0; i < layers.Count; i++)
		{
			MapLayer val = layers[i];
			if (!((Object)(object)val == (Object)null))
			{
				Transform transform = ((Component)val).transform;
				if (ShouldZoomTabMapLayer(map, transform))
				{
					AddTransformSnapshot(transform, tabMapLayerSnapshots);
				}
			}
		}
	}

	private void ApplyTabMapLayerZoom()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < tabMapLayerSnapshots.Count; i++)
		{
			TabMapTransformSnapshot tabMapTransformSnapshot = tabMapLayerSnapshots[i];
			if (!((Object)(object)tabMapTransformSnapshot.Transform == (Object)null))
			{
				tabMapTransformSnapshot.Transform.localPosition = tabMapTransformSnapshot.LocalPosition;
				Vector3 localScale = tabMapTransformSnapshot.LocalScale;
				localScale.x *= tabMapZoomMultiplier;
				localScale.z *= tabMapZoomMultiplier;
				tabMapTransformSnapshot.Transform.localScale = localScale;
			}
		}
	}

	private void RestoreTabMapLayerSnapshots()
	{
		RestoreTransformSnapshots(tabMapLayerSnapshots);
	}

	private void RefreshTabMapSnapshots(Map map, Transform target)
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		tabMapLayerSnapshots.Clear();
		tabMapModuleSnapshots.Clear();
		tabMapModuleChildSnapshots.Clear();
		CaptureTabMapLayerSnapshots(map);
		CaptureTabMapModuleSnapshots(map);
		UpdateTabMapStructureCounts(map);
		CacheTabMapOverLayerData(map);
		tabMapHasOriginalCenter = TryGetMapContentBounds(map, target, out var bounds);
		tabMapOriginalCenterLocal = (tabMapHasOriginalCenter ? target.InverseTransformPoint(((Bounds)(ref bounds)).center) : Vector3.zero);
		tabMapZoomDirty = true;
		tabMapLastAppliedZoom = float.MinValue;
	}

	private void CaptureTabMapModuleSnapshots(Map map)
	{
		if ((Object)(object)map == (Object)null || map.MapModules == null)
		{
			return;
		}
		List<MapModule> mapModules = map.MapModules;
		for (int i = 0; i < mapModules.Count; i++)
		{
			MapModule val = mapModules[i];
			if ((Object)(object)val == (Object)null || (Object)(object)val.module == (Object)null)
			{
				continue;
			}
			Transform transform = ((Component)val).transform;
			Transform transform2 = ((Component)val.module).transform;
			if (!((Object)(object)transform == (Object)null) && !((Object)(object)transform2 == (Object)null))
			{
				tabMapModuleSnapshots.Add(new TabMapModuleRuntimeSnapshot
				{
					ModuleTransform = transform,
					SourceTransform = transform2
				});
				int childCount = transform.childCount;
				for (int j = 0; j < childCount; j++)
				{
					AddTransformSnapshot(transform.GetChild(j), tabMapModuleChildSnapshots);
				}
			}
		}
	}

	private void ApplyTabMapModuleZoom(Map map)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)map == (Object)null)
		{
			return;
		}
		RestoreTabMapModulePositions(map);
		for (int i = 0; i < tabMapModuleChildSnapshots.Count; i++)
		{
			TabMapTransformSnapshot tabMapTransformSnapshot = tabMapModuleChildSnapshots[i];
			if (!((Object)(object)tabMapTransformSnapshot.Transform == (Object)null))
			{
				Vector3 localPosition = tabMapTransformSnapshot.LocalPosition;
				localPosition.x *= tabMapZoomMultiplier;
				localPosition.z *= tabMapZoomMultiplier;
				tabMapTransformSnapshot.Transform.localPosition = localPosition;
				Vector3 localScale = tabMapTransformSnapshot.LocalScale;
				localScale.x *= tabMapZoomMultiplier;
				localScale.z *= tabMapZoomMultiplier;
				tabMapTransformSnapshot.Transform.localScale = localScale;
			}
		}
	}

	private void RestoreTabMapModuleChildSnapshots()
	{
		RestoreTransformSnapshots(tabMapModuleChildSnapshots);
	}

	private static void RestoreTabMapModulePositions(Map map)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Instance == (Object)null || (Object)(object)map == (Object)null || (Object)(object)Instance.tabMapOverLayerTransform == (Object)null)
		{
			return;
		}
		Vector3 position = Instance.tabMapOverLayerTransform.position;
		for (int i = 0; i < Instance.tabMapModuleSnapshots.Count; i++)
		{
			TabMapModuleRuntimeSnapshot tabMapModuleRuntimeSnapshot = Instance.tabMapModuleSnapshots[i];
			if (!((Object)(object)tabMapModuleRuntimeSnapshot.ModuleTransform == (Object)null) && !((Object)(object)tabMapModuleRuntimeSnapshot.SourceTransform == (Object)null))
			{
				tabMapModuleRuntimeSnapshot.ModuleTransform.position = tabMapModuleRuntimeSnapshot.SourceTransform.position * map.Scale + position + Instance.tabMapOverLayerOffset;
			}
		}
	}

	private bool HasTabMapStructureChanged(Map map)
	{
		if ((Object)(object)map == (Object)null)
		{
			return false;
		}
		int num = ((map.Layers != null) ? map.Layers.Count : 0);
		int num2 = ((map.MapModules != null) ? map.MapModules.Count : 0);
		if (num == tabMapKnownLayerCount && num2 == tabMapKnownModuleCount)
		{
			return (Object)(object)map.OverLayerParent != (Object)(object)tabMapOverLayerTransform;
		}
		return true;
	}

	private void UpdateTabMapStructureCounts(Map map)
	{
		tabMapKnownLayerCount = ((map?.Layers != null) ? map.Layers.Count : 0);
		tabMapKnownModuleCount = ((map?.MapModules != null) ? map.MapModules.Count : 0);
	}

	private static bool ShouldZoomTabMapLayer(Map map, Transform transform)
	{
		if ((Object)(object)transform == (Object)null)
		{
			return false;
		}
		if (!((Object)(object)map == (Object)null) && !((Object)(object)map.OverLayerParent == (Object)null))
		{
			return (Object)(object)transform != (Object)(object)map.OverLayerParent;
		}
		return true;
	}

	private static Vector3 GetTabMapAnchorInParentSpace(Map map, Transform target)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: 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)
		Transform val = (((Object)(object)map != (Object)null && (Object)(object)map.ActiveParent != (Object)null) ? map.ActiveParent.transform : target.parent);
		if (!((Object)(object)val != (Object)null))
		{
			return Vector3.zero;
		}
		return ToParentSpace(target, val.position);
	}

	private static bool TryGetMapContentBounds(Map map, Transform target, out Bounds bounds)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		bounds = default(Bounds);
		bool hasBounds = false;
		if ((Object)(object)map != (Object)null && map.Layers != null)
		{
			foreach (MapLayer layer in map.Layers)
			{
				if (!((Object)(object)layer == (Object)null) && ShouldZoomTabMapLayer(map, ((Component)layer).transform))
				{
					EncapsulateRenderers(((Component)layer).transform, ref bounds, ref hasBounds);
				}
			}
		}
		if (hasBounds)
		{
			return true;
		}
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		EncapsulateRenderers(target, ref bounds, ref hasBounds);
		return hasBounds;
	}

	private static void EncapsulateRenderers(Transform root, ref Bounds bounds, ref bool hasBounds)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)root == (Object)null)
		{
			return;
		}
		Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(false);
		foreach (Renderer val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && val.enabled)
			{
				if (!hasBounds)
				{
					bounds = val.bounds;
					hasBounds = true;
				}
				else
				{
					((Bounds)(ref bounds)).Encapsulate(val.bounds);
				}
			}
		}
	}

	private static Vector3 ToParentSpace(Transform target, Vector3 worldPoint)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)target != (Object)null) || !((Object)(object)target.parent != (Object)null))
		{
			return worldPoint;
		}
		return target.parent.InverseTransformPoint(worldPoint);
	}

	private static Vector3 ScaleTabMapLocalVector(Vector3 value, float multiplier)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		value.x *= multiplier;
		value.z *= multiplier;
		return value;
	}

	private static void AddTransformSnapshot(Transform transform, List<TabMapTransformSnapshot> snapshots)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)transform == (Object)null))
		{
			snapshots?.Add(new TabMapTransformSnapshot
			{
				Transform = transform,
				LocalPosition = transform.localPosition,
				LocalScale = transform.localScale
			});
		}
	}

	private static void RestoreTransformSnapshots(List<TabMapTransformSnapshot> snapshots)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		if (snapshots == null)
		{
			return;
		}
		for (int i = 0; i < snapshots.Count; i++)
		{
			TabMapTransformSnapshot tabMapTransformSnapshot = snapshots[i];
			if (!((Object)(object)tabMapTransformSnapshot.Transform == (Object)null))
			{
				tabMapTransformSnapshot.Transform.localPosition = tabMapTransformSnapshot.LocalPosition;
				tabMapTransformSnapshot.Transform.localScale = tabMapTransformSnapshot.LocalScale;
			}
		}
	}

	private void CacheTabMapOverLayerData(Map map)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		tabMapOverLayerTransform = (((Object)(object)map != (Object)null) ? map.OverLayerParent : null);
		tabMapOverLayerOffset = Vector3.zero;
		if (!((Object)(object)map == (Object)null) && !((Object)(object)tabMapOverLayerTransform == (Object)null))
		{
			MapLayer component = ((Component)tabMapOverLayerTransform).GetComponent<MapLayer>();
			if ((Object)(object)component != (Object)null)
			{
				tabMapOverLayerOffset = map.GetLayerPosition(component.layer);
			}
		}
	}

	private void ApplyHarmonyPatches()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		harmony = new Harmony("zichen.tabmapzoom.patch");
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Map), "ActiveSet", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ZichenTabMapZoomPlugin), "MapActiveSetPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private void TryBootstrapUpdateLoopFromCurrentMap()
	{
		Map instance = Map.Instance;
		bool flag = (Object)(object)instance != (Object)null && instance.Active && IsRunLevelActive() && IsTabMapZoomEnabledEffective();
		SetUpdateLoopActive(flag);
		if (flag)
		{
			tabMapZoomDirty = true;
		}
	}

	private void SetUpdateLoopActive(bool active)
	{
		((Behaviour)this).enabled = active;
	}

	private void OnMapActiveSet(Map map, bool active)
	{
		if (!active)
		{
			if (tabMapRestoreOfficialOnOpen != null && tabMapRestoreOfficialOnOpen.Value)
			{
				ResetTabMapZoom();
			}
			SetUpdateLoopActive(active: false);
		}
		else
		{
			tabMapZoomDirty = true;
			bool updateLoopActive = (Object)(object)map != (Object)null && IsRunLevelActive() && IsTabMapZoomEnabledEffective();
			SetUpdateLoopActive(updateLoopActive);
		}
	}

	private static void MapActiveSetPostfix(Map __instance, bool active)
	{
		Instance?.OnMapActiveSet(__instance, active);
	}

	private float ClampTabMapZoom(float value)
	{
		float num = Mathf.Min(tabMapMinZoom.Value, tabMapMaxZoom.Value);
		float num2 = Mathf.Max(tabMapMinZoom.Value, tabMapMaxZoom.Value);
		return Mathf.Clamp(value, num, num2);
	}

	private static bool IsRunLevelActive()
	{
		try
		{
			return SemiFunc.RunIsLevel();
		}
		catch
		{
			return true;
		}
	}

	private void MakePluginHostPersistent()
	{
		try
		{
			((Component)this).transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to mark plugin host persistent: " + ex.GetType().Name + ": " + ex.Message));
		}
	}

	private void ResetConfigIfVersionChanged()
	{
		try
		{
			string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
			string text = ReadConfigPluginVersion(configFilePath);
			if (!string.IsNullOrWhiteSpace(text) && !(text == "1.1.1"))
			{
				ResetConfigFileToDefaults(configFilePath);
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Config version changed. Old config was reset to defaults.");
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to reset config by version: " + ex.Message));
		}
	}

	private static string ReadConfigPluginVersion(string configPath)
	{
		if (!File.Exists(configPath))
		{
			return null;
		}
		Match match = Regex.Match(File.ReadAllText(configPath), "(?m)^模组版本号\\s*=\\s*(.+?)\\s*$");
		if (!match.Success)
		{
			return null;
		}
		return match.Groups[1].Value.Trim();
	}

	private void ResetConfigFileToDefaults(string configPath)
	{
		((BaseUnityPlugin)this).Config.Clear();
		if (File.Exists(configPath))
		{
			File.Delete(configPath);
		}
		((BaseUnityPlugin)this).Config.Reload();
	}
}
internal struct TabMapTransformSnapshot
{
	public Transform Transform;

	public Vector3 LocalPosition;

	public Vector3 LocalScale;
}
internal struct TabMapModuleRuntimeSnapshot
{
	public Transform ModuleTransform;

	public Transform SourceTransform;
}
namespace Zichen_TabMapZoom.I18N
{
	internal static class LanguageDetector
	{
		public static readonly string[] DefaultChineseKeywords = new string[6] { "chinese", "简体", "繁體", "繁体", "汉化", "中文" };

		public static readonly string[] DefaultChineseEnvironmentPluginGuids = new string[1] { "gravydevsupreme.xunity.autotranslator" };

		private const string ChineseLocaleCodePrefix = "zh";

		private static bool _reflectionResolved;

		private static Type _localizationSettingsType;

		private static PropertyInfo _selectedLocaleProp;

		private static PropertyInfo _localeIdentifierProp;

		private static PropertyInfo _identifierCodeProp;

		public static bool DetectDefault()
		{
			if (DetectFromGameLocale())
			{
				return true;
			}
			return DetectDefault(DefaultChineseKeywords, DefaultChineseEnvironmentPluginGuids);
		}

		public static bool IsGameLocaleChinese()
		{
			return DetectFromGameLocale();
		}

		public static bool TryReadGameLocaleCode(out string code)
		{
			code = null;
			try
			{
				code = TryReadGameActiveLocaleCode();
				if (!string.IsNullOrEmpty(code))
				{
					return true;
				}
				code = TryReadSelectedLocaleCode();
				return !string.IsNullOrEmpty(code);
			}
			catch
			{
				code = null;
				return false;
			}
		}

		public static bool IsChineseCode(string code)
		{
			if (!string.IsNullOrEmpty(code))
			{
				return code.StartsWith("zh", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private static bool DetectFromGameLocale()
		{
			if (TryReadGameLocaleCode(out var code))
			{
				return IsChineseCode(code);
			}
			return false;
		}

		private static string TryReadGameActiveLocaleCode()
		{
			try
			{
				Type type = Type.GetType("LocalizationManager, Assembly-CSharp");
				if (type == null)
				{
					return null;
				}
				object obj = type.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null)
				{
					return null;
				}
				object obj2 = type.GetField("ActiveLocale")?.GetValue(obj);
				if (obj2 == null)
				{
					return null;
				}
				return ReadLocaleCode(obj2.GetType().GetField("LocaleReference")?.GetValue(obj2));
			}
			catch
			{
				return null;
			}
		}

		private static string TryReadSelectedLocaleCode()
		{
			try
			{
				ResolveReflectionCache();
				if (_localizationSettingsType == null || _selectedLocaleProp == null)
				{
					return null;
				}
				return ReadLocaleCode(_selectedLocaleProp.GetValue(null, null));
			}
			catch
			{
				return null;
			}
		}

		private static string ReadLocaleCode(object locale)
		{
			if (locale == null)
			{
				return null;
			}
			try
			{
				object obj = _localeIdentifierProp?.GetValue(locale, null);
				if (obj == null)
				{
					return null;
				}
				return _identifierCodeProp?.GetValue(obj, null) as string;
			}
			catch
			{
				return null;
			}
		}

		private static void ResolveReflectionCache()
		{
			if (_reflectionResolved)
			{
				return;
			}
			_reflectionResolved = true;
			try
			{
				_localizationSettingsType = Type.GetType("UnityEngine.Localization.Settings.LocalizationSettings, Unity.Localization");
				if (_localizationSettingsType != null)
				{
					_selectedLocaleProp = _localizationSettingsType.GetProperty("SelectedLocale");
					if (_selectedLocaleProp != null)
					{
						_localeIdentifierProp = _selectedLocaleProp.PropertyType?.GetProperty("Identifier");
						_identifierCodeProp = (_localeIdentifierProp?.PropertyType)?.GetProperty("Code");
					}
				}
			}
			catch
			{
				_localizationSettingsType = null;
				_selectedLocaleProp = null;
			}
		}

		public static bool DetectDefault(IEnumerable<string> chineseKeywords, IEnumerable<string> chineseEnvironmentPluginGuids)
		{
			string[] array = ToFilteredArray(chineseKeywords) ?? DefaultChineseKeywords;
			string[] array2 = ToFilteredArray(chineseEnvironmentPluginGuids) ?? DefaultChineseEnvironmentPluginGuids;
			try
			{
				foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
				{
					string text = pluginInfo.Key ?? string.Empty;
					PluginInfo value = pluginInfo.Value;
					object obj;
					if (value == null)
					{
						obj = null;
					}
					else
					{
						BepInPlugin metadata = value.Metadata;
						obj = ((metadata != null) ? metadata.Name : null);
					}
					if (obj == null)
					{
						obj = string.Empty;
					}
					string text2 = (string)obj;
					foreach (string value2 in array)
					{
						if (text.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return true;
						}
					}
					for (int j = 0; j < array2.Length; j++)
					{
						if (string.Equals(text, array2[j], StringComparison.OrdinalIgnoreCase))
						{
							return true;
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static string[] ToFilteredArray(IEnumerable<string> source)
		{
			if (source == null)
			{
				return null;
			}
			List<string> list = new List<string>();
			foreach (string item in source)
			{
				if (!string.IsNullOrEmpty(item))
				{
					list.Add(item);
				}
			}
			if (list.Count != 0)
			{
				return list.ToArray();
			}
			return null;
		}
	}
	internal sealed class I18NRegistry
	{
		public sealed class CfgI18N
		{
			public string SectionEN;

			public string SectionCN;

			public string KeyEN;

			public string KeyCN;

			public string DescEN;

			public string DescCN;

			public ConfigurationManagerAttributes Attrs;

			public string ValueEN;

			public string ValueCN;

			public ConfigEntry<string> ReadOnlyEntry;
		}

		public enum DisplayLanguage
		{
			中文,
			English
		}

		private readonly ConfigFile _config;

		private readonly ManualLogSource _logger;

		private readonly List<CfgI18N> _all = new List<CfgI18N>(20);

		private readonly Dictionary<string, CfgI18N> _bySection = new Dictionary<string, CfgI18N>(StringComparer.Ordinal);

		private readonly Dictionary<string, Dictionary<string, CfgI18N>> _bySectionAndKey = new Dictionary<string, Dictionary<string, CfgI18N>>(StringComparer.Ordinal);

		public ConfigEntry<DisplayLanguage> LanguageEntry { get; private set; }

		public bool UseChinese
		{
			get
			{
				if (LanguageEntry != null)
				{
					return LanguageEntry.Value == DisplayLanguage.中文;
				}
				return false;
			}
		}

		public int RegisteredCount => _all.Count;

		public IReadOnlyList<CfgI18N> All => _all;

		public event Action LanguageChanged;

		public I18NRegistry(ConfigFile config, ManualLogSource logger = null)
		{
			_config = config ?? throw new ArgumentNullException("config");
			_logger = logger;
		}

		public ConfigEntry<DisplayLanguage> BindLanguage(bool defaultChinese, string sectionEN = "Mod Info", string sectionCN = "模组信息")
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			DisplayLanguage displayLanguage = ((!defaultChinese) ? DisplayLanguage.English : DisplayLanguage.中文);
			CfgI18N cfgI18N = NewI18N(sectionEN, sectionCN, "Language", "语言", "Switch display language.", "切换显示语言。", readOnly: false);
			LanguageEntry = _config.Bind<DisplayLanguage>(sectionEN, "Language", displayLanguage, new ConfigDescription(cfgI18N.DescEN, (AcceptableValueBase)null, new object[1] { cfgI18N.Attrs }));
			LanguageEntry.SettingChanged += delegate
			{
				RefreshAttrs();
				InvokeLanguageChanged();
			};
			return LanguageEntry;
		}

		public ConfigEntry<T> Bind<T>(string sectEN, string sectCN, string keyEN, string keyCN, string descEN, string descCN, T defaultValue, AcceptableValueBase acceptableValues = null, int order = 0, Action<ConfigEntryBase> customDrawer = null, bool? showRangeAsPercent = null, bool? isAdvanced = null, bool? browsable = null)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			CfgI18N cfgI18N = NewI18N(sectEN, sectCN, keyEN, keyCN, descEN, descCN, readOnly: false);
			if (order != 0)
			{
				cfgI18N.Attrs.Order = order;
			}
			if (customDrawer != null)
			{
				cfgI18N.Attrs.CustomDrawer = customDrawer;
			}
			if (showRangeAsPercent.HasValue)
			{
				cfgI18N.Attrs.ShowRangeAsPercent = showRangeAsPercent.Value;
			}
			if (isAdvanced.HasValue)
			{
				cfgI18N.Attrs.IsAdvanced = isAdvanced.Value;
			}
			if (browsable.HasValue)
			{
				cfgI18N.Attrs.Browsable = browsable.Value;
			}
			return _config.Bind<T>(sectEN, keyEN, defaultValue, new ConfigDescription(descEN, acceptableValues, new object[1] { cfgI18N.Attrs }));
		}

		public ConfigEntry<string> BindReadOnly(string sectEN, string sectCN, string keyEN, string keyCN, string valueEN, string valueCN, int order = 0, Action<ConfigEntryBase> customDrawer = null)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			CfgI18N cfgI18N = NewI18N(sectEN, sectCN, keyEN, keyCN, "", "", readOnly: true);
			cfgI18N.ValueEN = valueEN;
			cfgI18N.ValueCN = valueCN;
			if (order != 0)
			{
				cfgI18N.Attrs.Order = order;
			}
			if (customDrawer != null)
			{
				cfgI18N.Attrs.CustomDrawer = customDrawer;
			}
			cfgI18N.ReadOnlyEntry = _config.Bind<string>(sectEN, keyEN, valueEN, new ConfigDescription("", (AcceptableValueBase)null, new object[1] { cfgI18N.Attrs }));
			string text = (UseChinese ? valueCN : valueEN);
			if (cfgI18N.ReadOnlyEntry.Value != text)
			{
				cfgI18N.ReadOnlyEntry.Value = text;
			}
			cfgI18N.ReadOnlyEntry.SettingChanged += MakeReadOnlyValueGuard(cfgI18N);
			return cfgI18N.ReadOnlyEntry;
		}

		private EventHandler MakeReadOnlyValueGuard(CfgI18N i18n)
		{
			return delegate
			{
				if (i18n.ReadOnlyEntry != null)
				{
					string text = (UseChinese ? i18n.ValueCN : i18n.ValueEN);
					if (i18n.ReadOnlyEntry.Value != text)
					{
						i18n.ReadOnlyEntry.Value = text;
						InvokeLanguageChanged();
					}
				}
			};
		}

		private void InvokeLanguageChanged()
		{
			Action action = this.LanguageChanged;
			if (action == null)
			{
				return;
			}
			Delegate[] invocationList = action.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action2 = (Action)invocationList[i];
				try
				{
					action2();
				}
				catch (Exception ex)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogWarning((object)("LanguageChanged 订阅方异常:" + ex.Message));
					}
				}
			}
		}

		private CfgI18N NewI18N(string sectEN, string sectCN, string keyEN, string keyCN, string descEN, string descCN, bool readOnly)
		{
			CfgI18N cfgI18N = new CfgI18N
			{
				SectionEN = sectEN,
				SectionCN = sectCN,
				KeyEN = keyEN,
				KeyCN = keyCN,
				DescEN = descEN,
				DescCN = descCN,
				Attrs = (readOnly ? new ConfigurationManagerAttributes
				{
					ReadOnly = true,
					HideDefaultButton = true
				} : new ConfigurationManagerAttributes())
			};
			ApplyI18N(cfgI18N);
			_all.Add(cfgI18N);
			_bySection[sectEN] = cfgI18N;
			if (!_bySectionAndKey.TryGetValue(sectEN, out var value))
			{
				value = new Dictionary<string, CfgI18N>(StringComparer.Ordinal);
				_bySectionAndKey[sectEN] = value;
			}
			value[keyEN] = cfgI18N;
			return cfgI18N;
		}

		private void ApplyI18N(CfgI18N i18n)
		{
			bool useChinese = UseChinese;
			i18n.Attrs.Category = (useChinese ? i18n.SectionCN : i18n.SectionEN);
			i18n.Attrs.DispName = (useChinese ? i18n.KeyCN : i18n.KeyEN);
			i18n.Attrs.Description = (useChinese ? i18n.DescCN : i18n.DescEN);
			if (i18n.ReadOnlyEntry != null)
			{
				string text = (useChinese ? i18n.ValueCN : i18n.ValueEN);
				if (i18n.ReadOnlyEntry.Value != text)
				{
					i18n.ReadOnlyEntry.Value = text;
				}
			}
		}

		public void RefreshAttrs()
		{
			for (int i = 0; i < _all.Count; i++)
			{
				ApplyI18N(_all[i]);
			}
		}

		public void RefreshNow()
		{
			RefreshAttrs();
			InvokeLanguageChanged();
		}

		public bool TryGetBySection(string sectEN, out CfgI18N i18n)
		{
			return _bySection.TryGetValue(sectEN, out i18n);
		}

		public bool TryGetByKey(string keyEN, out CfgI18N i18n)
		{
			i18n = null;
			foreach (KeyValuePair<string, Dictionary<string, CfgI18N>> item in _bySectionAndKey)
			{
				if (item.Value.TryGetValue(keyEN, out i18n))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? ShowRangeAsPercent;

		public Action<ConfigEntryBase> CustomDrawer;

		public bool? Browsable;

		public string Category;

		public object DefaultValue;

		public bool? HideDefaultButton;

		public bool? HideSettingName;

		public string Description;

		public string DispName;

		public int? Order;

		public bool? ReadOnly;

		public bool? IsAdvanced;
	}
	internal sealed class I18NSwitcher
	{
		private sealed class LiveLabel
		{
			public WeakReference<TextMeshProUGUI> Tmp;

			public I18NRegistry.CfgI18N I18N;

			public bool IsSection;
		}

		private sealed class LiveValue
		{
			public WeakReference<Object> InputField;

			public I18NRegistry.CfgI18N I18N;
		}

		private sealed class LiveToggleButtons
		{
			public WeakReference<TextMeshProUGUI> LeftTmp;

			public WeakReference<TextMeshProUGUI> RightTmp;

			public bool IsLanguage;
		}

		private readonly I18NRegistry _registry;

		private readonly Harmony _harmony;

		private readonly ManualLogSource _logger;

		private readonly string _pluginName;

		private readonly string _pluginNameFixedForm;

		private readonly List<LiveLabel> _liveLabels = new List<LiveLabel>(64);

		private readonly List<LiveValue> _liveValues = new List<LiveValue>(8);

		private readonly List<LiveToggleButtons> _liveToggleButtons = new List<LiveToggleButtons>(16);

		private static readonly Dictionary<Type, FieldInfo> _labelTmpFieldCache = new Dictionary<Type, FieldInfo>(8);

		private static readonly Dictionary<Type, FieldInfo> _inputStringSystemFieldCache = new Dictionary<Type, FieldInfo>(2);

		private static readonly Dictionary<Type, MethodInfo> _inputStringSystemSetValueCache = new Dictionary<Type, MethodInfo>(2);

		private static readonly Dictionary<Type, FieldInfo> _toggleLeftTmpCache = new Dictionary<Type, FieldInfo>(4);

		private static readonly Dictionary<Type, FieldInfo> _toggleRightTmpCache = new Dictionary<Type, FieldInfo>(4);

		private static readonly object _reflectionCacheLock = new object();

		private static readonly object _globalInstancesLock = new object();

		private static readonly List<WeakReference<I18NSwitcher>> _globalInstances = new List<WeakReference<I18NSwitcher>>(2);

		public int LiveUiCount => _liveLabels.Count + _liveValues.Count + _liveToggleButtons.Count;

		public I18NSwitcher(I18NRegistry registry, Harmony harmony, string pluginName, ManualLogSource logger = null)
		{
			_registry = registry ?? throw new ArgumentNullException("registry");
			_harmony = harmony ?? throw new ArgumentNullException("harmony");
			_pluginName = pluginName ?? throw new ArgumentNullException("pluginName");
			_pluginNameFixedForm = FixNamingForOwnership(pluginName);
			_logger = logger;
			_registry.LanguageChanged += RefreshLiveUi;
		}

		private static string FixNamingForOwnership(string input)
		{
			if (string.IsNullOrEmpty(input))
			{
				return input;
			}
			input = Regex.Replace(input, "([a-z])([A-Z])", "$1 $2");
			input = Regex.Replace(input, "([A-Z])([A-Z][a-z])", "$1 $2");
			input = Regex.Replace(input, "\\s+", " ");
			input = Regex.Replace(input, "([A-Z]\\.)\\s([A-Z]\\.)", "$1$2");
			return input.Trim();
		}

		public void InstallRepoConfigHook()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("MenuLib.MenuAPI");
				if (type == null)
				{
					ManualLogSource logger = _logger;
					if (logger != null)
					{
						logger.LogInfo((object)"MenuLib 未安装,跳过 REPOConfig 双语劫持。");
					}
					return;
				}
				HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(I18NSwitcher), "PostfixDispatch", (Type[])null, (Type[])null))
				{
					priority = 0
				};
				HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal) { "CreateREPOLabel", "CreateREPOToggle", "CreateREPOSlider", "CreateREPOInputField", "CreateREPOButton" };
				int num = 0;
				foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
				{
					if (!hashSet.Contains(declaredMethod.Name))
					{
						continue;
					}
					ParameterInfo[] parameters = declaredMethod.GetParameters();
					if (parameters.Length != 0 && !(parameters[0].ParameterType != typeof(string)))
					{
						try
						{
							_harmony.Patch((MethodBase)declaredMethod, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							num++;
						}
						catch
						{
						}
					}
				}
				if (num > 0)
				{
					ManualLogSource logger2 = _logger;
					if (logger2 != null)
					{
						logger2.LogInfo((object)$"REPOConfig 双语显示已挂载({num} 个 UI 创建方法)。");
					}
				}
				else
				{
					ManualLogSource logger3 = _logger;
					if (logger3 != null)
					{
						logger3.LogInfo((object)"REPOConfig 没找到可劫持的 UI 方法。");
					}
				}
				RegisterGlobalInstance(this);
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = _logger;
				if (logger4 != null)
				{
					logger4.LogInfo((object)("REPOConfig 劫持失败:" + ex.Message));
				}
			}
		}

		private static void RegisterGlobalInstance(I18NSwitcher inst)
		{
			lock (_globalInstancesLock)
			{
				_globalInstances.Add(new WeakReference<I18NSwitcher>(inst));
			}
		}

		public static void PostfixDispatch(object[] __args, object __result)
		{
			try
			{
				if (__args == null || __args.Length == 0 || __result == null || !(__args[0] is string text) || string.IsNullOrEmpty(text))
				{
					return;
				}
				List<I18NSwitcher> list = null;
				lock (_globalInstancesLock)
				{
					for (int num = _globalInstances.Count - 1; num >= 0; num--)
					{
						if (!_globalInstances[num].TryGetTarget(out var target))
						{
							_globalInstances.RemoveAt(num);
						}
						else
						{
							(list ?? (list = new List<I18NSwitcher>(_globalInstances.Count))).Add(target);
						}
					}
				}
				if (list != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						list[i].TryRegisterLiveLabel(text, __result);
					}
				}
			}
			catch
			{
			}
		}

		private static string GetOwningPluginName(object uiElement)
		{
			try
			{
				object obj = ((uiElement is Component) ? uiElement : null);
				GameObject val = (GameObject)(((obj != null) ? ((Component)obj).gameObject : null) ?? ((uiElement is GameObject) ? uiElement : null));
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				Transform val2 = val.transform;
				while ((Object)(object)val2 != (Object)null)
				{
					string name = ((Object)((Component)val2).gameObject).name;
					if (name != null && name.StartsWith("Menu Page ", StringComparison.Ordinal))
					{
						return name.Substring("Menu Page ".Length);
					}
					val2 = val2.parent;
				}
			}
			catch
			{
			}
			return null;
		}

		private void TryRegisterLiveLabel(string label, object uiElement)
		{
			string owningPluginName = GetOwningPluginName(uiElement);
			if ((owningPluginName != null && !string.Equals(owningPluginName, _pluginNameFixedForm, StringComparison.Ordinal)) || (!_registry.TryGetBySection(label, out var i18n) && !_registry.TryGetByKey(label, out i18n)))
			{
				return;
			}
			bool flag = string.Equals(label, i18n.SectionEN, StringComparison.Ordinal);
			TextMeshProUGUI labelTmp = GetLabelTmp(uiElement);
			if ((Object)(object)labelTmp == (Object)null)
			{
				return;
			}
			bool useChinese = _registry.UseChinese;
			string text = ((!flag) ? (useChinese ? i18n.KeyCN : i18n.KeyEN) : (useChinese ? i18n.SectionCN : i18n.SectionEN));
			if (!string.IsNullOrEmpty(text))
			{
				try
				{
					((TMP_Text)labelTmp).text = text;
				}
				catch
				{
				}
			}
			_liveLabels.Add(new LiveLabel
			{
				Tmp = new WeakReference<TextMeshProUGUI>(labelTmp),
				I18N = i18n,
				IsSection = flag
			});
			if (!flag && i18n.ReadOnlyEntry != null)
			{
				Object val = (Object)((uiElement is Object) ? uiElement : null);
				if (val != null && HasInputStringSystemField(((object)val).GetType()))
				{
					_liveValues.Add(new LiveValue
					{
						InputField = new WeakReference<Object>(val),
						I18N = i18n
					});
					string text2 = (useChinese ? i18n.ValueCN : i18n.ValueEN);
					if (i18n.ReadOnlyEntry.Value != text2)
					{
						i18n.ReadOnlyEntry.Value = text2;
					}
					TrySetInputFieldValue(val, text2);
				}
			}
			if (flag)
			{
				return;
			}
			Type type = uiElement.GetType();
			FieldInfo value;
			FieldInfo value2;
			lock (_reflectionCacheLock)
			{
				if (!_toggleLeftTmpCache.TryGetValue(type, out value))
				{
					value = AccessTools.Field(type, "leftButtonTMP");
					_toggleLeftTmpCache[type] = value;
				}
				if (!_toggleRightTmpCache.TryGetValue(type, out value2))
				{
					value2 = AccessTools.Field(type, "rightButtonTMP");
					_toggleRightTmpCache[type] = value2;
				}
			}
			if (value != null && value2 != null)
			{
				object? value3 = value.GetValue(uiElement);
				TextMeshProUGUI val2 = (TextMeshProUGUI)((value3 is TextMeshProUGUI) ? value3 : null);
				object? value4 = value2.GetValue(uiElement);
				TextMeshProUGUI val3 = (TextMeshProUGUI)((value4 is TextMeshProUGUI) ? value4 : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val3 != (Object)null)
				{
					_liveToggleButtons.Add(new LiveToggleButtons
					{
						LeftTmp = new WeakReference<TextMeshProUGUI>(val2),
						RightTmp = new WeakReference<TextMeshProUGUI>(val3),
						IsLanguage = false
					});
					ApplyToggleButtonText(val2, val3, useChinese, isLanguage: false);
				}
			}
		}

		private static TextMeshProUGUI GetLabelTmp(object uiElement)
		{
			try
			{
				Type type = uiElement.GetType();
				FieldInfo value;
				lock (_reflectionCacheLock)
				{
					if (!_labelTmpFieldCache.TryGetValue(type, out value))
					{
						value = AccessTools.Field(type, "labelTMP");
						_labelTmpFieldCache[type] = value;
					}
				}
				object? obj = value?.GetValue(uiElement);
				return (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null);
			}
			catch
			{
				return null;
			}
		}

		private static bool HasInputStringSystemField(Type t)
		{
			lock (_reflectionCacheLock)
			{
				if (!_inputStringSystemFieldCache.TryGetValue(t, out var value))
				{
					value = AccessTools.Field(t, "inputStringSystem");
					_inputStringSystemFieldCache[t] = value;
				}
				return value != null;
			}
		}

		private static bool TrySetInputFieldValue(Object ifObj, string newVal)
		{
			try
			{
				Type type = ((object)ifObj).GetType();
				FieldInfo value;
				lock (_reflectionCacheLock)
				{
					if (!_inputStringSystemFieldCache.TryGetValue(type, out value))
					{
						value = AccessTools.Field(type, "inputStringSystem");
						_inputStringSystemFieldCache[type] = value;
					}
				}
				if (value == null)
				{
					return false;
				}
				object value2 = value.GetValue(ifObj);
				if (value2 == null)
				{
					return false;
				}
				MethodInfo value3;
				lock (_reflectionCacheLock)
				{
					Type type2 = value2.GetType();
					if (!_inputStringSystemSetValueCache.TryGetValue(type2, out value3))
					{
						value3 = AccessTools.Method(type2, "SetValue", new Type[2]
						{
							typeof(string),
							typeof(bool)
						}, (Type[])null);
						_inputStringSystemSetValueCache[type2] = value3;
					}
				}
				if (value3 == null)
				{
					return false;
				}
				value3.Invoke(value2, new object[2]
				{
					newVal ?? string.Empty,
					false
				});
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void ApplyToggleButtonText(TextMeshProUGUI leftTmp, TextMeshProUGUI rightTmp, bool cn, bool isLanguage)
		{
			try
			{
				if (isLanguage)
				{
					((TMP_Text)leftTmp).text = (cn ? "中文" : "Chinese");
					((TMP_Text)rightTmp).text = (cn ? "英文" : "English");
				}
				else
				{
					((TMP_Text)leftTmp).text = (cn ? "开" : "ON");
					((TMP_Text)rightTmp).text = (cn ? "关" : "OFF");
				}
			}
			catch
			{
			}
		}

		private void RefreshLiveUi()
		{
			bool useChinese = _registry.UseChinese;
			for (int num = _liveLabels.Count - 1; num >= 0; num--)
			{
				LiveLabel liveLabel = _liveLabels[num];
				if (!liveLabel.Tmp.TryGetTarget(out var target) || (Object)(object)target == (Object)null || (Object)(object)((Component)target).gameObject == (Object)null)
				{
					_liveLabels.RemoveAt(num);
				}
				else
				{
					string text = ((!liveLabel.IsSection) ? (useChinese ? liveLabel.I18N.KeyCN : liveLabel.I18N.KeyEN) : (useChinese ? liveLabel.I18N.SectionCN : liveLabel.I18N.SectionEN));
					try
					{
						((TMP_Text)target).text = text;
					}
					catch
					{
						_liveLabels.RemoveAt(num);
					}
				}
			}
			for (int num2 = _liveValues.Count - 1; num2 >= 0; num2--)
			{
				LiveValue liveValue = _liveValues[num2];
				if (!liveValue.InputField.TryGetTarget(out var target2) || target2 == (Object)null)
				{
					_liveValues.RemoveAt(num2);
				}
				else
				{
					string newVal = (useChinese ? liveValue.I18N.ValueCN : liveValue.I18N.ValueEN);
					if (!TrySetInputFieldValue(target2, newVal))
					{
						_liveValues.RemoveAt(num2);
					}
				}
			}
			for (int num3 = _liveToggleButtons.Count - 1; num3 >= 0; num3--)
			{
				LiveToggleButtons liveToggleButtons = _liveToggleButtons[num3];
				if (!liveToggleButtons.LeftTmp.TryGetTarget(out var target3) || (Object)(object)target3 == (Object)null || !liveToggleButtons.RightTmp.TryGetTarget(out var target4) || (Object)(object)target4 == (Object)null)
				{
					_liveToggleButtons.RemoveAt(num3);
				}
				else
				{
					ApplyToggleButtonText(target3, target4, useChinese, liveToggleButtons.IsLanguage);
				}
			}
		}
	}
}