Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of REPO JP TranslationAndFont Updated v4.1.0
REPOJPTranslationAndFontUpdated.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using REPOJapaneseTranslation.Localization; using REPOJapaneseTranslation.Patches; using TMPro; using UnityEngine; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("LocalBuild")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Japanese localization and Checkpoint Revenge font mod for R.E.P.O. v0.4.4.")] [assembly: AssemblyFileVersion("4.1.0.0")] [assembly: AssemblyInformationalVersion("4.1.0")] [assembly: AssemblyProduct("REPO JP Translation and Font Updated")] [assembly: AssemblyTitle("REPOJPTranslationAndFontUpdated")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.1.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 REPOJapaneseTranslation { [BepInPlugin("local.REPOJPTranslationAndFontUpdated", "REPO JP Translation and Font Updated", "4.1.0")] [BepInProcess("REPO.exe")] public sealed class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("local.REPOJPTranslationAndFontUpdated"); internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<bool> EnableTranslation { get; private set; } internal static ConfigEntry<bool> EnableJapaneseFont { get; private set; } internal static ConfigEntry<float> FontSizeScale { get; private set; } internal static ConfigEntry<float> FontLineHeightScale { get; private set; } internal static ConfigEntry<bool> LogUntranslated { get; private set; } private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)((Component)this).gameObject); EnableTranslation = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableTranslation", true, "ゲーム内テキストを日本語へ翻訳します。"); EnableJapaneseFont = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableJapaneseFont", true, "チェックポイント★リベンジをTextMeshProへ適用します。"); FontSizeScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FontSizeScale", 0.72f, new ConfigDescription("日本語フォントの表示倍率。1.0がゲーム本来のフォントサイズです。", (AcceptableValueBase)new AcceptableValueRange<float>(0.5f, 1f), Array.Empty<object>())); FontLineHeightScale = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FontLineHeightScale", 1.35f, new ConfigDescription("複数行テキストの行高倍率。文字が重なる場合に大きくします。", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 2f), Array.Empty<object>())); LogUntranslated = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogUntranslated", false, "未翻訳テキストをBepInExログへ出力します(翻訳追加作業用)。"); TranslationManager.Initialize(((BaseUnityPlugin)this).Info.Location); FontManager.Initialize(((BaseUnityPlugin)this).Info.Location); _harmony.PatchAll(typeof(TMPTextTranslationPatch).Assembly); InstallTMPComponentHooks(); InstallUGUITextHooks(); Log.LogInfo((object)"REPO JP Translation and Font Updated v4.1.0 を読み込みました。"); Log.LogInfo((object)$"翻訳エントリ: {TranslationManager.TranslationCount}件"); } private void InstallTMPComponentHooks() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(TMPComponentRefreshHook), "Postfix", (Type[])null, (Type[])null); Type[] obj = new Type[2] { typeof(TextMeshProUGUI), typeof(TextMeshPro) }; int num = 0; Type[] array = obj; foreach (Type type in array) { MethodInfo methodInfo2 = AccessTools.Method(type, "OnEnable", (Type[])null, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)("TMP表示対象をパッチしました: " + type.Name + ".OnEnable")); num++; } } Log.LogInfo((object)$"TMP表示パッチ数: {num}"); } private void InstallUGUITextHooks() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(UGUITextRefreshHook), "Postfix", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(UGUITextSetterHook), "Prefix", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(Text), "OnEnable", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.PropertySetter(typeof(Text), "text"); int num = 0; if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"UGUI表示対象をパッチしました: Text.OnEnable"); num++; } if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"UGUI表示対象をパッチしました: Text.text"); num++; } Log.LogInfo((object)$"UGUI表示パッチ数: {num}"); } private void OnDestroy() { _harmony.UnpatchSelf(); } internal bool RefreshTextComponent(TMP_Text textComponent) { if (!FontManager.ShouldProcess(textComponent)) { return false; } if (!EnableTranslation.Value || string.IsNullOrEmpty(textComponent.text)) { return false; } string text = TranslationManager.Translate(textComponent.text); bool num = text != textComponent.text; if (num) { textComponent.text = text; } FontManager.AdjustTranslatedLayout(textComponent, text); return num; } internal bool RefreshTextComponent(Text textComponent) { if (!EnableTranslation.Value || string.IsNullOrEmpty(textComponent.text)) { return false; } string text = TranslationManager.Translate(textComponent.text); bool num = text != textComponent.text; if (num) { textComponent.text = text; } FontManager.AdjustTranslatedLayout(textComponent, text); return num; } } internal static class PluginInfo { public const string PLUGIN_GUID = "local.REPOJPTranslationAndFontUpdated"; public const string PLUGIN_NAME = "REPO JP Translation and Font Updated"; public const string PLUGIN_VERSION = "4.1.0"; } } namespace REPOJapaneseTranslation.Patches { [HarmonyPatch(typeof(ItemAttributes), "GetItemNameLocalized")] internal static class ItemAttributesLocalizedNamePatch { [HarmonyPostfix] private static void Postfix(ItemAttributes __instance, ref string __result) { string text = __result; string text2 = (((Object)(object)__instance != (Object)null && (Object)(object)__instance.item != (Object)null) ? __instance.item.itemName : null); if (string.IsNullOrWhiteSpace(text)) { text = text2; } if (!string.IsNullOrEmpty(text)) { string text3 = TranslationManager.Translate(text, logUntranslated: false); if (string.IsNullOrWhiteSpace(text3)) { text3 = text; } if (string.IsNullOrWhiteSpace(text3)) { text3 = text2; } __result = NormalizeItemName(text3); } } internal static string NormalizeItemName(string text) { if (string.IsNullOrEmpty(text)) { return text; } return text.Replace("\r\n", " ").Replace('\r', ' ').Replace('\n', ' ') .Trim(); } } [HarmonyPatch(typeof(StatsUI), "GetUpgradeDisplayName")] internal static class StatsUIUpgradeDisplayNamePatch { [HarmonyPostfix] private static void Postfix(ref string __result) { string text = __result; if (!string.IsNullOrWhiteSpace(text)) { string text2 = TranslationManager.Translate(text, logUntranslated: false); if (string.IsNullOrWhiteSpace(text2)) { text2 = text; } __result = ItemAttributesLocalizedNamePatch.NormalizeItemName(text2); } } } [HarmonyPatch(typeof(StatsUI), "Fetch")] internal static class StatsUIColumnLayoutPatch { [HarmonyPostfix] private static void Postfix(StatsUI __instance) { TextMeshProUGUI component = ((Component)__instance).GetComponent<TextMeshProUGUI>(); Transform val = ((Component)__instance).transform.Find("StatsNumbers"); TextMeshProUGUI val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TextMeshProUGUI>() : null); if (!((Object)(object)component == (Object)null) && !((Object)(object)val2 == (Object)null)) { ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontSize = ((TMP_Text)component).fontSize; ((TMP_Text)val2).fontSizeMin = ((TMP_Text)component).fontSizeMin; ((TMP_Text)val2).fontSizeMax = ((TMP_Text)component).fontSizeMax; ((TMP_Text)val2).enableAutoSizing = false; ((TMP_Text)val2).enableWordWrapping = false; ((TMP_Text)val2).overflowMode = (TextOverflowModes)0; ((TMP_Text)val2).lineSpacing = ((TMP_Text)component).lineSpacing; } } } [HarmonyPatch(typeof(ItemInfoUI), "ItemInfoText")] internal static class ItemInfoUITranslationPatch { [HarmonyPrefix] private static void Prefix(ref string message) { message = TranslationManager.Translate(message, logUntranslated: false); } } [HarmonyPatch(typeof(ItemInfoUI), "Update")] internal static class ItemInfoUIPositionPatch { [HarmonyPostfix] private static void Postfix(ItemInfoUI __instance) { //IL_0015: 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) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)((SemiUI)__instance).textRectTransform == (Object)null)) { Vector3 localPosition = ((SemiUI)__instance).textRectTransform.localPosition; localPosition.y += 3f; ((SemiUI)__instance).textRectTransform.localPosition = localPosition; } } } [HarmonyPatch(typeof(ItemInfoExtraUI), "ItemInfoText")] internal static class ItemInfoExtraUITranslationPatch { [HarmonyPrefix] private static void Prefix(ref string message) { message = TranslationManager.Translate(message, logUntranslated: false); } } [HarmonyPatch(typeof(ArenaMessageUI), "ArenaText")] internal static class ArenaMessageUITranslationPatch { [HarmonyPrefix] private static void Prefix(ref string message) { message = TranslationManager.Translate(message, logUntranslated: false); } } [HarmonyPatch(typeof(ArenaMessageWinUI), "ArenaText")] internal static class ArenaMessageWinUITranslationPatch { [HarmonyPrefix] private static void Prefix(ref string message) { message = TranslationManager.Translate(message, logUntranslated: false); } } [HarmonyPatch(typeof(MenuButton), "Awake")] internal static class MenuButtonTranslationPatch { [HarmonyPrefix] private static void Prefix() { FontManager.SuppressTMPTranslation = true; } [HarmonyPostfix] private static void Postfix(MenuButton __instance) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown FontManager.SuppressTMPTranslation = false; if ((Object)__instance == (Object)null) { return; } TextMeshProUGUI componentInChildren = ((Component)__instance).GetComponentInChildren<TextMeshProUGUI>(); if (string.Equals(__instance.buttonTextString, "BUTTON", StringComparison.Ordinal)) { if (!((Object)componentInChildren == (Object)null) && string.Equals(((TMP_Text)componentInChildren).text, "BUTTON", StringComparison.Ordinal)) { ((TMP_Text)componentInChildren).text = string.Empty; } } else if (!string.IsNullOrEmpty(__instance.buttonTextString) && !((Object)componentInChildren == (Object)null)) { string text = TranslationManager.Translate(__instance.buttonTextString); ((TMP_Text)componentInChildren).text = text; } } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception) { FontManager.SuppressTMPTranslation = false; return __exception; } } [HarmonyPatch(typeof(MenuButton), "RegisterHover")] internal static class LobbyButtonRowAlignmentPatch { [HarmonyPrefix] private static void Prefix(MenuButton __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if ((Object)__instance == (Object)null) { return; } string text = TranslationManager.Translate(__instance.buttonTextString); string text2; if (text == "招待") { text2 = "カスタマイズ"; } else { if (text != "はじめる") { return; } text2 = "退室"; } MenuPage componentInParent = ((Component)__instance).GetComponentInParent<MenuPage>(); if ((Object)componentInParent == (Object)null) { return; } MenuButton[] componentsInChildren = ((Component)componentInParent).GetComponentsInChildren<MenuButton>(true); foreach (MenuButton val in componentsInChildren) { if ((Object)val != (Object)null && TranslationManager.Translate(val.buttonTextString) == text2) { RectTransform component = ((Component)__instance).GetComponent<RectTransform>(); RectTransform component2 = ((Component)val).GetComponent<RectTransform>(); Vector3 position = ((Transform)component).position; position.y = ((Transform)component2).position.y; ((Transform)component).position = position; break; } } } } [HarmonyPatch(typeof(MenuManager), "PageOpen", new Type[] { typeof(MenuPageIndex), typeof(bool) })] internal static class MenuPageOpenTranslationPatch { [HarmonyPostfix] private static void Postfix(MenuPage __result) { MenuPageTranslator.TranslatePage(__result); } } [HarmonyPatch(typeof(MenuPageSaves), "SaveFileSelected")] internal static class MenuPageSavesSaveFileSelectedPatch { [HarmonyPostfix] private static void Postfix(MenuPageSaves __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_0174: Expected O, but got Unknown if ((Object)__instance == (Object)null) { return; } string newValue = TranslationManager.Translate("Total Haul:", logUntranslated: false); string newValue2 = TranslationManager.Translate("Current Moon:", logUntranslated: false); TMP_Text[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val in componentsInChildren) { if (!((Object)val == (Object)null) && !string.IsNullOrEmpty(val.text) && FontManager.ShouldProcess(val)) { string text = val.text; string text2 = text.Replace("Total Haul:", newValue).Replace("Current Moon:", newValue2); if (text2 != text) { val.text = text2; } FontManager.AdjustTranslatedLayout(val, text2); } } if (!((Object)__instance.saveFileHeader != (Object)null)) { return; } TextMeshProUGUI saveFileHeader = __instance.saveFileHeader; ((TMP_Text)saveFileHeader).enableWordWrapping = false; ((TMP_Text)saveFileHeader).overflowMode = (TextOverflowModes)0; ((TMP_Text)saveFileHeader).maxVisibleCharacters = int.MaxValue; float targetWidth = ((TMP_Text)saveFileHeader).GetPreferredValues(((TMP_Text)saveFileHeader).text).x + 8f; ExpandKeepingLeft(((TMP_Text)saveFileHeader).rectTransform, targetWidth); if ((Object)__instance.saveFileRenameButton != (Object)null) { RectTransform component = __instance.saveFileRenameButton.GetComponent<RectTransform>(); ExpandKeepingLeft(component, targetWidth); MenuButton component2 = __instance.saveFileRenameButton.GetComponent<MenuButton>(); if ((Object)component2 != (Object)null && (Object)component2.rectTransformSelection != (Object)null && (Object)component2.rectTransformSelection != (Object)component) { ExpandKeepingLeft(component2.rectTransformSelection, targetWidth); } } ((TMP_Text)saveFileHeader).ForceMeshUpdate(true, true); } private static void ExpandKeepingLeft(RectTransform rectTransform, float targetWidth) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) //IL_0032: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!((Object)rectTransform == (Object)null)) { Rect rect = rectTransform.rect; if (!(targetWidth <= ((Rect)(ref rect)).width)) { rect = rectTransform.rect; float num = targetWidth - ((Rect)(ref rect)).width; Vector2 anchoredPosition = rectTransform.anchoredPosition; anchoredPosition.x += num * rectTransform.pivot.x; rectTransform.SetSizeWithCurrentAnchors((Axis)0, targetWidth); rectTransform.anchoredPosition = anchoredPosition; } } } } [HarmonyPatch(typeof(MenuPage), "Start")] internal static class MenuPageStartTranslationPatch { [HarmonyPostfix] private static void Postfix(MenuPage __instance) { MenuPageTranslator.TranslatePage(__instance); } } internal static class MenuPageTranslator { internal static void TranslatePage(MenuPage? menuPage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if (!((Object)menuPage == (Object)null)) { menuPage.menuHeaderName = TranslationManager.Translate(menuPage.menuHeaderName, logUntranslated: false); TMP_Text[] componentsInChildren = ((Component)menuPage).GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { TranslateTextComponent(componentsInChildren[i]); } } } private static void TranslateTextComponent(TMP_Text text) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if (!((Object)text == (Object)null) && !string.IsNullOrEmpty(text.text) && FontManager.ShouldProcess(text)) { string text2 = TranslationManager.Translate(text.text, logUntranslated: false); if (text2 != text.text) { text.text = text2; } FontManager.AdjustTranslatedLayout(text, text2); } } } [HarmonyPatch(typeof(MenuManager), "PagePopUp")] internal static class MenuPopUpTranslationPatch { [HarmonyPrefix] private static void Prefix(ref string headerText, ref string bodyText, ref string buttonText) { headerText = TranslationManager.Translate(headerText); bodyText = TranslationManager.Translate(bodyText); buttonText = TranslationManager.Translate(buttonText); } } [HarmonyPatch(typeof(MenuManager), "PagePopUpTwoOptions")] internal static class MenuTwoOptionPopUpTranslationPatch { [HarmonyPrefix] private static void Prefix(ref string popUpHeader, ref string popUpText, ref string option1Text, ref string option2Text) { popUpHeader = TranslationManager.Translate(popUpHeader); popUpText = TranslationManager.Translate(popUpText); option1Text = TranslationManager.Translate(option1Text); option2Text = TranslationManager.Translate(option2Text); } } internal static class SkipPromptInputTagResolver { internal static void Resolve(TMP_Text skipText) { if (!((Object)(object)skipText == (Object)null) && !((Object)(object)InputManager.instance == (Object)null) && !string.IsNullOrEmpty(skipText.text) && skipText.text.IndexOf("[menu]", StringComparison.OrdinalIgnoreCase) >= 0) { string text = InputManager.instance.InputDisplayReplaceTags(skipText.text, "<color=#FF8500><u><b>", "</b></u></color>"); if (!string.Equals(text, skipText.text, StringComparison.Ordinal)) { skipText.text = text; } } } } [HarmonyPatch(typeof(MoonUI), "StateStart")] internal static class MoonUISkipPromptInputTagPatch { [HarmonyPostfix] private static void Postfix(MoonUI __instance) { SkipPromptInputTagResolver.Resolve((TMP_Text)(object)__instance.skipText); } } [HarmonyPatch(typeof(ResultScreenUI), "StateFadeIn")] internal static class ResultScreenUISkipPromptInputTagPatch { [HarmonyPostfix] private static void Postfix(ResultScreenUI __instance) { SkipPromptInputTagResolver.Resolve((TMP_Text)(object)__instance.skipText); } } internal static class TMPComponentRefreshHook { private static bool s_loggedFirstComponent; internal static void Postfix(TMP_Text __instance) { if (!s_loggedFirstComponent) { s_loggedFirstComponent = true; Plugin.Log.LogInfo((object)("TMP表示コンポーネントを検出しました: " + ((object)__instance).GetType().Name)); } Plugin.Instance.RefreshTextComponent(__instance); } } [HarmonyPatch] internal static class TMPFontPatch { [HarmonyPatch(typeof(RunManager), "Awake")] [HarmonyPostfix] private static void ApplyFontAfterSceneLoad() { FontManager.ApplyToAllTextComponents(); } } [HarmonyPatch] internal static class TMPTextTranslationPatch { [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { MethodInfo methodInfo = AccessTools.PropertySetter(typeof(TMP_Text), "text"); if (methodInfo != null) { yield return methodInfo; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(TMP_Text))) { if (!(declaredMethod.Name != "SetText")) { ParameterInfo[] parameters = declaredMethod.GetParameters(); if (parameters.Length != 0 && !(parameters[0].ParameterType != typeof(string))) { yield return declaredMethod; } } } } [HarmonyPrefix] private static void TranslateText(TMP_Text __instance, ref string __0) { if (!FontManager.SuppressTMPTranslation && FontManager.ShouldProcess(__instance)) { __0 = TranslationManager.Translate(__0); __0 = FontManager.NormalizeTranslatedMarkup(__instance, __0); FontManager.AdjustTranslatedLayout(__instance, __0); } } } [HarmonyPatch(typeof(TruckScreenText), "UpdateTaxmanNickname")] internal static class TruckScreenTextUpdateTaxmanNicknamePatch { [HarmonyPrefix] private static void Prefix(ref string newName) { newName = TranslationManager.Translate(newName, logUntranslated: false); } } [HarmonyPatch(typeof(TuckScreenLocked), "LockChatToggle")] internal static class TuckScreenLockedLockChatTogglePatch { [HarmonyPrefix] private static void Prefix(ref string _lockedText) { _lockedText = TranslationManager.Translate(_lockedText, logUntranslated: false); } } internal static class UGUITextRefreshHook { private static bool s_loggedFirstComponent; internal static void Postfix(Text __instance) { if (!s_loggedFirstComponent) { s_loggedFirstComponent = true; Plugin.Log.LogInfo((object)"UGUI Textコンポーネントを検出しました。"); } Plugin.Instance.RefreshTextComponent(__instance); } } internal static class UGUITextSetterHook { internal static void Prefix(Text __instance, ref string __0) { __0 = TranslationManager.Translate(__0); FontManager.AdjustTranslatedLayout(__instance, __0); } } } namespace REPOJapaneseTranslation.Localization { internal static class FontManager { private readonly struct LayoutProfile { internal float Scale { get; } internal float MinimumScale { get; } internal bool AllowWrapping { get; } internal bool AutoSizing { get; } internal float AdditionalLineSpacing { get; } internal bool ConstrainToBounds { get; } internal float AbsoluteSize { get; } internal LayoutProfile(float scale, float minimumScale, bool allowWrapping, bool autoSizing = true, float additionalLineSpacing = 0f, bool constrainToBounds = false, float absoluteSize = 0f) { Scale = scale; MinimumScale = minimumScale; AllowWrapping = allowWrapping; AutoSizing = autoSizing; AdditionalLineSpacing = additionalLineSpacing; ConstrainToBounds = constrainToBounds; AbsoluteSize = absoluteSize; } } private readonly struct TMPFontState { private WeakReference<TMP_Text> Owner { get; } internal TMP_FontAsset Font { get; } internal float FontSize { get; } internal float FontSizeMin { get; } internal float FontSizeMax { get; } internal bool AutoSizing { get; } internal bool WordWrapping { get; } internal TextOverflowModes Overflow { get; } internal float LineSpacing { get; } internal TMPFontState(TMP_Text component) { //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) Owner = new WeakReference<TMP_Text>(component); Font = component.font; FontSize = component.fontSize; FontSizeMin = component.fontSizeMin; FontSizeMax = component.fontSizeMax; AutoSizing = component.enableAutoSizing; WordWrapping = component.enableWordWrapping; Overflow = component.overflowMode; LineSpacing = component.lineSpacing; } internal bool Matches(TMP_Text component) { if (Owner.TryGetTarget(out TMP_Text target)) { return (Object)(object)target == (Object)(object)component; } return false; } internal void Restore(TMP_Text component) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) component.font = Font; component.fontSize = FontSize; component.fontSizeMin = FontSizeMin; component.fontSizeMax = FontSizeMax; component.enableAutoSizing = AutoSizing; component.enableWordWrapping = WordWrapping; component.overflowMode = Overflow; component.lineSpacing = LineSpacing; } } private readonly struct UGUIFontState { private WeakReference<Text> Owner { get; } internal Font Font { get; } internal int FontSize { get; } internal int MinSize { get; } internal int MaxSize { get; } internal bool BestFit { get; } internal HorizontalWrapMode Overflow { get; } internal UGUIFontState(Text component) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Owner = new WeakReference<Text>(component); Font = component.font; FontSize = component.fontSize; MinSize = component.resizeTextMinSize; MaxSize = component.resizeTextMaxSize; BestFit = component.resizeTextForBestFit; Overflow = component.horizontalOverflow; } internal bool Matches(Text component) { if (Owner.TryGetTarget(out Text target)) { return (Object)(object)target == (Object)(object)component; } return false; } internal void Restore(Text component) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) component.font = Font; component.fontSize = FontSize; component.resizeTextMinSize = MinSize; component.resizeTextMaxSize = MaxSize; component.resizeTextForBestFit = BestFit; component.horizontalOverflow = Overflow; } } private const string FontResourceName = "REPOJapaneseTranslation.fonts.CP_Revenge.ttf"; private const string FontEnginePatchId = "local.REPOJPTranslationAndFontUpdated.FontEngine"; private static readonly Dictionary<Font, byte[]> s_fontBytesByDummyFont = new Dictionary<Font, byte[]>(); private static readonly Dictionary<int, TMPFontState> s_originalTMPStates = new Dictionary<int, TMPFontState>(); private static readonly Dictionary<int, UGUIFontState> s_originalUGUIStates = new Dictionary<int, UGUIFontState>(); private static readonly HashSet<string> s_compactTitles = new HashSet<string>(StringComparer.Ordinal) { "ゲームプレイ", "グラフィックス", "オーディオ", "コントロール", "パスワード", "ロビー", "メインメニュー", "警告", "自爆", "ランダム", "プリセット", "セーブをロード", "ゲームをホストする", "設定を初期化", "デフォルト設定にリセット" }; private static readonly HashSet<string> s_dialogButtons = new HashSet<string>(StringComparer.Ordinal) { "はい", "はい!", "いいえ", "いいえ…", "戻る", "続ける", "スキップ", "わかりました", "セーブをロード", "セーブを削除" }; private static readonly HashSet<string> s_uniformMenuItems = new HashSet<string>(StringComparer.Ordinal) { "プライベート", "パブリック", "プライベートゲーム", "パブリックゲーム", "フレンドに参加", "シングルプレイ", "シングルプレイモード", "チュートリアル", "続ける", "カスタマイズ", "変更", "設定", "はじめる", "閉じる", "自爆", "メインメニュー", "タイトルに戻る", "ゲームを終わる", "ゲームを終了する" }; private static readonly HashSet<string> s_settingsRows = new HashSet<string>(StringComparer.Ordinal) { "ヒント", "プレイヤー名", "光感受性", "光過敏症設定", "クモ恐怖症", "照準感度", "エイム感度", "カメラスムージング", "カメラの滑らかさ", "カメラシェイク", "カメラの揺れ", "シャドウ距離", "モーションブラー", "レンズ歪み", "ブルーム", "色収差", "グレイン", "グリッチループ", "ピクセル化", "すべての音量", "音楽音量", "BGM", "効果音", "効果音音量", "近接音声", "近接ボイス音量", "読み上げ", "マイク音量", "プッシュトゥトーク", "掴む", "回転", "押す", "引く", "ウィンドウモード", "垂直同期", "ガンマ", "最大FPS", "ライト距離", "シャドウ品質", "シャドウ距離", "マスター音量", "テキスト読み上げ音量", "オン", "オフ", "デフォルト", "フルスクリーン", "ウィンドウ", "ボーダーレス", "低", "中", "高", "最高" }; private static readonly HashSet<string> s_extractionStatusLabels = new HashSet<string>(StringComparer.Ordinal) { "アクティブ", "準備完了", "未準備", "回収中", "完了", "回収ポイントが起動した", "回収ポイント完了" }; private static readonly HashSet<string> s_settingsNavigationItems = new HashSet<string>(StringComparer.Ordinal) { "ゲームプレイ", "グラフィック", "グラフィックス", "音声", "オーディオ", "コントロール", "操作", "戻る" }; private static readonly HashSet<string> s_settingsPageTitles = new HashSet<string>(StringComparer.Ordinal) { "ゲームプレイ", "グラフィック", "グラフィックス", "音声", "オーディオ", "コントロール", "操作" }; private static readonly HashSet<string> s_controlSectionTitles = new HashSet<string>(StringComparer.Ordinal) { "移動", "掴み動作", "その他", "プレイヤー表情" }; private static readonly HashSet<string> s_controlRows = new HashSet<string>(StringComparer.Ordinal) { "前", "前進", "左", "後", "後退", "右", "右移動", "ジャンプ", "しゃがむ", "スプリント", "転がる", "掴み", "回転", "押す", "引く", "引っぱる", "インベントリ1", "インベントリ2", "インベントリ3", "マップ", "インタラクト", "チャット", "次の観戦", "前の観戦", "プッシュトゥトーク", "表情 - 目を閉じる", "表情 - 怪しむ", "表情 - 悲しみ", "表情 - 怒り", "表情 - クレイジー", "表情 - 幸せ" }; private static TMP_FontAsset? s_checkpointFont; private static Font? s_checkpointUnityFont; private static bool s_initialized; private static bool s_fontEnginePatched; internal static bool SuppressTMPTranslation { get; set; } internal static void Initialize(string pluginLocation) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown if (s_initialized) { return; } s_initialized = true; if (!Plugin.EnableJapaneseFont.Value) { return; } try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("REPOJapaneseTranslation.fonts.CP_Revenge.ttf"); if (stream == null) { Plugin.Log.LogError((object)"埋め込みフォントが見つかりません: REPOJapaneseTranslation.fonts.CP_Revenge.ttf"); return; } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num == 0) { throw new EndOfStreamException("埋め込みフォントを最後まで読み取れませんでした。"); } } PatchFontEngine(); s_checkpointFont = CreateFontAsset(array); if ((Object)s_checkpointFont == (Object)null) { Plugin.Log.LogError((object)"チェックポイント★リベンジのTMPフォント生成に失敗しました。"); return; } ApplyToAllTextComponents(); Plugin.Log.LogInfo((object)$"チェックポイント★リベンジを読み込みました (埋め込み未改変TTF ({array.Length:N0} bytes))。"); } catch (Exception arg) { Plugin.Log.LogError((object)$"フォント初期化に失敗しました: {arg}"); } } internal static void ApplyToText(TMP_Text? textComponent) { if (ShouldProcess(textComponent) && ContainsJapanese(textComponent.text)) { AdjustTranslatedLayout(textComponent, textComponent.text); } } internal static bool ShouldProcess(TMP_Text? textComponent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)textComponent == (Object)null) { return false; } if (IsPlayerNameText(textComponent)) { return false; } string text = GetHierarchyPath(textComponent.transform).ToLowerInvariant(); return !text.Contains("monitor") && !text.Contains("truckscreen") && (!text.Contains("truck") || !text.Contains("screen")); } private static bool IsPlayerNameText(TMP_Text component) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_002b: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_004a: 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) //IL_005a: Expected O, but got Unknown //IL_005a: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_0089: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00cd: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_00ff: Expected O, but got Unknown MenuPlayerListed componentInParent = ((Component)component).GetComponentInParent<MenuPlayerListed>(); if ((Object)componentInParent != (Object)null && (Object)componentInParent.playerName == (Object)component) { return true; } WorldSpaceUIPlayerName componentInParent2 = ((Component)component).GetComponentInParent<WorldSpaceUIPlayerName>(); if ((Object)componentInParent2 != (Object)null && (Object)componentInParent2.text == (Object)component) { return true; } LobbyChatUI componentInParent3 = ((Component)component).GetComponentInParent<LobbyChatUI>(); if ((Object)componentInParent3 != (Object)null && (Object)componentInParent3.spectateName == (Object)component) { return true; } if ((Object)((Component)component).GetComponentInParent<SpectateNameUI>() != (Object)null) { return true; } PlayerListDisplay componentInParent4 = ((Component)component).GetComponentInParent<PlayerListDisplay>(); if ((Object)componentInParent4 != (Object)null && (Object)componentInParent4.playerListText == (Object)component) { return true; } MenuPageSaves componentInParent5 = ((Component)component).GetComponentInParent<MenuPageSaves>(); if ((Object)componentInParent5 != (Object)null) { return (Object)componentInParent5.saveFileInfoRow3 == (Object)component; } return false; } internal static void ApplyToText(Text? textComponent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)textComponent != (Object)null && ContainsJapanese(textComponent.text)) { AdjustTranslatedLayout(textComponent, textComponent.text); } } internal static void ApplyToAllTextComponents() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if ((Object)s_checkpointFont == (Object)null) { return; } TMP_Text[] array = Object.FindObjectsOfType<TMP_Text>(true); TMP_Text[] array2 = array; foreach (TMP_Text textComponent in array2) { if (ShouldProcess(textComponent)) { ApplyToText(textComponent); } } Plugin.Log.LogDebug((object)$"{array.Length}個のTMPテキストを確認しました。"); } internal static void AdjustTranslatedLayout(TMP_Text textComponent, string translatedText) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if (!Plugin.EnableJapaneseFont.Value || (Object)s_checkpointFont == (Object)null || !ShouldProcess(textComponent)) { return; } int instanceID = ((Object)textComponent).GetInstanceID(); if (!s_originalTMPStates.TryGetValue(instanceID, out var value) || !value.Matches(textComponent)) { value = new TMPFontState(textComponent); s_originalTMPStates[instanceID] = value; } if (!ContainsJapanese(translatedText)) { value.Restore(textComponent); if (IsSettingsHierarchy(GetHierarchyPath(textComponent.transform)) && ContainsDigit(translatedText)) { ApplyOriginalFontScale(textComponent, value, 0.78f); } return; } LayoutProfile layoutProfile = ResolveProfile(textComponent, translatedText); textComponent.font = s_checkpointFont; textComponent.enableAutoSizing = layoutProfile.AutoSizing; float val = ((layoutProfile.AbsoluteSize > 0f) ? layoutProfile.AbsoluteSize : (value.FontSize * layoutProfile.Scale)); float val2 = ((layoutProfile.AbsoluteSize > 0f) ? layoutProfile.AbsoluteSize : (value.FontSizeMax * layoutProfile.Scale)); float val3 = ((layoutProfile.AbsoluteSize > 0f) ? (layoutProfile.AbsoluteSize * layoutProfile.MinimumScale) : (value.FontSizeMax * layoutProfile.MinimumScale)); textComponent.fontSize = Math.Max(1f, val); textComponent.fontSizeMax = Math.Max(1f, val2); textComponent.fontSizeMin = Math.Max(1f, val3); textComponent.enableWordWrapping = layoutProfile.AllowWrapping; textComponent.overflowMode = (TextOverflowModes)layoutProfile.ConstrainToBounds; textComponent.lineSpacing = value.LineSpacing + layoutProfile.AdditionalLineSpacing; } internal static void AdjustTranslatedLayout(Text textComponent, string translatedText) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (Plugin.EnableJapaneseFont.Value && !((Object)s_checkpointUnityFont == (Object)null) && !((Object)textComponent == (Object)null)) { int instanceID = ((Object)textComponent).GetInstanceID(); if (!s_originalUGUIStates.TryGetValue(instanceID, out var value) || !value.Matches(textComponent)) { value = new UGUIFontState(textComponent); s_originalUGUIStates[instanceID] = value; } if (!ContainsJapanese(translatedText)) { value.Restore(textComponent); return; } float num = ResolveUGUIScale(translatedText); textComponent.font = s_checkpointUnityFont; textComponent.fontSize = Math.Max(1, (int)Math.Round((float)value.FontSize * num)); textComponent.resizeTextForBestFit = true; textComponent.resizeTextMinSize = Math.Max(1, (int)Math.Round((float)value.MaxSize * 0.28f)); textComponent.resizeTextMaxSize = Math.Max(1, (int)Math.Round((float)value.MaxSize * num)); textComponent.horizontalOverflow = (HorizontalWrapMode)(!translatedText.Contains('\n')); } } private static LayoutProfile ResolveProfile(TMP_Text component, string text) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_004d: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_009c: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_00e9: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_0136: Expected O, but got Unknown //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Expected O, but got Unknown //IL_0183: Expected O, but got Unknown string text2 = RemoveSimpleRichText(text).Trim(); string text3 = GetHierarchyPath(component.transform).ToLowerInvariant(); ItemInfoUI componentInParent = ((Component)component).GetComponentInParent<ItemInfoUI>(); if ((Object)componentInParent != (Object)null && (Object)component.transform == (Object)((Component)componentInParent).transform) { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 15f); } StatsUI componentInParent2 = ((Component)component).GetComponentInParent<StatsUI>(); if ((Object)componentInParent2 != (Object)null && (Object)component.transform == (Object)((Component)componentInParent2).transform) { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 20f); } MoonAttributeUI componentInParent3 = ((Component)component).GetComponentInParent<MoonAttributeUI>(); if ((Object)componentInParent3 != (Object)null && (Object)componentInParent3.text == (Object)component) { return new LayoutProfile(1f, 0.45f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: false, 10f); } MenuElementMoonAttribute componentInParent4 = ((Component)component).GetComponentInParent<MenuElementMoonAttribute>(); if ((Object)componentInParent4 != (Object)null && (Object)componentInParent4.text == (Object)component) { return new LayoutProfile(1f, 0.45f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 10f); } ExtractionPoint componentInParent5 = ((Component)component).GetComponentInParent<ExtractionPoint>(); if ((Object)componentInParent5 != (Object)null && (Object)componentInParent5.tubeScreenText == (Object)component) { return new LayoutProfile(0.55f, 0.42f, allowWrapping: false, autoSizing: false); } if (text2 == "モード: 強" || text2 == "モード: 弱") { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 10f); } if (IsExtractionHierarchy(text3) && s_extractionStatusLabels.Contains(text2)) { return new LayoutProfile(0.36f, 0.28f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); } bool flag = IsSettingsHierarchy(text3); bool flag2 = IsLeftSideOfScreen(component); bool flag3 = text3.Contains("lobby"); bool flag4 = IsLowerHalfOfScreen(component); if (s_settingsNavigationItems.Contains(text2) && flag2 && (flag || text2 == "操作")) { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 15f); } if (s_settingsPageTitles.Contains(text2) && flag && !flag2) { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 15f); } if (text2 == "設定" && !flag3 && flag4) { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 18f); } if (text2 == "設定" && flag && !flag3) { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 14f); } if (text2 == "デフォルト設定にリセット" && flag) { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 15f); } if (flag3 && text2 == "Tを押してチャット") { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 8f); } if (text2 == "地域") { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 18f); } if (text2 == "最適な地域を選択する") { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 11f); } if (flag3) { switch (text2) { case "カスタマイズ": case "退室": case "設定": case "招待": case "はじめる": return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 18f); } } if (IsFocusMissionHudText(text3, text2)) { return new LayoutProfile(1f, 0.78f, allowWrapping: true, autoSizing: false, 2f, constrainToBounds: false, 10f); } switch (text2) { case "パスワード": return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 24f); case "ロビー": return new LayoutProfile(0.46f, 0.23f, allowWrapping: false); case "セーブをロード": return new LayoutProfile(0.52f, 0.26f, allowWrapping: false); case "光敏感性発作についての警告": case "光過敏症の警告": return new LayoutProfile(0.62f, 0.52f, allowWrapping: true, autoSizing: false, 12f); case "サーバー一覧": return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 15f); default: if (text2.StartsWith("このゲームには点滅する光が含まれています。", StringComparison.Ordinal) || text2.StartsWith("<このゲームには光の点滅表現が含まれています>", StringComparison.Ordinal)) { return new LayoutProfile(0.65f, 0.54f, allowWrapping: true, autoSizing: false, 14f); } if (text2.StartsWith("一部の方は、光のパターンや点滅する光", StringComparison.Ordinal) || text2.StartsWith("一部の人は光や点滅や模様に晒されると", StringComparison.Ordinal)) { return new LayoutProfile(0.58f, 0.46f, allowWrapping: true, autoSizing: false, 24f); } if (text2 == "メニュー") { return new LayoutProfile(0.4f, 0.28f, allowWrapping: false); } if (s_uniformMenuItems.Contains(text2)) { return new LayoutProfile(1f, 0.78f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 20f); } if (text2.StartsWith("総回収額:", StringComparison.Ordinal) || text2.StartsWith("現在の月:", StringComparison.Ordinal)) { return new LayoutProfile(0.68f, 0.48f, allowWrapping: false); } switch (text2) { case "(クリックして名前変更)": return new LayoutProfile(0.52f, 0.36f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "シングルプレイモード": return new LayoutProfile(0.44f, 0.3f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "ウィンドウモード": return new LayoutProfile(0.23f, 0.16f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "モーションブラー": return new LayoutProfile(0.24f, 0.16f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "カメラの滑らかさ": case "カメラスムージング": return new LayoutProfile(0.22f, 0.15f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "カメラアニメーション": case "カメラの動き": return new LayoutProfile(0.22f, 0.15f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "アンチエイリアシング": return new LayoutProfile(0.22f, 0.15f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "リッチプレゼンス": return new LayoutProfile(0.22f, 0.15f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "アイテム自動装備": return new LayoutProfile(0.22f, 0.15f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); case "オフ": case "オン": return new LayoutProfile(0.48f, 0.34f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true); default: { if (s_controlSectionTitles.Contains(text2)) { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: false, 0f, constrainToBounds: false, 14f); } if (s_settingsRows.Contains(text2) || s_controlRows.Contains(text2)) { return new LayoutProfile(1f, 0.72f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true, 10f); } if (IsControlHierarchy(text3)) { return new LayoutProfile(1f, 0.58f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true, 10f); } if (text2 == "プリセット") { return new LayoutProfile(0.82f, 0.58f, allowWrapping: false); } if (text2 == "確認") { return new LayoutProfile(0.95f, 0.66f, allowWrapping: false); } if (text2.StartsWith("マイク", StringComparison.Ordinal)) { return new LayoutProfile(1f, 0.5f, allowWrapping: false, autoSizing: true, 0f, constrainToBounds: true, 9f); } if (s_dialogButtons.Contains(text2)) { return new LayoutProfile(0.58f, 0.3f, allowWrapping: false); } if (s_compactTitles.Contains(text2)) { return new LayoutProfile(0.52f, 0.25f, allowWrapping: false); } bool flag5 = text3.Contains("popup") || text3.Contains("dialog") || text3.Contains("confirm") || text3.Contains("warning"); bool flag6 = flag; bool num = text3.Contains("password"); bool flag7 = text3.Contains("lobby"); bool flag8 = text3.Contains("save"); if (num) { return new LayoutProfile(0.5f, 0.24f, text.Contains('\n')); } if (flag7) { return new LayoutProfile(0.5f, 0.24f, text.Contains('\n')); } if (flag8) { return new LayoutProfile(0.62f, 0.34f, text.Length > 18 || text.Contains('\n')); } if (flag6) { return new LayoutProfile(0.24f, 0.14f, text.Length > 20 || text.Contains('\n'), autoSizing: true, 0f, constrainToBounds: true); } if (flag5) { return new LayoutProfile(0.45f, 0.2f, allowWrapping: true, autoSizing: true, 0f, constrainToBounds: true); } if (text.Contains('\n') || text2.Length >= 18) { return new LayoutProfile(0.46f, 0.2f, allowWrapping: true, autoSizing: true, 0f, constrainToBounds: true); } return new LayoutProfile(Plugin.FontSizeScale.Value, 0.28f, allowWrapping: false); } } } } private static float ResolveUGUIScale(string text) { string text2 = RemoveSimpleRichText(text).Trim(); if (s_dialogButtons.Contains(text2)) { return 0.58f; } if (s_settingsRows.Contains(text2)) { return 0.47f; } if (s_compactTitles.Contains(text2)) { return 0.52f; } if (text2.Length < 18 && !text.Contains('\n')) { return Plugin.FontSizeScale.Value; } return 0.46f; } private static bool ContainsJapanese(string? text) { if (string.IsNullOrEmpty(text)) { return false; } foreach (char c in text) { if ((c >= '\u3040' && c <= 'ヿ') || (c >= '㐀' && c <= '鿿') || (c >= '豈' && c <= '\ufaff') || (c >= 'ヲ' && c <= '゚')) { return true; } } return false; } private static bool ContainsDigit(string? text) { if (string.IsNullOrEmpty(text)) { return false; } for (int i = 0; i < text.Length; i++) { if (char.IsDigit(text[i])) { return true; } } return false; } private static bool IsSettingsHierarchy(string hierarchy) { string text = hierarchy.ToLowerInvariant(); if (!text.Contains("setting") && !text.Contains("graphic") && !text.Contains("audio") && !text.Contains("control")) { return text.Contains("gameplay"); } return true; } private static bool IsControlHierarchy(string hierarchy) { string text = hierarchy.ToLowerInvariant(); if (!text.Contains("control") && !text.Contains("keybind")) { return text.Contains("input"); } return true; } private static bool IsExtractionHierarchy(string hierarchy) { string text = hierarchy.ToLowerInvariant(); if (!text.Contains("extraction") && !text.Contains("extractpoint")) { return text.Contains("extractionpoint"); } return true; } private static bool IsLeftSideOfScreen(TMP_Text component) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0020: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (Screen.width <= 0) { return false; } Canvas componentInParent = ((Component)component).GetComponentInParent<Canvas>(); return RectTransformUtility.WorldToScreenPoint(((Object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null, ((Transform)component.rectTransform).position).x <= (float)Screen.width * 0.48f; } private static bool IsLowerHalfOfScreen(TMP_Text component) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0020: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (Screen.height <= 0) { return false; } Canvas componentInParent = ((Component)component).GetComponentInParent<Canvas>(); return RectTransformUtility.WorldToScreenPoint(((Object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null, ((Transform)component.rectTransform).position).y <= (float)Screen.height * 0.5f; } internal static string NormalizeTranslatedMarkup(TMP_Text component, string text) { string hierarchy = GetHierarchyPath(component.transform).ToLowerInvariant(); string text2 = RemoveSimpleRichText(text).Trim(); if (text2 == "パスワード") { return "<voffset=0.65em>パスワード</voffset>"; } if (text2 == "サーバー一覧") { return "<voffset=-0.15em>サーバー一覧</voffset>"; } if (s_controlSectionTitles.Contains(text2)) { return text2; } if (!ShouldProcess(component) || !IsFocusMissionHudText(hierarchy, text2)) { return text; } return RemoveSizeTags(text); } private static bool IsFocusMissionHudText(string hierarchy, string text) { if (hierarchy.Contains("uifocustext") || hierarchy.Contains("localizedfocustext") || hierarchy.Contains("focustext")) { return true; } if (!text.StartsWith("FOCUS >", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("FOCUS>", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("目標 >", StringComparison.Ordinal) && !text.StartsWith("目標>", StringComparison.Ordinal) && !text.StartsWith("ミッション >", StringComparison.Ordinal) && !text.StartsWith("ミッション>", StringComparison.Ordinal) && !text.StartsWith("注目 >", StringComparison.Ordinal)) { return text.StartsWith("注目>", StringComparison.Ordinal); } return true; } private static string RemoveSizeTags(string text) { StringBuilder stringBuilder = new StringBuilder(text.Length); for (int i = 0; i < text.Length; i++) { if (text[i] == '<' && (text.AsSpan(i).StartsWith("<size=", StringComparison.OrdinalIgnoreCase) || text.AsSpan(i).StartsWith("</size>", StringComparison.OrdinalIgnoreCase))) { int num = text.IndexOf('>', i); if (num >= 0) { i = num; continue; } } stringBuilder.Append(text[i]); } return stringBuilder.ToString(); } private static void ApplyOriginalFontScale(TMP_Text component, TMPFontState original, float scale) { component.enableAutoSizing = false; component.fontSize = Math.Max(1f, original.FontSize * scale); component.fontSizeMax = Math.Max(1f, original.FontSizeMax * scale); component.fontSizeMin = Math.Max(1f, original.FontSizeMax * scale * 0.65f); component.overflowMode = (TextOverflowModes)0; } private static string GetHierarchyPath(Transform? transform) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if ((Object)transform == (Object)null) { return string.Empty; } string text = ((Object)transform).name; Transform parent = transform.parent; int num = 0; while ((Object)parent != (Object)null && num++ < 12) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private static string RemoveSimpleRichText(string text) { StringBuilder stringBuilder = new StringBuilder(text.Length); bool flag = false; foreach (char c in text) { if (c == '<') { flag = true; } else if (c == '>' && flag) { flag = false; } else if (!flag) { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private static TMP_FontAsset? CreateFontAsset(byte[] fontBytes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_003c: Expected O, but got Unknown //IL_003d: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown FontEngine.InitializeFontEngine(); FontEngineError val = FontEngine.LoadFontFace(fontBytes); if ((int)val != 0) { Plugin.Log.LogError((object)$"TTFの検証に失敗しました: {val}"); return null; } Font val2 = new Font("CP_Revenge"); s_checkpointUnityFont = val2; Font val3 = val2; s_fontBytesByDummyFont[val3] = fontBytes; TMP_FontAsset val4 = TMP_FontAsset.CreateFontAsset(val3); if ((Object)val4 == (Object)null) { s_fontBytesByDummyFont.Remove(val3); s_checkpointUnityFont = null; Object.Destroy((Object)val3); return null; } ((Object)val4).name = "Checkpoint Revenge Dynamic"; val4.atlasPopulationMode = (AtlasPopulationMode)1; FaceInfo faceInfo = val4.faceInfo; ((FaceInfo)(ref faceInfo)).lineHeight = ((FaceInfo)(ref faceInfo)).lineHeight * Plugin.FontLineHeightScale.Value; val4.faceInfo = faceInfo; ConfigureTextMeshProMaterial(val4); return val4; } private static void ConfigureTextMeshProMaterial(TMP_FontAsset fontAsset) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("TextMeshPro/Distance Field"); if ((Object)val == (Object)null) { Plugin.Log.LogWarning((object)"TextMeshPro/Distance Fieldシェーダーが見つかりません。"); return; } Material material = ((TMP_Asset)fontAsset).material; material.shader = val; if (material.HasProperty("_GlowColor")) { material.SetColor("_GlowColor", Color.clear); } if (material.HasProperty("_GlowPower")) { material.SetFloat("_GlowPower", 0f); } } private static void PatchFontEngine() { //IL_007c: 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) //IL_0091: Expected O, but got Unknown if (!s_fontEnginePatched) { MethodInfo method = typeof(FontEngine).GetMethod("LoadFontFace", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Font), typeof(int) }, null); MethodInfo method2 = typeof(FontManager).GetMethod("LoadFontFacePrefix", BindingFlags.Static | BindingFlags.NonPublic); if (method == null || method2 == null) { throw new MissingMethodException("FontEngine.LoadFontFace(Font, int) が見つかりません。"); } new Harmony("local.REPOJPTranslationAndFontUpdated.FontEngine").Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); s_fontEnginePatched = true; } } private static bool LoadFontFacePrefix(Font font, int pointSize, ref FontEngineError __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected I4, but got Unknown if ((Object)font == (Object)null || !s_fontBytesByDummyFont.TryGetValue(font, out byte[] value)) { return true; } __result = (FontEngineError)(int)FontEngine.LoadFontFace(value, pointSize); return false; } } internal static class TranslationManager { private sealed class TranslationTemplate { private readonly Regex _pattern; private readonly string _translatedTemplate; private readonly string[] _placeholderTokens; internal int SourceLength { get; } private TranslationTemplate(Regex pattern, string translatedTemplate, string[] placeholderTokens, int sourceLength) { _pattern = pattern; _translatedTemplate = translatedTemplate; _placeholderTokens = placeholderTokens; SourceLength = sourceLength; } internal static TranslationTemplate Create(string sourceTemplate, string translatedTemplate) { MatchCollection matchCollection = s_placeholderTokenRegex.Matches(sourceTemplate); StringBuilder stringBuilder = new StringBuilder(); string[] array = new string[matchCollection.Count]; stringBuilder.Append('^'); int num = 0; int num2; for (int i = 0; i < matchCollection.Count; i++) { Match match = matchCollection[i]; num2 = num; stringBuilder.Append(Regex.Escape(sourceTemplate.Substring(num2, match.Index - num2))); stringBuilder.Append($"(?<p{i}>.+?)"); array[i] = match.Value; num = match.Index + match.Length; } num2 = num; stringBuilder.Append(Regex.Escape(sourceTemplate.Substring(num2, sourceTemplate.Length - num2))); stringBuilder.Append('$'); return new TranslationTemplate(new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant), translatedTemplate, array, sourceTemplate.Length); } internal bool TryTranslate(string text, out string result) { Match match = _pattern.Match(text); if (!match.Success) { result = text; return false; } Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); for (int i = 0; i < _placeholderTokens.Length; i++) { string key = _placeholderTokens[i]; if (!dictionary.ContainsKey(key)) { dictionary[key] = match.Groups[$"p{i}"].Value; } } result = _translatedTemplate; foreach (KeyValuePair<string, string> item in dictionary) { item.Deconstruct(out var key2, out var value); string oldValue = key2; string newValue = value; result = result.Replace(oldValue, newValue, StringComparison.Ordinal); } return true; } } private static readonly string[] s_originalTranslationResources = new string[4] { "REPOJapaneseTranslation.original.TranslationJP_Main.txt", "REPOJapaneseTranslation.original.TranslationJP_MOD.txt", "REPOJapaneseTranslation.original.TranslationJP_Other.txt", "REPOJapaneseTranslation.original.TranslationJP_Upgrade.txt" }; private static readonly Regex s_placeholderTokenRegex = new Regex("\\{[^{}]+\\}|\\[[^\\[\\]]+\\]", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex s_actionSuffixRegex = new Regex("^(?<body>.+?)(?<suffix>\\s*(?:<[^>]+>)*\\[[^\\[\\]]+\\](?:</[^>]+>)*\\s*)$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex s_richTextSuffixRegex = new Regex("^(?<body>.+?)(?<suffix>\\s*(?:<[^>]+>)+\\s*)$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex s_labeledPrefixRegex = new Regex("^(?<leadingTags>(?:<[^>]+>)*)(?<label>[^<>]+?)(?<separator>\\s*>\\s*)(?<trailingTags>(?:</[^>]+>)*)(?<body>.+)$", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Dictionary<string, string> s_translations = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<string, string> s_translationsUpper = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly List<TranslationTemplate> s_templates = new List<TranslationTemplate>(); private static readonly HashSet<string> s_loggedUntranslated = new HashSet<string>(StringComparer.Ordinal); private static bool s_initialized; internal static int TranslationCount => s_translations.Count; internal static void Initialize(string pluginLocation) { if (s_initialized) { return; } s_initialized = true; Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream("REPOJapaneseTranslation.translations.ja.json"); if (stream == null) { Plugin.Log.LogError((object)"埋め込みリソース 'REPOJapaneseTranslation.translations.ja.json' が見つかりません。"); return; } using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); LoadJson(streamReader.ReadToEnd()); string[] array = s_originalTranslationResources; foreach (string resourceName in array) { LoadXUnityResource(executingAssembly, resourceName); } string path = Path.Combine(Path.GetDirectoryName(pluginLocation) ?? string.Empty, "translations.custom.json"); if (File.Exists(path)) { LoadJson(File.ReadAllText(path, Encoding.UTF8)); Plugin.Log.LogInfo((object)"translations.custom.jsonを追加読み込みしました。"); } RebuildTemplates(); Plugin.Log.LogInfo((object)$"翻訳辞書を読み込みました: {s_translations.Count} 件"); } private static void LoadXUnityResource(Assembly assembly, string resourceName) { using Stream stream = assembly.GetManifestResourceStream(resourceName); if (stream == null) { Plugin.Log.LogWarning((object)("原版翻訳リソースが見つかりません: " + resourceName)); return; } using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); LoadXUnityText(streamReader.ReadToEnd()); } private static void LoadXUnityText(string contents) { using StringReader stringReader = new StringReader(contents); string text; while ((text = stringReader.ReadLine()) != null) { string text2 = text.TrimStart(); if (text2.Length != 0 && !text2.StartsWith("//", StringComparison.Ordinal)) { int num = FindUnescapedSeparator(text); if (num > 0) { string source = UnescapeXUnity(text.Substring(0, num).Trim()); string translated = UnescapeXUnity(text.Substring(num + 1)); AddTranslation(source, translated); } } } } private static int FindUnescapedSeparator(string line) { for (int i = 0; i < line.Length; i++) { if (line[i] == '=' && (i == 0 || line[i - 1] != '\\')) { return i; } } return -1; } private static string UnescapeXUnity(string text) { StringBuilder stringBuilder = new StringBuilder(text.Length); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c != '\\' || i + 1 >= text.Length) { stringBuilder.Append(c); continue; } char c2 = text[++i]; switch (c2) { case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case '=': case '\\': stringBuilder.Append(c2); break; default: stringBuilder.Append('\\').Append(c2); break; } } return stringBuilder.ToString(); } private static void LoadJson(string json) { //IL_0077: Expected O, but got Unknown try { Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json); if (dictionary == null) { return; } foreach (var (text3, translated) in dictionary) { if (!string.IsNullOrEmpty(text3) && text3[0] != '_' && !text3.StartsWith("//", StringComparison.Ordinal)) { AddTranslation(text3, translated); } } } catch (JsonException ex) { JsonException ex2 = ex; Plugin.Log.LogError((object)("翻訳JSONのパースに失敗しました: " + ((Exception)(object)ex2).Message)); } } private static void AddTranslation(string source, string translated) { if (!string.IsNullOrEmpty(source)) { string text = NormalizeKey(source); string value = NormalizeTranslationValue(translated); s_translations[text] = value; s_translationsUpper[text.ToUpperInvariant()] = value; } } private static void RebuildTemplates() { s_templates.Clear(); foreach (KeyValuePair<string, string> s_translation in s_translations) { if (s_placeholderTokenRegex.IsMatch(s_translation.Key)) { s_templates.Add(TranslationTemplate.Create(s_translation.Key, s_translation.Value)); } } s_templates.Sort((TranslationTemplate left, TranslationTemplate right) => right.SourceLength.CompareTo(left.SourceLength)); } internal static string Translate(string text, bool logUntranslated = true) { if (!Plugin.EnableTranslation.Value || string.IsNullOrEmpty(text)) { return text; } SplitOuterWhitespace(text, out string leadingWhitespace, out string coreText, out string trailingWhitespace); if (coreText.Length == 0) { return text; } if (TryTranslateCore(coreText, out string result)) { return leadingWhitespace + result + trailingWhitespace; } if (logUntranslated && Plugin.LogUntranslated.Value && s_loggedUntranslated.Add(text)) { Plugin.Log.LogInfo((object)("[未翻訳] \"" + text.Replace("\n", "\\n") + "\"")); } return text; } private static bool TryTranslateCore(string text, out string result) { if (TryTranslateInlineText(text, out result)) { return true; } if (TryTranslateMultilineBlock(text, out result)) { return true; } result = text; return false; } private static bool TryTranslateInlineText(string text, out string result) { if (TryTranslateLookup(text, out result)) { return true; } if (TryTranslateTemplate(text, out result)) { return true; } if (TryTranslateLabeledPrefix(text, out result)) { return true; } if (TryTranslateRichTextSuffix(text, out result)) { return true; } if (TryTranslateActionSuffix(text, out result)) { return true; } if (TryTranslatePhraseSequence(text, out result)) { return true; } result = text; return false; } private static bool TryTranslateLookup(string text, out string result) { if (s_translations.TryGetValue(text, out result)) { return true; } string text2 = NormalizeKey(text); if (text2 != text && s_translations.TryGetValue(text2, out result)) { return true; } string key = text2.ToUpperInvariant(); if (s_translationsUpper.TryGetValue(key, out result)) { return true; } result = text; return false; } private static bool TryTranslateTemplate(string text, out string result) { string text2 = NormalizeKey(text); foreach (TranslationTemplate s_template in s_templates) { if (s_template.TryTranslate(text2, out result)) { return true; } } result = text; return false; } private static bool TryTranslateLabeledPrefix(string text, out string result) { Match match = s_labeledPrefixRegex.Match(text); if (!match.Success) { result = text; return false; } string value = match.Groups["leadingTags"].Value; string value2 = match.Groups["label"].Value; string value3 = match.Groups["separator"].Value; string value4 = match.Groups["trailingTags"].Value; if (!TryTranslateCore(match.Groups["body"].Value, out string result2)) { result = text; return false; } string result3; string text2 = (TryTranslateLookup(value2, out result3) ? result3 : value2); result = value + text2 + value3 + value4 + result2; return true; } private static bool TryTranslateActionSuffix(string text, out string result) { Match match = s_actionSuffixRegex.Match(text); if (!match.Success) { result = text; return false; } string value = match.Groups["body"].Value; string value2 = match.Groups["suffix"].Value; if (!TryTranslateLookup(value, out string result2) && !TryTranslateTemplate(value, out result2) && !TryTranslatePhraseSequence(value, out result2)) { result = text; return false; } result = result2 + value2; return true; } private static bool TryTranslateRichTextSuffix(string text, out string result) { Match match = s_richTextSuffixRegex.Match(text); if (!match.Success) { result = text; return false; } string value = match.Groups["body"].Value; string value2 = match.Groups["suffix"].Value; if (!TryTranslateLookup(value, out string result2) && !TryTranslateTemplate(value, out result2) && !TryTranslatePhraseSequence(value, out result2)) { result = text; return false; } result = result2 + value2; return true; } private static bool TryTranslateMultilineBlock(string text, out string result) { if (!text.Contains('\n')) { result = text; return false; } string[] array = text.Split('\n'); bool flag = false; for (int i = 0; i < array.Length; i++) { string text2 = array[i]; if (string.IsNullOrWhiteSpace(text2)) { continue; } SplitOuterWhitespace(text2, out string leadingWhitespace, out string coreText, out string trailingWhitespace); if (coreText.Length != 0 && TryTranslateInlineText(coreText, out string result2)) { string text3 = leadingWhitespace + result2 + trailingWhitespace; if (!(text3 == text2)) { array[i] = text3; flag = true; } } } result = (flag ? string.Join("\n", array) : text); return flag; } private static bool TryTranslatePhraseSequence(string text, out string result) { result = text; if (!CanUsePhraseSegmentation(text)) { return false; } SplitNumericPrefix(text, out string prefix, out string body); if (body.Length == 0) { return false; } string[] array = body.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (array.Length < 2) { return false; } List<string> list = new List<string>(); int matchedTokenCount; for (int i = 0; i < array.Length; i += matchedTokenCount) { if (!TryMatchLongestPhrase(array, i, out matchedTokenCount, out string translatedFragment)) { return false; } list.Add(translatedFragment); } if (list.Count < 2) { return false; } result = prefix + string.Join("\n", list); return true; } private static bool TryMatchLongestPhrase(IReadOnlyList<string> tokens, int startIndex, out int matchedTokenCount, out string translatedFragment) { int val = tokens.Count - startIndex; for (int num = Math.Min(5, val); num >= 1; num--) { if (TryTranslateLookup(string.Join(" ", tokens, startIndex, num), out translatedFragment)) { matchedTokenCount = num; return true; } } matchedTokenCount = 0; translatedFragment = string.Empty; return false; } private static bool CanUsePhraseSegmentation(string text) { bool result = false; foreach (char c in text) { if (char.IsLetter(c)) { result = true; } else if (!char.IsDigit(c) && !char.IsWhiteSpace(c) && c != '\'' && c != '-' && c != '(' && c != ')' && c != '&') { return false; } } return result; } private static void SplitNumericPrefix(string text, out string prefix, out string body) { int i; for (i = 0; i < text.Length && char.IsDigit(text[i]); i++) { } if (i == 0 || i >= text.Length || !char.IsWhiteSpace(text[i])) { prefix = string.Empty; body = text; return; } for (; i < text.Length && char.IsWhiteSpace(text[i]); i++) { } prefix = text.Substring(0, i); int num = i; body = text.Substring(num, text.Length - num); } private static void SplitOuterWhitespace(string text, out string leadingWhitespace, out string coreText, out string trailingWhitespace) { int i; for (i = 0; i < text.Length && char.IsWhiteSpace(text[i]); i++) { } int num = text.Length - 1; while (num >= i && char.IsWhiteSpace(text[num])) { num--; } leadingWhitespace = text.Substring(0, i); string text2; if (i > num) { text2 = string.Empty; } else { int num2 = i; text2 = text.Substring(num2, num + 1 - num2); } coreText = text2; string text3; if (num + 1 >= text.Length) { text3 = string.Empty; } else { int num3 = num + 1; text3 = text.Substring(num3, text.Length - num3); } trailingWhitespace = text3; } private static string NormalizeKey(string text) { return text.Replace("\r\n", "\n").Trim(); } private static string NormalizeTranslationValue(string text) { return text.TrimStart(' ', '\t', '\u3000'); } } }