Decompiled source of JSONLocalizeAPI v1.0.0

JSONLocalizeAPI.dll

Decompiled a month 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.InteropServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Necro.UI;
using SimpleJSON;
using UnityEngine;

[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("JSONLocalizeAPI")]
[assembly: ComVisible(false)]
[assembly: AssemblyDescription("JSON-based localization library for Necropolis mods")]
[assembly: AssemblyTrademark("")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCopyright("Copyright © KoMiKoZa 2025")]
[assembly: CompilationRelaxations(8)]
[assembly: Guid("71311014-fbb4-4e33-9234-e39e359a9e78")]
[assembly: AssemblyCompany("KoMiKoZa")]
[assembly: AssemblyProduct("JSONLocalizeAPI")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace KoMiKoZa.Necropolis.JSONLocalizeAPI
{
	internal class TranslationCache
	{
		public Dictionary<string, List<Dictionary<string, string>>> ArrayTranslations;

		public Dictionary<string, Dictionary<string, string>> ObjectTranslations;

		public Dictionary<string, int> LastIndexByArray;

		public string CurrentLang;

		public TranslationCache()
		{
			ArrayTranslations = new Dictionary<string, List<Dictionary<string, string>>>();
			ObjectTranslations = new Dictionary<string, Dictionary<string, string>>();
			LastIndexByArray = new Dictionary<string, int>();
			CurrentLang = "en";
		}
	}
	public static class JSONLocalizeAPI
	{
		private static Dictionary<Assembly, TranslationCache> translationsByAssembly = new Dictionary<Assembly, TranslationCache>();

		public static string GetRandomFromArray(Assembly callingAssembly, string arrayKey, string fallback)
		{
			try
			{
				if ((object)callingAssembly == null)
				{
					LogWarning("GetRandomFromArray: callingAssembly is null");
					return fallback;
				}
				TranslationCache orLoadTranslations = GetOrLoadTranslations(callingAssembly);
				if (orLoadTranslations == null || !orLoadTranslations.ArrayTranslations.ContainsKey(arrayKey))
				{
					if (JSONLocalizePlugin.DebugMode.Value)
					{
						LogInfo($"Array key '{arrayKey}' not found in {callingAssembly.GetName().Name}");
					}
					return fallback;
				}
				List<Dictionary<string, string>> list = orLoadTranslations.ArrayTranslations[arrayKey];
				if (list.Count == 0)
				{
					LogWarning($"Array '{arrayKey}' is empty in {callingAssembly.GetName().Name}");
					return fallback;
				}
				int num = (orLoadTranslations.LastIndexByArray.ContainsKey(arrayKey) ? orLoadTranslations.LastIndexByArray[arrayKey] : (-1));
				int num2;
				if (list.Count > 1 && num >= 0)
				{
					do
					{
						num2 = Random.Range(0, list.Count);
					}
					while (num2 == num);
				}
				else
				{
					num2 = Random.Range(0, list.Count);
				}
				orLoadTranslations.LastIndexByArray[arrayKey] = num2;
				string localizedString = GetLocalizedString(orLoadTranslations, list[num2], fallback);
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"GetRandomFromArray({arrayKey}): index={num2}, result={localizedString}");
				}
				return localizedString;
			}
			catch (Exception arg)
			{
				LogError($"GetRandomFromArray error: {arg}");
				return fallback;
			}
		}

		public static string GetFromObject(Assembly callingAssembly, string objectKey, string fallback)
		{
			try
			{
				if ((object)callingAssembly == null)
				{
					LogWarning("GetFromObject: callingAssembly is null");
					return fallback;
				}
				TranslationCache orLoadTranslations = GetOrLoadTranslations(callingAssembly);
				if (orLoadTranslations == null || !orLoadTranslations.ObjectTranslations.ContainsKey(objectKey))
				{
					if (JSONLocalizePlugin.DebugMode.Value)
					{
						LogInfo($"Object key '{objectKey}' not found in {callingAssembly.GetName().Name}");
					}
					return fallback;
				}
				string localizedString = GetLocalizedString(orLoadTranslations, orLoadTranslations.ObjectTranslations[objectKey], fallback);
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"GetFromObject({objectKey}): result={localizedString}");
				}
				return localizedString;
			}
			catch (Exception arg)
			{
				LogError($"GetFromObject error: {arg}");
				return fallback;
			}
		}

		public static string GetFromArrayIndex(Assembly callingAssembly, string arrayKey, int index, string fallback)
		{
			try
			{
				if ((object)callingAssembly == null)
				{
					LogWarning("GetFromArrayIndex: callingAssembly is null");
					return fallback;
				}
				TranslationCache orLoadTranslations = GetOrLoadTranslations(callingAssembly);
				if (orLoadTranslations == null || !orLoadTranslations.ArrayTranslations.ContainsKey(arrayKey))
				{
					if (JSONLocalizePlugin.DebugMode.Value)
					{
						LogInfo($"Array key '{arrayKey}' not found in {callingAssembly.GetName().Name}");
					}
					return fallback;
				}
				List<Dictionary<string, string>> list = orLoadTranslations.ArrayTranslations[arrayKey];
				if (index < 0 || index >= list.Count)
				{
					LogWarning($"Index {index} out of range for array '{arrayKey}' (count: {list.Count}) in {callingAssembly.GetName().Name}");
					return fallback;
				}
				string localizedString = GetLocalizedString(orLoadTranslations, list[index], fallback);
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"GetFromArrayIndex({arrayKey}, {index}): result={localizedString}");
				}
				return localizedString;
			}
			catch (Exception arg)
			{
				LogError($"GetFromArrayIndex error: {arg}");
				return fallback;
			}
		}

		private static TranslationCache GetOrLoadTranslations(Assembly assembly)
		{
			if ((object)assembly == null)
			{
				return null;
			}
			if (translationsByAssembly.ContainsKey(assembly))
			{
				return translationsByAssembly[assembly];
			}
			TranslationCache translationCache = new TranslationCache();
			translationsByAssembly[assembly] = translationCache;
			try
			{
				string location = assembly.Location;
				string directoryName = Path.GetDirectoryName(location);
				string text = Path.Combine(directoryName, "translations.json");
				string name = assembly.GetName().Name;
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"Looking for translations at: {text}");
				}
				if (!File.Exists(text))
				{
					LogWarning($"No translations.json found for {name}, using fallbacks");
					return translationCache;
				}
				string text2 = File.ReadAllText(text);
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"JSON content length for {name}: {text2.Length} chars");
				}
				JSONNode jSONNode = JSON.Parse(text2);
				if (jSONNode == null)
				{
					LogError($"Failed to parse translations.json for {name}");
					return translationCache;
				}
				LogInfo($"Successfully parsed translations.json for {name}");
				JSONNode.Enumerator enumerator = jSONNode.GetEnumerator();
				while (enumerator.MoveNext())
				{
					KeyValuePair<string, JSONNode> current = enumerator.Current;
					if (current.Value.IsArray)
					{
						List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
						JSONNode.Enumerator enumerator2 = current.Value.AsArray.GetEnumerator();
						while (enumerator2.MoveNext())
						{
							JSONNode jSONNode2 = enumerator2.Current;
							Dictionary<string, string> dictionary = new Dictionary<string, string>();
							JSONNode.Enumerator enumerator3 = jSONNode2.GetEnumerator();
							while (enumerator3.MoveNext())
							{
								KeyValuePair<string, JSONNode> current2 = enumerator3.Current;
								dictionary[current2.Key] = current2.Value.Value;
							}
							list.Add(dictionary);
						}
						translationCache.ArrayTranslations[current.Key] = list;
						if (JSONLocalizePlugin.DebugMode.Value)
						{
							LogInfo($"Loaded array '{current.Key}' with {list.Count} items for {name}");
						}
					}
					else if (current.Value.IsObject)
					{
						Dictionary<string, string> dictionary = new Dictionary<string, string>();
						JSONNode.Enumerator enumerator2 = current.Value.GetEnumerator();
						while (enumerator2.MoveNext())
						{
							KeyValuePair<string, JSONNode> current2 = enumerator2.Current;
							dictionary[current2.Key] = current2.Value.Value;
						}
						translationCache.ObjectTranslations[current.Key] = dictionary;
						if (JSONLocalizePlugin.DebugMode.Value)
						{
							LogInfo($"Loaded object '{current.Key}' with {dictionary.Count} languages for {name}");
						}
					}
				}
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"Loaded translations for {name}: {translationCache.ArrayTranslations.Count} arrays, {translationCache.ObjectTranslations.Count} objects");
				}
			}
			catch (Exception arg)
			{
				LogError($"Error loading translations for {assembly.GetName().Name}: {arg}");
			}
			return translationCache;
		}

		private static string GetLocalizedString(TranslationCache cache, Dictionary<string, string> dict, string fallback)
		{
			if (dict == null || dict.Count == 0)
			{
				return fallback;
			}
			string currentLanguage = GetCurrentLanguage();
			if (currentLanguage != cache.CurrentLang)
			{
				cache.CurrentLang = currentLanguage;
				if (JSONLocalizePlugin.DebugMode.Value)
				{
					LogInfo($"Language changed to: {currentLanguage}");
				}
			}
			if (dict.ContainsKey(currentLanguage))
			{
				string text = dict[currentLanguage];
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			if (dict.ContainsKey("en"))
			{
				string text = dict["en"];
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			foreach (KeyValuePair<string, string> item in dict)
			{
				if (!string.IsNullOrEmpty(item.Value))
				{
					return item.Value;
				}
			}
			return fallback;
		}

		private static string GetCurrentLanguage()
		{
			try
			{
				string currentLang = Strings.CurrentLang;
				if (string.IsNullOrEmpty(currentLang))
				{
					return "en";
				}
				return currentLang;
			}
			catch
			{
				return "en";
			}
		}

		private static void LogInfo(string message)
		{
			if (JSONLocalizePlugin.Logger != null)
			{
				JSONLocalizePlugin.Logger.LogInfo((object)$"[LOCALIZE] {message}");
			}
		}

		private static void LogWarning(string message)
		{
			if (JSONLocalizePlugin.Logger != null)
			{
				JSONLocalizePlugin.Logger.LogWarning((object)$"[LOCALIZE] {message}");
			}
		}

		private static void LogError(string message)
		{
			if (JSONLocalizePlugin.Logger != null)
			{
				JSONLocalizePlugin.Logger.LogError((object)$"[LOCALIZE] {message}");
			}
		}
	}
	[BepInPlugin("komikoza.necropolis.jsonlocalizeapi", "JSONLocalizeAPI", "1.0.0")]
	public class JSONLocalizePlugin : BaseUnityPlugin
	{
		private const string GUID = "komikoza.necropolis.jsonlocalizeapi";

		private const string NAME = "JSONLocalizeAPI";

		private const string VERSION = "1.0.0";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<bool> DebugMode;

		public static JSONLocalizePlugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugMode", false, "Enable debug logging for translation loading and lookups");
			Logger.LogInfo((object)"================================================");
			Logger.LogInfo((object)string.Format("[{0}] v{1} loaded!", "JSONLocalizeAPI", "1.0.0"));
			Logger.LogInfo((object)" - JSON-based localization for mod content");
			Logger.LogInfo((object)"================================================");
		}
	}
}
namespace SimpleJSON
{
	public enum JSONNodeType
	{
		Array = 1,
		Object = 2,
		String = 3,
		Number = 4,
		NullValue = 5,
		Boolean = 6,
		None = 7,
		Custom = 255
	}
	public enum JSONTextMode
	{
		Compact,
		Indent
	}
	public abstract class JSONNode
	{
		public struct Enumerator
		{
			private enum Type
			{
				None,
				Array,
				Object
			}

