Decompiled source of RussianLanguageMod v1.0.0

plugins/LanguageLoaderPlugin.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using CommonAPI;
using CommonAPI.Systems.ModLocalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LanguageLoaderPlugin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LanguageLoaderPlugin")]
[assembly: AssemblyTitle("LanguageLoaderPlugin")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LanguageLoaderPlugin
{
	[BepInPlugin("org.kremnev8.LanguageLoaderPlugin", "Language Loader Plugin", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[CommonAPISubmoduleDependency(new string[] { "LocalizationModule" })]
	public class LoaderPlugin : BaseUnityPlugin
	{
		public const string GUID = "org.kremnev8.LanguageLoaderPlugin";

		public const string DISPNAME = "Language Loader Plugin";

		public const string VERSION = "1.0.0";

		public static ManualLogSource logger;

		private void Awake()
		{
			logger = ((BaseUnityPlugin)this).Logger;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string directoryName = Path.GetDirectoryName(executingAssembly.Location);
			string fullName = Directory.GetParent(directoryName).FullName;
			LoadLanguages(fullName, executingAssembly);
			logger.LogInfo((object)"Finished loading all JSON mods");
		}

		private static void LoadLanguages(string pluginsDir, Assembly assembly)
		{
			foreach (string item in Directory.EnumerateDirectories(pluginsDir))
			{
				string path = Path.Combine(item, assembly.GetName().Name + ".dll");
				if (File.Exists(path))
				{
					try
					{
						LoadDirectory(item);
					}
					catch (Exception arg)
					{
						logger.LogError((object)$"Exception while loading folder {item} language data!\n{arg}");
					}
				}
			}
		}

		internal static void LoadDirectory(string directory)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(directory, "language.tsv");
			if (!File.Exists(path))
			{
				logger.LogError((object)("Failed to load language folder " + directory + ", because manifest file is missing!"));
				return;
			}
			string text = File.ReadAllText(path);
			string[] array = text.Split(new char[1] { '\t' });
			string text2 = array[3];
			string text3 = array[4];
			string value = array[5];
			Language val = new Language
			{
				name = array[0],
				abbr = array[1],
				abbr2 = array[2]
			};
			if (int.TryParse(text2, out var result))
			{
				val.fallback = result;
			}
			else
			{
				result = LocalizationModule.GetLanguageId(text2);
				if (result == 0)
				{
					result = 1033;
				}
				val.fallback = result;
			}
			if (Enum.TryParse<EGlyph>(value, ignoreCase: true, out EGlyph result2))
			{
				val.glyph = result2;
			}
			int num = LocalizationModule.AddLanguage(val);
			if (!string.IsNullOrEmpty(text3))
			{
				if (text3 == "$bundle")
				{
					string text4 = Path.Combine(directory, "font_bundle");
					LocalizationModule.RegisterFontForLanguageFromBundle(num, text4);
				}
				else
				{
					LocalizationModule.RegisterFontForLanguage(num, text3);
				}
			}
			string text5 = Path.Combine(directory, "Locale");
			LocalizationModule.LoadTranslationsFromFolder(text5);
			logger.LogInfo((object)("Done adding custom language " + val.name + "!"));
		}
	}
}
namespace LanguageLoaderPlugin.SimpleJson
{
	public enum JsonOption
	{
		FAIL_SILENTLY,
		ALLOW_COMMENTS,
		ALLOW_TRAILING_COMMA,
		ALLOW_SINGLE_QUOTES,
		ALLOW_NON_QUOTED_KEYS,
		ALLOW_NON_OBJECT_AS_ROOT,
		ALLOW_DECIMAL_AS_FLOAT_FIRST_CHAR,
		OVERWRITE_DUPLICATE_KEYS,
		ALLOW_PYTHON_PRIMITIVES
	}
	public class JsonParser
	{
		private class Token
		{
			public string Value { get; set; }

			public int Line { get; set; }

			public int Column { get; set; }

			public override string ToString()
			{
				return "TOKEN: " + Value;
			}

			public Token(string value, int line, int column)
			{
				Value = value;
				Line = line;
				Column = column;
			}

			public Exception Throw(string message)
			{
				throw new JsonParserException("Line " + Line + ", Column " + Column + ": " + message);
			}
		}

		private class TokenStream
		{
			private enum TokenizerState
			{
				NONE,
				COMMENT,
				STRING,
				WORD
			}

			private int index;

			private int length;

			private Token[] tokens;

			public int Length => length;

			public Token Last => tokens[length - 1];

			public TokenStream(string text, bool allowComments)
			{
				tokens = Init(text, allowComments);
				index = 0;
				length = tokens.Length;
			}

			public void Reset()
			{
				index = 0;
			}

			private static Token[] Init(string text, bool allowComments)
			{
				List<Token> list = new List<Token>();
				text += "\n";
				int num = text.Length;
				TokenizerState tokenizerState = TokenizerState.NONE;
				List<string> list2 = new List<string>();
				int num2 = 0;
				int[] array = new int[num];
				int[] array2 = new int[num];
				int num3 = 1;
				int num4 = 1;
				for (int i = 0; i < num; i++)
				{
					array[i] = num3;
					array2[i] = num4++;
					if (text[i] == '\n')
					{
						num3++;
						num4 = 1;
					}
				}
				char c = '\0';
				for (int j = 0; j < num; j++)
				{
					char c2 = text[j];
					switch (tokenizerState)
					{
					case TokenizerState.NONE:
						switch (c2)
						{
						case '"':
						case '\'':
							c = c2;
							num2 = j;
							tokenizerState = TokenizerState.STRING;
							break;
						case '/':
							if (allowComments && j + 1 < num && text[j + 1] == '*')
							{
								tokenizerState = TokenizerState.COMMENT;
								j++;
							}
							else
							{
								list.Add(new Token("/", array[j], array2[j]));
							}
							break;
						default:
							if ((c2 >= '0' && c2 <= '9') || (c2 >= 'a' && c2 <= 'z') || (c2 >= 'A' && c2 <= 'Z') || c2 == '_' || c2 == '.' || c2 == '-')
							{
								tokenizerState = TokenizerState.WORD;
								num2 = j;
							}
							else
							{
								list.Add(new Token(c2.ToString(), array[j], array2[j]));
							}
							break;
						case '\t':
						case '\n':
						case '\r':
						case ' ':
							break;
						}
						break;
					case TokenizerState.COMMENT:
						if (c2 == '*' && j + 1 < num && text[j + 1] == '/')
						{
							j++;
							tokenizerState = TokenizerState.NONE;
						}
						break;
					case TokenizerState.STRING:
						if (c2 == c)
						{
							list.Add(new Token(text.Substring(num2, j - num2 + 1), array[num2], array2[num2]));
							tokenizerState = TokenizerState.NONE;
						}
						else if (c2 == '\\')
						{
							j++;
						}
						break;
					case TokenizerState.WORD:
						if ((c2 < '0' || c2 > '9') && (c2 < 'a' || c2 > 'z') && (c2 < 'A' || c2 > 'Z') && c2 != '_' && c2 != '.' && c2 != '-')
						{
							list.Add(new Token(text.Substring(num2, j - num2), array[num2], array2[num2]));
							j--;
							tokenizerState = TokenizerState.NONE;
						}
						break;
					}
				}
				return tokenizerState switch
				{
					TokenizerState.COMMENT => throw new JsonParserException("Unexpected EOF detected. A comment seems to be left unclosed."), 
					TokenizerState.NONE => list.ToArray(), 
					_ => throw new JsonParserException("Unexpected EOF detected. A string seems to be left unclosed."), 
				};
			}

			public Token Pop()
			{
				if (index == length)
				{
					throw new InvalidOperationException();
				}
				return tokens[index++];
			}

			public Token Peek()
			{
				if (index < length)
				{
					return tokens[index];
				}
				throw Last.Throw("Unexpected EOF");
			}

			public string PeekValue()
			{
				if (index < length)
				{
					return tokens[index].Value;
				}
				throw Last.Throw("Unexpected EOF");
			}

			public void PopExpected(string value)
			{
				if (index < length)
				{
					Token token = tokens[index];
					if (token.Value != value)
					{
						token.Throw("Unexpected token. Expected '" + value + "' but found '" + token.Value + "' instead.");
					}
					index++;
				}
				else
				{
					Last.Throw("Unexpected EOF. Expected '" + value + "'.");
				}
			}

			public bool PopIfPresent(string value)
			{
				if (index < length && tokens[index].Value == value)
				{
					index++;
					return true;
				}
				return false;
			}
		}

		public class JsonParserException : Exception
		{
			public JsonParserException(string message)
				: base(message)
			{
			}
		}

		private class ReadOnlyOrderedDictionary : IDictionary<string, object>, ICollection<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable
		{
			private Dictionary<string, object> lookup = new Dictionary<string, object>();

			private string[] keyOrder;

			public object this[string key]
			{
				get
				{
					return lookup[key];
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int Count => keyOrder.Length;

			public bool IsReadOnly => true;

			public ICollection<string> Keys => new List<string>(keyOrder);

			public ICollection<object> Values => new List<object>(keyOrder.Select((string key) => lookup[key]));

			public ReadOnlyOrderedDictionary(Dictionary<string, object> lookup, List<string> keyOrder)
			{
				this.lookup = lookup;
				this.keyOrder = keyOrder.ToArray();
			}

			public bool Contains(KeyValuePair<string, object> item)
			{
				return lookup.Contains(item);
			}

			public bool ContainsKey(string key)
			{
				return lookup.ContainsKey(key);
			}

			public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
			{
				return lookup.GetEnumerator();
			}

			public bool TryGetValue(string key, out object value)
			{
				return lookup.TryGetValue(key, out value);
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return lookup.GetEnumerator();
			}

			public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
			{
				Dictionary<string, KeyValuePair<string, object>> dictionary = new Dictionary<string, KeyValuePair<string, object>>();
				foreach (KeyValuePair<string, object> item in lookup)
				{
					dictionary.Add(item.Key, item);
				}
				string[] array2 = keyOrder;
				foreach (string key in array2)
				{
					array[arrayIndex++] = dictionary[key];
				}
			}

			public void Add(KeyValuePair<string, object> item)
			{
				throw new NotImplementedException();
			}

			public void Add(string key, object value)
			{
				throw new NotImplementedException();
			}

			public void Clear()
			{
				throw new NotImplementedException();
			}

			public bool Remove(KeyValuePair<string, object> item)
			{
				throw new NotImplementedException();
			}

			public bool Remove(string key)
			{
				throw new NotImplementedException();
			}
		}

		private string text;

		private HashSet<JsonOption> options = new HashSet<JsonOption>();

		private static readonly IFormatProvider EN_US = CultureInfo.GetCultureInfo("en-us");

		private static readonly NumberStyles DOUBLE_FLAG = NumberStyles.Float;

		public JsonParser(string text)
		{
			this.text = text;
		}

		public JsonParser AddOption(JsonOption option)
		{
			options.Add(option);
			return this;
		}

		public IDictionary<string, object> ParseAsDictionary()
		{
			if (options.Contains(JsonOption.ALLOW_NON_OBJECT_AS_ROOT))
			{
				throw new InvalidOperationException("Cannot use ParseAsDictionary if ALLOW_NON_OBJECT_AS_ROOT option is enabled.");
			}
			return (IDictionary<string, object>)Parse();
		}

		public object Parse()
		{
			try
			{
				TokenStream tokenStream = new TokenStream(text, options.Contains(JsonOption.ALLOW_COMMENTS));
				if (tokenStream.Length == 0)
				{
					throw new JsonParserException("Content is blank.");
				}
				object obj = ParseThing(tokenStream);
				if (!options.Contains(JsonOption.ALLOW_NON_OBJECT_AS_ROOT) && !(obj is IDictionary<string, object>))
				{
					tokenStream.Reset();
					tokenStream.PopExpected("{");
				}
				return obj;
			}
			catch (JsonParserException ex)
			{
				if (options.Contains(JsonOption.FAIL_SILENTLY))
				{
					return null;
				}
				throw ex;
			}
		}

		private object ParseThing(TokenStream tokens)
		{
			string text = tokens.PeekValue();
			switch (text)
			{
			case "true":
			case "false":
				tokens.Pop();
				return text == "true";
			case "null":
				tokens.Pop();
				return null;
			default:
			{
				if (options.Contains(JsonOption.ALLOW_PYTHON_PRIMITIVES))
				{
					switch (text)
					{
					case "True":
					case "False":
						tokens.Pop();
						return text == "True";
					case "None":
						tokens.Pop();
						return null;
					}
				}
				char c = text[0];
				switch (c)
				{
				case '"':
				case '\'':
					return ParseString(tokens.Pop(), allowUnquoted: false);
				case '{':
					return ParseDictionary(tokens);
				case '[':
					return ParseList(tokens);
				default:
					if (c >= '0' && c <= '9')
					{
						if (Enumerable.Contains(text, '.'))
						{
							return ParseFloat(tokens.Pop());
						}
						return ParseInteger(tokens.Pop());
					}
					if (c == '.')
					{
						return ParseFloat(tokens.Pop());
					}
					throw tokens.Pop().Throw("Unrecognized/unexpected value: '" + text + "'");
				}
			}
			}
		}

		private int ParseInteger(Token token)
		{
			if (int.TryParse(token.Value, out var result))
			{
				return result;
			}
			throw token.Throw("Unrecognized integer value: '" + result + "'");
		}

		private double ParseFloat(Token token)
		{
			if (token.Value[0] == '.' && !options.Contains(JsonOption.ALLOW_DECIMAL_AS_FLOAT_FIRST_CHAR))
			{
				token.Throw("Invalid format for decimal. Use ALLOW_DECIMAL_AS_FLOAT_FIRST_CHAR or add '0' prefix before decimal.");
			}
			if (double.TryParse(token.Value, DOUBLE_FLAG, EN_US, out var result))
			{
				return result;
			}
			throw token.Throw("Unrecognized float value: '" + token.Value + "'");
		}

		private char GetUnicodeChar(string fourDigitHex)
		{
			if (int.TryParse(fourDigitHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
			{
				return (char)result;
			}
			throw new JsonParserException("Could not parse unicode escape sequence: \"\\u" + fourDigitHex + "\"");
		}

		private string ParseString(Token token, bool allowUnquoted)
		{
			string value = token.Value;
			char c = value[0];
			if (c == '"' || c == '\'')
			{
				StringBuilder stringBuilder = new StringBuilder();
				int num = value.Length - 1;
				for (int i = 1; i < num; i++)
				{
					char c2 = value[i];
					if (c2 == '\\')
					{
						if (i + 1 >= num)
						{
							throw token.Throw("Trailing backslash in string.");
						}
						switch (value[i + 1])
						{
						case '\\':
							stringBuilder.Append('\\');
							break;
						case 'r':
							stringBuilder.Append('\r');
							break;
						case 'n':
							stringBuilder.Append('\n');
							break;
						case '0':
							stringBuilder.Append('\0');
							break;
						case 't':
							stringBuilder.Append('\t');
							break;
						case '\'':
							stringBuilder.Append('\'');
							break;
						case '"':
							stringBuilder.Append('"');
							break;
						case 'u':
							if (i + 5 >= num)
							{
								throw token.Throw("Unicode escape sequence is invalid.");
							}
							stringBuilder.Append(GetUnicodeChar(value.Substring(i + 2, 4)));
							i += 4;
							break;
						default:
							throw token.Throw("Unrecognized escape sequence: '\\" + value[i + 1] + "'.");
						}
						i++;
					}
					else
					{
						stringBuilder.Append(c2);
					}
				}
				return stringBuilder.ToString();
			}
			if (allowUnquoted)
			{
				return value;
			}
			throw token.Throw("Found unquoted string: " + value);
		}

		private object[] ParseList(TokenStream tokens)
		{
			List<object> list = new List<object>();
			tokens.PopExpected("[");
			bool flag = true;
			Token token = null;
			while (!tokens.PopIfPresent("]"))
			{
				if (!flag)
				{
					tokens.PopExpected(",");
				}
				list.Add(ParseThing(tokens));
				token = tokens.Peek();
				flag = tokens.PopIfPresent(",");
			}
			if (flag && list.Count > 0 && !options.Contains(JsonOption.ALLOW_TRAILING_COMMA))
			{
				throw token.Throw("Unexpected comma at end of list. Remove or use ALLOW_TRAILING_COMMA option.");
			}
			return list.ToArray();
		}

		private ReadOnlyOrderedDictionary ParseDictionary(TokenStream tokens)
		{
			List<string> list = new List<string>();
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			tokens.PopExpected("{");
			bool flag = true;
			bool allowUnquoted = options.Contains(JsonOption.ALLOW_NON_QUOTED_KEYS);
			Token token = null;
			while (!tokens.PopIfPresent("}"))
			{
				if (!flag)
				{
					tokens.PopExpected(",");
				}
				Token token2 = tokens.Peek();
				string text = ParseString(tokens.Pop(), allowUnquoted);
				tokens.PopExpected(":");
				object value = ParseThing(tokens);
				if (dictionary.ContainsKey(text))
				{
					if (options.Contains(JsonOption.OVERWRITE_DUPLICATE_KEYS))
					{
						dictionary[text] = value;
					}
					else
					{
						token2.Throw("Duplicate object key declaration: '" + text + "'.");
					}
				}
				else
				{
					list.Add(text);
					dictionary[text] = value;
				}
				token = tokens.Peek();
				flag = tokens.PopIfPresent(",");
			}
			if (flag && list.Count > 0 && !options.Contains(JsonOption.ALLOW_TRAILING_COMMA))
			{
				throw token.Throw("Unexpected comma at end of object. Remove or use ALLOW_TRAILING_COMMA option.");
			}
			return new ReadOnlyOrderedDictionary(dictionary, list);
		}
	}
	public class JsonLookup
	{
		private IDictionary<string, object> root;

		public JsonLookup(IDictionary<string, object> root)
		{
			this.root = root;
		}

		public string GetAsString(string path, string defaultValue)
		{
			return GetAsString(path) ?? defaultValue;
		}

		public string GetAsString(string path)
		{
			return Get(path) as string;
		}

		public int GetAsInteger(string path, int defaultValue)
		{
			object obj = Get(path);
			return (obj == null) ? defaultValue : ((int)obj);
		}

		public int GetAsInteger(string path)
		{
			return GetAsInteger(path, 0);
		}

		public double GetAsDouble(string path, double defaultValue)
		{
			object obj = Get(path);
			return (obj == null) ? defaultValue : ((double)obj);
		}

		public double GetAsDouble(string path)
		{
			return GetAsDouble(path, 0.0);
		}

		public bool GetAsBoolean(string path, bool defaultValue)
		{
			object obj = Get(path);
			return (obj == null) ? defaultValue : ((bool)obj);
		}

		public bool GetAsBoolean(string path)
		{
			return GetAsBoolean(path, defaultValue: false);
		}

		public object[] GetAsList(string path)
		{
			return (Get(path) as object[]) ?? new object[0];
		}

		public IDictionary<string, object> GetAsDictionary(string path)
		{
			return (Get(path) as IDictionary<string, object>) ?? new Dictionary<string, object>();
		}

		public JsonLookup GetAsLookup(string path)
		{
			return new JsonLookup(GetAsDictionary(path));
		}

		public JsonLookup[] GetAsListOfLookups(string path)
		{
			return (from d in GetAsList(path).OfType<IDictionary<string, object>>()
				select new JsonLookup(d)).ToArray();
		}

		public object Get(string path)
		{
			string[] array = path.Split(new char[1] { '.' });
			IDictionary<string, object> dictionary = root;
			for (int i = 0; i < array.Length; i++)
			{
				if (dictionary.ContainsKey(array[i]))
				{
					if (i == array.Length - 1)
					{
						return dictionary[array[i]];
					}
					if (dictionary[array[i]] is IDictionary<string, object>)
					{
						dictionary = (IDictionary<string, object>)dictionary[array[i]];
						continue;
					}
					return null;
				}
				return null;
			}
			return null;
		}
	}
}