Decompiled source of CustomCharacterTranslationFix v1.0.1

BepInEx/plugins/TranslationFix.dll

Decompiled a day 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.Security;
using System.Security.Permissions;
using System.Text.Json;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime.Injection;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TranslationFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TranslationFix")]
[assembly: AssemblyTitle("TranslationFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 TranslationFix
{
	[BepInPlugin("com.custom.translationfix", "Custom Character Translation Fix", "3.1.0")]
	public class TranslationFixPlugin : BasePlugin
	{
		internal static ManualLogSource Logger;

		public override void Load()
		{
			Logger = ((BasePlugin)this).Log;
			ClassInjector.RegisterTypeInIl2Cpp<TranslationFixRunner>();
			((BasePlugin)this).AddComponent<TranslationFixRunner>();
			((BasePlugin)this).Log.LogInfo((object)"Custom Character Translation Fix 3.1.0 loaded.");
		}
	}
	public class TranslationFixRunner : MonoBehaviour
	{
		private const string TableName = "Main Menu";

		private static readonly Regex CustomKey = new Regex("^\\d{6,}\\.", RegexOptions.Compiled);

		private static readonly Dictionary<string, (string section, string field)> Fields = new Dictionary<string, (string, string)>
		{
			{
				"characterName",
				("character", "characterName")
			},
			{
				"characterDescription",
				("character", "characterDescription")
			},
			{
				"weaponName",
				("weapon", "weaponName")
			},
			{
				"weaponDescription",
				("weapon", "weaponDescription")
			},
			{
				"passiveName",
				("passive", "passiveName")
			},
			{
				"passiveDescription",
				("passive", "passiveDescription")
			}
		};

		private Dictionary<string, string> _values;

		private readonly HashSet<string> _reported = new HashSet<string>();

		private float _nextRun;

		private int _totalFixed;

		private bool _loggedError;

		public TranslationFixRunner(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			if (Time.unscaledTime < _nextRun)
			{
				return;
			}
			_nextRun = Time.unscaledTime + 1.5f;
			try
			{
				Fix();
			}
			catch (Exception ex)
			{
				if (!_loggedError)
				{
					_loggedError = true;
					TranslationFixPlugin.Logger.LogWarning((object)("Translation fix failed: " + ex));
				}
			}
		}

		private void LoadJsonValues()
		{
			_values = new Dictionary<string, string>();
			string[] files = Directory.GetFiles(Paths.BepInExRootPath, "*.custom.json", SearchOption.AllDirectories);
			TranslationFixPlugin.Logger.LogInfo((object)("Found " + files.Length + " .custom.json file(s)."));
			string[] array = files;
			foreach (string text in array)
			{
				try
				{
					using JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(text), new JsonDocumentOptions
					{
						AllowTrailingCommas = true
					});
					JsonElement rootElement = jsonDocument.RootElement;
					if (!rootElement.TryGetProperty("character", out var value) || !value.TryGetProperty("eCharacter", out var value2))
					{
						continue;
					}
					long @int = value2.GetInt64();
					foreach (KeyValuePair<string, (string, string)> field in Fields)
					{
						if (rootElement.TryGetProperty(field.Value.Item1, out var value3) && value3.TryGetProperty(field.Value.Item2, out var value4) && value4.ValueKind == JsonValueKind.String)
						{
							_values[@int + "." + field.Key] = value4.GetString();
						}
					}
					if (rootElement.TryGetProperty("skins", out var value5) && value5.ValueKind == JsonValueKind.Array)
					{
						int num = 0;
						foreach (JsonElement item in value5.EnumerateArray())
						{
							num++;
							JsonElement value7;
							string value6 = ((item.TryGetProperty("skinName", out value7) && value7.ValueKind == JsonValueKind.String) ? value7.GetString() : null);
							JsonElement value8;
							string text2 = ((item.TryGetProperty("description", out value8) && value8.ValueKind == JsonValueKind.String) ? value8.GetString() : null);
							if (!string.IsNullOrEmpty(value6))
							{
								_values[@int + ".skinName" + num] = value6;
							}
							_values[@int + ".skinDescription" + num] = (string.IsNullOrEmpty(text2) ? " " : text2);
						}
					}
					TranslationFixPlugin.Logger.LogInfo((object)("Read texts for character id " + @int + " from " + Path.GetFileName(text)));
				}
				catch (Exception ex)
				{
					TranslationFixPlugin.Logger.LogWarning((object)("Could not read " + text + ": " + ex.Message));
				}
			}
		}

		private void Fix()
		{
			if (!LocalizationSettings.HasSettings || !LocalizationSettings.InitializationOperation.IsDone)
			{
				return;
			}
			if (_values == null)
			{
				LoadJsonValues();
			}
			List<Locale> locales = LocalizationSettings.AvailableLocales.Locales;
			LocalizedStringDatabase stringDatabase = LocalizationSettings.StringDatabase;
			TableReference val = TableReference.TableReferenceFromString("Main Menu");
			List<StringTable> list = new List<StringTable>();
			for (int i = 0; i < locales.Count; i++)
			{
				StringTable table = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)stringDatabase).GetTable(val, locales[i]);
				if ((Object)(object)table != (Object)null)
				{
					list.Add(table);
				}
			}
			if (list.Count == 0)
			{
				return;
			}
			List<SharedTableEntry> entries = ((LocalizationTable)list[0]).SharedData.Entries;
			int num = 0;
			for (int j = 0; j < entries.Count; j++)
			{
				string key = entries[j].Key;
				if (string.IsNullOrEmpty(key) || !CustomKey.IsMatch(key))
				{
					continue;
				}
				string value = null;
				for (int k = 0; k < list.Count; k++)
				{
					if (value != null)
					{
						break;
					}
					StringTableEntry entry = ((DetailedLocalizationTable<StringTableEntry>)(object)list[k]).GetEntry(key);
					if (entry != null && !string.IsNullOrEmpty(entry.Value))
					{
						value = entry.Value;
					}
				}
				if (value == null)
				{
					_values.TryGetValue(key, out value);
				}
				if (value == null)
				{
					if (_reported.Add(key))
					{
						TranslationFixPlugin.Logger.LogWarning((object)("No text known for key '" + key + "' (not in any language, not in the JSON files)."));
					}
					continue;
				}
				for (int l = 0; l < list.Count; l++)
				{
					StringTableEntry entry2 = ((DetailedLocalizationTable<StringTableEntry>)(object)list[l]).GetEntry(key);
					if (entry2 == null || string.IsNullOrEmpty(entry2.Value))
					{
						((DetailedLocalizationTable<StringTableEntry>)(object)list[l]).AddEntry(key, value);
						num++;
					}
				}
			}
			if (num > 0)
			{
				_totalFixed += num;
				TranslationFixPlugin.Logger.LogInfo((object)("Filled " + num + " missing entries across " + list.Count + " language table(s) (total " + _totalFixed + ")."));
			}
		}
	}
}