			private Type type;

			private Dictionary<string, JSONNode>.Enumerator m_Object;

			private List<JSONNode>.Enumerator m_Array;

			public bool IsValid => type != Type.None;

			public KeyValuePair<string, JSONNode> Current
			{
				get
				{
					if (type == Type.Array)
					{
						return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current);
					}
					if (type == Type.Object)
					{
						return m_Object.Current;
					}
					return new KeyValuePair<string, JSONNode>(string.Empty, null);
				}
			}

			public Enumerator(List<JSONNode>.Enumerator aArrayEnum)
			{
				type = Type.Array;
				m_Object = default(Dictionary<string, JSONNode>.Enumerator);
				m_Array = aArrayEnum;
			}

			public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
			{
				type = Type.Object;
				m_Object = aDictEnum;
				m_Array = default(List<JSONNode>.Enumerator);
			}

			public bool MoveNext()
			{
				if (type == Type.Array)
				{
					return m_Array.MoveNext();
				}
				if (type == Type.Object)
				{
					return m_Object.MoveNext();
				}
				return false;
			}
		}

		public struct ValueEnumerator
		{
			private Enumerator m_Enumerator;

			public JSONNode Current => m_Enumerator.Current.Value;

			public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum)
				: this(new Enumerator(aArrayEnum))
			{
			}

