Decompiled source of SimpleSilksongLocalizer v0.1.0

SimpleSilksongLocalizer.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Xml;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GlobalEnums;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using TeamCherry.Localization;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SimpleSilksongLocalizer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+9037140b01be5b0bad4d9e3f007d5c35de03136c")]
[assembly: AssemblyProduct("SimpleSilksongLocalizer")]
[assembly: AssemblyTitle("SimpleSilksongLocalizer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace SimpleSilksongLocalizer
{
	public static class Extensions
	{
		public static TValue GetOrInsertNew<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TValue : new()
		{
			if (dict.TryGetValue(key, out TValue value))
			{
				return value;
			}
			return dict[key] = new TValue();
		}
	}
	public static class LanguagePatch
	{
		[HarmonyPatch(typeof(Language), "DoSwitch")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SlackenXmlReader(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(XmlReader), "Create", new Type[1] { typeof(TextReader) }, (Type[])null), (string)null)
			});
			CodeInstruction val2 = Transpilers.EmitDelegate<Func<StringReader, XmlReader>>((Func<StringReader, XmlReader>)delegate(StringReader reader)
			{
				XmlReaderSettings settings = new XmlReaderSettings
				{
					ConformanceLevel = ConformanceLevel.Fragment
				};
				return XmlReader.Create(reader, settings);
			});
			val.Set(val2.opcode, val2.operand);
			return val.InstructionEnumeration();
		}

		[HarmonyPatch(typeof(Language), "DoSwitch")]
		[HarmonyPostfix]
		private static void InsertCurrentLanguageExtraStrings()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!SimpleSilksongLocalizerPlugin.ModExtraEntries.TryGetValue(Language._currentLanguage, out Dictionary<string, Dictionary<string, string>> value))
			{
				return;
			}
			foreach (KeyValuePair<string, Dictionary<string, string>> item in value)
			{
				item.Deconstruct(out var key, out var value2);
				string key2 = key;
				Dictionary<string, string> dictionary = value2;
				Dictionary<string, string> orInsertNew = Language._currentEntrySheets.GetOrInsertNew(key2);
				foreach (KeyValuePair<string, string> item2 in dictionary)
				{
					item2.Deconstruct(out key, out var value3);
					string key3 = key;
					string value4 = value3;
					orInsertNew[key3] = value4;
				}
			}
		}

		[HarmonyPatch(typeof(Language), "HasLanguageFile")]
		[HarmonyPostfix]
		private static void HasModdedLanguageFile(ref bool __result, string lang, string sheetTitle)
		{
			if (__result)
			{
				return;
			}
			foreach (KeyValuePair<string, LocalizationSettings> modLocalizationDirectory in SimpleSilksongLocalizerPlugin.ModLocalizationDirectories)
			{
				modLocalizationDirectory.Deconstruct(out var key, out var value);
				string path = key;
				LocalizationSettings localizationSettings = value;
				string path2 = Path.Combine(path, lang, sheetTitle);
				if (File.Exists(path2))
				{
					__result = true;
					break;
				}
				string text = ((object)(LanguageCode)(ref Language._currentLanguage)).ToString();
				string text2 = localizationSettings?.GetFallbackLang(text);
				if (string.IsNullOrEmpty(text2) || text2 == text || !File.Exists(Path.Combine(path, text2, sheetTitle)))
				{
					continue;
				}
				__result = true;
				break;
			}
		}

		[HarmonyPatch(typeof(Language), "GetLanguageFileContents")]
		[HarmonyPostfix]
		private static void AddModdedLanguageFileContents(ref string __result, string sheetTitle)
		{
			string text = string.Empty;
			string key;
			LocalizationSettings value;
			foreach (KeyValuePair<string, LocalizationSettings> modLocalizationDirectory in SimpleSilksongLocalizerPlugin.ModLocalizationDirectories)
			{
				modLocalizationDirectory.Deconstruct(out key, out value);
				string path = key;
				LocalizationSettings localizationSettings = value;
				string text2 = ((object)(LanguageCode)(ref Language._currentLanguage)).ToString();
				string text3 = localizationSettings?.GetFallbackLang(text2);
				if (!string.IsNullOrEmpty(text3) && !(text3 == text2))
				{
					string path2 = Path.Combine(path, text3, sheetTitle);
					if (File.Exists(path2))
					{
						text += File.ReadAllText(path2);
					}
				}
			}
			text += __result;
			foreach (KeyValuePair<string, LocalizationSettings> modLocalizationDirectory2 in SimpleSilksongLocalizerPlugin.ModLocalizationDirectories)
			{
				modLocalizationDirectory2.Deconstruct(out key, out value);
				string path3 = key;
				string path4 = Path.Combine(path3, ((object)(LanguageCode)(ref Language._currentLanguage)).ToString(), sheetTitle);
				if (File.Exists(path4))
				{
					text += File.ReadAllText(path4);
				}
			}
			__result = text;
		}
	}
	internal class LocalizationSettings
	{
		internal class FallbackSettings
		{
			[JsonProperty(/*Could not decode attribute arguments.*/)]
			[JsonConverter(typeof(StringEnumConverter))]
			public LanguageCode Language { get; set; }

			[JsonProperty(/*Could not decode attribute arguments.*/)]
			public string[]? Excluded { get; set; }
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string[]? CustomSheets { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public LanguageCode[]? CustomLanguages { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public FallbackSettings? Fallback { get; set; }

		public string GetFallbackLang(string sourceLanguage)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!SimpleSilksongLocalizerPlugin.EnableFallbacks.Value || Fallback == null || (Fallback.Excluded != null && Fallback.Excluded.Contains(sourceLanguage)))
			{
				return string.Empty;
			}
			LanguageCode language = Fallback.Language;
			return ((int)language != 0) ? string.Empty : ((object)(LanguageCode)(ref language)).ToString();
		}
	}
	public class MenuLanguageSettingPatch
	{
		[HarmonyPatch(typeof(MenuLanguageSetting), "RefreshAvailableLanguages")]
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> SupportAllAvailableLanguages(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			CodeInstruction del = Transpilers.EmitDelegate<Func<SupportedLanguages[]>>((Func<SupportedLanguages[]>)delegate
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				List<SupportedLanguages> list = new List<SupportedLanguages>();
				foreach (string availableLanguage in Language._availableLanguages)
				{
					if (Enum.TryParse<LanguageCode>(availableLanguage, out LanguageCode result))
					{
						list.Add((SupportedLanguages)result);
					}
				}
				return list.ToArray();
			});
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[3]
			{
				new CodeMatch((OpCode?)OpCodes.Ldtoken, (object)typeof(SupportedLanguages), (string)null),
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Type), "GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) }, (Type[])null), (string)null),
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Enum), "GetValues", new Type[1] { typeof(Type) }, (Type[])null), (string)null)
			}).Repeat((Action<CodeMatcher>)delegate(CodeMatcher matcher)
			{
				matcher.RemoveInstructions(2).SetAndAdvance(del.opcode, del.operand);
			}, (Action<string>)null);
			return val.InstructionEnumeration();
		}

		[HarmonyPatch(typeof(MenuLanguageSetting), "UpdateLangsArray")]
		[HarmonyPostfix]
		public static void UpdateLangsArrayStrings(ref string[] ___optionList, SupportedLanguages[] ___langs)
		{
			___optionList = ___langs.Select(delegate(SupportedLanguages opt)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				LanguageCode val = (LanguageCode)opt;
				return ((object)(LanguageCode)(ref val)).ToString();
			}).ToArray();
		}
	}
	[BepInPlugin("capitalistspz.simplesilksonglocalizer", "SimpleSilksongLocalizer", "0.1.0")]
	public class SimpleSilksongLocalizerPlugin : BaseUnityPlugin
	{
		internal static Dictionary<string, LocalizationSettings?> ModLocalizationDirectories = new Dictionary<string, LocalizationSettings>();

		internal static List<string> ModCustomSheets = new List<string>();

		internal static List<LanguageCode> ModCustomLanguages = new List<LanguageCode>();

		internal static Dictionary<LanguageCode, Dictionary<string, Dictionary<string, string>>> ModExtraEntries = new Dictionary<LanguageCode, Dictionary<string, Dictionary<string, string>>>();

		internal static ConfigEntry<bool> EnableFallbacks;

		public static ManualLogSource Logger;

		private Harmony harmony;

		private string[] originalSheetTitles;

		public const string Id = "capitalistspz.simplesilksonglocalizer";

		public static string Name => "SimpleSilksongLocalizer";

		public static string Version => "0.1.0";

		public void RegisterSheet(string sheetTitle)
		{
			ModCustomSheets.Add(sheetTitle);
		}

		public static void AddLocalizationDirectory(string localizationDirectory)
		{
			//IL_0066: Expected O, but got Unknown
			DirectoryInfo directoryInfo = new DirectoryInfo(localizationDirectory);
			FileInfo fileInfo = directoryInfo.EnumerateFiles("LocalizationSettings.json").FirstOrDefault();
			if (fileInfo == null)
			{
				ModLocalizationDirectories.Add(localizationDirectory, null);
				return;
			}
			string fullName = fileInfo.FullName;
			try
			{
				LocalizationSettings localizationSettings = JsonConvert.DeserializeObject<LocalizationSettings>(File.ReadAllText(fullName));
				if (localizationSettings != null)
				{
					ModLocalizationDirectories.Add(localizationDirectory, localizationSettings);
				}
			}
			catch (JsonSerializationException val)
			{
				JsonSerializationException arg = val;
				Logger.LogError((object)$"Failed to parse language settings at '{fullName}': {arg}");
			}
			catch (Exception arg2)
			{
				Logger.LogError((object)$"Unexpected exception: {arg2}");
			}
		}

		public static void AddSheet(LanguageCode languageCode, string sheet, Dictionary<string, string> entries)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> orInsertNew = ModExtraEntries.GetOrInsertNew(languageCode).GetOrInsertNew(sheet);
			foreach (KeyValuePair<string, string> entry in entries)
			{
				entry.Deconstruct(out var key, out var value);
				string key2 = key;
				string value2 = value;
				orInsertNew[key2] = value2;
			}
		}

		public static void AddSheetEntry(LanguageCode languageCode, string sheet, string key, string value)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> orInsertNew = ModExtraEntries.GetOrInsertNew(languageCode).GetOrInsertNew(sheet);
			orInsertNew[key] = value;
		}

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			harmony = new Harmony("capitalistspz.simplesilksonglocalizer");
			EnableFallbacks = ((BaseUnityPlugin)this).Config.Bind<bool>("Fallbacks", "Enable", false, "Enable fallback strings for untranslated text, if the source has them enabled");
			Logger.LogInfo((object)("Plugin " + Name + " (capitalistspz.simplesilksonglocalizer) has loaded!"));
		}

		private void FindDirectories()
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(Paths.PluginPath);
			foreach (DirectoryInfo item in directoryInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly))
			{
				foreach (DirectoryInfo item2 in item.EnumerateDirectories("SSL.Localization", SearchOption.TopDirectoryOnly))
				{
					AddLocalizationDirectory(item2.FullName);
				}
			}
		}

		private void Start()
		{
			FindDirectories();
			Apply();
		}

		private void OnEnable()
		{
			if (((MonoBehaviour)this).didStart && !harmony.GetPatchedMethods().Any())
			{
				Apply();
			}
		}

		private void OnDisable()
		{
			Unapply();
		}

		private void Apply()
		{
			foreach (LocalizationSettings value in ModLocalizationDirectories.Values)
			{
				if (value != null)
				{
					if (value.CustomSheets != null)
					{
						ModCustomSheets.AddRange(value.CustomSheets);
					}
					if (value.CustomLanguages != null)
					{
						ModCustomLanguages.AddRange(value.CustomLanguages);
					}
				}
			}
			originalSheetTitles = Language._settings.sheetTitles;
			Language._settings.sheetTitles = Language._settings.sheetTitles.Union(ModCustomSheets).ToArray();
			harmony.PatchAll(typeof(LanguagePatch));
			harmony.PatchAll(typeof(MenuLanguageSettingPatch));
			Language.LoadAvailableLanguages();
			Language.LoadLanguage();
		}

		private void Unapply()
		{
			harmony.UnpatchSelf();
			Language._settings.sheetTitles = originalSheetTitles;
			Language.LoadAvailableLanguages();
			Language.LoadLanguage();
		}
	}
}