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 OnlyKorean PureKorean v0.3.7
BepInEx/plugins/OnlyKoreanPureKorean/OnlyKorean.PureKorean.dll
Decompiled 21 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using OnlyKorean.KoreanSupport; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.TextCore.LowLevel; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("OnlyKorean.PureKorean")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.7.0")] [assembly: AssemblyInformationalVersion("0.3.7")] [assembly: AssemblyProduct("OnlyKorean.PureKorean")] [assembly: AssemblyTitle("OnlyKorean.PureKorean")] [assembly: AssemblyVersion("0.3.7.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OnlyKorean.KoreanSupport { internal static class KoreanSupport { private static byte[]? _fontBytes; private static Font? _proxy; private static TMP_FontAsset? _font; private static bool _installed; private static bool _fontWarning; private static float _nextScan; private static float _lastCompositionAt = -100f; private static int _lastCompositionField; private static Terminal? _terminal; private static bool _needsSceneScan; private static readonly Queue<TMP_Text> PendingFonts = new Queue<TMP_Text>(); private static readonly HashSet<TMP_InputField> Inputs = new HashSet<TMP_InputField>(); private static Action<string>? _log; internal static TMP_FontAsset? Font { get { EnsureFont(); return _font; } } internal static bool Initialize(Harmony harmony, string assetDirectory, Action<string>? log = null) { //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown if (_installed) { return _fontBytes != null; } _installed = true; _log = log; Patch(harmony, typeof(FontEngine), "LoadFontFace", "LoadBundledFace", new Type[2] { typeof(Font), typeof(int) }); Patch(harmony, typeof(TMP_InputField), "KeyPressed", "BeforeInputKey", new Type[1] { typeof(Event) }); Patch(harmony, typeof(TMP_InputField), "OnUpdateSelected", "BeforeInputUpdate"); Patch(harmony, typeof(Terminal), "OnSubmit", "BeforeTerminalSubmit"); Patch(harmony, typeof(HUDManager), "SubmitChat_performed", "BeforeChatSubmit"); MethodInfo methodInfo = AccessTools.Method(typeof(TextMeshProUGUI), "OnEnable", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(KoreanSupport), "AfterTextEnabled", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo2 = AccessTools.Method(typeof(TextMeshPro), "OnEnable", (Type[])null, (Type[])null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(KoreanSupport), "AfterTextEnabled", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo3 = AccessTools.Method(typeof(Terminal), "Awake", (Type[])null, (Type[])null); if (methodInfo3 != null) { harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(KoreanSupport), "AfterTerminalAwake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } SceneManager.sceneLoaded += SceneLoaded; _needsSceneScan = true; try { _fontBytes = File.ReadAllBytes(Path.Combine(assetDirectory, "Orbit-Regular.ttf")); if (_fontBytes.Length < 1024) { throw new InvalidDataException("Font file is incomplete."); } _proxy = new Font("OnlyKorean bundled Orbit") { hideFlags = (HideFlags)61 }; return true; } catch (Exception ex) { _fontBytes = null; _log?.Invoke("Bundled Korean font unavailable: " + ex.GetType().Name); return false; } } private static void Patch(Harmony harmony, Type type, string method, string prefix, Type[]? args = null) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown MethodInfo methodInfo = ((args == null) ? AccessTools.Method(type, method, (Type[])null, (Type[])null) : AccessTools.Method(type, method, args, (Type[])null)); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(KoreanSupport), prefix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { _log?.Invoke("Korean input hook unavailable: " + type.Name + "." + method); } } private static bool LoadBundledFace(Font __0, int __1, ref FontEngineError __result) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected I4, but got Unknown if ((Object)(object)_proxy == (Object)null || (Object)(object)__0 != (Object)(object)_proxy || _fontBytes == null) { return true; } __result = (FontEngineError)(int)FontEngine.LoadFontFace(_fontBytes, __1); return false; } private static void EnsureFont() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_font != (Object)null || (Object)(object)_proxy == (Object)null || _fontBytes == null) { return; } try { _font = TMP_FontAsset.CreateFontAsset(_proxy, 48, 5, (GlyphRenderMode)4165, 1024, 1024, (AtlasPopulationMode)1, true); if ((Object)(object)_font == (Object)null) { throw new InvalidOperationException("TMP did not create the bundled font."); } ((Object)_font).name = "OnlyKorean Orbit"; ((Object)_font).hideFlags = (HideFlags)61; ((Object)((TMP_Asset)_font).material).hideFlags = (HideFlags)61; ((TMP_Asset)_font).material.SetColor(ShaderUtilities.ID_FaceColor, Color.white); ((TMP_Asset)_font).material.SetFloat(ShaderUtilities.ID_FaceDilate, 0f); ((TMP_Asset)_font).material.SetFloat(ShaderUtilities.ID_OutlineWidth, 0f); _font.TryAddCharacters("우리말지킴이음성채팅신호판정중평범한잡음해석불가처벌없음이전말", false); } catch (Exception ex) { if (!_fontWarning) { _fontWarning = true; _log?.Invoke("Korean font creation deferred: " + ex.GetType().Name); } } } internal static void ApplyFont(TMP_Text? text) { if (!((Object)(object)text == (Object)null)) { EnsureFont(); if (!((Object)(object)_font == (Object)null) && (!((Object)(object)text.font != (Object)null) || !(((Object)text.font).name == "OnlyKorean Orbit"))) { text.font = _font; text.fontSharedMaterial = ((TMP_Asset)_font).material; ((Graphic)text).SetAllDirty(); } } } internal static void ConfigureInput(TMP_InputField? field) { if (!((Object)(object)field == (Object)null)) { Inputs.Add(field); field.characterValidation = (CharacterValidation)0; field.inputType = (InputType)0; ApplyFont(field.textComponent); Graphic placeholder = field.placeholder; TMP_Text val = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null); if (val != null) { ApplyFont(val); } } } internal static void Tick() { if (!_installed) { return; } if (_needsSceneScan) { _needsSceneScan = false; _terminal = Object.FindObjectOfType<Terminal>(); TMP_Text[] array = Object.FindObjectsOfType<TMP_Text>(true); foreach (TMP_Text item in array) { PendingFonts.Enqueue(item); } } for (int j = 0; j < 24; j++) { if (PendingFonts.Count <= 0) { break; } ApplyFont(PendingFonts.Dequeue()); } foreach (TMP_InputField input in Inputs) { if (!((Object)(object)input == (Object)null) && input.isFocused) { ObserveComposition(input); } } if (!(Time.realtimeSinceStartup < _nextScan)) { _nextScan = Time.realtimeSinceStartup + 1f; EnsureFont(); Inputs.RemoveWhere((TMP_InputField field) => (Object)(object)field == (Object)null); ConfigureInput(HUDManager.Instance?.chatTextField); if ((Object)(object)_terminal != (Object)null) { ConfigureInput(_terminal.screenText); } } } internal static void Shutdown() { SceneManager.sceneLoaded -= SceneLoaded; PendingFonts.Clear(); } private static bool IsSupported(TMP_InputField field) { if (!Inputs.Contains(field) && (!((Object)(object)HUDManager.Instance != (Object)null) || !((Object)(object)field == (Object)(object)HUDManager.Instance.chatTextField))) { if ((Object)(object)_terminal != (Object)null) { return (Object)(object)field == (Object)(object)_terminal.screenText; } return false; } return true; } private static void ObserveComposition(TMP_InputField field) { if (!string.IsNullOrEmpty(Input.compositionString)) { _lastCompositionAt = Time.realtimeSinceStartup; _lastCompositionField = ((Object)field).GetInstanceID(); } } private static bool IsImeCommit(TMP_InputField? field) { if ((Object)(object)field == (Object)null || !IsSupported(field)) { return false; } ObserveComposition(field); if (_lastCompositionField == ((Object)field).GetInstanceID()) { return Time.realtimeSinceStartup - _lastCompositionAt < 0.15f; } return false; } private static void BeforeInputUpdate(TMP_InputField __instance) { if (IsSupported(__instance)) { ConfigureInput(__instance); if (__instance.isFocused) { ObserveComposition(__instance); } } } private static void BeforeInputKey(TMP_InputField __instance, Event __0) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if (IsSupported(__instance)) { ObserveComposition(__instance); if (((int)__0.keyCode == 13 || (int)__0.keyCode == 271) && IsImeCommit(__instance)) { __0.keyCode = (KeyCode)0; __0.character = '\0'; } } } private static bool BeforeTerminalSubmit(Terminal __instance) { ConfigureInput(__instance.screenText); return !IsImeCommit(__instance.screenText); } private static bool BeforeChatSubmit(HUDManager __instance) { ConfigureInput(__instance.chatTextField); return !IsImeCommit(__instance.chatTextField); } private static void SceneLoaded(Scene scene, LoadSceneMode mode) { _needsSceneScan = true; } private static void AfterTerminalAwake(Terminal __instance) { _terminal = __instance; ConfigureInput(__instance.screenText); } private static void AfterTextEnabled(TMP_Text __instance) { ApplyFont(__instance); } } } namespace OnlyKorean.PureKorean { [HarmonyPatch(typeof(TerminalAccessibleObject), "SetCodeTo")] internal static class CodeSetPatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(TerminalAccessibleObject __instance) { KoreanCodeLabels.Apply(__instance); } } [HarmonyPatch(typeof(TerminalAccessibleObject), "InitializeValues")] internal static class CodeInitializePatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(TerminalAccessibleObject __instance) { KoreanCodeLabels.Apply(__instance); } } internal sealed class KoreanCodeLabels : MonoBehaviour { private static readonly FieldInfo RadarText = AccessTools.Field(typeof(TerminalAccessibleObject), "mapRadarText"); private readonly Dictionary<MeshRenderer, TextMeshPro> plates = new Dictionary<MeshRenderer, TextMeshPro>(); private readonly Dictionary<MeshRenderer, bool> originalVisibility = new Dictionary<MeshRenderer, bool>(); internal static void Apply(TerminalAccessibleObject source) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Plugin.Instance == (Object)null || (Object)(object)source == (Object)null) { return; } string text = TerminalInput.DisplayCode(source.objectCode); if (text == source.objectCode) { return; } object? obj = RadarText?.GetValue(source); TextMeshProUGUI val = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null); if ((Object)(object)val != (Object)null) { OnlyKorean.KoreanSupport.KoreanSupport.ApplyFont((TMP_Text?)(object)val); ((TMP_Text)val).text = text; ((TMP_Text)val).enableAutoSizing = true; } if (source.codeMaterials == null || (Object)(object)OnlyKorean.KoreanSupport.KoreanSupport.Font == (Object)null) { return; } KoreanCodeLabels koreanCodeLabels = ((Component)source).GetComponent<KoreanCodeLabels>() ?? ((Component)source).gameObject.AddComponent<KoreanCodeLabels>(); MeshRenderer[] codeMaterials = source.codeMaterials; foreach (MeshRenderer val2 in codeMaterials) { if ((Object)(object)val2 == (Object)null) { continue; } if (!koreanCodeLabels.plates.TryGetValue(val2, out TextMeshPro value) || (Object)(object)value == (Object)null) { MeshFilter component = ((Component)val2).GetComponent<MeshFilter>(); Mesh val3 = ((component != null) ? component.sharedMesh : null); if ((Object)(object)val3 == (Object)null) { continue; } Bounds bounds = val3.bounds; float[] sizes = new float[3] { ((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z }; Vector3[] array = (Vector3[])(object)new Vector3[3] { Vector3.right, Vector3.up, Vector3.forward }; int[] array2 = (from num in Enumerable.Range(0, 3) orderby sizes[num] descending select num).ToArray(); if (sizes[array2[1]] < 1E-05f) { continue; } Vector3 val4 = array[array2[0]]; Vector3 val5 = array[array2[1]]; Vector3 val6 = Vector3.Cross(val4, val5); Vector3 val7 = ((Vector3)(ref val6)).normalized; if (val3.isReadable && val3.normals.Length != 0) { Vector3 val8 = val3.normals[0]; if (Vector3.Dot(val7, val8) < 0f) { val7 = -val7; } } GameObject val9 = new GameObject("OnlyKoreanDoorCode", new Type[1] { typeof(RectTransform) }) { layer = ((Component)val2).gameObject.layer }; val9.transform.SetParent(((Component)val2).transform, false); val9.transform.localPosition = ((Bounds)(ref bounds)).center + val7 * Mathf.Max(0.0002f, sizes[array2[0]] * 0.002f); val9.transform.localRotation = Quaternion.LookRotation(-val7, val5); value = val9.AddComponent<TextMeshPro>(); ((TMP_Text)value).font = OnlyKorean.KoreanSupport.KoreanSupport.Font; ((TMP_Text)value).rectTransform.sizeDelta = new Vector2(sizes[array2[0]] * 0.95f, sizes[array2[1]] * 0.95f); ((TMP_Text)value).alignment = (TextAlignmentOptions)514; ((Graphic)value).color = new Color(0.85f, 1f, 0.8f, 1f); ((TMP_Text)value).enableAutoSizing = true; ((TMP_Text)value).fontSizeMin = 0.01f; ((TMP_Text)value).fontSizeMax = 150f; ((TMP_Text)value).enableWordWrapping = false; ((TMP_Text)value).overflowMode = (TextOverflowModes)0; ((TMP_Text)value).richText = false; koreanCodeLabels.plates[val2] = value; koreanCodeLabels.originalVisibility[val2] = ((Renderer)val2).enabled; } ((TMP_Text)value).text = text; ((TMP_Text)value).ForceMeshUpdate(true, true); if (((TMP_Text)value).textInfo.characterCount > 0) { ((Renderer)val2).enabled = false; } } } private void OnDestroy() { foreach (KeyValuePair<MeshRenderer, bool> item in originalVisibility) { if ((Object)(object)item.Key != (Object)null) { ((Renderer)item.Key).enabled = item.Value; } } foreach (KeyValuePair<MeshRenderer, TextMeshPro> plate in plates) { if ((Object)(object)plate.Value != (Object)null) { Object.Destroy((Object)(object)((Component)plate.Value).gameObject); } } } } internal static class ControlHints { private static readonly FieldInfo Actions = AccessTools.Field(typeof(PlayerControllerB), "playerActions"); internal static string? Binding(InputActionAsset? asset, string name, bool controller) { //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) InputAction val = ((asset != null) ? asset.FindAction(name, false) : null); if (val == null) { return null; } for (int i = 0; i < val.bindings.Count; i++) { InputBinding val2 = val.bindings[i]; string text = ((InputBinding)(ref val2)).effectivePath ?? ""; if (((InputBinding)(ref val2)).isComposite || ((InputBinding)(ref val2)).isPartOfComposite || text.Length == 0 || controller != text.StartsWith("<Gamepad>", StringComparison.OrdinalIgnoreCase) || (!controller && !text.StartsWith("<Keyboard>", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("<Mouse>", StringComparison.OrdinalIgnoreCase))) { continue; } string text2 = text.Substring(text.IndexOf('/') + 1); if (text.StartsWith("<Keyboard>", StringComparison.OrdinalIgnoreCase)) { if (text2.Length != 1) { return InputActionRebindingExtensions.GetBindingDisplayString(val, i, (DisplayStringOptions)0); } return text2.ToUpperInvariant(); } if (text.StartsWith("<Mouse>", StringComparison.OrdinalIgnoreCase)) { return text2 switch { "leftButton" => "LMB", "rightButton" => "RMB", "middleButton" => "MMB", _ => InputActionRebindingExtensions.GetBindingDisplayString(val, i, (DisplayStringOptions)0), }; } return text2 switch { "buttonWest" => "왼쪽 단추", "buttonEast" => "오른쪽 단추", "buttonNorth" => "위쪽 단추", "buttonSouth" => "아래쪽 단추", _ => InputActionRebindingExtensions.GetBindingDisplayString(val, i, (DisplayStringOptions)0), }; } return "없음"; } internal static string? For(PlayerControllerB player, string action) { InputActionAsset actions = InputSystem.actions; if (((actions != null) ? actions.FindAction(action, false) : null) != null) { return Binding(InputSystem.actions, action, StartOfRound.Instance?.localPlayerUsingController ?? false); } if ((Object)(object)player == (Object)null) { return null; } object? value = Actions.GetValue(player); object? obj = ((value is PlayerActions) ? value : null); return Binding((obj != null) ? ((PlayerActions)obj).asset : null, action, StartOfRound.Instance?.localPlayerUsingController ?? false); } } [HarmonyPatch(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger")] internal static class InteractHintPatch { private static void Postfix(PlayerControllerB __instance) { if (!((Object)(object)__instance.cursorTip == (Object)null)) { string text = ControlHints.For(__instance, "Interact"); if (text != null) { string text2 = ((TMP_Text)__instance.cursorTip).text; StartOfRound instance = StartOfRound.Instance; string oldValue = ((instance != null && instance.localPlayerUsingController) ? "[X]" : "[E]"); ((TMP_Text)__instance.cursorTip).text = text2.Replace(oldValue, "[" + text + "]"); } } } } [HarmonyPatch(typeof(GrabbableObject), "SetControlTipsForItem")] internal static class HeldItemHintPatch { private static void Postfix(GrabbableObject __instance) { PlayerControllerB playerHeldBy = __instance.playerHeldBy; HUDManager instance = HUDManager.Instance; if ((Object)(object)playerHeldBy == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)playerHeldBy != (Object)(object)GameNetworkManager.Instance?.localPlayerController) { return; } string text = ControlHints.For(playerHeldBy, "ActivateItem"); string text2 = ControlHints.For(playerHeldBy, "Discard"); TextMeshProUGUI[] controlTipLines = instance.controlTipLines; foreach (TextMeshProUGUI val in controlTipLines) { if (!((Object)(object)val == (Object)null)) { string text3 = ((TMP_Text)val).text; if (text != null) { text3 = text3.Replace("[LMB]", "[" + text + "]"); } if (text2 != null) { text3 = text3.Replace("[G]", "[" + text2 + "]"); } ((TMP_Text)val).text = text3; } } } } internal static class DisplayRules { private static readonly Dictionary<string, string> Weather = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { ["DustClouds"] = "흙먼지", ["Dust Clouds"] = "흙먼지", ["Rainy"] = "비", ["Stormy"] = "비바람", ["Foggy"] = "안개", ["Flooded"] = "물잠김", ["Eclipsed"] = "해가림" }; private const string Latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private const string Hangul = "ㅁㅠㅊㅇㄷㄹㅎㅗㅑㅓㅏㅣㅡㅜㅐㅔㅂㄱㄴㅅㅕㅍㅈㅌㅛㅋ"; private static readonly Dictionary<string, string> Keys = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { ["LMB"] = "왼쪽 누름", ["RMB"] = "오른쪽 누름", ["MMB"] = "가운데 누름", ["Left mouse button"] = "왼쪽 누름", ["Right mouse button"] = "오른쪽 누름", ["Scroll"] = "굴림쇠", ["Mouse scroll"] = "굴림쇠", ["Scroll wheel"] = "굴림쇠", ["Space"] = "띄움", ["Spacebar"] = "띄움", ["Tab"] = "칸 넘김", ["Shift"] = "윗글", ["Left Shift"] = "왼쪽 윗글", ["Ctrl"] = "누름", ["Control"] = "누름", ["Left Ctrl"] = "왼쪽 누름", ["Alt"] = "바꿈", ["Esc"] = "나가기", ["Escape"] = "나가기", ["Enter"] = "줄바꿈", ["Return"] = "줄바꿈", ["Backspace"] = "뒤 지움", ["Delete"] = "지움", ["Up"] = "↑", ["Down"] = "↓", ["Left"] = "←", ["Right"] = "→", ["L-Alt"] = "왼쪽 바꿈", ["L-Shift"] = "왼쪽 윗글", ["L-Ctrl"] = "왼쪽 누름", ["R-Trigger"] = "오른쪽 아래 누름", ["L-Trigger"] = "왼쪽 아래 누름", ["L-Shoulder"] = "왼쪽 위 누름", ["R-Shoulder"] = "오른쪽 위 누름", ["Left Button"] = "왼쪽 누름", ["Right Button"] = "오른쪽 누름", ["Middle Button"] = "가운데 누름" }; internal static string TraditionalWeight(double grams) { if (double.IsNaN(grams) || double.IsInfinity(grams) || grams < 0.0) { return "0돈"; } (double, string)[] array = new(double, string)[5] { (60000.0, "칭"), (3750.0, "관"), (600.0, "근"), (37.5, "냥"), (3.75, "돈") }; for (int i = 0; i < array.Length; i++) { (double, string) tuple = array[i]; if (grams >= tuple.Item1 || tuple.Item2 == "돈") { return (grams / tuple.Item1).ToString("0.#", CultureInfo.InvariantCulture) + tuple.Item2; } } return "0돈"; } internal static string WeatherText(string text) { string[] array = Regex.Split(text, "(<[^>]*>)"); for (int i = 0; i < array.Length; i += 2) { array[i] = Regex.Replace(array[i], "(?<![A-Za-z])Weather\\s*:\\s*None\\b", "날씨: 맑음", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); array[i] = Regex.Replace(array[i], "(?<![A-Za-z])Weather(?=\\s*:)", "날씨", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); array[i] = Regex.Replace(array[i], "(?<![A-Za-z])(?:DustClouds|Dust Clouds|Rainy|Stormy|Foggy|Flooded|Eclipsed)(?![A-Za-z])", (Match m) => Weather[m.Value], RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); array[i] = Regex.Replace(array[i], "날씨\\s*:\\s*None\\b", "날씨: 맑음", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); } return string.Concat(array); } internal static string KeyName(string key) { string text = key.Trim(); if (Regex.IsMatch(text, "^(?:[A-Za-z]/){1,3}[A-Za-z]$")) { return string.Join("/", Array.ConvertAll(text.Split('/'), KeyName)); } if (text.Equals("WASD", StringComparison.OrdinalIgnoreCase)) { return "ㅈㅁㄴㅇ"; } if (text.Length == 1) { int num = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".IndexOf(char.ToUpperInvariant(text[0])); if (num >= 0) { return "ㅁㅠㅊㅇㄷㄹㅎㅗㅑㅓㅏㅣㅡㅜㅐㅔㅂㄱㄴㅅㅕㅍㅈㅌㅛㅋ"[num].ToString(); } } if (Keys.TryGetValue(text, out string value)) { return value; } if (Regex.IsMatch(text, "^F(?:[1-9]|1[0-2])$", RegexOptions.IgnoreCase)) { return "윗줄 " + text.Substring(1); } return key; } internal static string PreserveBindings(string source, string translated) { MatchCollection before = Regex.Matches(source, "\\[([^\\[\\]\\r\\n]+)\\]"); MatchCollection matchCollection = Regex.Matches(translated, "\\[([^\\[\\]\\r\\n]+)\\]"); if (before.Count != matchCollection.Count) { return translated; } int index = 0; return Regex.Replace(translated, "\\[([^\\[\\]\\r\\n]+)\\]", delegate(Match m) { Match match = before[index++]; return (!(KeyName(match.Groups[1].Value) != match.Groups[1].Value)) ? m.Value : match.Value; }); } internal static string Format(string text) { return Format(text, formatKeys: true); } internal static string Format(string text, bool formatKeys) { text = WeatherText(text); text = Regex.Replace(text, "(?<![\\p{L}\\p{N}])([0-9]+(?:\\.[0-9]+)?)\\s*(lbs?\\b|파운드|kg\\b)", (Match m) => TraditionalWeight(double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture) * ((m.Groups[2].Value == "kg") ? 1000.0 : 453.59237))); text = Regex.Replace(text, "\\bDrop(?=\\s*(?::|\\[))", "놓기", RegexOptions.IgnoreCase); text = Regex.Replace(text, "(?<![\\p{L}\\p{N}_])[vV](\\d+(?:\\.\\d+)*)(?![\\p{L}\\p{N}_])", "ㅍ$1"); if (formatKeys) { text = Regex.Replace(text, "\\[([^\\[\\]\\r\\n]{1,24})\\]", (Match m) => "[" + KeyName(m.Groups[1].Value) + "]"); } text = Regex.Replace(text, "\\$(?=\\s*\\d)", "₩"); text = Regex.Replace(text, "\\b배치(?=\\s*:)", "놓기"); text = Regex.Replace(text, "\\b회전(?=\\s*:)", "돌리기"); text = Regex.Replace(text, "\\b확정(?=\\s*:)", "마치기"); return text.Replace("위태로운 만큼", "위태로움").Replace("벌어야 할 몫:", "채울 몫:"); } internal static string SystemNotice(string text) { Match match = Regex.Match(text, "^(.*) joined the ship\\.$", RegexOptions.Singleline); if (match.Success) { return match.Groups[1].Value + " 님이 배에 올랐습니다."; } Match match2 = Regex.Match(text, "^(.*) (?:left the ship|disconnected)\\.$", RegexOptions.Singleline); if (match2.Success) { return match2.Groups[1].Value + " 님이 배를 떠났습니다."; } Match match3 = Regex.Match(text, "^(.*) started the ship\\.$", RegexOptions.Singleline); if (match3.Success) { return match3.Groups[1].Value + " 님이 배를 출발시켰습니다."; } Match match4 = Regex.Match(text, "^(.*) was left behind\\.$", RegexOptions.Singleline); if (match4.Success) { return match4.Groups[1].Value + " 님이 남겨졌습니다."; } return text; } } internal static class ImageGeometry { internal static void Apply(Graphic image, Texture? source, VertexHelper mesh) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_049c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || mesh.currentVertCount == 0) { return; } bool flag = ((Object)source).name == "LogoTextV1"; if (!flag && ((Object)source).name != "endgameStatsDeceased" && ((Object)source).name != "endgameStatsMissing") { return; } Texture2D val = Plugin.Instance?.Textures?.Replacement(source); if ((Object)(object)val == (Object)null) { return; } UIVertex simpleVert = UIVertex.simpleVert; mesh.PopulateUIVertex(ref simpleVert, 0); Vector3 val2 = simpleVert.position; Vector3 val3 = simpleVert.position; Vector2 val4 = Vector4.op_Implicit(simpleVert.uv0); Vector2 val5 = val4; for (int i = 1; i < mesh.currentVertCount; i++) { mesh.PopulateUIVertex(ref simpleVert, i); val2 = Vector3.Min(val2, simpleVert.position); val3 = Vector3.Max(val3, simpleVert.position); val4 = Vector2.Min(val4, Vector4.op_Implicit(simpleVert.uv0)); val5 = Vector2.Max(val5, Vector4.op_Implicit(simpleVert.uv0)); } float num = val3.x - val2.x; float num2 = val3.y - val2.y; float num3 = val5.x - val4.x; float num4 = val5.y - val4.y; if (num <= 0f || num2 <= 0f || num3 <= 0f || num4 <= 0f) { return; } Image val6 = (Image)(object)((image is Image) ? image : null); if (val6 != null && (Object)(object)val6.overrideSprite != (Object)null) { Rect rect = val6.overrideSprite.rect; Vector2 val7 = default(Vector2); ((Vector2)(ref val7))..ctor(((Rect)(ref rect)).xMin / (float)source.width, ((Rect)(ref rect)).yMin / (float)source.height); Vector2 val8 = default(Vector2); ((Vector2)(ref val8))..ctor(((Rect)(ref rect)).xMax / (float)source.width, ((Rect)(ref rect)).yMax / (float)source.height); Vector2 val9 = default(Vector2); ((Vector2)(ref val9))..ctor(num / num3, num2 / num4); val2.x -= (val4.x - val7.x) * val9.x; val2.y -= (val4.y - val7.y) * val9.y; val3.x += (val8.x - val5.x) * val9.x; val3.y += (val8.y - val5.y) * val9.y; val4 = val7; val5 = val8; num = val3.x - val2.x; num2 = val3.y - val2.y; num3 = val5.x - val4.x; num4 = val5.y - val4.y; Color color = image.color; mesh.Clear(); mesh.AddVert(new Vector3(val2.x, val2.y, val2.z), Color32.op_Implicit(color), Vector4.op_Implicit(new Vector2(val4.x, val4.y))); mesh.AddVert(new Vector3(val2.x, val3.y, val2.z), Color32.op_Implicit(color), Vector4.op_Implicit(new Vector2(val4.x, val5.y))); mesh.AddVert(new Vector3(val3.x, val3.y, val2.z), Color32.op_Implicit(color), Vector4.op_Implicit(new Vector2(val5.x, val5.y))); mesh.AddVert(new Vector3(val3.x, val2.y, val2.z), Color32.op_Implicit(color), Vector4.op_Implicit(new Vector2(val5.x, val4.y))); mesh.AddTriangle(0, 1, 2); mesh.AddTriangle(2, 3, 0); } if (flag) { float num5 = num3 * (float)((Texture)val).width / (num4 * (float)((Texture)val).height); float num6 = 1f; float num7 = 1f; if (num / num2 > num5) { num6 = num2 * num5 / num; } else { num7 = num / num5 / num2; } Vector3 val10 = (val2 + val3) * 0.5f; for (int j = 0; j < mesh.currentVertCount; j++) { mesh.PopulateUIVertex(ref simpleVert, j); simpleVert.position = new Vector3(val10.x + (simpleVert.position.x - val10.x) * num6, val10.y + (simpleVert.position.y - val10.y) * num7, simpleVert.position.z); mesh.SetUIVertex(simpleVert, j); } } } } [HarmonyPatch(typeof(Image), "OnPopulateMesh", new Type[] { typeof(VertexHelper) })] internal static class TranslatedImageGeometryPatch { private static void Postfix(Image __instance, VertexHelper toFill) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)__instance.type == 0) { Sprite overrideSprite = __instance.overrideSprite; ImageGeometry.Apply((Graphic)(object)__instance, (Texture?)(object)((overrideSprite != null) ? overrideSprite.texture : null), toFill); } } } [HarmonyPatch(typeof(RawImage), "OnPopulateMesh", new Type[] { typeof(VertexHelper) })] internal static class LogoRawGeometryPatch { private static void Postfix(RawImage __instance, VertexHelper vh) { ImageGeometry.Apply((Graphic)(object)__instance, __instance.texture, vh); } } internal static class LiveText { internal static string Translate(string value) { return TranslatePending(value, formatKeys: true); } internal static string TranslatePending(string value, bool formatKeys) { TranslationData translationData = Plugin.Instance?.Data; if (translationData == null || string.IsNullOrEmpty(value)) { return value; } string[] array = (from n in (from p in StartOfRound.Instance?.allPlayerScripts?.Where((PlayerControllerB p) => (Object)(object)p != (Object)null && !string.IsNullOrEmpty(p.playerUsername)) select p.playerUsername).Distinct() orderby n.Length descending select n).ToArray() ?? Array.Empty<string>(); if (array.Contains(value)) { return value; } Dictionary<string, string> dictionary = new Dictionary<string, string>(); string[] array2 = array; foreach (string text in array2) { string marker = "\ue000" + dictionary.Count + "\ue001"; string pattern = "(?<![\\p{L}\\p{N}_])" + Regex.Escape(text) + "(?![\\p{L}\\p{N}_])"; value = Regex.Replace(value, pattern, (Match _) => marker); dictionary[marker] = text; } value = DisplayRules.Format(DisplayRules.PreserveBindings(value, translationData.TranslateStatic(value)), formatKeys); foreach (KeyValuePair<string, string> item in dictionary) { value = value.Replace(item.Key, item.Value); } return value; } internal static bool IsGameLabel(TMP_Text text) { if ((Object)(object)text == (Object)null) { return false; } TMP_InputField componentInParent = ((Component)text).GetComponentInParent<TMP_InputField>(true); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.placeholder != (Object)(object)text) { return false; } if ((Object)(object)HUDManager.Instance != (Object)null && ((Object)(object)text == (Object)(object)HUDManager.Instance.chatText || (Object)(object)text == (Object)(object)HUDManager.Instance.signalTranslatorText)) { return false; } if ((Object)(object)HUDManager.Instance != (Object)null && (Object)(object)text == (Object)(object)HUDManager.Instance.typingIndicator) { return true; } Transform val = text.transform; while ((Object)(object)val != (Object)null) { string text2 = ((Object)val).name.ToLowerInvariant(); if (text2.Contains("username") || text2.Contains("playername") || text2.Contains("lobbyname") || text2.Contains("servername") || text2.Contains("speech history") || text2.Contains("chattext") || text2.Contains("signaltranslatortext")) { return false; } val = val.parent; } return true; } internal static void Refresh() { TMP_Text[] array = Object.FindObjectsOfType<TMP_Text>(true); for (int i = 0; i < array.Length; i++) { Apply(array[i]); } } internal static void Apply(TMP_Text label) { TextLayout.Apply(label); if (IsGameLabel(label) && !string.IsNullOrEmpty(label.text)) { string text = Translate(label.text); if (text != label.text) { label.text = text; } } } } [HarmonyPatch(typeof(TextMeshProUGUI), "OnPreRenderCanvas")] internal static class RenderTextPatch { private static void Prefix(TextMeshProUGUI __instance) { if ((Object)(object)Plugin.Instance == (Object)null || !((UIBehaviour)__instance).IsActive() || !((TMP_Text)__instance).havePropertiesChanged) { return; } TextLayout.Apply((TMP_Text)(object)__instance); if (LiveText.IsGameLabel((TMP_Text)(object)__instance) && !string.IsNullOrEmpty(((TMP_Text)__instance).text)) { string text = LiveText.Translate(((TMP_Text)__instance).text); if (text != ((TMP_Text)__instance).text) { ((TMP_Text)__instance).text = text; } OnlyKorean.KoreanSupport.KoreanSupport.ApplyFont((TMP_Text?)(object)__instance); } } } [HarmonyPatch] internal static class TerminalOpenDataPatch { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo methodInfo = AccessTools.Method(typeof(Terminal), "BeginUsingTerminal", (Type[])null, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } private static void Prefix(Terminal __instance) { if (!((Object)(object)Plugin.Instance == (Object)null)) { TextLayout.ConfigureTerminal(__instance); TerminalCatalog.For(__instance).RefreshStaticData(); } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class LiveTextSetterPatch { private static void Prefix(TMP_Text __instance, ref string value) { if ((Object)(object)Plugin.Instance != (Object)null && !string.IsNullOrEmpty(value) && PlanetRiskLabel.IsTarget(__instance)) { value = PlanetRiskLabel.Translate(value); } else if ((Object)(object)Plugin.Instance != (Object)null && !string.IsNullOrEmpty(value) && LiveText.IsGameLabel(__instance)) { value = LiveText.TranslatePending(value, formatKeys: false); } } } [HarmonyPatch(typeof(HUDManager), "AddChatMessage")] internal static class SystemChatPatch { private static void Prefix(ref string __0, string __1) { if (string.IsNullOrEmpty(__1) && !__0.Contains(" 님이 쓴 금지 낱말: ")) { __0 = LiveText.Translate(DisplayRules.SystemNotice(__0)); } } } [HarmonyPatch(typeof(HUDManager), "ReadDialogue")] internal static class DialogueTextPatch { private static void Prefix(DialogueSegment[] __0) { if (__0 == null) { return; } foreach (DialogueSegment val in __0) { if (val != null) { val.bodyText = LiveText.Translate(val.bodyText); } } } } [HarmonyPatch] internal static class TerminalFinalTextPatch { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo methodInfo = AccessTools.Method(typeof(Terminal), "TextPostProcess", (Type[])null, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } private static void Postfix(object __instance, object[] __args, MethodBase __originalMethod, ref string __result) { if (__result != null) { Terminal val = (Terminal)(__originalMethod.IsStatic ? __args.OfType<Terminal>().FirstOrDefault() : ((__instance is Terminal) ? __instance : null)); object obj; if (val == null) { obj = null; } else { TMP_InputField screenText = val.screenText; obj = ((screenText != null) ? screenText.text : null); } if (obj == null) { obj = ""; } int num = Math.Min(((string)obj).Length, Math.Max(0, val?.textAdded ?? 0)); string text = ((string)obj).Substring(((string)obj).Length - num); if (!string.IsNullOrWhiteSpace(text)) { __result = __result.Replace(text, "\ue010\ue011\ue012"); } __result = LiveText.Translate(__result); if (!string.IsNullOrWhiteSpace(text)) { __result = __result.Replace("\ue010\ue011\ue012", text); } } } } [HarmonyPatch] internal static class ChangingMenuTextPatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[3] { "Update", "HostSetLobbyPublic", "DisplayMenuNotification" }; foreach (string text in array) { MethodInfo methodInfo = AccessTools.Method(typeof(MenuManager), text, (Type[])null, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } MethodInfo methodInfo2 = AccessTools.Method(typeof(QuickMenuManager), "Update", (Type[])null, (Type[])null); if (methodInfo2 != null) { yield return methodInfo2; } } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Piggy.LCKR" })] private static void Postfix(object __instance, MethodBase __originalMethod) { Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null) { return; } string name = __originalMethod.Name; string[] array = ((name == "HostSetLobbyPublic") ? new string[1] { "privatePublicDescription" } : ((!(name == "DisplayMenuNotification")) ? new string[1] { "settingsBackButton" } : new string[2] { "menuNotificationText", "menuNotificationButtonText" })); string[] array2 = array; foreach (string text in array2) { object? obj = AccessTools.Field(__instance.GetType(), text)?.GetValue(__instance); TextMeshProUGUI val = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null); if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((TMP_Text)val).text)) { if (instance.Data.Replacements.TryGetValue(((TMP_Text)val).text, out string value)) { ((TMP_Text)val).text = value; } else if (text == "menuNotificationText" && ((TMP_Text)val).text.StartsWith("일부 저장 파일은 버전")) { ((TMP_Text)val).text = instance.Data.TranslateStatic(((TMP_Text)val).text); } } } } } internal static class PlanetRiskLabel { private sealed class Baseline { internal float FontSize; } private static readonly ConditionalWeakTable<TMP_Text, Baseline> Sizes = new ConditionalWeakTable<TMP_Text, Baseline>(); internal static bool IsTarget(TMP_Text? text) { if ((Object)(object)text != (Object)null && (Object)(object)HUDManager.Instance != (Object)null) { return (object)text == HUDManager.Instance.planetRiskLevelText; } return false; } internal static string Translate(string value) { switch (value.Trim()) { case "S": case "S+": case "S++": return "매우 위험함"; case "A": return "위험함"; case "B": return "조금 위험함"; case "C": return "살만함"; case "D": return "그정도 아님"; case "Safe": return "안전함"; default: return value; } } internal static bool Apply(TMP_Text text) { if (!IsTarget(text)) { return false; } string text2 = Translate(text.text ?? ""); if (text2 != text.text) { text.text = text2; } Baseline value = Sizes.GetValue(text, (TMP_Text t) => new Baseline { FontSize = Mathf.Max(1f, t.fontSize) }); text.enableAutoSizing = true; text.fontSizeMax = value.FontSize; text.fontSizeMin = Mathf.Min(value.FontSize, Mathf.Max(18f, value.FontSize * 0.6f)); text.enableWordWrapping = false; text.overflowMode = (TextOverflowModes)3; return true; } } [BepInPlugin("tacal.OnlyKorean.PureKorean", "OnlyKorean Pure Korean", "0.3.7")] [BepInIncompatibility("Piggy.LCKR")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "tacal.OnlyKorean.PureKorean"; internal static Plugin? Instance; internal TranslationData Data; private Harmony? harmony; private float nextRefresh; private readonly Queue<Transform> scan = new Queue<Transform>(); private readonly List<Component> components = new List<Component>(); private readonly HashSet<int> queuedScenes = new HashSet<int>(); private TextureOverrides? textures; internal int LastScanWork { get; private set; } internal TextureOverrides? Textures => textures; private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown GameObject gameObject = ((Component)this).gameObject; ((Object)gameObject).hideFlags = (HideFlags)(((Object)gameObject).hideFlags | 0x3D); Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); Instance = this; try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Data = new TranslationData(directoryName); textures = new TextureOverrides(Path.Combine(directoryName, "textures")); harmony = new Harmony("tacal.OnlyKorean.PureKorean"); harmony.PatchAll(typeof(Plugin).Assembly); OnlyKorean.KoreanSupport.KoreanSupport.Initialize(harmony, Path.Combine(directoryName, "fonts"), delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); SceneManager.sceneLoaded += SceneLoaded; ((MonoBehaviour)this).StartCoroutine(StartupSong.Load(Path.Combine(directoryName, "audio", "hangul-day.mp3"), delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); })); ((BaseUnityPlugin)this).Logger.LogInfo((object)"OnlyKorean Pure Korean ready. Independent translation and Hangul terminal controls enabled."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Pure Korean patch could not start: " + ex.GetType().Name)); Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Instance = null; ((Behaviour)this).enabled = false; } } private void Update() { OnlyKorean.KoreanSupport.KoreanSupport.Tick(); ScanSlice(); } private void SceneLoaded(Scene scene, LoadSceneMode mode) { scan.Clear(); nextRefresh = 0f; } private void QueueScene(Scene scene) { if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded || !queuedScenes.Add(((Scene)(ref scene)).handle)) { return; } GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { if ((Object)(object)val != (Object)null) { scan.Enqueue(val.transform); } } } private void ScanSlice() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) LastScanWork = 0; if (scan.Count == 0) { if (Time.unscaledTime < nextRefresh) { return; } nextRefresh = Time.unscaledTime + 5f; queuedScenes.Clear(); for (int i = 0; i < SceneManager.sceneCount; i++) { QueueScene(SceneManager.GetSceneAt(i)); } QueueScene(((Component)this).gameObject.scene); } long timestamp = Stopwatch.GetTimestamp(); while (scan.Count > 0 && LastScanWork < 24 && (LastScanWork == 0 || (double)(Stopwatch.GetTimestamp() - timestamp) * 1000.0 / (double)Stopwatch.Frequency < 1.0)) { Transform val = scan.Dequeue(); LastScanWork++; if ((Object)(object)val == (Object)null) { continue; } for (int j = 0; j < val.childCount; j++) { scan.Enqueue(val.GetChild(j)); } components.Clear(); ((Component)val).GetComponents<Component>(components); foreach (Component component in components) { if (!((Object)(object)component == (Object)null)) { WorldTranslations.Apply(component); TMP_Text val2 = (TMP_Text)(object)((component is TMP_Text) ? component : null); if (val2 != null) { LiveText.Apply(val2); } Renderer val3 = (Renderer)(object)((component is Renderer) ? component : null); if (val3 != null) { textures?.Apply(val3); } } } } } private void OnDestroy() { SceneManager.sceneLoaded -= SceneLoaded; scan.Clear(); components.Clear(); OnlyKorean.KoreanSupport.KoreanSupport.Shutdown(); Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } internal static void ApplyExactStaticText(TextMeshProUGUI text) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) Plugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)text == (Object)null || string.IsNullOrEmpty(((TMP_Text)text).text) || (Object)(object)((Component)text).GetComponentInParent<TMP_InputField>() != (Object)null) { return; } Scene scene = ((Component)text).gameObject.scene; string name = ((Scene)(ref scene)).name; int num; switch (name) { default: num = ((name == "InitScene") ? 1 : 0); break; case "MainMenu": case "InitSceneLaunchOptions": case "ColdOpen1": case "ColdOpen2": num = 1; break; } bool flag = (byte)num != 0; Transform val = ((TMP_Text)text).transform; while ((Object)(object)val != (Object)null) { string text2 = ((Object)val).name.ToLowerInvariant(); if (text2.Contains("lobby") || text2.Contains("serverlist") || text2.Contains("username") || text2.Contains("playername") || text2.Contains("leaderboard") || text2.Contains("chat") || text2.Contains("signal") || text2.Contains("spectat") || text2.Contains("radar")) { return; } val = val.parent; } if (flag || instance.Data.Replacements.ContainsKey(((TMP_Text)text).text)) { ((TMP_Text)text).text = LiveText.Translate(((TMP_Text)text).text); } } } [HarmonyPatch(typeof(TextMeshProUGUI), "Awake")] internal static class MenuTextPatch { [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Piggy.LCKR" })] private static void Postfix(TextMeshProUGUI __instance) { Plugin.ApplyExactStaticText(__instance); } } [HarmonyPatch(typeof(Image), "OnPopulateMesh", new Type[] { typeof(VertexHelper) })] internal static class ReportImagePatch { private static readonly Dictionary<int, Vector2> SolidPixels = new Dictionary<int, Vector2>(); private static void Postfix(Image __instance, VertexHelper toFill) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_022b: 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) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.overrideSprite == (Object)null || ((Object)__instance).name != "AllDead" || toFill.currentVertCount < 4) { return; } Texture mainTexture = ((Graphic)__instance).mainTexture; Texture2D val = (Texture2D)(object)((mainTexture is Texture2D) ? mainTexture : null); if (val == null || !((Object)val).name.StartsWith("OnlyKorean replacement:")) { return; } if (!SolidPixels.TryGetValue(((Object)val).GetInstanceID(), out var value)) { int num = Array.FindIndex(val.GetPixels32(), (Color32 c) => c.a == byte.MaxValue); if (num < 0) { return; } ((Vector2)(ref value))..ctor(((float)(num % ((Texture)val).width) + 0.5f) / (float)((Texture)val).width, ((float)(num / ((Texture)val).width) + 0.5f) / (float)((Texture)val).height); SolidPixels[((Object)val).GetInstanceID()] = value; } List<UIVertex> list = new List<UIVertex>(); toFill.GetUIVertexStream(list); Vector2 uvMin = Vector4.op_Implicit(list[0].uv0); Vector2 uvMax = uvMin; Vector3 min = list[0].position; Vector3 max = min; foreach (UIVertex item in list) { uvMin = Vector2.Min(uvMin, Vector4.op_Implicit(item.uv0)); uvMax = Vector2.Max(uvMax, Vector4.op_Implicit(item.uv0)); min = Vector3.Min(min, item.position); max = Vector3.Max(max, item.position); } if (!(uvMax.x <= uvMin.x) && !(uvMax.y <= uvMin.y)) { UIVertex[] array = (UIVertex[])(object)new UIVertex[4]; Vector3[] array2 = (Vector3[])(object)new Vector3[4] { At(0.148f, 0.135f), At(0.148f, 0.245f), At(0.47f, 0.245f), At(0.47f, 0.135f) }; for (int num2 = 0; num2 < 4; num2++) { array[num2] = UIVertex.simpleVert; array[num2].position = array2[num2]; array[num2].uv0 = Vector4.op_Implicit(value); array[num2].color = Color32.op_Implicit(new Color(0f, 0f, 0f, ((Graphic)__instance).color.a)); } toFill.Clear(); toFill.AddUIVertexQuad(array); for (int num3 = 0; num3 < list.Count; num3 += 3) { int currentVertCount = toFill.currentVertCount; toFill.AddVert(list[num3]); toFill.AddVert(list[num3 + 1]); toFill.AddVert(list[num3 + 2]); toFill.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); } } Vector3 At(float u, float v) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) return new Vector3(Mathf.LerpUnclamped(min.x, max.x, (u - uvMin.x) / (uvMax.x - uvMin.x)), Mathf.LerpUnclamped(min.y, max.y, (v - uvMin.y) / (uvMax.y - uvMin.y)), min.z); } } } internal static class ResultScreen { internal static string Grade(string value) { return value.Trim() switch { "S" => "잘함", "A" => "조금 잘함", "B" => "보통임", "C" => "못함", "D" => "너무 못함", "F" => "너무 못함", _ => value, }; } internal static void Install(EndOfGameStatUIElements ui) { if ((Object)(object)ui?.gradeLetter == (Object)null) { return; } ((TMP_Text)ui.gradeLetter).text = Grade(((TMP_Text)ui.gradeLetter).text); TextLayout.Fit((TMP_Text?)(object)ui.gradeLetter, 22f, 9f); TextLayout.Fit((TMP_Text?)(object)ui.quotaNumerator, 14f, 8f); TextLayout.Fit((TMP_Text?)(object)ui.quotaDenominator, 14f, 8f); if (ui.playerNotesText != null) { TextMeshProUGUI[] playerNotesText = ui.playerNotesText; for (int i = 0; i < playerNotesText.Length; i++) { TextLayout.Fit((TMP_Text?)(object)playerNotesText[i], 9f, 7f, wrap: true); } } } } [HarmonyPatch(typeof(HUDManager), "FillEndGameStats")] internal static class ResultScreenPatch { private static void Postfix(HUDManager __instance) { ResultScreen.Install(__instance.statsUIElements); } } internal static class StartupSong { internal static AudioClip? Clip; internal static IEnumerator Load(string path, Action<string> log) { if (!File.Exists(path)) { log("Startup song file is missing."); yield break; } UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, (AudioType)13); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { log("Startup song could not be decoded: " + request.error); yield break; } Clip = DownloadHandlerAudioClip.GetContent(request); ((Object)Clip).name = "OnlyKorean Hangul Day song"; ((Object)Clip).hideFlags = (HideFlags)61; } finally { ((IDisposable)request)?.Dispose(); } } internal static AudioClip Resolve(AudioSource source, AudioClip requested, AudioSource? speaker, AudioClip? intro) { if (!((Object)(object)Clip != (Object)null) || !((Object)(object)source == (Object)(object)speaker) || !((Object)(object)requested == (Object)(object)intro)) { return requested; } return Clip; } } [HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip), typeof(float) })] internal static class StartupSongPatch { private static void Prefix(AudioSource __instance, ref AudioClip __0) { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null)) { __0 = StartupSong.Resolve(__instance, __0, instance.speakerAudioSource, instance.shipIntroSpeechSFX); } } } internal sealed class TerminalCatalog { private static readonly ConditionalWeakTable<Terminal, TerminalCatalog> Catalogs = new ConditionalWeakTable<Terminal, TerminalCatalog>(); private readonly Terminal terminal; private readonly Dictionary<string, TerminalKeyword> canonical = new Dictionary<string, TerminalKeyword>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<TerminalKeyword, string> original = new Dictionary<TerminalKeyword, string>(); private readonly Dictionary<string, string> aliases = new Dictionary<string, string>(StringComparer.Ordinal); private readonly Dictionary<TerminalNode, string> translatedTexts = new Dictionary<TerminalNode, string>(); private readonly Dictionary<TerminalNode, string> translatedNames = new Dictionary<TerminalNode, string>(); private bool ready; private int fallbackCount; private TranslationData Data => Plugin.Instance.Data; internal IReadOnlyDictionary<string, string> Aliases => aliases; internal static TerminalCatalog For(Terminal terminal) { return Catalogs.GetValue(terminal, (Terminal t) => new TerminalCatalog(t)); } private TerminalCatalog(Terminal terminal) { this.terminal = terminal; CaptureOriginalKeywords(); } internal void CaptureOriginalKeywords() { if (terminal.terminalNodes?.allKeywords == null) { return; } TerminalKeyword[] allKeywords = terminal.terminalNodes.allKeywords; foreach (TerminalKeyword val in allKeywords) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.word)) { if (!original.ContainsKey(val)) { original[val] = val.word; } if (!canonical.ContainsKey(original[val])) { canonical[original[val]] = val; } } } } internal string? Resolve(string originalWord) { switch (originalWord) { case "transmit": case "ping": case "flash": return originalWord; default: { if (canonical.TryGetValue(originalWord, out TerminalKeyword value) && (Object)(object)value != (Object)null) { return value.word; } if (Data.KeywordFallbacks.TryGetValue(originalWord, out string fallback)) { TerminalKeyword val = ((IEnumerable<TerminalKeyword>)terminal.terminalNodes.allKeywords).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword k) => (Object)(object)k != (Object)null && k.word == fallback)); if ((Object)(object)val != (Object)null) { canonical[originalWord] = val; return val.word; } } if (originalWord == "confirm" || originalWord == "deny") { return originalWord; } return null; } } } internal void BuildAliases() { if ((Object)(object)Plugin.Instance == (Object)null || terminal.terminalNodes?.allKeywords == null) { return; } foreach (KeyValuePair<string, string> alias in Data.Aliases) { if (Resolve(alias.Value) != null) { aliases[alias.Key] = alias.Value; } } aliases["전송"] = "transmit"; aliases["신호"] = "ping"; aliases["번쩍"] = "flash"; aliases["좋아"] = "confirm"; aliases["그만"] = "deny"; TerminalKeyword[] allKeywords = terminal.terminalNodes.allKeywords; foreach (TerminalKeyword val in allKeywords) { if ((Object)(object)val == (Object)null || val.accessTerminalObjects || string.IsNullOrWhiteSpace(val.word)) { continue; } string value; string text = (original.TryGetValue(val, out value) ? value : val.word); if (!canonical.ContainsKey(text)) { canonical[text] = val; } if (!aliases.Values.Contains<string>(text, StringComparer.OrdinalIgnoreCase)) { string text2 = (((Object)val).name.Contains("LogFile") ? Data.Table("Sigurd", ((Object)val).name) : Data.TranslateStatic(val.word).Trim()); if (text2.Length == 0 || text2.Any((char c) => char.IsLetter(c) && (c < '가' || c > '힣'))) { int num = ++fallbackCount; text2 = "덧말" + num; } if (aliases.ContainsKey(text2) || text2 == "도움말" || text2 == "명령어") { int num = ++fallbackCount; text2 = "덧말" + num; } aliases[text2] = text; } } ready = true; } internal void RefreshStaticData() { if ((Object)(object)Plugin.Instance == (Object)null) { return; } if (!ready) { BuildAliases(); } if (terminal.buyableItemsList != null) { Item[] buyableItemsList = terminal.buyableItemsList; foreach (Item val in buyableItemsList) { if ((Object)(object)val != (Object)null) { val.itemName = Data.Table("Item", val.itemName); } } } if ((Object)(object)terminal.terminalNodes != (Object)null) { HashSet<TerminalNode> visited = new HashSet<TerminalNode>(); if (terminal.terminalNodes.specialNodes != null) { foreach (TerminalNode specialNode in terminal.terminalNodes.specialNodes) { TranslateNode(specialNode, visited); } } if (terminal.terminalNodes.allKeywords != null) { TerminalKeyword[] allKeywords = terminal.terminalNodes.allKeywords; foreach (TerminalKeyword val2 in allKeywords) { if ((Object)(object)val2 == (Object)null) { continue; } TranslateNode(val2.specialKeywordResult, visited); if (val2.compatibleNouns == null) { continue; } CompatibleNoun[] compatibleNouns = val2.compatibleNouns; foreach (CompatibleNoun val3 in compatibleNouns) { if (val3 != null) { TranslateNode(val3.result, visited); } } } } if (terminal.enemyFiles != null) { foreach (TerminalNode enemyFile in terminal.enemyFiles) { TranslateNode(enemyFile, visited); } } if (terminal.logEntryFiles != null) { foreach (TerminalNode logEntryFile in terminal.logEntryFiles) { TranslateNode(logEntryFile, visited); } } } if (terminal.buyableVehicles != null) { BuyableVehicle[] buyableVehicles = terminal.buyableVehicles; foreach (BuyableVehicle val4 in buyableVehicles) { if (val4 != null) { val4.vehicleDisplayName = Data.TranslateStatic(val4.vehicleDisplayName); } } } StartOfRound instance = StartOfRound.Instance; if (instance?.levels != null) { SelectableLevel[] levels = instance.levels; foreach (SelectableLevel val5 in levels) { if ((Object)(object)val5 != (Object)null) { val5.PlanetName = Data.Table("Planets", val5.PlanetName); } } } if (instance?.unlockablesList?.unlockables == null) { return; } foreach (UnlockableItem unlockable in instance.unlockablesList.unlockables) { if (unlockable != null) { unlockable.unlockableName = Data.Table("UnlockableItem", unlockable.unlockableName); TranslateNode(unlockable.shopSelectionNode, new HashSet<TerminalNode>()); } } } internal void TranslateNode(TerminalNode? node, HashSet<TerminalNode>? visited = null) { if ((Object)(object)node == (Object)null || (Object)(object)Plugin.Instance == (Object)null) { return; } if (visited == null) { visited = new HashSet<TerminalNode>(); } if (!visited.Add(node)) { return; } if (!translatedTexts.TryGetValue(node, out string value) || value != node.displayText) { node.displayText = (Data.NodeOverrides.TryGetValue(((Object)node).name, out string value2) ? value2 : Data.TranslateStatic(node.displayText)); translatedTexts[node] = node.displayText; } if (!translatedNames.TryGetValue(node, out string value3) || value3 != node.creatureName) { string[] value5; if (Data.Tables["Terminal"].TryGetValue(((Object)node).name, out string[] value4) && value4.Length > 1) { node.creatureName = value4[0]; } else if (Data.Tables["Sigurd"].TryGetValue(((Object)node).name + "Keyword", out value5) && value5.Length > 1) { node.creatureName = value5[1]; } else { node.creatureName = Data.TranslateStatic(node.creatureName); } translatedNames[node] = node.creatureName; } if (node.terminalOptions == null) { return; } CompatibleNoun[] terminalOptions = node.terminalOptions; foreach (CompatibleNoun val in terminalOptions) { if (val != null) { TranslateNode(val.result, visited); } } } internal TerminalNode HelpNode(int requestedPage) { TerminalKeyword value; TerminalNode val = (canonical.TryGetValue("help", out value) ? value.specialKeywordResult : null); if ((Object)(object)val == (Object)null) { val = terminal.terminalNodes?.specialNodes?.FirstOrDefault((Func<TerminalNode, bool>)((TerminalNode n) => (Object)(object)n != (Object)null && ((Object)n).name == "HelpCommands")); } if ((Object)(object)val == (Object)null) { return Message(""); } TranslateNode(val); return val; } internal TerminalNode Dispatch(string internalText) { TerminalNode currentNode = terminal.currentNode; if ((Object)(object)currentNode != (Object)null && currentNode.overrideOptions) { return (currentNode.terminalOptions?.FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun o) => (Object)(object)o?.noun != (Object)null && string.Equals(o.noun.word, internalText.Trim(), StringComparison.OrdinalIgnoreCase))))?.result ?? Message("‘좋아’ 또는 ‘그만’을 적어 주세요."); } terminal.playerDefinedAmount = 1; Match match = Regex.Match(internalText, "\\s+(\\d+)$"); if (match.Success) { terminal.playerDefinedAmount = int.Parse(match.Groups[1].Value); internalText = internalText.Substring(0, match.Index); } TerminalKeyword[] source = (from k in canonical.Values.Where((TerminalKeyword k) => (Object)(object)k != (Object)null).Distinct() orderby k.word.Length descending select k).ToArray(); List<TerminalKeyword> list = new List<TerminalKeyword>(); string rest = internalText.Trim(); while (rest.Length > 0) { TerminalKeyword val = ((IEnumerable<TerminalKeyword>)source).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword k) => string.Equals(rest, k.word, StringComparison.OrdinalIgnoreCase) || rest.StartsWith(k.word + " ", StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null) { return Message("이 배에서 쓸 수 없는 이름입니다. ‘도움말’을 살펴보세요."); } list.Add(val); rest = rest.Substring(val.word.Length).TrimStart(); } if (list.Count == 1 && (Object)(object)list[0].specialKeywordResult != (Object)null) { return list[0].specialKeywordResult; } TerminalKeyword noun = ((IEnumerable<TerminalKeyword>)list).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword k) => !k.isVerb)); return (((IEnumerable<TerminalKeyword>)list).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword k) => k.isVerb)) ?? noun?.defaultVerb)?.compatibleNouns?.FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun n) => n != null && (Object)(object)n.noun == (Object)(object)noun))?.result ?? Message("함께 쓸 이름을 적어 주세요. 예: 사기 손불 2 / 길잡기 해봄"); } internal static TerminalNode Message(string text) { TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>(); ((Object)obj).name = "OnlyKoreanHelp"; obj.displayText = "\n" + text + "\n"; obj.clearPreviousText = true; obj.maxCharactersToType = 160; obj.buyItemIndex = -1; obj.buyRerouteToMoon = -1; obj.shipUnlockableID = -1; obj.buyVehicleIndex = -1; obj.creatureFileID = -1; obj.storyLogFileID = -1; obj.displayPlanetInfo = -1; obj.playSyncedClip = -1; return obj; } } internal static class TerminalInput { internal static readonly string[] CodeLetters = new string[26] { "가", "나", "다", "라", "마", "바", "사", "아", "자", "차", "카", "타", "파", "하", "거", "너", "더", "러", "머", "버", "서", "어", "저", "처", "커", "터" }; private static readonly Regex AsciiCode = new Regex("^[A-Za-z][0-9]{1,3}$", RegexOptions.CultureInvariant); private static readonly Regex Digits = new Regex("^[0-9]{1,2}$", RegexOptions.CultureInvariant); internal static string DisplayCode(string code) { if (string.IsNullOrEmpty(code) || !AsciiCode.IsMatch(code)) { return code ?? ""; } return CodeLetters[char.ToUpperInvariant(code[0]) - 65] + code.Substring(1); } internal static bool TryCode(string input, out string code) { code = ""; if (input.Length < 2 || input.Length > 4 || !input.Skip(1).All((char c) => c >= '0' && c <= '9')) { return false; } int num = Array.IndexOf(CodeLetters, input.Substring(0, 1)); if (num < 0) { return false; } code = (char)(97 + num) + input.Substring(1); return true; } internal static InputDecision Translate(string raw, IReadOnlyDictionary<string, string> aliases, Func<string, string?> resolve) { string text = (raw ?? "").TrimStart(); if (text.Length == 0) { return InputDecision.Reject("쓸 말을 적어 주세요. ‘도움말’을 적으면 쓰는 법을 볼 수 있습니다."); } int num = text.IndexOfAny(new char[4] { ' ', '\t', '\r', '\n' }); string text2 = ((num < 0) ? text : text.Substring(0, num)); string text3 = ((num < 0) ? "" : text.Substring(num + 1)); if (text2 == "도움말" || text2 == "명령어") { if (!string.IsNullOrWhiteSpace(text3)) { return InputDecision.Reject("알 수 없는 쓰임말입니다."); } return InputDecision.Help(1); } if (TryCode(text.TrimEnd(), out string code)) { return InputDecision.Accept(code, tail: false); } if (aliases.TryGetValue(text2, out string value)) { switch (value) { case "transmit": case "ping": case "flash": case "switch": if (text3.Length > 0) { return InputDecision.Accept(value + " " + text3, tail: true); } if (value == "switch") { return InputDecision.Accept(resolve("switch") ?? "switch", tail: false); } return InputDecision.Reject((value == "transmit") ? "‘전송 보낼말’처럼 적어 주세요." : "쓰임말 뒤에 화면에 보이는 이름을 그대로 적어 주세요."); } } if (text.Any((char c) => (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) { return InputDecision.Reject("쓰임말과 물건 이름은 한글로 적어 주세요. ‘도움말’을 살펴보세요."); } string[] source = aliases.Keys.OrderByDescending((string k) => k.Length).ThenBy<string, string>((string k) => k, StringComparer.Ordinal).ToArray(); List<string> list = new List<string>(); string remaining = text; while (remaining.Length > 0) { remaining = remaining.TrimStart(); if (remaining.Length == 0) { break; } string text4 = source.FirstOrDefault((string a) => remaining == a || (remaining.StartsWith(a, StringComparison.Ordinal) && remaining.Length > a.Length && char.IsWhiteSpace(remaining[a.Length]))); if (text4 != null) { string text5 = resolve(aliases[text4]); if (string.IsNullOrEmpty(text5)) { return InputDecision.Reject("이 배에는 그 쓰임말이 없습니다. ‘도움말’에서 쓸 수 있는 말을 살펴보세요."); } list.Add(text5); remaining = remaining.Substring(text4.Length); continue; } int num2 = remaining.IndexOfAny(new char[4] { ' ', '\t', '\r', '\n' }); string text6 = ((num2 < 0) ? remaining : remaining.Substring(0, num2)); if (!Digits.IsMatch(text6) || !int.TryParse(text6, out var result) || result > 10) { return InputDecision.Reject("알 수 없는 쓰임말입니다. ‘도움말’에 나온 이름을 그대로 적어 주세요."); } list.Add(result.ToString(CultureInfo.InvariantCulture)); remaining = ((num2 < 0) ? "" : remaining.Substring(num2)); } if (list.Count == 0 || list.Count > 5) { return InputDecision.Reject("한 번에 한 가지 일을 적어 주세요. ‘도움말’에서 쓰는 법을 볼 수 있습니다."); } return InputDecision.Accept(string.Join(" ", list), tail: false); } } internal sealed class InputDecision { internal bool Accepted { get; private set; } internal bool PreserveTail { get; private set; } internal string InternalText { get; private set; } = ""; internal string Error { get; private set; } = ""; internal int HelpPage { get; private set; } internal static InputDecision Accept(string text, bool tail) { return new InputDecision { Accepted = true, InternalText = text, PreserveTail = tail }; } internal static InputDecision Reject(string reason) { return new InputDecision { Error = reason }; } internal static InputDecision Help(int page) { return new InputDecision { HelpPage = page }; } } [HarmonyPatch(typeof(Terminal), "Start")] internal static class TerminalStartPatch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "Piggy.LCKR" })] private static void Prefix(Terminal __instance) { if ((Object)(object)Plugin.Instance != (Object)null) { TerminalCatalog.For(__instance).CaptureOriginalKeywords(); } } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Piggy.LCKR" })] private static void Postfix(Terminal __instance) { if (!((Object)(object)Plugin.Instance == (Object)null)) { TextLayout.ConfigureTerminal(__instance); TerminalCatalog terminalCatalog = TerminalCatalog.For(__instance); terminalCatalog.BuildAliases(); terminalCatalog.RefreshStaticData(); } } } [HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")] internal static class TerminalParsePatch { internal sealed class ParseState { internal Terminal Terminal; internal string OriginalText = ""; internal string InternalText = ""; internal int OriginalAdded; internal bool PreserveTail; internal bool Restored; } [ThreadStatic] internal static ParseState? Active; [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "Piggy.LCKR" })] private static bool Prefix(Terminal __instance, ref TerminalNode __result, out ParseState? __state) { __state = null; if ((Object)(object)Plugin.Instance == (Object)null) { return true; } TMP_InputField screenText = __instance.screenText; if ((Object)(object)screenText == (Object)null) { return true; } int num = Math.Min(Math.Max(__instance.textAdded, 0), screenText.text.Length); string raw = screenText.text.Substring(screenText.text.Length - num); TerminalCatalog terminalCatalog = TerminalCatalog.For(__instance); terminalCatalog.BuildAliases(); InputDecision inputDecision = TerminalInput.Translate(raw, terminalCatalog.Aliases, terminalCatalog.Resolve); if (inputDecision.HelpPage > 0) { __result = terminalCatalog.HelpNode(inputDecision.HelpPage); return false; } if (!inputDecision.Accepted) { __result = TerminalCatalog.Message(inputDecision.Error); return false; } if (!inputDecision.PreserveTail && !Regex.IsMatch(inputDecision.InternalText, "^[a-z][0-9]{1,3}$")) { __result = terminalCatalog.Dispatch(inputDecision.InternalText); terminalCatalog.TranslateNode(__result); return false; } __state = new ParseState { Terminal = __instance, OriginalText = screenText.text, OriginalAdded = __instance.textAdded, InternalText = inputDecision.InternalText, PreserveTail = inputDecision.PreserveTail }; Active = __state; screenText.SetTextWithoutNotify(screenText.text.Substring(0, screenText.text.Length - num) + inputDecision.InternalText); __instance.textAdded = inputDecision.InternalText.Length; return true; } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ParseState? __state) { Restore(__state); } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, ParseState? __state) { Restore(__state); return __exception; } private static void Restore(ParseState? state) { if (state != null && !state.Restored) { state.Restored = true; if ((Object)(object)state.Terminal != (Object)null && (Object)(object)state.Terminal.screenText != (Object)null) { state.Terminal.screenText.SetTextWithoutNotify(state.OriginalText); state.Terminal.textAdded = state.OriginalAdded; } if (Active == state) { Active = null; } } } } [HarmonyPatch(typeof(Terminal), "RemovePunctuation")] internal static class PreservePayloadPatch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "Piggy.LCKR" })] private static bool Prefix(Terminal __instance, string __0, ref string __result) { TerminalParsePatch.ParseState active = TerminalParsePatch.Active; if (active == null || (Object)(object)active.Terminal != (Object)(object)__instance || !active.PreserveTail || __0 != active.InternalText) { return true; } __result = __0; return false; } } [HarmonyPatch(typeof(Terminal), "CheckForPlayerNameCommand")] internal static class FullTargetNamePatch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "Piggy.LCKR" })] private static bool Prefix(Terminal __instance, ref int __result) { TerminalParsePatch.ParseState active = TerminalParsePatch.Active; if (active == null || (Object)(object)active.Terminal != (Object)(object)__instance || !active.PreserveTail || active.InternalText.StartsWith("transmit ", StringComparison.Ordinal)) { return true; } int num = active.InternalText.IndexOf(' '); if (num < 0) { return true; } string text = active.InternalText.Substring(num + 1).Trim(); List<TransformAndName> list = StartOfRound.Instance?.mapScreen?.radarTargets; if (list == null) { __result = -1; return false; } List<int> list2 = new List<int>(); for (int i = 0; i < list.Count; i++) { if (string.Equals(list[i].name, text, StringComparison.OrdinalIgnoreCase)) { list2.Add(i); } } if (list2.Count == 1) { __result = list2[0]; return false; } if (list2.Count == 0 && text.Length >= 2) { for (int j = 0; j < list.Count; j++) { if (list[j].name.StartsWith(text, StringComparison.OrdinalIgnoreCase)) { list2.Add(j); } } } __result = ((list2.Count == 1) ? list2[0] : (-1)); return false; } } [HarmonyPatch(typeof(Terminal), "LoadNewNode")] internal static class TerminalNodePatch { [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "Piggy.LCKR" })] private static void Prefix(Terminal __instance, TerminalNode node) { if ((Object)(object)Plugin.Instance != (Object)null) { TerminalCatalog.For(__instance).TranslateNode(node); } } } internal static class TextLayout { private sealed class Baseline { internal float Size; } private static readonly ConditionalWeakTable<TMP_Text, Baseline> Sizes = new ConditionalWeakTable<TMP_Text, Baseline>(); private static TMP_InputField? TerminalInput; internal static void Fit(TMP_Text? text, float maximum, float minimum, bool wrap = false) { if (!((Object)(object)text == (Object)null)) { text.enableAutoSizing = true; text.fontSizeMax = maximum; text.fontSizeMin = minimum; text.enableWordWrapping = wrap; text.overflowMode = (TextOverflowModes)3; } } internal static void ConfigureTerminal(Terminal terminal) { TerminalInput = terminal.screenText; TMP_InputField? terminalInput = TerminalInput; if ((Object)(object)((terminalInput != null) ? terminalInput.textComponent : null) != (Object)null) { Apply(TerminalInput.textComponent); } } internal static void Apply(TMP_Text text) { if (!(text is TextMeshProUGUI) || PlanetRiskLabel.Apply(text)) { return; } if (((Object)text).name == "CurrentCreditsNum") { FitCredits(text); return; } if (((Object)text).name == "doorHydraulics") { Fit(text, 26f, 14f); return; } if (((Object)text).name == "meter" && (text.text ?? "").EndsWith("%", StringComparison.Ordinal)) { Fit(text, 36f, 18f); return; } TMP_InputField componentInParent = ((Component)text).GetComponentInParent<TMP_InputField>(true); bool flag = (Object)(object)componentInParent != (Object)null && ((Object)(object)componentInParent == (Object)(object)TerminalInput || (Object)(object)((Component)componentInParent).GetComponentInParent<Terminal>() != (Object)null); bool flag2 = (Object)(object)componentInParent == (Object)null && ((Object)text).name == "HeaderText" && (text.text ?? "").StartsWith("채울 몫:\n", StringComparison.Ordinal); if (!flag && !flag2) { return; } float num = Sizes.GetValue(text, (TMP_Text t) =