			public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
				: this(new Enumerator(aDictEnum))
			{
			}

			public ValueEnumerator(Enumerator aEnumerator)
			{
				m_Enumerator = aEnumerator;
			}

			public bool MoveNext()
			{
				return m_Enumerator.MoveNext();
			}

			public ValueEnumerator GetEnumerator()
			{
				return this;
			}
		}

		public struct KeyEnumerator
		{
			private Enumerator m_Enumerator;

			public string Current => m_Enumerator.Current.Key;

			public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum)
				: this(new Enumerator(aArrayEnum))
			{
			}

			public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
				: this(new Enumerator(aDictEnum))
			{
			}

			public KeyEnumerator(Enumerator aEnumerator)
			{
				m_Enumerator = aEnumerator;
			}

			public bool MoveNext()
			{
				return m_Enumerator.MoveNext();
			}

			public KeyEnumerator GetEnumerator()
			{
				return this;
			}
		}

		public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>, IDisposable, IEnumerator, IEnumerable<KeyValuePair<string, JSONNode>>, IEnumerable
		{
			private JSONNode m_Node;

			private Enumerator m_Enumerator;

			public KeyValuePair<string, JSONNode> Current => m_Enumerator.Current;

			object IEnumerator.Current => m_Enumerator.Current;

			internal LinqEnumerator(JSONNode aNode)
			{
				m_Node = aNode;
				if (m_Node != null)
				{
					m_Enumerator = m_Node.GetEnumerator();
				}
			}

			public bool MoveNext()
			{
				return m_Enumerator.MoveNext();
			}

			public void Dispose()
			{
				m_Node = null;
				m_Enumerator = default(Enumerator);
			}

			public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()
			{
				return new LinqEnumerator(m_Node);
			}

			public void Reset()
			{
				if (m_Node != null)
				{
					m_Enumerator = m_Node.GetEnumerator();
				}
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return new LinqEnumerator(m_Node);
			}
		}

		public static bool forceASCII = false;

		public static bool longAsString = false;

		public static bool allowLineComments = true;

		[ThreadStatic]
		private static StringBuilder m_EscapeBuilder;

		public abstract JSONNodeType Tag { get; }

		public virtual JSONNode this[int aIndex]
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual JSONNode this[string aKey]
		{
			get
			{
				return null;
			}
			set
			{
			}
		}

		public virtual string Value
		{
			get
			{
				return "";
			}
			set
			{
			}
		}

		public virtual int Count => 0;

		public virtual bool IsNumber => false;

		public virtual bool IsString => false;

		public virtual bool IsBoolean => false;

		public virtual bool IsNull => false;

		public virtual bool IsArray => false;

		public virtual bool IsObject => false;

		public virtual bool Inline
		{
			get
			{
				return false;
			}
			set
			{
			}
		}

		public virtual IEnumerable<JSONNode> Children
		{
			get
			{
				yield break;
			}
		}

		public IEnumerable<JSONNode> DeepChildren
		{
			get
			{
				foreach (JSONNode C in Children)
				{
					foreach (JSONNode deepChild in C.DeepChildren)
					{
						yield return deepChild;
					}
				}
			}
		}

		public IEnumerable<KeyValuePair<string, JSONNode>> Linq => new LinqEnumerator(this);

		public KeyEnumerator Keys => new KeyEnumerator(GetEnumerator());

		public ValueEnumerator Values => new ValueEnumerator(GetEnumerator());

		public virtual double AsDouble
		{
			get
			{
				double result = 0.0;
				if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
				{
					return result;
				}
				return 0.0;
			}
			set
			{
				Value = value.ToString(CultureInfo.InvariantCulture);
			}
		}

		public virtual int AsInt
		{
			get
			{
				return (int)AsDouble;
			}
			set
			{
				AsDouble = value;
			}
		}

		public virtual float AsFloat
		{
			get
			{
				return (float)AsDouble;
			}
			set
			{
				AsDouble = value;
			}
		}

		public virtual bool AsBool
		{
			get
			{
				bool result = false;
				if (bool.TryParse(Value, out result))
				{
					return result;
				}
				return !string.IsNullOrEmpty(Value);
			}
			set
			{
				Value = (value ? "true" : "false");
			}
		}

		public virtual long AsLong
		{
			get
			{
				long result = 0L;
				if (long.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
				{
					return result;
				}
				return 0L;
			}
			set
			{
				Value = value.ToString(CultureInfo.InvariantCulture);
			}
		}

		public virtual ulong AsULong
		{
			get
			{
				ulong result = 0uL;
				if (ulong.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
				{
					return result;
				}
				return 0uL;
			}
			set
			{
				Value = value.ToString(CultureInfo.InvariantCulture);
			}
		}

		public virtual JSONArray AsArray => this as JSONArray;

		public virtual JSONObject AsObject => this as JSONObject;

		internal static StringBuilder EscapeBuilder
		{
			get
			{
				if (m_EscapeBuilder == null)
				{
					m_EscapeBuilder = new StringBuilder();
				}
				return m_EscapeBuilder;
			}
		}

		public virtual void Add(string aKey, JSONNode aItem)
		{
		}

		public virtual void Add(JSONNode aItem)
		{
			Add("", aItem);
		}

		public virtual JSONNode Remove(string aKey)
		{
			return null;
		}

		public virtual JSONNode Remove(int aIndex)
		{
			return null;
		}

		public virtual JSONNode Remove(JSONNode aNode)
		{
			return aNode;
		}

		public virtual void Clear()
		{
		}

		public virtual JSONNode Clone()
		{
			return null;
		}

		public virtual bool HasKey(string aKey)
		{
			return false;
		}

		public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
		{
			return aDefault;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			WriteToStringBuilder(stringBuilder, 0, 0, JSONTextMode.Compact);
			return stringBuilder.ToString();
		}

		public virtual string ToString(int aIndent)
		{
			StringBuilder stringBuilder = new StringBuilder();
			WriteToStringBuilder(stringBuilder, 0, aIndent, JSONTextMode.Indent);
			return stringBuilder.ToString();
		}

		internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode);

		public abstract Enumerator GetEnumerator();

		public static implicit operator JSONNode(string s)
		{
			return (s == null) ? ((JSONNode)JSONNull.CreateOrGet()) : ((JSONNode)new JSONString(s));
		}

		public static implicit operator string(JSONNode d)
		{
			return (d == null) ? null : d.Value;
		}

		public static implicit operator JSONNode(double n)
		{
			return new JSONNumber(n);
		}

		public static implicit operator double(JSONNode d)
		{
			return (d == null) ? 0.0 : d.AsDouble;
		}

		public static implicit operator JSONNode(float n)
		{
			return new JSONNumber(n);
		}

		public static implicit operator float(JSONNode d)
		{
			return (d == null) ? 0f : d.AsFloat;
		}

		public static implicit operator JSONNode(int n)
		{
			return new JSONNumber(n);
		}

		public static implicit operator int(JSONNode d)
		{
			return (!(d == null)) ? d.AsInt : 0;
		}

		public static implicit operator JSONNode(long n)
		{
			if (longAsString)
			{
				return new JSONString(n.ToString(CultureInfo.InvariantCulture));
			}
			return new JSONNumber(n);
		}

		public static implicit operator long(JSONNode d)
		{
			return (d == null) ? 0 : d.AsLong;
		}

		public static implicit operator JSONNode(ulong n)
		{
			if (longAsString)
			{
				return new JSONString(n.ToString(CultureInfo.InvariantCulture));
			}
			return new JSONNumber(n);
		}

		public static implicit operator ulong(JSONNode d)
		{
			return (d == null) ? 0 : d.AsULong;
		}

		public static implicit operator JSONNode(bool b)
		{
			return new JSONBool(b);
		}

		public static implicit operator bool(JSONNode d)
		{
			return !(d == null) && d.AsBool;
		}

		public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue)
		{
			return aKeyValue.Value;
		}

		public static bool operator ==(JSONNode a, object b)
		{
			if (object.ReferenceEquals(a, b))
			{
				return true;
			}
			bool flag = a is JSONNull || object.ReferenceEquals(a, null) || a is JSONLazyCreator;
			bool flag2 = b is JSONNull || object.ReferenceEquals(b, null) || b is JSONLazyCreator;
			if (flag && flag2)
			{
				return true;
			}
			return !flag && a.Equals(b);
		}

		public static bool operator !=(JSONNode a, object b)
		{
			return !(a == b);
		}

		public override bool Equals(object obj)
		{
			return object.ReferenceEquals(this, obj);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}

		internal static string Escape(string aText)
		{
			StringBuilder escapeBuilder = EscapeBuilder;
			escapeBuilder.Length = 0;
			if (escapeBuilder.Capacity < aText.Length + aText.Length / 10)
			{
				escapeBuilder.Capacity = aText.Length + aText.Length / 10;
			}
			foreach (char c in aText)
			{
				switch (c)
				{
				case '\\':
					escapeBuilder.Append("\\\\");
					continue;
				case '"':
					escapeBuilder.Append("\\\"");
					continue;
				case '\n':
					escapeBuilder.Append("\\n");
					continue;
				case '\r':
					escapeBuilder.Append("\\r");
					continue;
				case '\t':
					escapeBuilder.Append("\\t");
					continue;
				case '\b':
					escapeBuilder.Append("\\b");
					continue;
				case '\f':
					escapeBuilder.Append("\\f");
					continue;
				}
				if (c < ' ' || (forceASCII && c > '\u007f'))
				{
					ushort num = c;
					escapeBuilder.Append("\\u").Append(num.ToString("X4"));
				}
				else
				{
					escapeBuilder.Append(c);
				}
			}
			string result = escapeBuilder.ToString();
			escapeBuilder.Length = 0;
			return result;
		}

		private static JSONNode ParseElement(string token, bool quoted)
		{
			if (quoted)
			{
				return token;
			}
			if (token.Length <= 5)
			{
				string text = token.ToLower();
				if (text == "false" || text == "true")
				{
					return text == "true";
				}
				if (text == "null")
				{
					return JSONNull.CreateOrGet();
				}
			}
			if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return token;
		}

		public static JSONNode Parse(string aJSON)
		{
			Stack<JSONNode> stack = new Stack<JSONNode>();
			JSONNode jSONNode = null;
			int i = 0;
			StringBuilder stringBuilder = new StringBuilder();
			string aKey = "";
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			for (; i < aJSON.Length; i++)
			{
				switch (aJSON[i])
				{
				case '{':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					stack.Push(new JSONObject());
					if (jSONNode != null)
					{
						jSONNode.Add(aKey, stack.Peek());
					}
					aKey = "";
					stringBuilder.Length = 0;
					jSONNode = stack.Peek();
					flag3 = false;
					break;
				case '[':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					stack.Push(new JSONArray());
					if (jSONNode != null)
					{
						jSONNode.Add(aKey, stack.Peek());
					}
					aKey = "";
					stringBuilder.Length = 0;
					jSONNode = stack.Peek();
					flag3 = false;
					break;
				case ']':
				case '}':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					if (stack.Count == 0)
					{
						throw new Exception("JSON Parse: Too many closing brackets");
					}
					stack.Pop();
					if (stringBuilder.Length > 0 || flag2)
					{
						jSONNode.Add(aKey, ParseElement(stringBuilder.ToString(), flag2));
					}
					if (jSONNode != null)
					{
						jSONNode.Inline = !flag3;
					}
					flag2 = false;
					aKey = "";
					stringBuilder.Length = 0;
					if (stack.Count > 0)
					{
						jSONNode = stack.Peek();
					}
					break;
				case ':':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					aKey = stringBuilder.ToString();
					stringBuilder.Length = 0;
					flag2 = false;
					break;
				case '"':
					flag = !flag;
					flag2 = flag2 || flag;
					break;
				case ',':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
						break;
					}
					if (stringBuilder.Length > 0 || flag2)
					{
						jSONNode.Add(aKey, ParseElement(stringBuilder.ToString(), flag2));
					}
					flag2 = false;
					aKey = "";
					stringBuilder.Length = 0;
					flag2 = false;
					break;
				case '\n':
				case '\r':
					flag3 = true;
					break;
				case '\t':
				case ' ':
					if (flag)
					{
						stringBuilder.Append(aJSON[i]);
					}
					break;
				case '\\':
					i++;
					if (flag)
					{
						char c = aJSON[i];
						switch (c)
						{
						case 't':
							stringBuilder.Append('\t');
							break;
						case 'r':
							stringBuilder.Append('\r');
							break;
						case 'n':
							stringBuilder.Append('\n');
							break;
						case 'b':
							stringBuilder.Append('\b');
							break;
						case 'f':
							stringBuilder.Append('\f');
							break;
						case 'u':
						{
							string s = aJSON.Substring(i + 1, 4);
							stringBuilder.Append((char)int.Parse(s, NumberStyles.AllowHexSpecifier));
							i += 4;
							break;
						}
						default:
							stringBuilder.Append(c);
							break;
						}
					}
					break;
				case '/':
					if (allowLineComments && !flag && i + 1 < aJSON.Length && aJSON[i + 1] == '/')
					{
						while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r')
						{
						}
					}
					else
					{
						stringBuilder.Append(aJSON[i]);
					}
					break;
				default:
					stringBuilder.Append(aJSON[i]);
					break;
				case '\ufeff':
					break;
				}
			}
			if (flag)
			{
				throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
			}
			if (jSONNode == null)
			{
				return ParseElement(stringBuilder.ToString(), flag2);
			}
			return jSONNode;
		}
	}
	public class JSONArray : JSONNode
	{
		private List<JSONNode> m_List = new List<JSONNode>();

		private bool inline = false;

		public override bool Inline
		{
			get
			{
				return inline;
			}
			set
			{
				inline = value;
			}
		}

		public override JSONNodeType Tag => JSONNodeType.Array;

		public override bool IsArray => true;

		public override JSONNode this[int aIndex]
		{
			get
			{
				if (aIndex < 0 || aIndex >= m_List.Count)
				{
					return new JSONLazyCreator(this);
				}
				return m_List[aIndex];
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				if (aIndex < 0 || aIndex >= m_List.Count)
				{
					m_List.Add(value);
				}
				else
				{
					m_List[aIndex] = value;
				}
			}
		}

		public override JSONNode this[string aKey]
		{
			get
			{
				return new JSONLazyCreator(this);
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				m_List.Add(value);
			}
		}

		public override int Count => m_List.Count;

		public override IEnumerable<JSONNode> Children
		{
			get
			{
				foreach (JSONNode item in m_List)
				{
					yield return item;
				}
			}
		}

		public override Enumerator GetEnumerator()
		{
			return new Enumerator(m_List.GetEnumerator());
		}

		public override void Add(string aKey, JSONNode aItem)
		{
			if (aItem == null)
			{
				aItem = JSONNull.CreateOrGet();
			}
			m_List.Add(aItem);
		}

		public override JSONNode Remove(int aIndex)
		{
			if (aIndex < 0 || aIndex >= m_List.Count)
			{
				return null;
			}
			JSONNode result = m_List[aIndex];
			m_List.RemoveAt(aIndex);
			return result;
		}

		public override JSONNode Remove(JSONNode aNode)
		{
			m_List.Remove(aNode);
			return aNode;
		}

		public override void Clear()
		{
			m_List.Clear();
		}

		public override JSONNode Clone()
		{
			JSONArray jSONArray = new JSONArray();
			jSONArray.m_List.Capacity = m_List.Capacity;
			foreach (JSONNode item in m_List)
			{
				if (item != null)
				{
					jSONArray.Add(item.Clone());
				}
				else
				{
					jSONArray.Add(null);
				}
			}
			return jSONArray;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append('[');
			int count = m_List.Count;
			if (inline)
			{
				aMode = JSONTextMode.Compact;
			}
			for (int i = 0; i < count; i++)
			{
				if (i > 0)
				{
					aSB.Append(',');
				}
				if (aMode == JSONTextMode.Indent)
				{
					aSB.AppendLine();
				}
				if (aMode == JSONTextMode.Indent)
				{
					aSB.Append(' ', aIndent + aIndentInc);
				}
				m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
			}
			if (aMode == JSONTextMode.Indent)
			{
				aSB.AppendLine().Append(' ', aIndent);
			}
			aSB.Append(']');
		}
	}
	public class JSONObject : JSONNode
	{
		private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>();

		private bool inline = false;

		public override bool Inline
		{
			get
			{
				return inline;
			}
			set
			{
				inline = value;
			}
		}

		public override JSONNodeType Tag => JSONNodeType.Object;

		public override bool IsObject => true;

		public override JSONNode this[string aKey]
		{
			get
			{
				if (m_Dict.TryGetValue(aKey, out var value))
				{
					return value;
				}
				return new JSONLazyCreator(this, aKey);
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				if (m_Dict.ContainsKey(aKey))
				{
					m_Dict[aKey] = value;
				}
				else
				{
					m_Dict.Add(aKey, value);
				}
			}
		}

		public override JSONNode this[int aIndex]
		{
			get
			{
				if (aIndex < 0 || aIndex >= m_Dict.Count)
				{
					return null;
				}
				return m_Dict.ElementAt(aIndex).Value;
			}
			set
			{
				if (value == null)
				{
					value = JSONNull.CreateOrGet();
				}
				if (aIndex >= 0 && aIndex < m_Dict.Count)
				{
					string key = m_Dict.ElementAt(aIndex).Key;
					m_Dict[key] = value;
				}
			}
		}

		public override int Count => m_Dict.Count;

		public override IEnumerable<JSONNode> Children
		{
			get
			{
				foreach (KeyValuePair<string, JSONNode> N in m_Dict)
				{
					KeyValuePair<string, JSONNode> keyValuePair = N;
					yield return keyValuePair.Value;
				}
			}
		}

		public override Enumerator GetEnumerator()
		{
			return new Enumerator(m_Dict.GetEnumerator());
		}

		public override void Add(string aKey, JSONNode aItem)
		{
			if (aItem == null)
			{
				aItem = JSONNull.CreateOrGet();
			}
			if (aKey != null)
			{
				if (m_Dict.ContainsKey(aKey))
				{
					m_Dict[aKey] = aItem;
				}
				else
				{
					m_Dict.Add(aKey, aItem);
				}
			}
			else
			{
				m_Dict.Add(Guid.NewGuid().ToString(), aItem);
			}
		}

		public override JSONNode Remove(string aKey)
		{
			if (!m_Dict.ContainsKey(aKey))
			{
				return null;
			}
			JSONNode result = m_Dict[aKey];
			m_Dict.Remove(aKey);
			return result;
		}

		public override JSONNode Remove(int aIndex)
		{
			if (aIndex < 0 || aIndex >= m_Dict.Count)
			{
				return null;
			}
			KeyValuePair<string, JSONNode> keyValuePair = m_Dict.ElementAt(aIndex);
			m_Dict.Remove(keyValuePair.Key);
			return keyValuePair.Value;
		}

		public override JSONNode Remove(JSONNode aNode)
		{
			try
			{
				KeyValuePair<string, JSONNode> keyValuePair = m_Dict.Where((KeyValuePair<string, JSONNode> k) => k.Value == aNode).First();
				m_Dict.Remove(keyValuePair.Key);
				return aNode;
			}
			catch
			{
				return null;
			}
		}

		public override void Clear()
		{
			m_Dict.Clear();
		}

		public override JSONNode Clone()
		{
			JSONObject jSONObject = new JSONObject();
			foreach (KeyValuePair<string, JSONNode> item in m_Dict)
			{
				jSONObject.Add(item.Key, item.Value.Clone());
			}
			return jSONObject;
		}

		public override bool HasKey(string aKey)
		{
			return m_Dict.ContainsKey(aKey);
		}

		public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
		{
			if (m_Dict.TryGetValue(aKey, out var value))
			{
				return value;
			}
			return aDefault;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append('{');
			bool flag = true;
			if (inline)
			{
				aMode = JSONTextMode.Compact;
			}
			foreach (KeyValuePair<string, JSONNode> item in m_Dict)
			{
				if (!flag)
				{
					aSB.Append(',');
				}
				flag = false;
				if (aMode == JSONTextMode.Indent)
				{
					aSB.AppendLine();
				}
				if (aMode == JSONTextMode.Indent)
				{
					aSB.Append(' ', aIndent + aIndentInc);
				}
				aSB.Append('"').Append(JSONNode.Escape(item.Key)).Append('"');
				if (aMode == JSONTextMode.Compact)
				{
					aSB.Append(':');
				}
				else
				{
					aSB.Append(" : ");
				}
				item.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
			}
			if (aMode == JSONTextMode.Indent)
			{
				aSB.AppendLine().Append(' ', aIndent);
			}
			aSB.Append('}');
		}
	}
	public class JSONString : JSONNode
	{
		private string m_Data;

		public override JSONNodeType Tag => JSONNodeType.String;

		public override bool IsString => true;

		public override string Value
		{
			get
			{
				return m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONString(string aData)
		{
			m_Data = aData;
		}

		public override JSONNode Clone()
		{
			return new JSONString(m_Data);
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append('"').Append(JSONNode.Escape(m_Data)).Append('"');
		}

		public override bool Equals(object obj)
		{
			if (base.Equals(obj))
			{
				return true;
			}
			if (obj is string text)
			{
				return m_Data == text;
			}
			JSONString jSONString = obj as JSONString;
			if (jSONString != null)
			{
				return m_Data == jSONString.m_Data;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return m_Data.GetHashCode();
		}

		public override void Clear()
		{
			m_Data = "";
		}
	}
	public class JSONNumber : JSONNode
	{
		private double m_Data;

		public override JSONNodeType Tag => JSONNodeType.Number;

		public override bool IsNumber => true;

		public override string Value
		{
			get
			{
				return m_Data.ToString(CultureInfo.InvariantCulture);
			}
			set
			{
				if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					m_Data = result;
				}
			}
		}

		public override double AsDouble
		{
			get
			{
				return m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override long AsLong
		{
			get
			{
				return (long)m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override ulong AsULong
		{
			get
			{
				return (ulong)m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONNumber(double aData)
		{
			m_Data = aData;
		}

		public JSONNumber(string aData)
		{
			Value = aData;
		}

		public override JSONNode Clone()
		{
			return new JSONNumber(m_Data);
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append(Value.ToString(CultureInfo.InvariantCulture));
		}

		private static bool IsNumeric(object value)
		{
			return value is int || value is uint || value is float || value is double || value is decimal || value is long || value is ulong || value is short || value is ushort || value is sbyte || value is byte;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (base.Equals(obj))
			{
				return true;
			}
			JSONNumber jSONNumber = obj as JSONNumber;
			if (jSONNumber != null)
			{
				return m_Data == jSONNumber.m_Data;
			}
			if (IsNumeric(obj))
			{
				return Convert.ToDouble(obj) == m_Data;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return m_Data.GetHashCode();
		}

		public override void Clear()
		{
			m_Data = 0.0;
		}
	}
	public class JSONBool : JSONNode
	{
		private bool m_Data;

		public override JSONNodeType Tag => JSONNodeType.Boolean;

		public override bool IsBoolean => true;

		public override string Value
		{
			get
			{
				return m_Data.ToString();
			}
			set
			{
				if (bool.TryParse(value, out var result))
				{
					m_Data = result;
				}
			}
		}

		public override bool AsBool
		{
			get
			{
				return m_Data;
			}
			set
			{
				m_Data = value;
			}
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONBool(bool aData)
		{
			m_Data = aData;
		}

		public JSONBool(string aData)
		{
			Value = aData;
		}

		public override JSONNode Clone()
		{
			return new JSONBool(m_Data);
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append(m_Data ? "true" : "false");
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is bool)
			{
				return m_Data == (bool)obj;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return m_Data.GetHashCode();
		}

		public override void Clear()
		{
			m_Data = false;
		}
	}
	public class JSONNull : JSONNode
	{
		private static JSONNull m_StaticInstance = new JSONNull();

		public static bool reuseSameInstance = true;

		public override JSONNodeType Tag => JSONNodeType.NullValue;

		public override bool IsNull => true;

		public override string Value
		{
			get
			{
				return "null";
			}
			set
			{
			}
		}

		public override bool AsBool
		{
			get
			{
				return false;
			}
			set
			{
			}
		}

		public static JSONNull CreateOrGet()
		{
			if (reuseSameInstance)
			{
				return m_StaticInstance;
			}
			return new JSONNull();
		}

		private JSONNull()
		{
		}

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public override JSONNode Clone()
		{
			return CreateOrGet();
		}

		public override bool Equals(object obj)
		{
			if (object.ReferenceEquals(this, obj))
			{
				return true;
			}
			return obj is JSONNull;
		}

		public override int GetHashCode()
		{
			return 0;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append("null");
		}
	}
	internal class JSONLazyCreator : JSONNode
	{
		private JSONNode m_Node = null;

		private string m_Key = null;

		public override JSONNodeType Tag => JSONNodeType.None;

		public override JSONNode this[int aIndex]
		{
			get
			{
				return new JSONLazyCreator(this);
			}
			set
			{
				Set(new JSONArray()).Add(value);
			}
		}

		public override JSONNode this[string aKey]
		{
			get
			{
				return new JSONLazyCreator(this, aKey);
			}
			set
			{
				Set(new JSONObject()).Add(aKey, value);
			}
		}

		public override int AsInt
		{
			get
			{
				Set(new JSONNumber(0.0));
				return 0;
			}
			set
			{
				Set(new JSONNumber(value));
			}
		}

		public override float AsFloat
		{
			get
			{
				Set(new JSONNumber(0.0));
				return 0f;
			}
			set
			{
				Set(new JSONNumber(value));
			}
		}

		public override double AsDouble
		{
			get
			{
				Set(new JSONNumber(0.0));
				return 0.0;
			}
			set
			{
				Set(new JSONNumber(value));
			}
		}

		public override long AsLong
		{
			get
			{
				if (JSONNode.longAsString)
				{
					Set(new JSONString("0"));
				}
				else
				{
					Set(new JSONNumber(0.0));
				}
				return 0L;
			}
			set
			{
				if (JSONNode.longAsString)
				{
					Set(new JSONString(value.ToString(CultureInfo.InvariantCulture)));
				}
				else
				{
					Set(new JSONNumber(value));
				}
			}
		}

		public override ulong AsULong
		{
			get
			{
				if (JSONNode.longAsString)
				{
					Set(new JSONString("0"));
				}
				else
				{
					Set(new JSONNumber(0.0));
				}
				return 0uL;
			}
			set
			{
				if (JSONNode.longAsString)
				{
					Set(new JSONString(value.ToString(CultureInfo.InvariantCulture)));
				}
				else
				{
					Set(new JSONNumber(value));
				}
			}
		}

		public override bool AsBool
		{
			get
			{
				Set(new JSONBool(aData: false));
				return false;
			}
			set
			{
				Set(new JSONBool(value));
			}
		}

		public override JSONArray AsArray => Set(new JSONArray());

		public override JSONObject AsObject => Set(new JSONObject());

		public override Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}

		public JSONLazyCreator(JSONNode aNode)
		{
			m_Node = aNode;
			m_Key = null;
		}

		public JSONLazyCreator(JSONNode aNode, string aKey)
		{
			m_Node = aNode;
			m_Key = aKey;
		}

		private T Set<T>(T aVal) where T : JSONNode
		{
			if (m_Key == null)
			{
				m_Node.Add(aVal);
			}
			else
			{
				m_Node.Add(m_Key, aVal);
			}
			m_Node = null;
			return aVal;
		}

		public override void Add(JSONNode aItem)
		{
			Set(new JSONArray()).Add(aItem);
		}

		public override void Add(string aKey, JSONNode aItem)
		{
			Set(new JSONObject()).Add(aKey, aItem);
		}

		public static bool operator ==(JSONLazyCreator a, object b)
		{
			if (b == null)
			{
				return true;
			}
			return object.ReferenceEquals(a, b);
		}

		public static bool operator !=(JSONLazyCreator a, object b)
		{
			return !(a == b);
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return true;
			}
			return object.ReferenceEquals(this, obj);
		}

		public override int GetHashCode()
		{
			return 0;
		}

		internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
		{
			aSB.Append("null");
		}
	}
	public static class JSON
	{
		public static JSONNode Parse(string aJSON)
		{
			return JSONNode.Parse(aJSON);
		}
	}
}