Decompiled source of Sweet Russian Translate v0.1.0

SweetRussianTranslate.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.TextCore;

[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("SweetRussianTranslate")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("SweetRussianTranslate")]
[assembly: AssemblyTitle("SweetRussianTranslate")]
[assembly: AssemblyVersion("0.1.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 SweetRussianTranslate
{
	[BepInPlugin("sweet.russiantranslate", "Sweet Russian Translate", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "sweet.russiantranslate";

		internal static ManualLogSource Log;

		internal static string ModFolder;

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ModFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			new Harmony("sweet.russiantranslate").PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)("Sweet Russian Translate loaded from " + ModFolder));
		}
	}
	[HarmonyPatch(typeof(SemiUI), "Start")]
	internal static class HardcodedLabelPatch
	{
		private static Dictionary<string, string> labels;

		[HarmonyPostfix]
		private static void Postfix(SemiUI __instance)
		{
			if (labels == null)
			{
				labels = LoadLabels();
			}
			if (labels.Count == 0)
			{
				return;
			}
			TMP_Text[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				if (val.text != null && labels.TryGetValue(val.text, out var value))
				{
					val.text = value;
				}
			}
		}

		private static Dictionary<string, string> LoadLabels()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string path = Path.Combine(Plugin.ModFolder, "Hardcoded.tsv");
			if (!File.Exists(path))
			{
				return dictionary;
			}
			try
			{
				string[] array = File.ReadAllLines(path, Encoding.UTF8);
				foreach (string text in array)
				{
					if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("#"))
					{
						string[] array2 = text.Split('\t');
						if (array2.Length == 2 && !string.IsNullOrWhiteSpace(array2[1]))
						{
							dictionary[array2[0]] = array2[1].Replace("\\n", "\n");
						}
					}
				}
				Plugin.Log.LogInfo((object)("Loaded " + dictionary.Count + " hardcoded label replacements."));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to read Hardcoded.tsv: " + ex.Message));
			}
			return dictionary;
		}
	}
	[HarmonyPatch(typeof(LocalizationManager), "Awake")]
	internal static class LocalizationOverridePatch
	{
		private static readonly string[] TableNames = new string[3] { "HUD", "Menu", "Game" };

		private static bool fontLoaded;

		[HarmonyPostfix]
		private static void Postfix()
		{
			LoadCyrillicFallbackFont();
			string[] tableNames = TableNames;
			foreach (string text in tableNames)
			{
				try
				{
					ApplyTable(text);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to apply " + text + ".tsv: " + ex.Message));
				}
			}
		}

		private static void ApplyTable(string tableName)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(Plugin.ModFolder, tableName + ".tsv");
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("Missing translation file: " + text));
				return;
			}
			StringTable table = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTable(TableReference.op_Implicit(tableName), LocalizationSettings.ProjectLocale);
			if ((Object)(object)table == (Object)null)
			{
				Plugin.Log.LogError((object)("String table not found: " + tableName));
				return;
			}
			int num = 0;
			string[] array = File.ReadAllLines(text, Encoding.UTF8);
			foreach (string text2 in array)
			{
				if (string.IsNullOrWhiteSpace(text2) || text2.StartsWith("#"))
				{
					continue;
				}
				string[] array2 = text2.Split('\t');
				if (array2.Length == 2 && !string.IsNullOrWhiteSpace(array2[1]))
				{
					string text3 = array2[1].Replace("\\n", "\n");
					StringTableEntry entry = ((DetailedLocalizationTable<StringTableEntry>)(object)table).GetEntry(array2[0]);
					if (entry != null)
					{
						entry.Value = text3;
					}
					else
					{
						((DetailedLocalizationTable<StringTableEntry>)(object)table).AddEntry(array2[0], text3);
					}
					num++;
				}
			}
			Plugin.Log.LogInfo((object)("Applied " + num + " strings to table " + tableName + "."));
		}

		private static void LoadCyrillicFallbackFont()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			if (fontLoaded)
			{
				return;
			}
			fontLoaded = true;
			string text = Path.Combine(Plugin.ModFolder, "Teko-Cyrillic.ttf");
			if (!File.Exists(text))
			{
				Plugin.Log.LogError((object)("Font not found: " + text));
				return;
			}
			try
			{
				TMP_FontAsset val = FindGameTekoAsset();
				TMP_FontAsset obj;
				if (!((Object)(object)val != (Object)null))
				{
					obj = TMP_FontAsset.CreateFontAsset(new Font(text));
				}
				else
				{
					Font val2 = new Font(text);
					FaceInfo faceInfo = val.faceInfo;
					obj = TMP_FontAsset.CreateFontAsset(val2, ((FaceInfo)(ref faceInfo)).pointSize, val.atlasPadding, val.atlasRenderMode, val.atlasWidth, val.atlasHeight, (AtlasPopulationMode)1, true);
				}
				TMP_FontAsset val3 = obj;
				((Object)val3).name = "Teko-Cyrillic SDF";
				((Object)val3).hideFlags = (HideFlags)32;
				if ((Object)(object)val != (Object)null)
				{
					CopyVerticalMetrics(val, val3);
				}
				TMP_Settings.fallbackFontAssets?.Insert(0, val3);
				TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				foreach (TMP_FontAsset val4 in array)
				{
					if (!((Object)(object)val4 == (Object)(object)val3) && ((Object)val4).name.Contains("Teko"))
					{
						if (val4.fallbackFontAssetTable == null)
						{
							val4.fallbackFontAssetTable = new List<TMP_FontAsset>();
						}
						val4.fallbackFontAssetTable.Insert(0, val3);
					}
				}
				Plugin.Log.LogInfo((object)("Cyrillic fallback font registered" + (((Object)(object)val != (Object)null) ? (" (matched to " + ((Object)val).name + ").") : " (no Teko reference found).")));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to load Cyrillic font: " + ex));
			}
		}

		private static void CopyVerticalMetrics(TMP_FontAsset from, TMP_FontAsset to)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			FaceInfo faceInfo = from.faceInfo;
			FaceInfo faceInfo2 = to.faceInfo;
			((FaceInfo)(ref faceInfo2)).scale = ((FaceInfo)(ref faceInfo)).scale;
			((FaceInfo)(ref faceInfo2)).lineHeight = ((FaceInfo)(ref faceInfo)).lineHeight;
			((FaceInfo)(ref faceInfo2)).ascentLine = ((FaceInfo)(ref faceInfo)).ascentLine;
			((FaceInfo)(ref faceInfo2)).capLine = ((FaceInfo)(ref faceInfo)).capLine;
			((FaceInfo)(ref faceInfo2)).meanLine = ((FaceInfo)(ref faceInfo)).meanLine;
			((FaceInfo)(ref faceInfo2)).baseline = ((FaceInfo)(ref faceInfo)).baseline;
			((FaceInfo)(ref faceInfo2)).descentLine = ((FaceInfo)(ref faceInfo)).descentLine;
			((FaceInfo)(ref faceInfo2)).superscriptOffset = ((FaceInfo)(ref faceInfo)).superscriptOffset;
			((FaceInfo)(ref faceInfo2)).superscriptSize = ((FaceInfo)(ref faceInfo)).superscriptSize;
			((FaceInfo)(ref faceInfo2)).subscriptOffset = ((FaceInfo)(ref faceInfo)).subscriptOffset;
			((FaceInfo)(ref faceInfo2)).subscriptSize = ((FaceInfo)(ref faceInfo)).subscriptSize;
			((FaceInfo)(ref faceInfo2)).underlineOffset = ((FaceInfo)(ref faceInfo)).underlineOffset;
			((FaceInfo)(ref faceInfo2)).underlineThickness = ((FaceInfo)(ref faceInfo)).underlineThickness;
			((FaceInfo)(ref faceInfo2)).strikethroughOffset = ((FaceInfo)(ref faceInfo)).strikethroughOffset;
			((FaceInfo)(ref faceInfo2)).strikethroughThickness = ((FaceInfo)(ref faceInfo)).strikethroughThickness;
			((FaceInfo)(ref faceInfo2)).tabWidth = ((FaceInfo)(ref faceInfo)).tabWidth;
			to.faceInfo = faceInfo2;
			Plugin.Log.LogInfo((object)$"Metrics aligned to {((Object)from).name}: pointSize {((FaceInfo)(ref faceInfo)).pointSize}, lineHeight {((FaceInfo)(ref faceInfo)).lineHeight}, baseline {((FaceInfo)(ref faceInfo)).baseline}, ascent {((FaceInfo)(ref faceInfo)).ascentLine}, descent {((FaceInfo)(ref faceInfo)).descentLine}.");
		}

		private static TMP_FontAsset FindGameTekoAsset()
		{
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val in array)
			{
				if (((Object)val).name.Contains("Teko"))
				{
					return val;
				}
			}
			return null;
		}
	}
}