Decompiled source of ConsoleFix v1.1.0

ConsoleFix_v1.1.0.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using TMPro;
using UnityEngine;

[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("ConsoleFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("ConsoleFix")]
[assembly: AssemblyTitle("ConsoleFix")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace ConsoleFix;

[BepInPlugin("DEEP_FROST.ConsoleFix", "ConsoleFix", "1.1.0")]
public class ConsoleFixPlugin : BaseUnityPlugin
{
	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static ConsoleEvent <>9__33_0;

		internal void <RegisterConsoleCommand>b__33_0(ConsoleEventArgs args)
		{
			if (args.Args != null && args.Args.Length >= 3)
			{
				string text = args.Args[1].ToLowerInvariant();
				string text2 = args.Args[2].ToLowerInvariant();
				bool flag = text2 == "on" || text2 == "1" || text2 == "true";
				bool flag2 = text2 == "off" || text2 == "0" || text2 == "false";
				if (!flag && !flag2)
				{
					args.Context.AddString("Использование: consolefix <translit|refocus|ime|chatrefocus|chatslash> <on|off>");
					return;
				}
				switch (text)
				{
				case "translit":
					CfgTranslit.Value = flag;
					break;
				case "refocus":
					CfgAutoRefocus.Value = flag;
					break;
				case "ime":
					CfgDisableIme.Value = flag;
					break;
				case "chatrefocus":
					CfgChatRefocus.Value = flag;
					break;
				case "chatslash":
					CfgChatSlash.Value = flag;
					break;
				default:
					args.Context.AddString("Неизвестная функция: " + text);
					return;
				}
			}
			args.Context.AddString(string.Format("ConsoleFix {0}: консоль translit={1}, refocus={2}, ime={3} | чат refocus={4}, slash={5}", "1.1.0", CfgTranslit.Value, CfgAutoRefocus.Value, CfgDisableIme.Value, CfgChatRefocus.Value, CfgChatSlash.Value));
		}
	}

	public const string PluginGuid = "DEEP_FROST.ConsoleFix";

	public const string PluginName = "ConsoleFix";

	public const string PluginVersion = "1.1.0";

	private static ManualLogSource Log;

	private static ConfigEntry<bool> CfgTranslit;

	private static ConfigEntry<bool> CfgAutoRefocus;

	private static ConfigEntry<bool> CfgDisableIme;

	private static ConfigEntry<bool> CfgChatRefocus;

	private static ConfigEntry<bool> CfgChatSlash;

	private static ConfigEntry<bool> CfgDebug;

	private const string RuChars = "ёйцукенгшщзхъфывапролджэячсмитьбю.";

	private const string EnChars = "`qwertyuiop[]asdfghjkl;'zxcvbnm,./";

	private static Dictionary<char, char> RuToEn;

	private static FieldInfo CommandsField;

	private static bool imeForcedOff;

	private static float lastRefocusLog;

	private static float lastChatRefocusLog;

	private static int refocusCount;

	private static int chatRefocusCount;

	private static bool loggedWatchdogError;

	private void Awake()
	{
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Expected O, but got Unknown
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Expected O, but got Unknown
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Expected O, but got Unknown
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Expected O, but got Unknown
		//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Expected O, but got Unknown
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Expected O, but got Unknown
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_0260: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		CfgTranslit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Translit", true, "Transliterate Cyrillic to Latin (QWERTY key positions) while typing in the F5 console. Chat is not affected.");
		CfgAutoRefocus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoRefocus", true, "Re-activate the console input field if it loses keyboard focus (e.g. after Enter on an empty line).");
		CfgDisableIme = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableIme", true, "Disable IME composition while the console input is focused (prevents IME from swallowing keystrokes after erasing text).");
		CfgChatRefocus = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "AutoRefocus", true, "Re-activate the chat input field if it loses focus (e.g. after switching keyboard layout while typing).");
		CfgChatSlash = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "CommandTranslit", true, "Transliterate a slash-command typed in Russian layout when sending a chat message ('.s text' -> '/s text'). Only the command word is translated; the message text is left untouched.");
		CfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Debug", false, "Verbose logging.");
		RuToEn = BuildRuToEnMap();
		CommandsField = AccessTools.Field(typeof(Terminal), "commands");
		Harmony val = new Harmony("DEEP_FROST.ConsoleFix");
		val.Patch((MethodBase)AccessTools.Method(typeof(TMP_InputField), "Append", new Type[1] { typeof(char) }, (Type[])null), new HarmonyMethod(typeof(ConsoleFixPlugin), "AppendCharPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(TMP_InputField), "Append", new Type[1] { typeof(string) }, (Type[])null), new HarmonyMethod(typeof(ConsoleFixPlugin), "AppendStringPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Terminal), "InputText", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ConsoleFixPlugin), "ConsoleInputTextPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Console), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ConsoleFixPlugin), "ConsoleUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Chat), "InputText", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ConsoleFixPlugin), "ChatInputTextPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Chat), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ConsoleFixPlugin), "ChatUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		RegisterConsoleCommand();
		Log.LogInfo((object)"[ConsoleFix] 1.1.0 загружен. Консоль: транслитерация, возврат фокуса, контроль IME. Чат: слэш-команды, возврат фокуса. Настройка — конфиг и команда 'consolefix'.");
	}

	private static Dictionary<char, char> BuildRuToEnMap()
	{
		Dictionary<char, char> dictionary = new Dictionary<char, char>("ёйцукенгшщзхъфывапролджэячсмитьбю.".Length * 2);
		for (int i = 0; i < "ёйцукенгшщзхъфывапролджэячсмитьбю.".Length; i++)
		{
			char c = "ёйцукенгшщзхъфывапролджэячсмитьбю."[i];
			char c2 = (dictionary[c] = "`qwertyuiop[]asdfghjkl;'zxcvbnm,./"[i]);
			char c4 = char.ToUpperInvariant(c);
			char value = char.ToUpperInvariant(c2);
			if (c4 != c)
			{
				dictionary[c4] = value;
			}
		}
		return dictionary;
	}

	private static bool HasCyrillic(string s)
	{
		foreach (char c in s)
		{
			if (c >= 'Ѐ' && c <= 'ӿ')
			{
				return true;
			}
		}
		return false;
	}

	private static string Translit(string s)
	{
		StringBuilder stringBuilder = null;
		for (int i = 0; i < s.Length; i++)
		{
			if (RuToEn.TryGetValue(s[i], out var value))
			{
				if (stringBuilder == null)
				{
					stringBuilder = new StringBuilder(s.Length);
					stringBuilder.Append(s, 0, i);
				}
				stringBuilder.Append(value);
			}
			else
			{
				stringBuilder?.Append(s[i]);
			}
		}
		if (stringBuilder == null)
		{
			return s;
		}
		return stringBuilder.ToString();
	}

	private static bool IsConsoleInput(TMP_InputField field)
	{
		Console instance = Console.instance;
		if ((Object)(object)instance != (Object)null)
		{
			return (object)field == ((Terminal)instance).m_input;
		}
		return false;
	}

	private static bool IsKnownCommand(string word)
	{
		if (string.IsNullOrEmpty(word) || CommandsField == null)
		{
			return false;
		}
		return ((Dictionary<string, ConsoleCommand>)CommandsField.GetValue(null))?.ContainsKey(word.ToLowerInvariant()) ?? false;
	}

	private static void AppendCharPrefix(TMP_InputField __instance, ref char input)
	{
		if (CfgTranslit.Value && input >= 'Ѐ' && input <= 'ӿ' && IsConsoleInput(__instance) && RuToEn.TryGetValue(input, out var value))
		{
			if (CfgDebug.Value)
			{
				Log.LogInfo((object)$"[ConsoleFix] символ '{input}' -> '{value}'");
			}
			input = value;
		}
	}

	private static void AppendStringPrefix(TMP_InputField __instance, ref string input)
	{
		if (CfgTranslit.Value && !string.IsNullOrEmpty(input) && HasCyrillic(input) && IsConsoleInput(__instance))
		{
			input = Translit(input);
			Log.LogInfo((object)"[ConsoleFix] вставленный в консоль текст транслитерирован");
		}
	}

	private static void ConsoleInputTextPrefix(Terminal __instance)
	{
		if (CfgTranslit.Value && __instance is Console)
		{
			GuiInputField input = __instance.m_input;
			if (!((Object)(object)input == (Object)null) && !string.IsNullOrEmpty(((TMP_InputField)input).text) && HasCyrillic(((TMP_InputField)input).text))
			{
				((TMP_InputField)input).text = Translit(((TMP_InputField)input).text);
				Log.LogInfo((object)"[ConsoleFix] команда консоли транслитерирована при отправке");
			}
		}
	}

	private static void ChatInputTextPrefix(Chat __instance)
	{
		if (!CfgChatSlash.Value)
		{
			return;
		}
		GuiInputField input = ((Terminal)__instance).m_input;
		if ((Object)(object)input == (Object)null)
		{
			return;
		}
		string text = ((TMP_InputField)input).text;
		if (!string.IsNullOrEmpty(text) && text[0] == '.')
		{
			int num = text.IndexOf(' ');
			string text2 = ((num < 0) ? text.Substring(1) : text.Substring(1, num - 1));
			string text3 = Translit(text2);
			if (!string.IsNullOrEmpty(text3) && !(text3 == text2) && IsKnownCommand(text3))
			{
				((TMP_InputField)input).text = "/" + text3 + ((num < 0) ? "" : text.Substring(num));
				Log.LogInfo((object)("[ConsoleFix] команда чата транслитерирована: " + ((TMP_InputField)input).text));
			}
		}
	}

	private static void ConsoleUpdatePostfix(Console __instance)
	{
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Invalid comparison between Unknown and I4
		try
		{
			if (!Console.IsVisible())
			{
				RestoreIme();
				return;
			}
			GuiInputField input = ((Terminal)__instance).m_input;
			if ((Object)(object)input == (Object)null)
			{
				return;
			}
			if (!((TMP_InputField)input).isFocused)
			{
				RestoreIme();
				if (CfgAutoRefocus.Value && !GuiInputField.VirtualKeyboardOpen)
				{
					input.ActivateInputField();
					((TMP_InputField)input).MoveTextEnd(false);
					refocusCount++;
					if (Time.unscaledTime - lastRefocusLog > 5f)
					{
						lastRefocusLog = Time.unscaledTime;
						Log.LogInfo((object)$"[ConsoleFix] фокус поля консоли потерян — восстановлен (всего: {refocusCount})");
					}
				}
			}
			else if (CfgDisableIme.Value && (int)Input.imeCompositionMode != 2)
			{
				Input.imeCompositionMode = (IMECompositionMode)2;
				imeForcedOff = true;
				if (CfgDebug.Value)
				{
					Log.LogInfo((object)"[ConsoleFix] IME выключен для поля консоли");
				}
			}
		}
		catch (Exception arg)
		{
			if (!loggedWatchdogError)
			{
				loggedWatchdogError = true;
				Log.LogWarning((object)$"[ConsoleFix] ошибка watchdog (дальше не повторяется): {arg}");
			}
		}
	}

	private static void ChatUpdatePostfix(Chat __instance)
	{
		try
		{
			GuiInputField input = ((Terminal)__instance).m_input;
			if (!((Object)(object)input == (Object)null) && ((Component)input).gameObject.activeSelf && !((TMP_InputField)input).isFocused && !((Object)(object)((Terminal)__instance).m_chatWindow == (Object)null) && ((Component)((Terminal)__instance).m_chatWindow).gameObject.activeInHierarchy && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.InTextInput() && !Menu.IsVisible() && !InventoryGui.IsVisible() && (!((Object)(object)ReportUser.instance != (Object)null) || !ReportUser.instance.IsReportUserWindowActive()) && CfgChatRefocus.Value && !GuiInputField.VirtualKeyboardOpen)
			{
				input.ActivateInputField();
				((TMP_InputField)input).MoveTextEnd(false);
				chatRefocusCount++;
				if (Time.unscaledTime - lastChatRefocusLog > 5f)
				{
					lastChatRefocusLog = Time.unscaledTime;
					Log.LogInfo((object)$"[ConsoleFix] фокус поля чата потерян — восстановлен (всего: {chatRefocusCount})");
				}
			}
		}
		catch (Exception arg)
		{
			if (!loggedWatchdogError)
			{
				loggedWatchdogError = true;
				Log.LogWarning((object)$"[ConsoleFix] ошибка watchdog чата (дальше не повторяется): {arg}");
			}
		}
	}

	private static void RestoreIme()
	{
		if (imeForcedOff)
		{
			imeForcedOff = false;
			Input.imeCompositionMode = (IMECompositionMode)0;
		}
	}

	private void RegisterConsoleCommand()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		object obj = <>c.<>9__33_0;
		if (obj == null)
		{
			ConsoleEvent val = delegate(ConsoleEventArgs args)
			{
				if (args.Args != null && args.Args.Length >= 3)
				{
					string text = args.Args[1].ToLowerInvariant();
					string text2 = args.Args[2].ToLowerInvariant();
					bool flag = text2 == "on" || text2 == "1" || text2 == "true";
					bool flag2 = text2 == "off" || text2 == "0" || text2 == "false";
					if (!flag && !flag2)
					{
						args.Context.AddString("Использование: consolefix <translit|refocus|ime|chatrefocus|chatslash> <on|off>");
						return;
					}
					switch (text)
					{
					case "translit":
						CfgTranslit.Value = flag;
						break;
					case "refocus":
						CfgAutoRefocus.Value = flag;
						break;
					case "ime":
						CfgDisableIme.Value = flag;
						break;
					case "chatrefocus":
						CfgChatRefocus.Value = flag;
						break;
					case "chatslash":
						CfgChatSlash.Value = flag;
						break;
					default:
						args.Context.AddString("Неизвестная функция: " + text);
						return;
					}
				}
				args.Context.AddString(string.Format("ConsoleFix {0}: консоль translit={1}, refocus={2}, ime={3} | чат refocus={4}, slash={5}", "1.1.0", CfgTranslit.Value, CfgAutoRefocus.Value, CfgDisableIme.Value, CfgChatRefocus.Value, CfgChatSlash.Value));
			};
			<>c.<>9__33_0 = val;
			obj = (object)val;
		}
		new ConsoleCommand("consolefix", "ConsoleFix: показать состояние или переключить (translit/refocus/ime/chatrefocus/chatslash on|off)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}
}