Decompiled source of PeakTcnPatch v1.3.0

ue.Peak.TcnPatch.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using ue.Peak.TcnPatch.API;
using ue.Peak.TcnPatch.Adapters;
using ue.Peak.TcnPatch.Patches;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ue.Peak.TcnPatch")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+734d1f27f4e0fe1aad6bc8c3b209d4e56a0a1e72")]
[assembly: AssemblyProduct("ue.Peak.TcnPatch")]
[assembly: AssemblyTitle("ue.Peak.TcnPatch")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ue.Peak.TcnPatch
{
	[BepInPlugin("ue.Peak.TcnPatch", "ue.Peak.TcnPatch", "1.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "ue.Peak.TcnPatch";

		public const string ModName = "ue.Peak.TcnPatch";

		public const string ModVersion = "1.3.0";

		private static FileSystemWatcher _watcher;

		public const string TcnTranslationFileName = "TcnTranslations.json";

		private static SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static TranslationFile EmptyTranslationFile { get; set; }

		internal static TranslationFile CurrentTranslationFile { get; private set; }

		internal static PluginConfig ModConfig { get; private set; }

		internal static HashSet<string> EphemeralTranslationKeys { get; } = new HashSet<string>();


		internal static bool HasOfficialTcn { get; private set; }

		internal static Dictionary<string, string> TcnTable { get; } = new Dictionary<string, string>();


		internal static Dictionary<string, string> RegisteredTable { get; } = new Dictionary<string, string>();


		internal static Dictionary<string, string> RegisteredOrigTable { get; } = new Dictionary<string, string>();


		private void Awake()
		{
			Instance = this;
			ModConfig = new PluginConfig(((BaseUnityPlugin)this).Config);
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"正在載入模組 - ue.Peak.TcnPatch");
			if (Enum.GetValues(typeof(Language)).Cast<int>().Any((int values) => values == 10))
			{
				HasOfficialTcn = true;
			}
			if (ModConfig.DownloadFromRemote.Value)
			{
				Task.Run(async delegate
				{
					string url = ModConfig.DownloadUrl.Value;
					Logger.LogInfo((object)"正在從遠端下載翻譯資料... (可以在模組設定停用)");
					Logger.LogInfo((object)("網址:" + url));
					HttpClient client = new HttpClient();
					try
					{
						string content = await client.GetStringAsync(url);
						try
						{
							JObject.Parse(content);
						}
						catch (Exception ex)
						{
							Exception e2 = ex;
							Logger.LogWarning((object)"無效的遠端翻譯資料!將使用本機資料。");
							Logger.LogWarning((object)e2);
							return;
						}
						string dir = Path.Combine(Paths.ConfigPath, "ue.Peak.TcnPatch");
						Directory.CreateDirectory(dir);
						string path = Path.Combine(dir, "TcnTranslations.json");
						await _lock.WaitAsync();
						try
						{
							FileStream targetStream = File.Open(path, FileMode.Truncate, FileAccess.Write);
							try
							{
								StreamWriter writer = new StreamWriter(targetStream);
								try
								{
									await writer.WriteAsync(content);
								}
								finally
								{
									if (writer != null)
									{
										await writer.DisposeAsync();
									}
								}
							}
							finally
							{
								if (targetStream != null)
								{
									await targetStream.DisposeAsync();
								}
							}
						}
						finally
						{
							_lock.Release();
						}
						Logger.LogInfo((object)"翻譯資料下載完成!");
					}
					catch (Exception ex)
					{
						Exception e = ex;
						Logger.LogError((object)"翻譯資料下載失敗!將使用本機資料。");
						Logger.LogError((object)e);
					}
					client.Dispose();
				});
			}
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "ue.Peak.TcnPatch");
			ue.Peak.TcnPatch.API.TcnPatch internalInstance = ue.Peak.TcnPatch.API.TcnPatch.InternalInstance;
			internalInstance.RegisterLocalizationKey("PeakTcnPatch.Passport.Crabland", "CRABLAND");
			MoreAscentsSupport.RegisterLocalizations();
			Logger.LogInfo((object)"已載入模組 - ue.Peak.TcnPatch");
			Logger.LogInfo((object)"  + 非官方繁體中文翻譯支援模組 -- by悠依");
		}

		private void Start()
		{
			string path = Path.Combine(Paths.ConfigPath, "ue.Peak.TcnPatch");
			Directory.CreateDirectory(path);
			_watcher = new FileSystemWatcher(path, "*.json");
			_watcher.NotifyFilter = NotifyFilters.LastWrite;
			_watcher.Changed += delegate(object _, FileSystemEventArgs args)
			{
				if (args.Name == "TcnTranslations.json")
				{
					Logger.LogInfo((object)"正在更新遊戲內繁體中文翻譯資料...");
					UpdateMainTable();
				}
			};
			UpdateMainTable();
			_watcher.EnableRaisingEvents = true;
		}

		internal static bool TryGetVanilla(string id, out string result)
		{
			return TcnTable.TryGetValue(id.ToUpperInvariant(), out result);
		}

		internal static bool TryGetRegistered(string id, Language? language, out string result)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Language valueOrDefault = language.GetValueOrDefault();
			if (!language.HasValue)
			{
				valueOrDefault = LocalizedText.CURRENT_LANGUAGE;
				language = valueOrDefault;
			}
			if ((int)language.GetValueOrDefault() == 10 && RegisteredTable.TryGetValue(id, out result))
			{
				return true;
			}
			return RegisteredOrigTable.TryGetValue(id, out result);
		}

		private static void UpdateMainTable()
		{
			_lock.Wait();
			try
			{
				if (!TryReadFromJson<JObject>("TcnTranslations.json", out var result, () => new JObject()))
				{
					return;
				}
				CurrentTranslationFile = TranslationFile.Deserialize(result);
			}
			catch (TranslationParseException ex)
			{
				Logger.LogError((object)ex.UserMessage);
				Logger.LogError((object)"翻譯資料分析失敗!");
				return;
			}
			catch (Exception ex2)
			{
				Logger.LogError((object)"翻譯資料分析失敗!");
				Logger.LogError((object)ex2);
				return;
			}
			finally
			{
				_lock.Release();
			}
			Dictionary<string, List<string>> mainTable = LocalizedText.mainTable;
			HashSet<string> hashSet = mainTable.Keys.ToHashSet();
			if (CurrentTranslationFile.Authors.Count > 0)
			{
				Logger.LogInfo((object)("翻譯資料作者:" + string.Join("、", CurrentTranslationFile.Authors)));
			}
			else
			{
				Logger.LogInfo((object)"翻譯資料作者:未知");
			}
			TcnTable.Clear();
			RegisteredTable.Clear();
			string key;
			string value;
			foreach (KeyValuePair<string, string> translation in CurrentTranslationFile.Translations)
			{
				translation.Deconstruct(out key, out value);
				string text = key;
				string value2 = value;
				if (!mainTable.ContainsKey(text.ToUpperInvariant()))
				{
					Logger.LogWarning((object)("已忽略未知的翻譯key:「" + text + "」!"));
					continue;
				}
				TcnTable[text] = value2;
				hashSet.Remove(text);
			}
			foreach (KeyValuePair<string, string> additionalTranslation in CurrentTranslationFile.AdditionalTranslations)
			{
				additionalTranslation.Deconstruct(out value, out key);
				string key2 = value;
				string value3 = key;
				RegisteredTable[key2] = value3;
			}
			HashSet<string> vanillaLocalizationKeys = LocalizedTextPatch.VanillaLocalizationKeys;
			foreach (string item in hashSet)
			{
				if (vanillaLocalizationKeys.Contains(item))
				{
					Logger.LogWarning((object)("缺少「" + item + "」翻譯key,請更新翻譯資料!"));
				}
				else if (ModConfig.WarnMissingAdditionalKeys.Value)
				{
					Logger.LogWarning((object)("*附加翻譯* 缺少「" + item + "」翻譯key!"));
				}
			}
		}

		private static bool TryReadFromJson<T>(string fileName, out T result, Func<T> defaultContent) where T : class
		{
			string text = Path.Combine(Paths.ConfigPath, "ue.Peak.TcnPatch");
			Directory.CreateDirectory(text);
			string path = Path.Combine(text, fileName);
			if (!File.Exists(path))
			{
				string contents = JsonConvert.SerializeObject((object)defaultContent());
				File.WriteAllText(path, contents);
			}
			try
			{
				using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
				using StreamReader streamReader = new StreamReader(stream);
				result = JsonConvert.DeserializeObject<T>(streamReader.ReadToEnd());
				return true;
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("無法讀取 JSON 設定:" + fileName));
				Logger.LogError((object)ex);
				result = null;
				return false;
			}
		}
	}
	public class PluginConfig
	{
		public ConfigEntry<bool> DownloadFromRemote { get; } = config.Bind<bool>("Update", "DownloadFromRemote", true, "是否每次啟動都要從遠端下載最新的翻譯資料? (true: 是, false: 否)");


		public ConfigEntry<string> DownloadUrl { get; } = config.Bind<string>("Update", "DownloadUrl", "https://raw.githubusercontent.com/Yuieii/ue.Peak.TcnPatch/refs/heads/master/TcnTranslations.json", "翻譯資料的 URL");


		public ConfigEntry<Language> AutoDumpLanguage { get; } = config.Bind<Language>("Debug", "AutoDumpLanguage", (Language)9, "自動輸出官方參考翻譯時選擇的原始語言");


		public ConfigEntry<bool> WarnMissingAdditionalKeys { get; } = config.Bind<bool>("Debug", "WarnMissingAdditionalKeys", false, "有缺失的附加翻譯key時是否觸發警告");


		public ConfigEntry<LanguagePatchMode> LanguagePatchMode { get; } = config.Bind<LanguagePatchMode>("Patch", "LanguagePatchMode", ue.Peak.TcnPatch.LanguagePatchMode.InsertAfterSimplifiedChinese, "設定修正設定中的語言清單時,要放在簡體中文後面,或是取代簡體中文");


		public ConfigEntry<bool> ShowPatchCredit { get; } = config.Bind<bool>("Patch", "ShowPatchCredit", true, "在主畫面版本文字後面顯示本模組作者?");


		public ConfigEntry<bool> ShowTranslatorCredit { get; } = config.Bind<bool>("Patch", "ShowTranslatorCredit", true, "在主畫面版本文字後面交替顯示翻譯資料的作者?");


		public ConfigEntry<bool> ShowModVersionInPatchCredit { get; } = config.Bind<bool>("Patch", "ShowModVersionInPatchCredit", true, "在主畫面版本文字後面顯示這個模組的版本? (v1.3.0)");


		public PluginConfig(ConfigFile config)
		{
		}
	}
	public enum LanguagePatchMode
	{
		InsertAfterSimplifiedChinese,
		ReplaceSimplifiedChinese,
		Append
	}
	internal static class ReflectionExtensions
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static TValue GetReflectionFieldValue<TOwner, TValue>(this TOwner owner, ReflectionMembers.TypedFieldInfo<TOwner, TValue> fieldInfo)
		{
			return (TValue)fieldInfo.FieldInfo.GetValue(owner);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool TryGetReflectionFieldValue<TOwner, TValue>(this TOwner owner, ReflectionMembers.TypedFieldInfo<TOwner, TValue> fieldInfo, out TValue result)
		{
			if (fieldInfo == null)
			{
				result = default(TValue);
				return false;
			}
			result = (TValue)fieldInfo.FieldInfo.GetValue(owner);
			return true;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void SetReflectionFieldValue<TOwner, TValue>(this TOwner owner, ReflectionMembers.TypedFieldInfo<TOwner, TValue> fieldInfo, TValue value)
		{
			fieldInfo.FieldInfo.SetValue(owner, value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool TrySetReflectionFieldValue<TOwner, TValue>(this TOwner owner, ReflectionMembers.TypedFieldInfo<TOwner, TValue> fieldInfo, TValue value)
		{
			if (fieldInfo == null)
			{
				return false;
			}
			fieldInfo.FieldInfo.SetValue(owner, value);
			return true;
		}
	}
	public static class ReflectionMembers
	{
		public static class Fields
		{
			public static TypedFieldInfo<LocalizedText, Language> CurrentLanguage { get; } = AccessTools.Field(typeof(LocalizedText), "CURRENT_LANGUAGE");


			public static TypedFieldInfo<VersionString, TextMeshProUGUI> VersionStringText { get; } = AccessTools.Field(typeof(VersionString), "m_text");


			public static TypedFieldInfo<LoadingScreenAnimation, string> LoadingScreenString { get; } = AccessTools.Field(typeof(LoadingScreenAnimation), "loadingString");


			public static TypedFieldInfo<LoadingScreenAnimation, float> LoadingScreenDefaultStringLength { get; } = AccessTools.Field(typeof(LoadingScreenAnimation), "defaultLoadingStringLength");

		}

		public class TypedFieldInfo<TOwner, TValue>
		{
			public FieldInfo FieldInfo { get; }

			public TypedFieldInfo(FieldInfo fieldInfo)
			{
				FieldInfo = fieldInfo;
				base..ctor();
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			public static implicit operator TypedFieldInfo<TOwner, TValue>(FieldInfo fieldInfo)
			{
				return (fieldInfo == null) ? null : new TypedFieldInfo<TOwner, TValue>(fieldInfo);
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			public static implicit operator FieldInfo(TypedFieldInfo<TOwner, TValue> fieldInfo)
			{
				return fieldInfo?.FieldInfo;
			}
		}
	}
	public class TranslationParseException : Exception
	{
		public string UserMessage { get; }

		public TranslationParseException(string message, string userMessage)
			: base(message)
		{
			UserMessage = userMessage;
		}

		public TranslationParseException(string message)
			: base(message)
		{
			UserMessage = message;
		}
	}
	public class TranslationFile
	{
		public const int CurrentFormatVersion = 0;

		public const string FormatVersionKey = "FormatVersion";

		public const string AuthorKey = "Authors";

		public const string TranslationEntriesKey = "Translations";

		public const string AdditionalTranslationEntriesKey = "AdditionalTranslations";

		public List<string> Authors { get; } = new List<string>();


		public Dictionary<string, string> Translations { get; } = new Dictionary<string, string>();


		public Dictionary<string, string> AdditionalTranslations { get; } = new Dictionary<string, string>();


		public static TranslationFile Deserialize(JObject obj)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			string[] source = new string[2] { "FormatVersion", "Translations" };
			if (!((IEnumerable<string>)source).All((Func<string, bool>)obj.ContainsKey))
			{
				return InternalDeserializeFromLegacy(obj);
			}
			TranslationFile translationFile = new TranslationFile();
			JToken val = obj["FormatVersion"];
			if ((int)val.Type != 6)
			{
				throw new TranslationParseException($"Format version must be an integer value, found {val.Type}", "無效的格式版本!格式版本必須為一個整數!");
			}
			int num = Extensions.Value<int>((IEnumerable<JToken>)val);
			if (num > 0)
			{
				Plugin.Logger.LogWarning((object)"正在讀取過新版本的翻譯資料!可能會無法正確讀取。");
			}
			JToken val2 = default(JToken);
			if (obj.TryGetValue("Authors", ref val2))
			{
				JArray val3 = (JArray)(object)((val2 is JArray) ? val2 : null);
				if (val3 != null)
				{
					foreach (JToken item in val3)
					{
						translationFile.Authors.Add(Extensions.Value<string>((IEnumerable<JToken>)item));
					}
				}
				else
				{
					JValue val4 = (JValue)(object)((val2 is JValue) ? val2 : null);
					if (val4 != null)
					{
						translationFile.Authors.Add(Extensions.Value<string>((IEnumerable<JToken>)val4));
					}
					else
					{
						Plugin.Logger.LogWarning((object)"無效的翻譯者資料! (Authors)");
					}
				}
			}
			JToken val5 = obj["Translations"];
			JObject val6 = (JObject)(object)((val5 is JObject) ? val5 : null);
			if (val6 == null)
			{
				throw new TranslationParseException($"Translation entries must be an object, found {val5.Type}", "無效的翻譯資料! (Translations)");
			}
			string key;
			JToken value;
			foreach (KeyValuePair<string, JToken> item2 in val6)
			{
				item2.Deconstruct(out key, out value);
				string key2 = key;
				JToken val7 = value;
				translationFile.Translations[key2] = Extensions.Value<string>((IEnumerable<JToken>)val7);
			}
			JToken val8 = default(JToken);
			if (obj.TryGetValue("AdditionalTranslations", ref val8))
			{
				JObject val9 = (JObject)(object)((val8 is JObject) ? val8 : null);
				if (val9 == null)
				{
					throw new TranslationParseException($"Additional translation entries must be an object, found {val8.Type}", "無效的附加翻譯資料! (AdditionalTranslations)");
				}
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, JToken> item3 in val9)
				{
					item3.Deconstruct(out key, out value);
					string text = key;
					JToken val10 = value;
					if (list.Contains<string>(text, StringComparer.InvariantCultureIgnoreCase))
					{
						Plugin.Logger.LogWarning((object)("翻譯資料出現已註冊過的附加翻譯key「" + text + "」!新的同名翻譯將會被忽略。"));
						continue;
					}
					list.Add(text);
					translationFile.AdditionalTranslations[text] = Extensions.Value<string>((IEnumerable<JToken>)val10);
				}
			}
			return translationFile;
		}

		private static TranslationFile InternalDeserializeFromLegacy(JObject obj)
		{
			TranslationFile translationFile = new TranslationFile();
			foreach (var (key, val2) in obj)
			{
				translationFile.Translations[key] = Extensions.Value<string>((IEnumerable<JToken>)val2);
			}
			return translationFile;
		}
	}
	public static class Utils
	{
		[CompilerGenerated]
		private sealed class <DelayFramesCoroutine>d__2<T> : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TaskCompletionSource<T> source;

			public int frames;

			public Func<T> resultGetter;

			private int <i>5__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<i>5__1 = 0;
					break;
				case 1:
					<>1__state = -1;
					<i>5__1++;
					break;
				}
				if (<i>5__1 < frames)
				{
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 1;
					return true;
				}
				source.SetResult(resultGetter());
				return false;
			}

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

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

		public static Task WaitForFramesAsync(int frames)
		{
			TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
			((MonoBehaviour)Plugin.Instance).StartCoroutine(DelayFramesCoroutine(taskCompletionSource, frames, () => true));
			return taskCompletionSource.Task;
		}

		public static async Task WaitForNextFrameAsync()
		{
			await WaitForFramesAsync(1);
		}

		[IteratorStateMachine(typeof(<DelayFramesCoroutine>d__2<>))]
		private static IEnumerator DelayFramesCoroutine<T>(TaskCompletionSource<T> source, int frames, Func<T> resultGetter)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayFramesCoroutine>d__2<T>(0)
			{
				source = source,
				frames = frames,
				resultGetter = resultGetter
			};
		}
	}
}
namespace ue.Peak.TcnPatch.Patches
{
	[HarmonyPatch]
	public class LanguageSettingPatch
	{
		[HarmonyPatch(typeof(LanguageSetting), "GetCustomLocalizedChoices")]
		[HarmonyPostfix]
		private static void PatchLanguageChoices(LanguageSetting __instance, ref List<string> __result)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.HasOfficialTcn)
			{
				switch (Plugin.ModConfig.LanguagePatchMode.Value)
				{
				case LanguagePatchMode.ReplaceSimplifiedChinese:
					break;
				case LanguagePatchMode.InsertAfterSimplifiedChinese:
				case LanguagePatchMode.Append:
				{
					int num = Enum.GetNames(typeof(Language)).Length;
					string text = LocalizedText.GetText("CURRENT_LANGUAGE", __instance.ValueToLanguage(num));
					Plugin.Logger.LogInfo((object)"正在修正設定中的語言清單...");
					__result.Add(text);
					break;
				}
				}
			}
		}

		[HarmonyPatch(typeof(LanguageSetting), "ValueToLanguage")]
		[HarmonyPostfix]
		private static void PatchValueToLanguage(int val, ref Language __result)
		{
			if (Plugin.HasOfficialTcn)
			{
				return;
			}
			switch (Plugin.ModConfig.LanguagePatchMode.Value)
			{
			case LanguagePatchMode.InsertAfterSimplifiedChinese:
				__result = (Language)val;
				break;
			case LanguagePatchMode.ReplaceSimplifiedChinese:
				if (val == 9)
				{
					__result = (Language)10;
				}
				break;
			case LanguagePatchMode.Append:
			{
				int length = Enum.GetValues(typeof(Language)).Length;
				if (val == length)
				{
					__result = (Language)10;
				}
				break;
			}
			}
		}
	}
	[HarmonyPatch]
	public class LoadingScreenAnimationPatch
	{
		private static bool _loadingScreenAnimationStartTranspiled;

		[HarmonyPatch(typeof(LoadingScreenAnimation), "Start")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> PatchLoadingAnimationSwitch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected O, but got Unknown
			if (Plugin.HasOfficialTcn)
			{
				_loadingScreenAnimationStartTranspiled = true;
				return instructions;
			}
			Plugin.Logger.LogInfo((object)"正在修補 LoadingScreenAnimation.Start() 的 IL code...");
			List<CodeInstruction> list = instructions.ToList();
			int num = -1;
			int num2 = -1;
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if (CodeInstructionExtensions.LoadsField(val, (FieldInfo)ReflectionMembers.Fields.CurrentLanguage, false))
				{
					CodeInstruction val2 = list[i + 1];
					if (!(val2.opcode != OpCodes.Ldc_I4_S) && val2.operand.Equals((sbyte)9))
					{
						num = i;
						num2 = i + 3;
						break;
					}
				}
			}
			if (num == -1 || num2 == -1)
			{
				Plugin.Logger.LogWarning((object)"沒有在 LoadingScreenAnimation.Start() 找到合適的對應 branch!");
				Plugin.Logger.LogWarning((object)"無法以 IL 方式修補 LoadingScreenAnimation.Start()!將會使用 Postfix 方式修補文字。");
				return list;
			}
			Plugin.Logger.LogInfo((object)"正在插入新的 IL code...");
			CodeInstruction val3 = list[num2];
			Label label = generator.DefineLabel();
			val3.labels.Add(label);
			List<CodeInstruction> list2 = new List<CodeInstruction>();
			list2.Add(CodeInstruction.LoadField(typeof(LocalizedText), "CURRENT_LANGUAGE", false));
			list2.Add(new CodeInstruction(OpCodes.Ldc_I4_S, (object)10));
			list2.Add(new CodeInstruction(OpCodes.Beq_S, (object)label));
			List<CodeInstruction> collection = list2;
			list.InsertRange(num, collection);
			_loadingScreenAnimationStartTranspiled = true;
			return list;
		}

		[HarmonyPatch(typeof(LoadingScreenAnimation), "Start")]
		[HarmonyPostfix]
		private static void PatchLoadingAnimation(LoadingScreenAnimation __instance)
		{
			if (!_loadingScreenAnimationStartTranspiled)
			{
				string text = LocalizedText.GetText("LOADING", true);
				if (ReflectionMembers.Fields.LoadingScreenString == null)
				{
					Plugin.Logger.LogWarning((object)"Patcher 找不到欄位: LoadingScreenAnimation.loadingString");
					return;
				}
				if (ReflectionMembers.Fields.LoadingScreenDefaultStringLength == null)
				{
					Plugin.Logger.LogWarning((object)"Patcher 找不到欄位: LoadingScreenAnimation.defaultLoadingStringLength");
					return;
				}
				Plugin.Logger.LogInfo((object)"正在修正載入中動畫的文字 @ LoadingScreenAnimation.Start()...");
				string text2 = text + "..." + text + "..." + text + "..." + text + "...";
				__instance.SetReflectionFieldValue(ReflectionMembers.Fields.LoadingScreenString, text2);
				__instance.SetReflectionFieldValue(ReflectionMembers.Fields.LoadingScreenDefaultStringLength, text2.Length);
			}
		}
	}
	[HarmonyPatch]
	public class LocalizedTextPatch
	{
		private class AutoDumpRecord
		{
			public int FormatVersion { get; } = 0;


			public List<string> Authors { get; } = new List<string>();


			public Dictionary<string, string> Translations { get; }

			public Dictionary<string, string> AdditionalTranslations { get; }

			public AutoDumpRecord(Dictionary<string, string> translations, Dictionary<string, string> additionalTranslations)
			{
				Translations = translations;
				AdditionalTranslations = additionalTranslations;
				base..ctor();
			}
		}

		private static bool _writtenMainTable;

		public static HashSet<string> VanillaLocalizationKeys { get; } = new HashSet<string>();


		[HarmonyPatch(typeof(LocalizedText), "GetText", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static void PatchGetText(string id, ref string __result, ref bool __runOriginal)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			PatchGetText(id, LocalizedText.CURRENT_LANGUAGE, ref __result, ref __runOriginal);
		}

		[HarmonyPatch(typeof(LocalizedText), "GetText", new Type[]
		{
			typeof(string),
			typeof(Language)
		})]
		[HarmonyPrefix]
		private static void PatchGetText(string id, Language language, ref string __result, ref bool __runOriginal)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (Plugin.TryGetRegistered(id, language, out var result))
			{
				__runOriginal = false;
				__result = result;
			}
			else if ((int)language == 10 && Plugin.TryGetVanilla(id, out result))
			{
				__runOriginal = false;
				__result = result;
			}
		}

		[HarmonyPatch(typeof(LocalizedText), "LoadMainTable")]
		[HarmonyPriority(800)]
		[HarmonyPostfix]
		private static void PatchLoadMainTableFirstChance()
		{
			if (VanillaLocalizationKeys.Count > 0)
			{
				foreach (string item in LocalizedText.mainTable.Keys.Where((string key) => !VanillaLocalizationKeys.Contains(key)))
				{
					LocalizedText.mainTable.Remove(item);
				}
				return;
			}
			foreach (string key in LocalizedText.mainTable.Keys)
			{
				VanillaLocalizationKeys.Add(key);
			}
		}

		[HarmonyPatch(typeof(LocalizedText), "LoadMainTable")]
		[HarmonyPriority(0)]
		[HarmonyPostfix]
		private static void PatchLoadMainTable()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (_writtenMainTable)
			{
				return;
			}
			_writtenMainTable = true;
			string text = Path.Combine(Paths.ConfigPath, "ue.Peak.TcnPatch");
			Directory.CreateDirectory(text);
			string path = Path.Combine(text, "_AutoTcnTranslations.json");
			Language language = Plugin.ModConfig.AutoDumpLanguage.Value;
			Dictionary<string, string> translations = LocalizedText.mainTable.Where((KeyValuePair<string, List<string>> p) => VanillaLocalizationKeys.Contains(p.Key)).ToDictionary((KeyValuePair<string, List<string>> p) => p.Key, (KeyValuePair<string, List<string>> p) => p.Value[(int)language]);
			Dictionary<string, string> dictionary = LocalizedText.mainTable.Where((KeyValuePair<string, List<string>> p) => !VanillaLocalizationKeys.Contains(p.Key)).ToDictionary((KeyValuePair<string, List<string>> p) => p.Key, (KeyValuePair<string, List<string>> p) => p.Value[(int)language]);
			foreach (KeyValuePair<string, string> item in Plugin.RegisteredOrigTable)
			{
				item.Deconstruct(out var key, out var value);
				string key2 = key;
				string value2 = value;
				dictionary[key2] = value2;
			}
			string contents = JsonConvert.SerializeObject((object)new AutoDumpRecord(translations, dictionary), (Formatting)1);
			File.WriteAllText(path, contents);
			Plugin.EmptyTranslationFile = new TranslationFile();
			foreach (string key3 in LocalizedText.mainTable.Keys)
			{
				if (VanillaLocalizationKeys.Contains(key3))
				{
					Plugin.EmptyTranslationFile.Translations[key3] = "";
				}
				else
				{
					Plugin.EmptyTranslationFile.AdditionalTranslations[key3] = "";
				}
			}
		}
	}
	[HarmonyPatch]
	public class PassportManagerPatch
	{
		[HarmonyPatch(typeof(PassportManager), "Awake")]
		[HarmonyPostfix]
		private static void PatchCrabland(PassportManager __instance)
		{
			Transform val = ((Component)__instance).transform.Find("PassportUI/Canvas/Panel/Panel/BG/Text/Nationality/Text");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogDebug((object)"!!: Failed to find the Crabland text in passport UI");
				return;
			}
			LocalizedText val2 = ((Component)val).gameObject.AddComponent<LocalizedText>();
			val2.index = "PeakTcnPatch.Passport.Crabland";
			val2.RefreshText();
		}
	}
	[HarmonyPatch]
	public class VersionStringPatch
	{
		private static bool _versionTextMissingWarned;

		[HarmonyPatch(typeof(VersionString), "Start")]
		[HarmonyPostfix]
		private static void PatchVersionStringWarnOnStart()
		{
			if (ReflectionMembers.Fields.VersionStringText == null && !_versionTextMissingWarned)
			{
				_versionTextMissingWarned = true;
				Plugin.Logger.LogWarning((object)"VersionString: 找不到版本資訊的 m_text 欄位!");
			}
		}

		[HarmonyPatch(typeof(VersionString), "Update")]
		[HarmonyPostfix]
		private static void PatchVersionString(VersionString __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)LocalizedText.CURRENT_LANGUAGE != 10 || !Plugin.ModConfig.ShowPatchCredit.Value)
			{
				return;
			}
			ReflectionMembers.TypedFieldInfo<VersionString, TextMeshProUGUI> versionStringText = ReflectionMembers.Fields.VersionStringText;
			if (versionStringText != null)
			{
				string name = ((Object)((Component)((Component)__instance).transform.GetParent()).gameObject).name;
				string name2 = ((Object)((Component)__instance).gameObject).name;
				if (!(name != "Logo") && !(name2 != "Version"))
				{
					TextMeshProUGUI reflectionFieldValue = __instance.GetReflectionFieldValue(versionStringText);
					bool flag = Plugin.ModConfig.ShowTranslatorCredit.Value && Plugin.CurrentTranslationFile.Authors.Count > 0 && Math.Floor(Time.realtimeSinceStartup / 10f) % 2.0 != 0.0;
					string text = "繁中翻譯by: " + string.Join("、", Plugin.CurrentTranslationFile.Authors);
					string text2 = (Plugin.ModConfig.ShowModVersionInPatchCredit.Value ? "繁中支援v1.3.0 by悠依" : "繁中支援by悠依");
					string text3 = (flag ? text : text2);
					((TMP_Text)reflectionFieldValue).text = ((TMP_Text)reflectionFieldValue).text + "  (" + text3 + ")";
				}
			}
		}
	}
}
namespace ue.Peak.TcnPatch.API
{
	public interface ITcnPatch
	{
		void RegisterLocalizationKey(string key, string unlocalized);
	}
	public class TcnPatch : ITcnPatch
	{
		public static ITcnPatch Instance => InternalInstance;

