Decompiled source of LookingGlass Chinese Patch v1.1.1

BepInEx/plugins/LookingGlassZhCN/LookingGlassZhCN.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace LookingGlassZhCN;

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("local.lookingglass.zhcn.settings", "LookingGlass Chinese Patch", "1.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Id = "local.lookingglass.zhcn.settings";

	private Harmony harmony;

	private void Start()
	{
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Expected O, but got Unknown
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Expected O, but got Unknown
		try
		{
			if (!Chainloader.PluginInfos.TryGetValue("com.rune580.riskofoptions", out var value))
			{
				throw new InvalidOperationException("Risk Of Options was not loaded.");
			}
			Assembly assembly = ((object)value.Instance).GetType().Assembly;
			Type type = assembly.GetType("RiskOfOptions.Lib.LanguageApi", throwOnError: true);
			FieldInfo field = type.GetField("LanguageEntries", BindingFlags.Static | BindingFlags.NonPublic);
			if (field == null)
			{
				throw new MissingFieldException(type.FullName, "LanguageEntries");
			}
			if (!(field.GetValue(null) is IDictionary<string, string> entries))
			{
				throw new InvalidOperationException("Unexpected language registry type.");
			}
			int num = MenuTranslation.Apply(entries);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("LookingGlass ESC settings translated: " + num + " entries."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not translate the settings menu: " + ex));
		}
		try
		{
			if (!Chainloader.PluginInfos.TryGetValue("droppod.lookingglass", out var value2))
			{
				throw new InvalidOperationException("LookingGlass was not loaded.");
			}
			Type type2 = ((object)value2.Instance).GetType().Assembly.GetType("LookingGlass.StatsDisplay.StatsDisplayClass", throwOnError: true);
			MethodInfo method = type2.GetMethod("CalculateStuff", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			if (method == null || method.ReturnType != typeof(void))
			{
				throw new MissingMethodException(type2.FullName, "CalculateStuff(string)");
			}
			harmony = new Harmony("local.lookingglass.zhcn.settings");
			harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(Plugin).GetMethod("TranslateStats", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LookingGlass main/Tab stats translation enabled. Original configuration is unchanged.");
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not translate the stats display: " + ex2));
		}
	}

	private static void TranslateStats(ref string __0)
	{
		__0 = StatsTranslation.Translate(__0);
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
public static class MenuTranslation
{
	private const string LookingGlassPrefix = "RISK_OF_OPTIONS.DROPPOD.LOOKINGGLASS.";

	private static readonly Dictionary<string, string> Translations = LoadTranslations();

	private static Dictionary<string, string> LoadTranslations()
	{
		Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
		using Stream stream = typeof(MenuTranslation).Assembly.GetManifestResourceStream("LookingGlassZhCN.translations.tsv");
		if (stream == null)
		{
			throw new InvalidOperationException("Missing translation resource.");
		}
		using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
		string text;
		while ((text = streamReader.ReadLine()) != null)
		{
			int num = text.IndexOf('\t');
			if (num <= 0)
			{
				throw new InvalidDataException("Invalid translation row.");
			}
			dictionary.Add(Unescape(text.Substring(0, num)), Unescape(text.Substring(num + 1)));
		}
		return dictionary;
	}

	private static string Unescape(string value)
	{
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < value.Length; i++)
		{
			char c = value[i];
			if (c != '\\')
			{
				stringBuilder.Append(c);
				continue;
			}
			if (++i >= value.Length)
			{
				throw new InvalidDataException("Invalid escape.");
			}
			switch (value[i])
			{
			case '\\':
				stringBuilder.Append('\\');
				break;
			case 'n':
				stringBuilder.Append('\n');
				break;
			case 'r':
				stringBuilder.Append('\r');
				break;
			case 't':
				stringBuilder.Append('\t');
				break;
			default:
				throw new InvalidDataException("Unknown escape.");
			}
		}
		return stringBuilder.ToString();
	}

	public static string Translate(string token, string text)
	{
		if (token == null || !token.StartsWith("RISK_OF_OPTIONS.DROPPOD.LOOKINGGLASS.", StringComparison.OrdinalIgnoreCase))
		{
			return text;
		}
		if (token.EndsWith(".ITEM.SET", StringComparison.OrdinalIgnoreCase))
		{
			return "保留当前设置";
		}
		if (token.EndsWith(".ITEM.LOOKINGGLASS", StringComparison.OrdinalIgnoreCase))
		{
			return "LookingGlass 默认";
		}
		if (Translations.TryGetValue(text, out var value))
		{
			return value;
		}
		if (text != null && text.StartsWith("Position of detached Stats Display.\n[Default: ", StringComparison.Ordinal))
		{
			return "独立属性面板的位置。\n[默认:" + text.Substring("Position of detached Stats Display.\n[Default: ".Length);
		}
		return text;
	}

	public static int Apply(IDictionary<string, string> entries)
	{
		List<string> list = new List<string>(entries.Keys);
		int num = 0;
		foreach (string item in list)
		{
			string text = entries[item];
			string text2 = Translate(item, text);
			if (!string.Equals(text, text2, StringComparison.Ordinal))
			{
				entries[item] = text2;
				num++;
			}
		}
		if (!entries.ContainsKey("RISK_OF_OPTIONS_MOD_OPTIONS_HEADER_BUTTON_TEXT") || entries["RISK_OF_OPTIONS_MOD_OPTIONS_HEADER_BUTTON_TEXT"] != "模组选项")
		{
			entries["RISK_OF_OPTIONS_MOD_OPTIONS_HEADER_BUTTON_TEXT"] = "模组选项";
			num++;
		}
		return num;
	}
}
public static class StatsTranslation
{
	private static readonly Dictionary<string, string> Labels = new Dictionary<string, string>(StringComparer.Ordinal)
	{
		{ "Stats", "属性" },
		{ "Damage", "伤害" },
		{ "Attack Speed", "攻击速度" },
		{ "Crit Chance", "暴击率" },
		{ "Crit Stats", "暴击率 / 暴击倍率" },
		{ "Bleed Chance", "流血几率" },
		{ "Regen", "生命恢复" },
		{ "Armor", "护甲 / 减伤" },
		{ "Speed", "移动速度" },
		{ "Jumps", "可用跳跃" },
		{ "Kills", "击杀" },
		{ "Total Kills", "总击杀" },
		{ "DPS", "每秒伤害" },
		{ "Combo", "连击伤害" },
		{ "Max Combo", "最高连击伤害" },
		{ "Combo Timer", "连击剩余时间" },
		{ "Mountain Shrines", "山之神龛" },
		{ "Portals", "传送门" },
		{ "Portal", "传送门" },
		{ "Luck", "幸运" },
		{ "Max Hp", "最大生命值" },
		{ "Ehp", "有效生命值" },
		{ "Ping", "延迟" },
		{ "Curse", "诅咒" },
		{ "Gold", "黄金" },
		{ "Shop", "商店" },
		{ "Celestial", "天界" },
		{ "Void", "虚空" }
	};

	private static readonly Regex Protected = new Regex("(<[^>]*>|\\[[^\\]\\r\\n]*\\])");

	private static readonly Regex LineLabel = new Regex("(?m)(^|[\\r\\n])([ \\t]*)(Stats|Damage|Attack Speed|Crit Chance|Crit Stats|Bleed Chance|Regen|Armor|Speed|Jumps|Kills|Total Kills|DPS|Combo|Max Combo|Combo Timer|Mountain Shrines|Portals|Portal|Luck|Max Hp|Ehp|Ping|Curse)(?=[ \\t]*[::])");

	private static readonly Regex Title = new Regex("(?m)(^|[\\r\\n])([ \\t]*)Stats([ \\t]*)(?=$|[\\r\\n])");

	private static readonly Regex PortalLabel = new Regex("(?<![\\p{L}\\p{N}_])(Gold|Shop|Celestial|Void)(?=[ \\t]*[::])");

	public static string Translate(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		string[] array = Protected.Split(text);
		StringBuilder stringBuilder = new StringBuilder(text.Length);
		for (int i = 0; i < array.Length; i++)
		{
			if ((i & 1) != 0)
			{
				stringBuilder.Append(array[i]);
				continue;
			}
			string input = LineLabel.Replace(array[i], (Match m) => m.Groups[1].Value + m.Groups[2].Value + Labels[m.Groups[3].Value]);
			input = Title.Replace(input, "$1$2属性$3");
			input = PortalLabel.Replace(input, (Match m) => Labels[m.Value]);
			stringBuilder.Append(input);
		}
		string text2 = stringBuilder.ToString();
		if (!string.Equals(text, text2, StringComparison.Ordinal))
		{
			return text2;
		}
		return text;
	}
}