Decompiled source of AF JPRefine v1.0.0

AF_JPRefine.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.ResourceManagement.AsyncOperations;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Kuraputi")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AF_JPRefine")]
[assembly: AssemblyTitle("AF_JPRefine")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AF_JPRefine
{
	[BepInPlugin("Kuraputi.AF_JPRefine", "AF_JPRefine", "1.0.0")]
	public class AF_JPRefine : BaseUnityPlugin
	{
		private const string TableName = "Game";

		private ConfigEntry<bool> DumpEnabled;

		internal static AF_JPRefine Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Patch();
			DumpEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDump", false, "ゲーム起動時に翻訳データのダンプを行う(OFF推奨)");
			((MonoBehaviour)this).StartCoroutine(DumpTables());
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//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_0020: Expected O, but got Unknown
			//IL_0025: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
		}

		private IEnumerator DumpTables()
		{
			yield return null;
			AsyncOperationHandle<LocalizationSettings> init = LocalizationSettings.InitializationOperation;
			yield return init;
			if ((int)init.Status != 1)
			{
				Logger.LogError((object)$"Localization init failed: {init.OperationException}");
				yield break;
			}
			_ = LocalizationSettings.AvailableLocales.Locales;
			Locale ja = FindLocale("ja-JP", "Japanese");
			Locale en = FindLocale("en-US", "English");
			if ((Object)(object)ja == (Object)null || (Object)(object)en == (Object)null)
			{
				Logger.LogError((object)"Japanese or English locale not found.");
				yield break;
			}
			if (DumpEnabled.Value)
			{
				AsyncOperationHandle<IList<StringTable>> allJaOp = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetAllTables(ja);
				yield return allJaOp;
				if ((int)allJaOp.Status != 1 || allJaOp.Result == null)
				{
					Logger.LogError((object)"Failed to load Japanese tables.");
					yield break;
				}
				StringBuilder sb = new StringBuilder();
				sb.AppendLine("Table\tKeyId\tKey\tEnglish\tJapanese");
				int total = 0;
				foreach (StringTable jaTable in allJaOp.Result)
				{
					string tableName = ((LocalizationTable)jaTable).TableCollectionName;
					AsyncOperationHandle<StringTable> enOp = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTableAsync(TableReference.op_Implicit(tableName), en);
					yield return enOp;
					StringTable result = enOp.Result;
					int num = 0;
					foreach (SharedTableEntry entry3 in ((LocalizationTable)jaTable).SharedData.Entries)
					{
						object obj;
						if (result == null)
						{
							obj = null;
						}
						else
						{
							StringTableEntry entry = ((DetailedLocalizationTable<StringTableEntry>)(object)result).GetEntry(entry3.Id);
							obj = ((entry != null) ? entry.Value : null);
						}
						if (obj == null)
						{
							obj = "";
						}
						string s = (string)obj;
						StringTableEntry entry2 = ((DetailedLocalizationTable<StringTableEntry>)(object)jaTable).GetEntry(entry3.Id);
						string s2 = ((entry2 != null) ? entry2.Value : null) ?? "";
						sb.AppendLine($"{tableName}\t{entry3.Id}\t{entry3.Key}\t{Escape(s)}\t{Escape(s2)}");
						num++;
					}
					Logger.LogInfo((object)$"Table '{tableName}': {num} entries");
					total += num;
				}
				string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "dump_All.tsv");
				File.WriteAllText(text, sb.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
				Logger.LogInfo((object)$"Dumped {total} entries to {text}");
			}
			yield return ((MonoBehaviour)this).StartCoroutine(ApplyOverrides(ja));
			RefreshDisplayedTexts();
		}

		private static Locale? FindLocale(string code, string nameHint)
		{
			List<Locale> locales = LocalizationSettings.AvailableLocales.Locales;
			return ((IEnumerable<Locale>)locales).FirstOrDefault((Func<Locale, bool>)delegate(Locale l)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				LocaleIdentifier identifier = l.Identifier;
				return ((LocaleIdentifier)(ref identifier)).Code == code;
			}) ?? ((IEnumerable<Locale>)locales).FirstOrDefault((Func<Locale, bool>)((Locale l) => l.LocaleName.Contains(nameHint)));
		}

		private static string Escape(string s)
		{
			return s.Replace("\\", "\\\\").Replace("\t", "\\t").Replace("\r", "")
				.Replace("\n", "\\n");
		}

		private IEnumerator ApplyOverrides(Locale ja)
		{
			string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "translation_ja.tsv");
			if (!File.Exists(path))
			{
				Logger.LogWarning((object)("Translation file not found: " + path));
				yield break;
			}
			int applied = 0;
			int lineNo = 0;
			Dictionary<string, StringTable?> tableCache = new Dictionary<string, StringTable>();
			string[] array = File.ReadAllLines(path, Encoding.UTF8);
			foreach (string text in array)
			{
				lineNo++;
				if (string.IsNullOrWhiteSpace(text) || text.StartsWith("#") || text.StartsWith("Table\t"))
				{
					continue;
				}
				string[] array2 = text.Split('\t');
				string tableName;
				string key;
				string text2;
				if (array2.Length >= 5)
				{
					tableName = array2[0].Trim();
					key = array2[2].Trim();
					text2 = Unescape(array2[4]);
				}
				else
				{
					if (array2.Length < 3)
					{
						Logger.LogWarning((object)$"Line {lineNo}: column count is wrong ({array2.Length})");
						continue;
					}
					tableName = array2[0].Trim();
					key = array2[1].Trim();
					text2 = Unescape(array2[2]);
				}
				if (string.IsNullOrEmpty(text2))
				{
					continue;
				}
				if (!tableCache.TryGetValue(tableName, out StringTable value))
				{
					AsyncOperationHandle<StringTable> op = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTableAsync(TableReference.op_Implicit(tableName), ja);
					yield return op;
					value = (tableCache[tableName] = op.Result);
				}
				if ((Object)(object)value == (Object)null)
				{
					Logger.LogWarning((object)$"Line {lineNo}: table '{tableName}' not found");
					continue;
				}
				if (!((LocalizationTable)value).SharedData.Contains(key))
				{
					Logger.LogWarning((object)$"Line {lineNo}: key '{key}' not found in '{tableName}'");
					continue;
				}
				StringTableEntry entry = ((DetailedLocalizationTable<StringTableEntry>)(object)value).GetEntry(key);
				if (entry == null)
				{
					((DetailedLocalizationTable<StringTableEntry>)(object)value).AddEntry(key, text2);
				}
				else
				{
					entry.Value = text2;
				}
				applied++;
			}
			Logger.LogInfo((object)$"Applied {applied} translation overrides from {path}");
		}

		private static string Unescape(string s)
		{
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			for (int i = 0; i < s.Length; i++)
			{
				if (s[i] == '\\' && i + 1 < s.Length)
				{
					switch (s[i + 1])
					{
					case 'n':
						stringBuilder.Append('\n');
						i++;
						continue;
					case 't':
						stringBuilder.Append('\t');
						i++;
						continue;
					case '\\':
						stringBuilder.Append('\\');
						i++;
						continue;
					}
				}
				stringBuilder.Append(s[i]);
			}
			return stringBuilder.ToString();
		}

		private void RefreshDisplayedTexts()
		{
			LocalizeStringEvent[] array = Object.FindObjectsByType<LocalizeStringEvent>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			LocalizeStringEvent[] array2 = array;
			foreach (LocalizeStringEvent val in array2)
			{
				val.RefreshString();
			}
			Logger.LogInfo((object)$"Refreshed {array.Length} localized texts");
		}
	}
}