Decompiled source of LethalFurryRU v1.0.3

plugins/LethalFurryRU/LethalFurry.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore;
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("LethalFurry")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LethalFurry")]
[assembly: AssemblyTitle("LethalFurry")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 LethalFurry
{
	[BepInPlugin("clauderushub.lethalfurry", "LethalFurry", "1.0.3")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "clauderushub.lethalfurry";

		internal static ManualLogSource Log;

		internal static string Dir;

		private void Awake()
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Dir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			Texts.Load(Path.Combine(Dir, "texts.json"));
			CodeStrings.Load(Path.Combine(Dir, "code.json"));
			Commands.Load(Path.Combine(Dir, "commands.json"));
			StoreNames.Load(Path.Combine(Dir, "store_names.json"));
			Voice.Load(Path.Combine(Dir, "audio"));
			Textures.Load(Path.Combine(Dir, "textures"));
			Harmony val = new Harmony("clauderushub.lethalfurry");
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly());
			foreach (Type type in typesFromAssembly)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0)
				{
					try
					{
						val.CreateClassProcessor(type).Patch();
					}
					catch (Exception ex)
					{
						Log.LogError((object)("перехват " + type.Name + ": " + (ex.InnerException?.Message ?? ex.Message)));
					}
				}
			}
			SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode)
			{
				Sweep(((Scene)(ref scene)).name);
			};
			CodeStrings.Patch(val);
			Log.LogInfo((object)$"готово: строк {Texts.Count}, в коде {CodeStrings.Patched} методов, команд {Commands.Count}, голосов {Voice.Count}, текстур {Textures.Count}");
		}

		private static void Sweep(string scene)
		{
			Safe("текстуры", Textures.Apply);
			Safe("шрифты", Fonts.Apply);
			Safe("терминал", Texts.ApplyTerminal);
			Safe("данные", Texts.ApplyData);
			Safe("ввод терминала", Commands.AllowCyrillic);
			Safe("текст сцены", Texts.ApplyScene);
		}

		private static void Safe(string what, Action a)
		{
			try
			{
				a();
			}
			catch (Exception ex)
			{
				Log.LogError((object)(what + ": " + ex));
			}
		}
	}
	internal static class Texts
	{
		private class File_
		{
			public Dictionary<string, string> exact;
		}

		private static Dictionary<string, string> exact = new Dictionary<string, string>();

		private static readonly (Type type, string[] fields)[] DataFields = new(Type, string[])[5]
		{
			(typeof(SelectableLevel), new string[1] { "LevelDescription" }),
			(typeof(InteractTrigger), new string[3] { "hoverTip", "disabledHoverTip", "holdTip" }),
			(typeof(Item), new string[1] { "toolTips" }),
			(typeof(ScanNodeProperties), new string[2] { "headerText", "subText" }),
			(typeof(StunGrenadeItem), new string[1] { "throwString" })
		};

		public static int Count => exact.Count;

		public static void Load(string path)
		{
			if (File.Exists(path))
			{
				File_ file_ = JsonConvert.DeserializeObject<File_>(File.ReadAllText(path));
				if (file_?.exact != null)
				{
					exact = file_.exact;
				}
			}
		}

		public static string Translate(string s)
		{
			if (string.IsNullOrEmpty(s) || exact.Count == 0)
			{
				return s;
			}
			if (exact.TryGetValue(s, out var value))
			{
				return value;
			}
			string text = s.Trim();
			if (text.Length != s.Length && exact.TryGetValue(text, out value))
			{
				return s.Substring(0, s.IndexOf(text, StringComparison.Ordinal)) + value + s.Substring(s.IndexOf(text, StringComparison.Ordinal) + text.Length);
			}
			return Words.Apply(s);
		}

		public static void ApplyTerminal()
		{
			TerminalNode[] array = Resources.FindObjectsOfTypeAll<TerminalNode>();
			foreach (TerminalNode val in array)
			{
				string text = Translate(val.displayText);
				if ((object)text != val.displayText)
				{
					val.displayText = text;
				}
			}
		}

		public static void ApplyData()
		{
			(Type, string[])[] dataFields = DataFields;
			for (int i = 0; i < dataFields.Length; i++)
			{
				(Type, string[]) tuple = dataFields[i];
				Type item = tuple.Item1;
				string[] item2 = tuple.Item2;
				List<FieldInfo> list = new List<FieldInfo>();
				string[] array = item2;
				foreach (string text in array)
				{
					FieldInfo fieldInfo = AccessTools.Field(item, text);
					if (fieldInfo != null)
					{
						list.Add(fieldInfo);
					}
				}
				Object[] array2 = Resources.FindObjectsOfTypeAll(item);
				foreach (Object o in array2)
				{
					foreach (FieldInfo item3 in list)
					{
						TranslateField(o, item3);
					}
				}
			}
			TimeOfDay[] array3 = Resources.FindObjectsOfTypeAll<TimeOfDay>();
			foreach (TimeOfDay obj in array3)
			{
				string[] array = new string[2] { "shipLeavingSoonDialogue", "shipLeavingEarlyDialogue" };
				foreach (string text2 in array)
				{
					if (AccessTools.Field(typeof(TimeOfDay), text2)?.GetValue(obj) is DialogueSegment[] array4)
					{
						DialogueSegment[] array5 = array4;
						foreach (DialogueSegment obj2 in array5)
						{
							obj2.bodyText = Translate(obj2.bodyText);
							obj2.speakerText = Translate(obj2.speakerText);
						}
					}
				}
			}
		}

		private static void TranslateField(object o, FieldInfo fi)
		{
			if (fi.FieldType == typeof(string))
			{
				string obj = (string)fi.GetValue(o);
				string text = Translate(obj);
				if ((object)obj != text)
				{
					fi.SetValue(o, text);
				}
			}
			else if (fi.FieldType == typeof(string[]) && fi.GetValue(o) is string[] array)
			{
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = Translate(array[i]);
				}
			}
		}

		public static void ApplyScene()
		{
			TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
			foreach (TMP_Text val in array)
			{
				string text = Translate(val.text);
				if ((object)text != val.text)
				{
					val.text = text;
				}
			}
			Text[] array2 = Resources.FindObjectsOfTypeAll<Text>();
			foreach (Text val2 in array2)
			{
				string text2 = Translate(val2.text);
				if ((object)text2 != val2.text)
				{
					val2.text = text2;
				}
			}
		}
	}
	internal static class CodeStrings
	{
		private static Dictionary<string, Dictionary<string, string>> map = new Dictionary<string, Dictionary<string, string>>();

		private static readonly Dictionary<MethodBase, Dictionary<string, string>> byMethod = new Dictionary<MethodBase, Dictionary<string, string>>();

		public static int Patched;

		public static void Load(string path)
		{
			if (File.Exists(path))
			{
				map = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(File.ReadAllText(path));
			}
		}

		public static void Patch(Harmony harmony)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(CodeStrings), "Transpiler", (Type[])null, (Type[])null));
			foreach (KeyValuePair<string, Dictionary<string, string>> item in map)
			{
				int num = item.Key.LastIndexOf("::", StringComparison.Ordinal);
				Type type = AccessTools.TypeByName(item.Key.Substring(0, num).Replace('/', '+'));
				string text = item.Key.Substring(num + 2);
				if (type == null)
				{
					Plugin.Log.LogWarning((object)("нет типа: " + item.Key));
					continue;
				}
				foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
				{
					if (!(declaredMethod.Name != text) && !declaredMethod.IsAbstract)
					{
						byMethod[declaredMethod] = item.Value;
						try
						{
							harmony.Patch((MethodBase)declaredMethod, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
							Patched++;
						}
						catch (Exception ex)
						{
							Plugin.Log.LogError((object)("код " + item.Key + ": " + ex.Message));
						}
					}
				}
				if (!(text == ".ctor") && !(text == ".cctor"))
				{
					continue;
				}
				foreach (ConstructorInfo declaredConstructor in AccessTools.GetDeclaredConstructors(type, (bool?)null))
				{
					byMethod[declaredConstructor] = item.Value;
					try
					{
						harmony.Patch((MethodBase)declaredConstructor, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
						Patched++;
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogError((object)("код " + item.Key + ": " + ex2.Message));
					}
				}
			}
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> code, MethodBase original)
		{
			byMethod.TryGetValue(original, out var strings);
			foreach (CodeInstruction item in code)
			{
				if (strings != null && item.opcode == OpCodes.Ldstr && item.operand is string key && strings.TryGetValue(key, out var value))
				{
					item.operand = value;
				}
				yield return item;
			}
		}
	}
	internal static class Commands
	{
		private static List<KeyValuePair<string[], string>> phrases = new List<KeyValuePair<string[], string>>();

		public static int Count => phrases.Count;

		public static void Load(string path)
		{
			if (!File.Exists(path))
			{
				return;
			}
			foreach (KeyValuePair<string, string> item in JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path)))
			{
				if (!item.Key.StartsWith("_"))
				{
					string[] key = item.Key.ToLowerInvariant().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					phrases.Add(new KeyValuePair<string[], string>(key, item.Value));
				}
			}
			phrases.Sort((KeyValuePair<string[], string> a, KeyValuePair<string[], string> b) => b.Key.Length.CompareTo(a.Key.Length));
		}

		public static void AllowCyrillic()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Terminal[] array = Resources.FindObjectsOfTypeAll<Terminal>();
			for (int i = 0; i < array.Length; i++)
			{
				TMP_InputField screenText = array[i].screenText;
				if (!((Object)(object)screenText == (Object)null) && (int)screenText.characterValidation != 0)
				{
					Plugin.Log.LogInfo((object)$"терминал: снят фильтр ввода {screenText.characterValidation}");
					screenText.characterValidation = (CharacterValidation)0;
				}
			}
		}

		public static string Translate(string input)
		{
			if (phrases.Count == 0 || string.IsNullOrEmpty(input))
			{
				return input;
			}
			string[] array = input.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			List<string> list = new List<string>();
			int num = 0;
			while (num < array.Length)
			{
				bool flag = false;
				foreach (KeyValuePair<string[], string> phrase in phrases)
				{
					string[] key = phrase.Key;
					if (num + key.Length <= array.Length)
					{
						bool flag2 = true;
						for (int i = 0; i < key.Length && flag2; i++)
						{
							flag2 = string.Equals(array[num + i], key[i], StringComparison.OrdinalIgnoreCase);
						}
						if (flag2)
						{
							list.Add(phrase.Value);
							num += key.Length;
							flag = true;
							break;
						}
					}
				}
				if (!flag)
				{
					list.Add(ByPrefix(array[num]) ?? array[num]);
					num++;
				}
			}
			return string.Join(" ", list);
		}

		private static string ByPrefix(string w)
		{
			if (w.Length < 2)
			{
				return null;
			}
			string text = null;
			foreach (KeyValuePair<string[], string> phrase in phrases)
			{
				if (phrase.Key.Length == 1 && phrase.Key[0].StartsWith(w, StringComparison.OrdinalIgnoreCase))
				{
					if (text != null && text != phrase.Value)
					{
						return null;
					}
					text = phrase.Value;
				}
			}
			return text;
		}
	}
	internal static class StoreNames
	{
		private static readonly List<KeyValuePair<Regex, string>> rules = new List<KeyValuePair<Regex, string>>();

		public static int Count => rules.Count;

		public static void Load(string path)
		{
			if (!File.Exists(path))
			{
				return;
			}
			foreach (KeyValuePair<string, string> item in JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path)))
			{
				if (!item.Key.StartsWith("_"))
				{
					Regex key = new Regex("(?m)^(\\*\\s*)?" + Regex.Escape(item.Key) + "[ \\t]+//[ \\t]+");
					rules.Add(new KeyValuePair<Regex, string>(key, "$1" + item.Key + " (" + item.Value + ")  //  "));
				}
			}
		}

		public static string Apply(string s)
		{
			if (string.IsNullOrEmpty(s) || s.IndexOf("//", StringComparison.Ordinal) < 0)
			{
				return s;
			}
			foreach (KeyValuePair<Regex, string> rule in rules)
			{
				s = rule.Key.Replace(s, rule.Value);
			}
			return s;
		}
	}
	[HarmonyPatch(typeof(Terminal), "TextPostProcess")]
	internal static class StoreScreen
	{
		private static void Postfix(ref string __result)
		{
			__result = Words.Apply(StoreNames.Apply(__result));
		}
	}
	[HarmonyPatch(typeof(HUDManager), "ReadDialogue")]
	internal static class PilotDialogue
	{
		private static void Prefix(DialogueSegment[] __0)
		{
			if (__0 == null)
			{
				return;
			}
			foreach (DialogueSegment val in __0)
			{
				if (val != null)
				{
					val.speakerText = Texts.Translate(val.speakerText);
					val.bodyText = Texts.Translate(val.bodyText);
				}
			}
		}
	}
	internal static class Words
	{
		private static readonly Dictionary<string, string> Weather = new Dictionary<string, string>
		{
			["Rainy"] = "Дождь",
			["Stormy"] = "Гроза",
			["Foggy"] = "Туман",
			["Flooded"] = "Потоп",
			["Eclipsed"] = "Затмение",
			["DustClouds"] = "Пыльная буря",
			["None"] = "Ясно"
		};

		private static readonly Dictionary<string, string> Days = new Dictionary<string, string>
		{
			["Monday"] = "понедельник",
			["Tuesday"] = "вторник",
			["Wednesday"] = "среда",
			["Thursday"] = "четверг",
			["Friday"] = "пятница",
			["Saturday"] = "суббота",
			["Sunday"] = "воскресенье"
		};

		private static readonly Regex InList = new Regex("\\((Rainy|Stormy|Foggy|Flooded|Eclipsed|DustClouds)\\)");

		private static readonly Regex OnScreen = new Regex("(Погода: )(Rainy|Stormy|Foggy|Flooded|Eclipsed|DustClouds|None)\\b");

		private static readonly Regex Today = new Regex("(Сегодня )(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)\\b");

		public static string Apply(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return s;
			}
			if (s.IndexOf('(') >= 0)
			{
				s = InList.Replace(s, (Match m) => "(" + Weather[m.Groups[1].Value] + ")");
			}
			if (s.IndexOf("Погода: ", StringComparison.Ordinal) >= 0)
			{
				s = OnScreen.Replace(s, (Match m) => m.Groups[1].Value + Weather[m.Groups[2].Value]);
			}
			if (s.IndexOf("Сегодня ", StringComparison.Ordinal) >= 0)
			{
				s = Today.Replace(s, (Match m) => m.Groups[1].Value + Days[m.Groups[2].Value]);
			}
			return s;
		}
	}
	[HarmonyPatch(typeof(Terminal), "RemovePunctuation")]
	internal static class TerminalInput
	{
		private static void Postfix(ref string __result)
		{
			string text = Commands.Translate(__result);
			if (text != __result)
			{
				Plugin.Log.LogInfo((object)("терминал: «" + __result + "» -> «" + text + "»"));
			}
			__result = text;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class TmpTextSetter
	{
		private static void Prefix(ref string value)
		{
			value = Texts.Translate(value);
		}
	}
	[HarmonyPatch]
	internal static class TmpSetText
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			Type[][] array = new Type[2][]
			{
				new Type[1] { typeof(string) },
				new Type[2]
				{
					typeof(string),
					typeof(bool)
				}
			};
			foreach (Type[] array2 in array)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(TMP_Text), "SetText", array2, (Type[])null);
				if (methodInfo != null)
				{
					yield return methodInfo;
				}
			}
		}

		private static void Prefix(ref string sourceText)
		{
			sourceText = Texts.Translate(sourceText);
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class UiTextSetter
	{
		private static void Prefix(ref string value)
		{
			value = Texts.Translate(value);
		}
	}
	internal static class Voice
	{
		private static readonly Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>();

		private static readonly HashSet<string> logged = new HashSet<string>();

		public static int Count => clips.Count;

		public static void Load(string dir)
		{
			if (!Directory.Exists(dir))
			{
				return;
			}
			string[] files = Directory.GetFiles(dir, "*.wav");
			foreach (string path in files)
			{
				try
				{
					AudioClip val = Wav.Read(path, Path.GetFileNameWithoutExtension(path));
					Object.DontDestroyOnLoad((Object)(object)val);
					((Object)val).hideFlags = (HideFlags)61;
					clips[((Object)val).name] = val;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)(Path.GetFileName(path) + ": " + ex.Message));
				}
			}
		}

		public static AudioClip Swap(AudioClip c)
		{
			if ((Object)(object)c == (Object)null || !clips.TryGetValue(((Object)c).name, out var value) || c == value)
			{
				return c;
			}
			if (logged.Add(((Object)c).name))
			{
				Plugin.Log.LogInfo((object)("голос: " + ((Object)c).name));
			}
			return value;
		}
	}
	[HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[]
	{
		typeof(AudioClip),
		typeof(float)
	})]
	internal static class PlayOneShot
	{
		private static void Prefix(ref AudioClip clip)
		{
			clip = Voice.Swap(clip);
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class ClipSetter
	{
		private static void Prefix(ref AudioClip value)
		{
			value = Voice.Swap(value);
		}
	}
	[HarmonyPatch]
	internal static class PlayStored
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(AudioSource), "Play", Type.EmptyTypes, (Type[])null);
			yield return AccessTools.Method(typeof(AudioSource), "Play", new Type[1] { typeof(ulong) }, (Type[])null);
			yield return AccessTools.Method(typeof(AudioSource), "PlayDelayed", new Type[1] { typeof(float) }, (Type[])null);
		}

		private static void Prefix(AudioSource __instance)
		{
			AudioClip clip = __instance.clip;
			AudioClip val = Voice.Swap(clip);
			if (clip != val)
			{
				__instance.clip = val;
			}
		}
	}
	[HarmonyPatch(typeof(AudioSource), "PlayClipAtPoint", new Type[]
	{
		typeof(AudioClip),
		typeof(Vector3),
		typeof(float)
	})]
	internal static class PlayAtPoint
	{
		private static void Prefix(ref AudioClip clip)
		{
			clip = Voice.Swap(clip);
		}
	}
	internal static class Wav
	{
		public static AudioClip Read(string path, string name)
		{
			byte[] array = File.ReadAllBytes(path);
			if (array.Length < 44 || array[0] != 82 || array[8] != 87)
			{
				throw new Exception("не WAV");
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = -1;
			int num5 = 0;
			int num6;
			for (int i = 12; i + 8 <= array.Length; i += 8 + num6 + (num6 & 1))
			{
				string text = Encoding.ASCII.GetString(array, i, 4);
				num6 = BitConverter.ToInt32(array, i + 4);
				if (text == "fmt ")
				{
					if (BitConverter.ToInt16(array, i + 8) != 1)
					{
						throw new Exception("не PCM");
					}
					num = BitConverter.ToInt16(array, i + 10);
					num2 = BitConverter.ToInt32(array, i + 12);
					num3 = BitConverter.ToInt16(array, i + 22);
				}
				else if (text == "data")
				{
					num4 = i + 8;
					num5 = Math.Min(num6, array.Length - num4);
					break;
				}
			}
			if (num3 != 16 || num4 < 0)
			{
				throw new Exception($"нужен PCM 16 бит (здесь {num3})");
			}
			int num7 = num5 / 2;
			float[] array2 = new float[num7];
			for (int j = 0; j < num7; j++)
			{
				array2[j] = (float)BitConverter.ToInt16(array, num4 + j * 2) / 32768f;
			}
			AudioClip obj = AudioClip.Create(name, num7 / num, num, num2, false);
			obj.SetData(array2, 0);
			return obj;
		}
	}
	internal static class Textures
	{
		private static readonly Dictionary<string, string> files = new Dictionary<string, string>();

		private static readonly HashSet<int> done = new HashSet<int>();

		private static readonly HashSet<string> point = new HashSet<string>();

		public static int Count => files.Count;

		public static void Load(string dir)
		{
			if (!Directory.Exists(dir))
			{
				return;
			}
			string[] array = Directory.GetFiles(dir, "*.png");
			foreach (string text in array)
			{
				files[Path.GetFileNameWithoutExtension(text)] = text;
			}
			string path = Path.Combine(dir, "point.txt");
			if (!File.Exists(path))
			{
				return;
			}
			array = File.ReadAllLines(path);
			foreach (string text2 in array)
			{
				if (text2.Trim().Length > 0 && !text2.TrimStart().StartsWith("#"))
				{
					point.Add(text2.Trim());
				}
			}
		}

		public static void Apply()
		{
			if (files.Count == 0)
			{
				return;
			}
			Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>();
			foreach (Texture2D val in array)
			{
				if (!files.TryGetValue(((Object)val).name, out var value) || done.Contains(((Object)val).GetInstanceID()))
				{
					continue;
				}
				if (ImageConversion.LoadImage(val, File.ReadAllBytes(value), false))
				{
					done.Add(((Object)val).GetInstanceID());
					if (point.Contains(((Object)val).name))
					{
						((Texture)val).filterMode = (FilterMode)0;
					}
					Plugin.Log.LogInfo((object)("текстура: " + ((Object)val).name));
				}
				else
				{
					Plugin.Log.LogWarning((object)("текстура не загрузилась: " + ((Object)val).name));
				}
			}
		}
	}
	internal static class Fonts
	{
		private static readonly HashSet<int> opened = new HashSet<int>();

		private static readonly Dictionary<string, TMP_FontAsset> fallbacks = new Dictionary<string, TMP_FontAsset>();

		public static void Apply()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			Font val = null;
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			foreach (Font val2 in array)
			{
				if (((Object)val2).name == "3270-Regular")
				{
					val = val2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(TMP_FontAsset), "m_SourceFontFile");
			List<string> list = new List<string>();
			TMP_FontAsset[] array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			FaceInfo faceInfo;
			foreach (TMP_FontAsset val3 in array2)
			{
				if ((int)val3.atlasPopulationMode != 1 || val3.atlasTextures == null || !opened.Add(((Object)val3).GetInstanceID()))
				{
					continue;
				}
				faceInfo = val3.faceInfo;
				int num;
				if (((FaceInfo)(ref faceInfo)).familyName != null)
				{
					faceInfo = val3.faceInfo;
					num = (((FaceInfo)(ref faceInfo)).familyName.Contains("3270") ? 1 : 0);
				}
				else
				{
					num = 0;
				}
				bool flag = (byte)num != 0;
				string text = "";
				if ((Object)(object)val3.sourceFontFile == (Object)null && flag && fieldInfo != null)
				{
					fieldInfo.SetValue(val3, val);
					text += " +исходник";
				}
				for (int j = 0; j < val3.atlasTextures.Length; j++)
				{
					Texture2D val4 = val3.atlasTextures[j];
					if ((Object)(object)val4 == (Object)null || ((Texture)val4).isReadable)
					{
						continue;
					}
					Texture2D val5 = Readable(val4);
					val3.atlasTextures[j] = val5;
					Material[] array3 = Resources.FindObjectsOfTypeAll<Material>();
					foreach (Material val6 in array3)
					{
						if (val6.HasProperty(ShaderUtilities.ID_MainTex) && (Object)(object)val6.GetTexture(ShaderUtilities.ID_MainTex) == (Object)(object)val4)
						{
							val6.SetTexture(ShaderUtilities.ID_MainTex, (Texture)(object)val5);
						}
					}
					text += " +атлас";
				}
				list.Add(((Object)val3).name + ((text.Length > 0) ? text : " (как есть)") + (((Object)(object)val3.sourceFontFile == (Object)null) ? " БЕЗ ИСХОДНИКА" : ""));
			}
			if (list.Count > 0)
			{
				Plugin.Log.LogInfo((object)("шрифты: " + string.Join("; ", list)));
			}
			array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val7 in array2)
			{
				if (((Object)val7).name.StartsWith("LethalFurry") || (val7.HasCharacter('Ж', false, true) && val7.HasCharacter('л', false, true)))
				{
					continue;
				}
				faceInfo = val7.faceInfo;
				if ((((FaceInfo)(ref faceInfo)).familyName ?? "").Contains("Liberation"))
				{
					continue;
				}
				TMP_FontAsset val8 = FallbackFor(val, val7);
				if (val7.fallbackFontAssetTable == null)
				{
					val7.fallbackFontAssetTable = new List<TMP_FontAsset>();
				}
				if (!val7.fallbackFontAssetTable.Contains(val8))
				{
					val7.fallbackFontAssetTable.Insert(0, val8);
					ManualLogSource log = Plugin.Log;
					string[] obj = new string[6]
					{
						"шрифты: ",
						((Object)val7).name,
						" (",
						null,
						null,
						null
					};
					Material material = ((TMP_Asset)val7).material;
					object obj2;
					if (material == null)
					{
						obj2 = null;
					}
					else
					{
						Shader shader = material.shader;
						obj2 = ((shader != null) ? ((Object)shader).name : null);
					}
					obj[3] = (string)obj2;
					obj[4] = ") <- ";
					obj[5] = ((Object)val8).name;
					log.LogInfo((object)string.Concat(obj));
				}
			}
		}

		private static TMP_FontAsset FallbackFor(Font src, TMP_FontAsset like)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_00a3: Invalid comparison between Unknown and I4
			//IL_00e0: 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_00fe: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			FaceInfo faceInfo = like.faceInfo;
			int num = Mathf.Max(8, Mathf.RoundToInt((float)((FaceInfo)(ref faceInfo)).pointSize));
			int num2 = ((like.atlasPadding > 0) ? like.atlasPadding : 9);
			GlyphRenderMode atlasRenderMode = like.atlasRenderMode;
			string text = $"{num}/{num2}/{atlasRenderMode}";
			if (fallbacks.TryGetValue(text, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			value = TMP_FontAsset.CreateFontAsset(src, num, num2, (GlyphRenderMode)4165, 1024, 1024, (AtlasPopulationMode)1, true);
			((Object)value).name = "LethalFurry Cyrillic " + text;
			if ((int)atlasRenderMode != 4165)
			{
				AccessTools.Field(typeof(TMP_FontAsset), "m_AtlasRenderMode")?.SetValue(value, atlasRenderMode);
			}
			if ((Object)(object)((TMP_Asset)like).material != (Object)null)
			{
				Material val = new Material(((TMP_Asset)like).material)
				{
					name = ((Object)value).name + " Material"
				};
				val.SetTexture(ShaderUtilities.ID_MainTex, (Texture)(object)value.atlasTexture);
				((TMP_Asset)value).material = val;
			}
			Object.DontDestroyOnLoad((Object)(object)value);
			fallbacks[text] = value;
			return value;
		}

		private static Texture2D Readable(Texture2D src)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0086: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00bd: Expected O, but got Unknown
			int width = ((Texture)src).width;
			int height = ((Texture)src).height;
			RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)1);
			Graphics.Blit((Texture)(object)src, temporary);
			RenderTexture active = RenderTexture.active;
			RenderTexture.active = temporary;
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, false, true);
			val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
			val.Apply();
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			Texture2D val2 = new Texture2D(width, height, (TextureFormat)(((int)src.format == 1) ? 1 : 4), false, true)
			{
				name = ((Object)src).name,
				filterMode = ((Texture)src).filterMode,
				wrapMode = ((Texture)src).wrapMode
			};
			val2.SetPixels32(val.GetPixels32());
			val2.Apply(false, false);
			Object.Destroy((Object)(object)val);
			Object.DontDestroyOnLoad((Object)val2);
			return val2;
		}
	}
}