		internal static TcnPatch InternalInstance { get; } = new TcnPatch();


		public void RegisterLocalizationKey(string key, string unlocalized)
		{
			Plugin.RegisteredOrigTable[key] = unlocalized;
		}
	}
}
namespace ue.Peak.TcnPatch.Adapters
{
	public static class MoreAscentsSupport
	{
		private static readonly Lazy<Type> _gimmickHandlerType = new Lazy<Type>(() => Type.GetType("MoreAscents.AscentGimmickHandler"));

		private static bool _setupSupport;

		public static bool IsMoreAscentsInstalled => _gimmickHandlerType.Value != null;

		private static Type GimmickHandlerType => _gimmickHandlerType.Value;

		public static void RegisterLocalizations()
		{
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			if (!IsMoreAscentsInstalled)
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(GimmickHandlerType, "HasInitialized");
			if (fieldInfo == null)
			{
				return;
			}
			if (!(bool)fieldInfo.GetValue(null))
			{
				Plugin.Logger.LogWarning((object)"MoreAscents 還沒初始化!?");
			}
			else
			{
				if (_setupSupport)
				{
					return;
				}
				_setupSupport = true;
				Plugin.Logger.LogInfo((object)"偵測到 MoreAscents!正在為 MoreAscents 提供繁中支援...");
				try
				{
					if (!TryFindTypeOrWarn("MoreAscents.AscentGimmick", out var type2) || !TryFindMethodOrWarn(type2, "GetTitle", out var gimmickGetTitleMethod) || !TryFindMethodOrWarn(type2, "GetDescription", out var gimmickGetDescriptionMethod) || !TryFindMethodOrWarn(type2, "GetTitleReward", out var method2) || !TryFindFieldOrWarn(GimmickHandlerType, "gimmicks", out var field2))
					{
						return;
					}
					IReadOnlyList<object> readOnlyList = (IReadOnlyList<object>)field2.GetValue(null);
					MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(AscentData), "Instance");
					AscentData val = (AscentData)methodInfo.Invoke(null, Array.Empty<object>());
					List<AscentInstanceData> ascents = val.ascents;
					foreach (object gimmick in readOnlyList)
					{
						AscentInstanceData val2 = ((IEnumerable<AscentInstanceData>)ascents).FirstOrDefault((Func<AscentInstanceData, bool>)((AscentInstanceData d) => d.title == (string)gimmickGetTitleMethod.Invoke(gimmick, Array.Empty<object>()) && d.description == (string)gimmickGetDescriptionMethod.Invoke(gimmick, Array.Empty<object>())));
						if (val2 != null)
						{
							string text = (val2.title = "MoreAscent." + gimmick.GetType().Name);
							val2.titleReward = text + ".Reward";
							ue.Peak.TcnPatch.API.TcnPatch.Instance.RegisterLocalizationKey(text ?? "", (string)gimmickGetTitleMethod.Invoke(gimmick, Array.Empty<object>()));
							ue.Peak.TcnPatch.API.TcnPatch.Instance.RegisterLocalizationKey(LocalizedText.GetDescriptionIndex(text), (string)gimmickGetDescriptionMethod.Invoke(gimmick, Array.Empty<object>()));
							ue.Peak.TcnPatch.API.TcnPatch.Instance.RegisterLocalizationKey(text + ".Reward", (string)method2.Invoke(gimmick, Array.Empty<object>()));
						}
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)"無法為 MoreAscents 提供繁中支援... x_x");
					Plugin.Logger.LogError((object)ex);
				}
			}
			static bool TryFindFieldOrWarn(Type type, string fieldName, out FieldInfo field)
			{
				field = AccessTools.Field(type, fieldName);
				if (field != null)
				{
					return true;
				}
				Plugin.Logger.LogWarning((object)("無法找到 " + type.Name + "." + fieldName + " 欄位!無法為 MoreAscents 提供繁中支援... x_x"));
				return false;
			}
			static bool TryFindMethodOrWarn(Type type, string methodName, out MethodInfo method)
			{
				method = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
				if (method != null)
				{
					return true;
				}
				Plugin.Logger.LogWarning((object)("無法找到 " + type.Name + "." + methodName + "() 方法!無法為 MoreAscents 提供繁中支援... x_x"));
				return false;
			}
			static bool TryFindTypeOrWarn(string typeName, out Type type)
			{
				type = AccessTools.TypeByName(typeName);
				if (type != null)
				{
					return true;
				}
				Plugin.Logger.LogWarning((object)("無法找到 " + typeName + " 類型!無法為 MoreAscents 提供繁中支援... x_x"));
				return false;
			}
		}
	}
}