Decompiled source of Better Portal v1.0.7

plugins/BetterPortal.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using LitJson;
using ModUtils;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BetterPortal")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BetterPortal")]
[assembly: AssemblyCopyright("Copyright © 2022-2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("AF8F4729-28E8-452D-8010-40C508E79EB0")]
[assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.0.7.0")]
namespace ModUtils
{
	public class Configuration
	{
		private sealed class LocalizedConfigEntry
		{
			public ConfigEntryBase Entry { get; set; }

			public L10N Localization { get; set; }

			public string Section { get; set; }

			public string Key { get; set; }

			public ConfigurationManagerAttributes Attributes { get; set; }

			public bool CategoryManaged { get; set; }

			public bool DispNameManaged { get; set; }

			public bool DescriptionManaged { get; set; }
		}

		private const int DefaultOrder = 4096;

		private static readonly object LocalizedEntriesLock;

		private static readonly Dictionary<ConfigEntryBase, LocalizedConfigEntry> LocalizedEntries;

		private static readonly string[] DescriptionFieldNames;

		private readonly ConfigFile _config;

		private readonly L10N _localization;

		private Logger _logger;

		private string Section { get; set; } = "general";


		private int Order { get; set; } = 4096;


		static Configuration()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			LocalizedEntriesLock = new object();
			DescriptionFieldNames = new string[4] { "<Description>k__BackingField", "Description", "description", "_description" };
			LocalizedEntries = new Dictionary<ConfigEntryBase, LocalizedConfigEntry>();
			if (!TomlTypeConverter.CanConvert(typeof(StringList)))
			{
				TomlTypeConverter.AddConverter(typeof(StringList), new TypeConverter
				{
					ConvertToObject = (string str, Type type) => (!string.IsNullOrEmpty(str)) ? new StringList(Csv.ParseLine(str, trimUnquotedFields: true)) : new StringList(),
					ConvertToString = delegate(object obj, Type type)
					{
						StringList source = (StringList)obj;
						return string.Join(", ", source.Select(Csv.Escape));
					}
				});
			}
			if (!TomlTypeConverter.CanConvert(typeof(KeyboardShortcut)))
			{
				TomlTypeConverter.AddConverter(typeof(KeyboardShortcut), new TypeConverter
				{
					ConvertToObject = (string str, Type type) => KeyboardShortcut.Deserialize(str),
					ConvertToString = delegate(object obj, Type type)
					{
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_0006: Unknown result type (might be due to invalid IL or missing references)
						KeyboardShortcut val = (KeyboardShortcut)obj;
						return ((KeyboardShortcut)(ref val)).Serialize();
					}
				});
			}
		}

		public Configuration(ConfigFile config, L10N localization)
		{
			_config = config;
			_localization = localization;
		}

		internal static void RefreshAllLocalizedMetadata()
		{
			LocalizedConfigEntry[] array;
			lock (LocalizedEntriesLock)
			{
				array = LocalizedEntries.Values.ToArray();
			}
			LocalizedConfigEntry[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RefreshLocalizedMetadata(array2[i]);
			}
		}

		private static void RegisterLocalizedEntry(ConfigEntryBase entry, L10N localization, string section, string key, ConfigurationManagerAttributes attributes, bool categoryManaged, bool dispNameManaged, bool descriptionManaged)
		{
			LocalizedConfigEntry localizedConfigEntry = new LocalizedConfigEntry
			{
				Entry = entry,
				Localization = localization,
				Section = section,
				Key = key,
				Attributes = attributes,
				CategoryManaged = categoryManaged,
				DispNameManaged = dispNameManaged,
				DescriptionManaged = descriptionManaged
			};
			lock (LocalizedEntriesLock)
			{
				LocalizedEntries[entry] = localizedConfigEntry;
			}
			RefreshLocalizedMetadata(localizedConfigEntry);
		}

		private static void RefreshLocalizedMetadata(LocalizedConfigEntry entry)
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			if (entry?.Entry == null || entry.Localization == null)
			{
				return;
			}
			try
			{
				ConfigurationManagerAttributes attributes = entry.Attributes;
				if (attributes != null)
				{
					if (entry.CategoryManaged)
					{
						attributes.Category = entry.Localization.Translate("@config_" + entry.Section + "_section");
					}
					if (entry.DispNameManaged)
					{
						attributes.DispName = entry.Localization.Translate("@config_" + entry.Section + "_" + entry.Key + "_name");
					}
					string text = (attributes.Description = (entry.DescriptionManaged ? entry.Localization.Translate("@config_" + entry.Section + "_" + entry.Key + "_description") : attributes.Description));
					ConfigDescription description = entry.Entry.Description;
					AcceptableValueBase val = ((description != null) ? description.AcceptableValues : null);
					object[] array = ReplaceConfigurationManagerAttributes((description != null) ? description.Tags : null, attributes);
					ConfigDescription description2 = new ConfigDescription(text, val, array);
					if (!TrySetEntryDescription(entry.Entry, description2))
					{
						Debug.LogError((object)("[ModUtils] Failed to replace ConfigDescription for [" + entry.Section + ":" + entry.Key + "]."));
					}
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to refresh localized config metadata for [{entry.Section}:{entry.Key}]: {arg}");
			}
		}

		private static object[] ReplaceConfigurationManagerAttributes(object[] tags, ConfigurationManagerAttributes attributes)
		{
			if (tags == null || tags.Length == 0)
			{
				return new object[1] { attributes };
			}
			bool flag = false;
			List<object> list = new List<object>(tags.Length);
			foreach (object obj in tags)
			{
				if (obj is ConfigurationManagerAttributes)
				{
					if (!flag)
					{
						list.Add(attributes);
						flag = true;
					}
				}
				else
				{
					list.Add(obj);
				}
			}
			if (!flag)
			{
				list.Add(attributes);
			}
			return list.ToArray();
		}

		private static bool TrySetEntryDescription(ConfigEntryBase entry, ConfigDescription description)
		{
			MethodInfo methodInfo = AccessTools.PropertySetter(((object)entry).GetType(), "Description") ?? AccessTools.PropertySetter(typeof(ConfigEntryBase), "Description");
			if (methodInfo != null)
			{
				methodInfo.Invoke(entry, new object[1] { description });
				return true;
			}
			string[] descriptionFieldNames = DescriptionFieldNames;
			foreach (string text in descriptionFieldNames)
			{
				FieldInfo fieldInfo = AccessTools.Field(((object)entry).GetType(), text) ?? AccessTools.Field(typeof(ConfigEntryBase), text);
				if (!(fieldInfo == null) && typeof(ConfigDescription).IsAssignableFrom(fieldInfo.FieldType))
				{
					fieldInfo.SetValue(entry, description);
					return true;
				}
			}
			return false;
		}

		private void LogSection(string section)
		{
			_logger?.Debug("[CONFIG] === " + GetSection(section) + " / [" + section + "]");
		}

		private void LogConfigEntry<T>(ConfigEntry<T> entry, ConfigurationManagerAttributes attributes)
		{
			_logger?.Debug("[CONFIG] ==== " + attributes.DispName + " / [" + ((ConfigEntryBase)entry).Definition.Key + "]");
			_logger?.Debug("[CONFIG] " + ((ConfigEntryBase)entry).Description.Description);
			_logger?.Debug("[CONFIG] ");
			Type type = typeof(T);
			object defaultValue = ((ConfigEntryBase)entry).DefaultValue;
			if (attributes.ObjToStr != null)
			{
				_logger?.Debug("[CONFIG] - Default value: " + attributes.ObjToStr(defaultValue));
			}
			else if (TomlTypeConverter.CanConvert(type))
			{
				_logger?.Debug("[CONFIG] - Default value: " + TomlTypeConverter.ConvertToString(defaultValue, type));
			}
			else
			{
				_logger?.Debug($"[CONFIG] - Default value: {defaultValue}");
			}
			AcceptableValueBase acceptableValues = ((ConfigEntryBase)entry).Description.AcceptableValues;
			if (acceptableValues != null)
			{
				string[] array = acceptableValues.ToDescriptionString().Split('\n');
				foreach (string text in array)
				{
					_logger?.Debug("[CONFIG] - " + text);
				}
			}
			else if (type.IsEnum)
			{
				List<string> list = (from x in Enum.GetValues(type).OfType<T>()
					select Enum.GetName(type, x)).ToList();
				_logger?.Debug("[CONFIG] - Acceptable values: " + string.Join(", ", list));
				if (type.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Any())
				{
					IEnumerable<string> values = list.Where((string x) => !string.Equals(x, "none", StringComparison.OrdinalIgnoreCase) && !string.Equals(x, "all", StringComparison.OrdinalIgnoreCase)).Take(2);
					_logger?.Debug("[CONFIG] - Multiple values can be set at the same time by separating them with , (e.g. " + string.Join(", ", values) + ")");
				}
			}
			_logger?.Debug("[CONFIG] ");
		}

		public void SetDebugLogger(Logger logger)
		{
			_logger = logger;
		}

		public void ChangeSection(string section, int initialOrder = 4096)
		{
			Section = section;
			Order = initialOrder;
			if (_logger != null)
			{
				LogSection(Section);
			}
		}

		private ConfigEntry<T> Bind<T>(string section, int order, string key, T defaultValue, AcceptableValueBase acceptableValue = null, Action<ConfigurationManagerAttributes> initializer = null)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			L10N.EnsurePatched();
			string section2 = GetSection(section);
			string name = GetName(section, key);
			ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
			{
				Category = section2,
				Order = order,
				DispName = name,
				CustomDrawer = ConfigurationCustomDrawer.Get(typeof(T), acceptableValue)
			};
			initializer?.Invoke(configurationManagerAttributes);
			bool categoryManaged = string.Equals(configurationManagerAttributes.Category, section2, StringComparison.Ordinal);
			bool dispNameManaged = string.Equals(configurationManagerAttributes.DispName, name, StringComparison.Ordinal);
			bool flag = string.IsNullOrEmpty(configurationManagerAttributes.Description);
			string text = (configurationManagerAttributes.Description = (flag ? GetDescription(section, key) : configurationManagerAttributes.Description));
			ConfigEntry<T> val = _config.Bind<T>(section, key, defaultValue, new ConfigDescription(text, acceptableValue, new object[1] { configurationManagerAttributes }));
			RegisterLocalizedEntry((ConfigEntryBase)(object)val, _localization, section, key, configurationManagerAttributes, categoryManaged, dispNameManaged, flag);
			if (_logger != null)
			{
				LogConfigEntry<T>(val, configurationManagerAttributes);
			}
			return val;
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, AcceptableValueBase acceptableValue = null, Action<ConfigurationManagerAttributes> initializer = null)
		{
			return Bind(section, Order--, key, defaultValue, acceptableValue, initializer);
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, (T, T) acceptableValue, Action<ConfigurationManagerAttributes> initializer = null) where T : IComparable
		{
			var (val, val2) = acceptableValue;
			return Bind(section, key, defaultValue, (AcceptableValueBase)(object)new AcceptableValueRange<T>(val, val2), initializer);
		}

		public ConfigEntry<T> Bind<T>(string key, T defaultValue, AcceptableValueBase acceptableValue = null, Action<ConfigurationManagerAttributes> initializer = null)
		{
			return Bind(Section, key, defaultValue, acceptableValue, initializer);
		}

		public ConfigEntry<T> Bind<T>(string key, T defaultValue, (T, T) acceptableValue, Action<ConfigurationManagerAttributes> initializer = null) where T : IComparable
		{
			return Bind(Section, key, defaultValue, acceptableValue, initializer);
		}

		private string GetSection(string section)
		{
			return _localization.Translate("@config_" + section + "_section");
		}

		private string GetName(string section, string key)
		{
			return _localization.Translate("@config_" + section + "_" + key + "_name");
		}

		private string GetDescription(string section, string key)
		{
			return _localization.Translate("@config_" + section + "_" + key + "_description");
		}
	}
	public class StringList : ICollection<string>, IEnumerable<string>, IEnumerable
	{
		private readonly HashSet<string> _values;

		public int Count => _values.Count;

		public bool IsReadOnly => false;

		public StringList()
		{
			_values = new HashSet<string>();
		}

		public StringList(IEnumerable<string> collection)
		{
			_values = new HashSet<string>(collection);
		}

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

		public IEnumerator<string> GetEnumerator()
		{
			return _values.GetEnumerator();
		}

		public void Add(string item)
		{
			_values.Add(item);
		}

		public void Clear()
		{
			_values.Clear();
		}

		public bool Contains(string item)
		{
			return _values.Contains(item);
		}

		public void CopyTo(string[] array, int arrayIndex)
		{
			_values.CopyTo(array, arrayIndex);
		}

		public bool Remove(string item)
		{
			return _values.Remove(item);
		}

		public bool TryAdd(string item)
		{
			return _values.Add(item);
		}
	}
	public class LocalizedDescriptionAttribute : DescriptionAttribute
	{
		private readonly string _prefix;

		private readonly string _key;

		public override string Description => L10N.Translate(_prefix, _key);

		public LocalizedDescriptionAttribute(string prefix, string key)
			: base(key)
		{
			_prefix = prefix;
			_key = key;
		}

		public LocalizedDescriptionAttribute(string key)
			: this("", key)
		{
		}
	}
	public class AcceptableValueEnum<T> : AcceptableValueBase where T : Enum
	{
		private readonly bool _isFlags;

		private readonly IList<T> _values;

		public AcceptableValueEnum(params T[] values)
			: base(typeof(T))
		{
			_isFlags = ((AcceptableValueBase)this).ValueType.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Any();
			_values = MakeValues(((AcceptableValueBase)this).ValueType, (IReadOnlyCollection<T>)(object)values, _isFlags);
		}

		private static IList<T> MakeValues(Type type, IReadOnlyCollection<T> values, bool isFlags)
		{
			object collection;
			if (values.Count != 0)
			{
				collection = values;
			}
			else
			{
				collection = Enum.GetValues(type).OfType<T>();
			}
			List<T> list = new List<T>((IEnumerable<T>)collection);
			if (!isFlags)
			{
				return list;
			}
			HashSet<long> hashSet = new HashSet<long>();
			foreach (long item in list.Select((T @enum) => Convert.ToInt64(@enum)))
			{
				long[] array = hashSet.ToArray();
				foreach (long num in array)
				{
					hashSet.Add(num | item);
				}
				hashSet.Add(item);
			}
			return hashSet.Select((long x) => Enum.ToObject(type, x)).Cast<T>().ToList();
		}

		public override object Clamp(object value)
		{
			if (!((AcceptableValueBase)this).IsValid(value))
			{
				return _values[0];
			}
			return value;
		}

		public override bool IsValid(object value)
		{
			if (value is T item)
			{
				return _values.Contains(item);
			}
			if (!(value is IConvertible))
			{
				return false;
			}
			long @long = Convert.ToInt64(value);
			return _values.Any((T x) => Convert.ToInt64(x) == @long);
		}

		public override string ToDescriptionString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			Type type = typeof(T);
			List<string> list = (from x in _values
				where Enum.IsDefined(type, x)
				select Enum.GetName(type, x)).ToList();
			stringBuilder.Append("# Acceptable values: ").Append(string.Join(", ", list));
			if (!_isFlags)
			{
				return stringBuilder.ToString();
			}
			List<string> list2 = list.Where((string x) => !string.Equals(x, "none", StringComparison.OrdinalIgnoreCase) && !string.Equals(x, "all", StringComparison.OrdinalIgnoreCase)).Take(2).ToList();
			if (list2.Count == 2)
			{
				stringBuilder.Append('\n').Append("# Multiple values can be set at the same time by separating them with , (e.g. ").Append(string.Join(", ", list2))
					.Append(")");
			}
			return stringBuilder.ToString();
		}
	}
	public static class ConfigurationCustomDrawer
	{
		public delegate bool IsMatchConfig(Type type, AcceptableValueBase acceptableValue);

		public delegate Action<ConfigEntryBase> CustomDrawerSupplier();

		private const string L10NPrefix = "mod_utils";

		private const string EnabledKey = "@config_button_enabled";

		private const string DisabledKey = "@config_button_disabled";

		private const string AddKey = "@config_button_add";

		private const string RemoveKey = "@config_button_remove";

		private static readonly Dictionary<IsMatchConfig, CustomDrawerSupplier> CustomDrawers;

		private static bool _defaultTranslationsInitialized;

		private static readonly Dictionary<string, Dictionary<string, string>> BuiltinDrawerTranslations;

		private static readonly Dictionary<string, Dictionary<string, string>> CustomDrawerTranslations;

		private static readonly Dictionary<string, string> OwnedDefaults;

		static ConfigurationCustomDrawer()
		{
			BuiltinDrawerTranslations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase)
			{
				{
					"English",
					new Dictionary<string, string>
					{
						{ "@config_button_enabled", "Enabled" },
						{ "@config_button_disabled", "Disabled" },
						{ "@config_button_add", "Add" },
						{ "@config_button_remove", "Remove" }
					}
				},
				{
					"Japanese",
					new Dictionary<string, string>
					{
						{ "@config_button_enabled", "有効" },
						{ "@config_button_disabled", "無効" },
						{ "@config_button_add", "追加" },
						{ "@config_button_remove", "削除" }
					}
				}
			};
			CustomDrawerTranslations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			OwnedDefaults = new Dictionary<string, string>();
			CustomDrawers = new Dictionary<IsMatchConfig, CustomDrawerSupplier>
			{
				{
					IsBool,
					() => Bool
				},
				{
					IsFloatWithRange,
					() => FloatSlider
				},
				{ IsStringList, StringList },
				{
					IsFlagsEnum,
					() => Flags
				}
			};
		}

		public static void RegisterDefaultDrawerTranslation(string language, string key, string value)
		{
			if (!CustomDrawerTranslations.TryGetValue(language, out var value2))
			{
				value2 = new Dictionary<string, string>();
				CustomDrawerTranslations[language] = value2;
			}
			value2[key] = value;
			if (_defaultTranslationsInitialized)
			{
				RefreshDefaultTranslations();
			}
		}

		private static void EnsureDefaultTranslations()
		{
			if (!_defaultTranslationsInitialized)
			{
				_defaultTranslationsInitialized = TryAddDefaultTranslations();
			}
		}

		internal static void RefreshDefaultTranslations()
		{
			_defaultTranslationsInitialized = false;
			_defaultTranslationsInitialized = TryAddDefaultTranslations();
			if (!_defaultTranslationsInitialized)
			{
				Debug.LogWarning((object)"[ModUtils] Failed to refresh custom drawer fallback translations for the current language.");
			}
		}

		private static Dictionary<string, string> ResolveDrawerTranslations(string language)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(BuiltinDrawerTranslations["English"]);
			if (CustomDrawerTranslations.TryGetValue("English", out var value))
			{
				foreach (KeyValuePair<string, string> item in value)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			if (!string.Equals(language, "English", StringComparison.OrdinalIgnoreCase))
			{
				if (BuiltinDrawerTranslations.TryGetValue(language, out var value2))
				{
					foreach (KeyValuePair<string, string> item2 in value2)
					{
						dictionary[item2.Key] = item2.Value;
					}
				}
				if (CustomDrawerTranslations.TryGetValue(language, out var value3))
				{
					foreach (KeyValuePair<string, string> item3 in value3)
					{
						dictionary[item3.Key] = item3.Value;
					}
				}
			}
			return dictionary;
		}

		private static bool TryAddDefaultTranslations()
		{
			Localization instance;
			try
			{
				instance = Localization.instance;
			}
			catch (Exception)
			{
				return false;
			}
			if (instance == null)
			{
				return false;
			}
			Dictionary<string, string> field = Reflections.GetField<Dictionary<string, string>>(instance, "m_translations");
			if (field == null)
			{
				return false;
			}
			string text;
			try
			{
				text = instance.GetSelectedLanguage();
			}
			catch (Exception)
			{
				return false;
			}
			if (string.IsNullOrEmpty(text))
			{
				text = "English";
			}
			foreach (KeyValuePair<string, string> item in ResolveDrawerTranslations(text))
			{
				string translationKey = L10N.GetTranslationKey("mod_utils", item.Key);
				if (field.TryGetValue(translationKey, out var value))
				{
					if (OwnedDefaults.TryGetValue(translationKey, out var value2) && value == value2)
					{
						field[translationKey] = item.Value;
					}
				}
				else
				{
					field[translationKey] = item.Value;
				}
				OwnedDefaults[translationKey] = item.Value;
			}
			return true;
		}

		private static bool IsBool(Type type, AcceptableValueBase acceptableValue)
		{
			return type == typeof(bool);
		}

		private static bool IsFloatWithRange(Type type, AcceptableValueBase acceptableValue)
		{
			if (type == typeof(float))
			{
				return acceptableValue is AcceptableValueRange<float>;
			}
			return false;
		}

		private static bool IsStringList(Type type, AcceptableValueBase acceptableValue)
		{
			return type == typeof(StringList);
		}

		private static bool HasFlagsAttribute(Type type)
		{
			if (type.IsEnum)
			{
				return type.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Any();
			}
			return false;
		}

		private static bool IsFlagsEnum(Type type, AcceptableValueBase acceptableValue)
		{
			return HasFlagsAttribute(type);
		}

		public static void Bool(ConfigEntryBase entry)
		{
			EnsureDefaultTranslations();
			bool flag = (bool)entry.BoxedValue;
			string text = L10N.Translate("mod_utils", flag ? "@config_button_enabled" : "@config_button_disabled");
			bool flag2 = GUILayout.Toggle(flag, text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (flag2 != flag)
			{
				entry.BoxedValue = flag2;
			}
		}

		public static void FloatSlider(ConfigEntryBase entry)
		{
			AcceptableValueRange<float> val = (AcceptableValueRange<float>)(object)entry.Description.AcceptableValues;
			float num = (float)entry.BoxedValue;
			float minValue = val.MinValue;
			float maxValue = val.MaxValue;
			float num2 = GUILayout.HorizontalSlider(num, minValue, maxValue, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			num2 = Mathf.Floor(num2 * 100f) / 100f;
			if (Math.Abs(num2 - num) > Mathf.Abs(maxValue - minValue) / 1000f)
			{
				entry.BoxedValue = num2;
			}
			string text = num.ToString("0.00", CultureInfo.InvariantCulture);
			string text2 = GUILayout.TextField(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			if (text2 == text)
			{
				return;
			}
			try
			{
				num2 = (float)Convert.ToDouble(text2, CultureInfo.InvariantCulture);
				object boxedValue = Convert.ChangeType(((AcceptableValueBase)val).Clamp((object)num2), entry.SettingType, CultureInfo.InvariantCulture);
				entry.BoxedValue = boxedValue;
			}
			catch (FormatException)
			{
			}
		}

		private static Action<ConfigEntryBase> StringList()
		{
			string inputText = "";
			return delegate(ConfigEntryBase entry)
			{
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0125: Expected O, but got Unknown
				//IL_0120: Unknown result type (might be due to invalid IL or missing references)
				//IL_013a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0144: Expected O, but got Unknown
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				EnsureDefaultTranslations();
				int num = Mathf.Min(Screen.width, 650);
				int num2 = num - Mathf.RoundToInt((float)num / 2.5f) - 115;
				string text = L10N.Translate("mod_utils", "@config_button_add");
				string text2 = L10N.Translate("mod_utils", "@config_button_remove");
				StringList stringList = new StringList((StringList)entry.BoxedValue);
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxWidth((float)num2) });
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				inputText = GUILayout.TextField(inputText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }) && !string.IsNullOrEmpty(inputText))
				{
					if (stringList.TryAdd(inputText))
					{
						entry.BoxedValue = stringList;
					}
					inputText = "";
				}
				GUILayout.EndHorizontal();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				double num3 = 0.0;
				foreach (string item in stringList.ToList())
				{
					int num4 = Mathf.FloorToInt(GUI.skin.label.CalcSize(new GUIContent(item)).x) + Mathf.FloorToInt(GUI.skin.button.CalcSize(new GUIContent(text2)).x);
					num3 += (double)num4;
					if (num3 > (double)num2)
					{
						GUILayout.EndHorizontal();
						num3 = num4;
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					}
					GUILayout.Label(item, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
					if (GUILayout.Button(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }) && stringList.Remove(item))
					{
						entry.BoxedValue = stringList;
					}
				}
				GUILayout.EndHorizontal();
				GUILayout.EndVertical();
				GUILayout.FlexibleSpace();
			};
		}

		public static void Flags(ConfigEntryBase entry)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Min(Screen.width, 650);
			int num2 = num - Mathf.RoundToInt((float)num / 2.5f) - 115;
			Type settingType = entry.SettingType;
			long num3 = Convert.ToInt64(entry.BoxedValue);
			AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxWidth((float)num2) });
			int num4 = 0;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			foreach (object value2 in Enum.GetValues(settingType))
			{
				if (acceptableValues != null && !acceptableValues.IsValid(value2))
				{
					continue;
				}
				long num5 = Convert.ToInt64(value2);
				if (num5 != 0L)
				{
					string enumLabel = GetEnumLabel(settingType, value2);
					int num6 = Mathf.FloorToInt(GUI.skin.toggle.CalcSize(new GUIContent(enumLabel + "_")).x);
					num4 += num6;
					if (num4 > num2)
					{
						GUILayout.EndHorizontal();
						num4 = num6;
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					}
					GUI.changed = false;
					bool flag = GUILayout.Toggle((num3 & num5) == num5, enumLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
					if (GUI.changed)
					{
						long value = (flag ? (num3 | num5) : (num3 & ~num5));
						entry.BoxedValue = Enum.ToObject(settingType, value);
					}
				}
			}
			GUILayout.EndHorizontal();
			GUI.changed = false;
			GUILayout.EndVertical();
			GUILayout.FlexibleSpace();
		}

		public static Action<ConfigEntryBase> MultiSelect<T>(Func<IEnumerable<T>> allElementSupplier, Func<T, string> labelGenerator) where T : IComparable<T>
		{
			return delegate(ConfigEntryBase entry)
			{
				//IL_013b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Expected O, but got Unknown
				//IL_0140: Unknown result type (might be due to invalid IL or missing references)
				int num = Mathf.Min(Screen.width, 650);
				int num2 = num - Mathf.RoundToInt((float)num / 2.5f) - 115;
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxWidth((float)num2) });
				Type settingType = entry.SettingType;
				ConstructorInfo constructor = settingType.GetConstructor(new Type[1] { typeof(IEnumerable<T>) });
				if ((object)constructor == null)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label($"{settingType} does not define a constructor that takes IEnumerable<{typeof(T)}> as an argument.", Array.Empty<GUILayoutOption>());
					GUILayout.EndHorizontal();
					GUI.changed = false;
					GUILayout.EndVertical();
					GUILayout.FlexibleSpace();
				}
				else
				{
					ICollection<T> collection = (ICollection<T>)constructor.Invoke(new object[1] { entry.BoxedValue });
					AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
					int num3 = 0;
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					foreach (T item in allElementSupplier())
					{
						if (acceptableValues == null || acceptableValues.IsValid((object)item))
						{
							string text = labelGenerator(item) ?? item.ToString();
							int num4 = Mathf.FloorToInt(GUI.skin.toggle.CalcSize(new GUIContent(text + "_")).x);
							num3 += num4;
							if (num3 > num2)
							{
								GUILayout.EndHorizontal();
								num3 = num4;
								GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
							}
							GUI.changed = false;
							bool flag = GUILayout.Toggle(collection.Contains(item), text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
							if (GUI.changed)
							{
								if (flag)
								{
									collection.Add(item);
								}
								else
								{
									collection.Remove(item);
								}
								entry.BoxedValue = collection;
							}
						}
					}
					GUILayout.EndHorizontal();
					GUI.changed = false;
					GUILayout.EndVertical();
					GUILayout.FlexibleSpace();
				}
			};
		}

		public static void Register(IsMatchConfig matcher, CustomDrawerSupplier supplier)
		{
			CustomDrawers[matcher] = supplier;
		}

		public static Action<ConfigEntryBase> Get(Type type, AcceptableValueBase acceptableValue)
		{
			return (from x in CustomDrawers
				where x.Key(type, acceptableValue)
				select x.Value()).FirstOrDefault();
		}

		private static string GetEnumLabel(Type type, object @object)
		{
			return (type.GetMember(Enum.GetName(type, @object) ?? "").FirstOrDefault()?.GetCustomAttributes(typeof(DescriptionAttribute), inherit: false).OfType<DescriptionAttribute>().FirstOrDefault())?.Description ?? @object.ToString();
		}
	}
	public sealed class ConfigurationManagerAttributes
	{
		public bool? ShowRangeAsPercent;

		public Action<ConfigEntryBase> CustomDrawer;

		public bool? Browsable;

		public string Category;

		public object DefaultValue;

		public bool? HideDefaultButton;

		public bool? HideSettingName;

		public string Description;

		public string DispName;

		public int? Order;

		public bool? ReadOnly;

		public bool? IsAdvanced;

		public Func<object, string> ObjToStr;

		public Func<string, object> StrToObj;
	}
	public static class Csv
	{
		public sealed class Parser
		{
			private readonly StringBuilder _fieldBuffer;

			private readonly List<string> _recordBuffer;

			private readonly string _source;

			private readonly bool _trimUnquotedFields;

			private bool _fieldQuoted;

			private bool _fieldStarted;

			private bool _inQuotes;

			private bool _lastTokenWasDelimiter;

			private bool _quotedFieldClosed;

			private int _offset;

			public Parser(string source, int offset = 0, bool trimUnquotedFields = false)
			{
				_source = source ?? "";
				_offset = offset;
				_trimUnquotedFields = trimUnquotedFields;
				_recordBuffer = new List<string>();
				_fieldBuffer = new StringBuilder();
			}

			public List<List<string>> Parse()
			{
				List<List<string>> list = new List<List<string>>();
				int num = -1;
				while (HasNext())
				{
					List<string> list2 = ParseLine();
					int count = list2.Count;
					if (count != 0)
					{
						if (num == -1)
						{
							num = count;
						}
						else if (num != count)
						{
							throw new Exception("Number of fields in a record is not uniform.");
						}
						list.Add(list2);
					}
				}
				return list;
			}

			public bool HasNext()
			{
				return _offset < _source.Length;
			}

			public List<string> ParseLine()
			{
				_recordBuffer.Clear();
				_fieldBuffer.Clear();
				_fieldQuoted = false;
				_fieldStarted = false;
				_inQuotes = false;
				_lastTokenWasDelimiter = false;
				_quotedFieldClosed = false;
				List<string> list = new List<string>();
				bool recordHasContent = false;
				while (_offset < _source.Length)
				{
					char c = _source[_offset++];
					if (!ParseChar(c, ref recordHasContent))
					{
						break;
					}
				}
				if (recordHasContent || _fieldStarted || _lastTokenWasDelimiter)
				{
					FlushField();
				}
				if (_recordBuffer.Count > 0)
				{
					list.AddRange(_recordBuffer);
				}
				return list;
			}

			private bool ParseChar(char c, ref bool recordHasContent)
			{
				switch (c)
				{
				case '"':
					recordHasContent = true;
					if (_inQuotes)
					{
						if (_offset < _source.Length && _source[_offset] == '"')
						{
							_fieldBuffer.Append('"');
							_offset++;
						}
						else
						{
							_inQuotes = false;
							_quotedFieldClosed = true;
						}
					}
					else if (CanStartQuotedField())
					{
						_fieldQuoted = true;
						_fieldStarted = true;
						_inQuotes = true;
						_quotedFieldClosed = false;
						_fieldBuffer.Clear();
					}
					else
					{
						_fieldBuffer.Append(c);
						_fieldStarted = true;
						_quotedFieldClosed = false;
					}
					_lastTokenWasDelimiter = false;
					return true;
				case ',':
					if (!_inQuotes)
					{
						recordHasContent = true;
						FlushField();
						_lastTokenWasDelimiter = true;
						return true;
					}
					break;
				}
				if ((c == '\r' || c == '\n') && !_inQuotes)
				{
					if (c == '\r' && _offset < _source.Length && _source[_offset] == '\n')
					{
						_offset++;
					}
					return false;
				}
				if (_trimUnquotedFields && _fieldQuoted && _quotedFieldClosed && char.IsWhiteSpace(c))
				{
					_lastTokenWasDelimiter = false;
					return true;
				}
				recordHasContent = true;
				_fieldBuffer.Append(c);
				_fieldStarted = true;
				_quotedFieldClosed = false;
				_lastTokenWasDelimiter = false;
				return true;
			}

			private bool CanStartQuotedField()
			{
				if (_fieldStarted)
				{
					if (_trimUnquotedFields && !_fieldQuoted)
					{
						return FieldBufferIsWhitespace();
					}
					return false;
				}
				return true;
			}

			private bool FieldBufferIsWhitespace()
			{
				for (int i = 0; i < _fieldBuffer.Length; i++)
				{
					if (!char.IsWhiteSpace(_fieldBuffer[i]))
					{
						return false;
					}
				}
				return true;
			}

			private void FlushField()
			{
				string text = _fieldBuffer.ToString();
				_recordBuffer.Add((_trimUnquotedFields && !_fieldQuoted) ? text.Trim() : text);
				_fieldBuffer.Clear();
				_fieldQuoted = false;
				_fieldStarted = false;
				_quotedFieldClosed = false;
			}
		}

		private static readonly char[] MustQuoteChars = new char[4] { '"', ',', '\r', '\n' };

		public static string Escape(string field)
		{
			if (field == null)
			{
				return "";
			}
			if (field.Length == 0 || field.IndexOfAny(MustQuoteChars) != -1 || (field.Length > 0 && (char.IsWhiteSpace(field[0]) || char.IsWhiteSpace(field[field.Length - 1]))))
			{
				return "\"" + field.Replace("\"", "\"\"") + "\"";
			}
			return field;
		}

		public static List<List<string>> Parse(string csv)
		{
			return Parse(csv, trimUnquotedFields: false);
		}

		public static List<List<string>> Parse(string csv, bool trimUnquotedFields)
		{
			return new Parser(csv, 0, trimUnquotedFields).Parse();
		}

		public static List<string> ParseLine(string line)
		{
			return ParseLine(line, trimUnquotedFields: false);
		}

		public static List<string> ParseLine(string line, bool trimUnquotedFields)
		{
			return new Parser(line, 0, trimUnquotedFields).ParseLine();
		}
	}
	public class InstanceCache<T> : MonoBehaviour
	{
		private static readonly HashSet<T> Cache;

		private T _instance;

		public static Action<T> OnCacheAdded { get; set; }

		public static Action<T> OnCacheRemoved { get; set; }

		static InstanceCache()
		{
			Cache = new HashSet<T>();
		}

		private void Awake()
		{
			_instance = GetInstance();
			if (_instance != null)
			{
				object obj = _instance;
				Object val = (Object)((obj is Object) ? obj : null);
				if (val == null || Object.op_Implicit(val))
				{
					Cache.Add(_instance);
					OnCacheAdded?.Invoke(_instance);
					return;
				}
			}
			throw new NullReferenceException("Failed to acquire instance.");
		}

		private void OnDestroy()
		{
			Cache.Remove(_instance);
			OnCacheRemoved?.Invoke(_instance);
			_instance = default(T);
		}

		protected virtual T GetInstance()
		{
			return ((Component)this).GetComponent<T>();
		}

		public static IEnumerable<T> GetAllInstance()
		{
			return Cache.ToList();
		}

		public static void Fill(List<T> buffer)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			buffer.Clear();
			buffer.AddRange(Cache);
		}
	}
	public enum WorldLevelMatchMode
	{
		Exact,
		CurrentOrHigher,
		Ignore
	}
	public static class Inventories
	{
		public static float CurrentWorldLevel
		{
			get
			{
				if (!((Object)(object)Game.instance != (Object)null))
				{
					return 0f;
				}
				return Game.m_worldLevel;
			}
		}

		private static bool IsWorldLevelMatch(ItemData data, float worldLevel, WorldLevelMatchMode matchMode)
		{
			return matchMode switch
			{
				WorldLevelMatchMode.Exact => (float)data.m_worldLevel == worldLevel, 
				WorldLevelMatchMode.CurrentOrHigher => (float)data.m_worldLevel >= CurrentWorldLevel, 
				WorldLevelMatchMode.Ignore => true, 
				_ => (float)data.m_worldLevel == worldLevel, 
			};
		}

		private static bool IsMatchedItem(ItemData data, string name, float worldLevel, int quality, bool isPrefabName, WorldLevelMatchMode matchMode)
		{
			if (data == null)
			{
				return false;
			}
			bool num;
			if (!isPrefabName)
			{
				num = data.m_shared.m_name == name;
			}
			else
			{
				if (!((Object)(object)data.m_dropPrefab != (Object)null))
				{
					goto IL_0057;
				}
				num = ((Object)data.m_dropPrefab).name == name;
			}
			if (num && (quality < 0 || data.m_quality == quality))
			{
				return IsWorldLevelMatch(data, worldLevel, matchMode);
			}
			goto IL_0057;
			IL_0057:
			return false;
		}

		private static void NotifyChanged(Inventory inventory)
		{
			Reflections.InvokeMethod(inventory, "Changed");
		}

		private static int CountItems(Inventory inventory, string name, float worldLevel, int quality, bool isPrefabName = false, WorldLevelMatchMode matchMode = WorldLevelMatchMode.Exact)
		{
			return GetItems(inventory, name, worldLevel, matchMode, quality, isPrefabName).Sum((ItemData x) => x.m_stack);
		}

		private static int FindFreeStackSpace(Inventory inventory, string name, float worldLevel, int quality, bool isPrefabName)
		{
			return (from item in GetItems(inventory, name, worldLevel, WorldLevelMatchMode.Exact, quality, isPrefabName)
				where item.m_stack < item.m_shared.m_maxStackSize
				select item).Sum((ItemData item) => item.m_shared.m_maxStackSize - item.m_stack);
		}

		public static IEnumerable<ItemData> GetItems(Inventory inventory, string name, float worldLevel, WorldLevelMatchMode matchMode, int quality = -1, bool isPrefabName = false)
		{
			return (from data in inventory.GetAllItems()
				where IsMatchedItem(data, name, worldLevel, quality, isPrefabName, matchMode)
				select data).ToList();
		}

		[Obsolete("Use overload with WorldLevelMatchMode parameter")]
		public static IEnumerable<ItemData> GetItems(Inventory inventory, string name, float worldLevel, int quality = -1, bool isPrefabName = false)
		{
			return GetItems(inventory, name, worldLevel, WorldLevelMatchMode.Exact, quality, isPrefabName);
		}

		public static int AddItem(Inventory inventory, GameObject prefab, int amount, int quality = -1)
		{
			if (amount <= 0)
			{
				return 0;
			}
			ItemData val = prefab.GetComponent<ItemDrop>().m_itemData.Clone();
			val.m_dropPrefab = prefab;
			val.m_stack = Mathf.Min(amount, val.m_shared.m_maxStackSize);
			val.m_quality = Mathf.Clamp(quality, 1, val.m_shared.m_maxQuality);
			if ((Object)(object)Game.instance != (Object)null)
			{
				val.m_worldLevel = Game.m_worldLevel;
			}
			int num = CountItems(inventory, val.m_shared.m_name, val.m_worldLevel, val.m_quality);
			inventory.AddItem(val);
			return CountItems(inventory, val.m_shared.m_name, val.m_worldLevel, val.m_quality) - num;
		}

		public static int FillFreeStackSpace(Inventory from, Inventory to, string name, float worldLevel, int amount, int quality = -1, bool isPrefabName = false)
		{
			if (amount <= 0)
			{
				return 0;
			}
			int num = Mathf.Min(amount, FindFreeStackSpace(to, name, worldLevel, quality, isPrefabName));
			if (num == 0)
			{
				return 0;
			}
			int num2 = 0;
			IEnumerable<ItemData> items = GetItems(to, name, worldLevel, WorldLevelMatchMode.Exact, quality, isPrefabName);
			foreach (ItemData item in GetItems(from, name, worldLevel, WorldLevelMatchMode.Exact, quality, isPrefabName))
			{
				foreach (ItemData item2 in items)
				{
					if (item2.m_stack >= item2.m_shared.m_maxStackSize)
					{
						continue;
					}
					int stack = item.m_stack;
					int num3 = Mathf.Min(Mathf.Min(num, stack), item2.m_shared.m_maxStackSize - item2.m_stack);
					if (num3 != 0)
					{
						item2.m_stack += num3;
						num2 += num3;
						num -= num3;
						from.RemoveItem(item, num3);
						NotifyChanged(to);
						if (num == 0)
						{
							goto end_IL_00ff;
						}
						if (stack - num3 <= 0)
						{
							break;
						}
					}
				}
				continue;
				end_IL_00ff:
				break;
			}
			return num2;
		}

		public static int FillFreeStackSpace(Inventory inventory, string name, float worldLevel, int amount, int quality = -1, bool isPrefabName = false)
		{
			if (amount <= 0)
			{
				return 0;
			}
			int num = amount;
			int num2 = 0;
			foreach (ItemData item in GetItems(inventory, name, worldLevel, WorldLevelMatchMode.Exact, quality, isPrefabName))
			{
				if (item.m_stack >= item.m_shared.m_maxStackSize)
				{
					continue;
				}
				int num3 = Mathf.Min(num, item.m_shared.m_maxStackSize - item.m_stack);
				if (num3 > 0)
				{
					item.m_stack += num3;
					num2 += num3;
					num -= num3;
					NotifyChanged(inventory);
					if (num == 0)
					{
						break;
					}
				}
			}
			return num2;
		}

		public static bool HaveItem(Inventory inventory, string name, float worldLevel, WorldLevelMatchMode matchMode, int amount, int quality = -1, bool isPrefabName = false)
		{
			if (amount <= 0)
			{
				return true;
			}
			int num = 0;
			foreach (ItemData item in GetItems(inventory, name, worldLevel, matchMode, quality, isPrefabName))
			{
				num += item.m_stack;
				if (num >= amount)
				{
					return true;
				}
			}
			return false;
		}

		[Obsolete("Use overload with WorldLevelMatchMode parameter")]
		public static bool HaveItem(Inventory inventory, string name, float worldLevel, int amount, int quality = -1, bool isPrefabName = false)
		{
			return HaveItem(inventory, name, worldLevel, WorldLevelMatchMode.Exact, amount, quality, isPrefabName);
		}

		public static int RemoveItem(Inventory inventory, string name, float worldLevel, WorldLevelMatchMode matchMode, int amount, int quality = -1, bool isPrefabName = false)
		{
			if (amount <= 0)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData item in GetItems(inventory, name, worldLevel, matchMode, quality, isPrefabName))
			{
				int num2 = Mathf.Min(amount, item.m_stack);
				inventory.RemoveItem(item, num2);
				num += num2;
				amount -= num2;
				if (amount == 0)
				{
					break;
				}
			}
			return num;
		}

		[Obsolete("Use overload with WorldLevelMatchMode parameter")]
		public static int RemoveItem(Inventory inventory, string name, float worldLevel, int amount, int quality = -1, bool isPrefabName = false)
		{
			return RemoveItem(inventory, name, worldLevel, WorldLevelMatchMode.Exact, amount, quality, isPrefabName);
		}
	}
	public static class Json
	{
		public static void AddImporter<TJson, TValue>(ImporterFunc<TJson, TValue> importer)
		{
			JsonMapper.RegisterImporter(importer);
		}

		public static void AddExporter<T>(ExporterFunc<T> exporter)
		{
			JsonMapper.RegisterExporter(exporter);
		}

		public static T Parse<T>(string jsonText, ReaderOption option)
		{
			return JsonMapper.ToObject<T>(new JsonReader(jsonText)
			{
				AllowComments = option.AllowComments,
				AllowSingleQuotedStrings = option.AllowSingleQuotedStrings,
				SkipNonMembers = option.SkipNonMembers
			});
		}

		public static T Parse<T>(string jsonText)
		{
			return Parse<T>(jsonText, new ReaderOption
			{
				AllowComments = true,
				AllowSingleQuotedStrings = false,
				SkipNonMembers = true
			});
		}

		public static string ToString(object obj, WriterOption option)
		{
			StringBuilder stringBuilder = new StringBuilder();
			JsonMapper.ToJson(obj, new JsonWriter(stringBuilder)
			{
				IndentValue = option.IndentSize,
				PrettyPrint = option.Pretty
			});
			return stringBuilder.ToString();
		}

		public static string ToString(object obj)
		{
			return ToString(obj, new WriterOption
			{
				Pretty = false,
				IndentSize = 0
			});
		}
	}
	public struct ReaderOption
	{
		public bool AllowComments;

		public bool AllowSingleQuotedStrings;

		public bool SkipNonMembers;
	}
	public struct WriterOption
	{
		public bool Pretty;

		public int IndentSize;
	}
	public class L10N
	{
		private struct TranslationSource
		{
			public L10N Localization;

			public string Directory;
		}

		private static readonly Regex InternalNamePattern;

		private static readonly Dictionary<string, string> TranslationCache;

		private static readonly Dictionary<string, string> RuntimeWords;

		private static readonly Regex WordPattern;

		private const string HarmonyId = "net.eideehi.modutils.localization";

		private static bool _patchesApplied;

		private static bool _initializePatchApplied;

		private static bool _setLanguagePatchApplied;

		private static bool _initializeMethodWarningLogged;

		private static bool _setLanguageMethodWarningLogged;

		private static bool _localizationCacheWarningLogged;

		private static string _currentLanguage;

		private static readonly List<TranslationSource> _translationSources;

		private readonly string _prefix;

		public static event Action<string> LanguageChanged;

		static L10N()
		{
			_translationSources = new List<TranslationSource>();
			InternalNamePattern = new Regex("^(\\$|@)(\\w|\\d|[^\\s(){}[\\]+\\-!?/\\\\&%,.:=<>])+$", RegexOptions.Compiled);
			TranslationCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			RuntimeWords = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			WordPattern = new Regex("(\\$|@)((?:\\w|\\d|[^\\s(){}[\\]+\\-!?/\\\\&%,.:=<>])+)", RegexOptions.Compiled);
		}

		public L10N(string prefix)
		{
			_prefix = prefix;
		}

		internal static void EnsurePatched()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			if (_patchesApplied)
			{
				return;
			}
			try
			{
				Harmony val = new Harmony("net.eideehi.modutils.localization");
				if (!_initializePatchApplied)
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(Localization), "Initialize", (Type[])null, (Type[])null);
					if (methodInfo == null)
					{
						if (!_initializeMethodWarningLogged)
						{
							Debug.LogWarning((object)"[ModUtils] Localization.Initialize method not found. Auto-reload for initialization will not work until it becomes available.");
							_initializeMethodWarningLogged = true;
						}
					}
					else
					{
						val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(L10N), "OnLocalizationInitialized", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						_initializePatchApplied = true;
					}
				}
				if (!_setLanguagePatchApplied)
				{
					MethodInfo methodInfo2 = AccessTools.Method(typeof(Localization), "SetLanguage", (Type[])null, (Type[])null);
					if (methodInfo2 == null)
					{
						if (!_setLanguageMethodWarningLogged)
						{
							Debug.LogWarning((object)"[ModUtils] Localization.SetLanguage method not found. Auto-reload for language change will not work until it becomes available.");
							_setLanguageMethodWarningLogged = true;
						}
					}
					else
					{
						val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(L10N), "OnLanguageSet", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						_setLanguagePatchApplied = true;
					}
				}
				_patchesApplied = _initializePatchApplied && _setLanguagePatchApplied;
			}
			catch (Exception arg)
			{
				Debug.LogWarning((object)$"[ModUtils] Failed to patch Localization lifecycle methods. Auto-reload will stay disabled. {arg}");
			}
		}

		private static void OnLocalizationInitialized()
		{
			try
			{
				Localization instance = Localization.instance;
				string text = ((instance != null) ? instance.GetSelectedLanguage() : null);
				if (!string.IsNullOrEmpty(text))
				{
					HandleLanguageChange(text);
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] OnLocalizationInitialized error: {arg}");
			}
		}

		private static void OnLanguageSet(string language)
		{
			try
			{
				if (!string.IsNullOrEmpty(language))
				{
					HandleLanguageChange(language);
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] OnLanguageSet error: {arg}");
			}
		}

		private static void HandleLanguageChange(string language)
		{
			ApplyLanguageChange(language, fireLanguageChanged: true);
		}

		public static string SyncCurrentLanguage()
		{
			EnsurePatched();
			try
			{
				Localization instance = Localization.instance;
				if (instance == null)
				{
					return null;
				}
				string selectedLanguage = instance.GetSelectedLanguage();
				if (string.IsNullOrEmpty(selectedLanguage))
				{
					return null;
				}
				ApplyLanguageChange(selectedLanguage, fireLanguageChanged: false);
				return selectedLanguage;
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] SyncCurrentLanguage failed: {arg}");
				return null;
			}
		}

		private static void ApplyLanguageChange(string language, bool fireLanguageChanged)
		{
			if (!string.IsNullOrEmpty(language) && !string.Equals(language, _currentLanguage, StringComparison.OrdinalIgnoreCase))
			{
				ReloadTranslations(language);
				_currentLanguage = language;
				RefreshConfigurationMetadata();
				RefreshDefaultDrawerTranslations();
				if (fireLanguageChanged)
				{
					FireLanguageChanged(language);
				}
			}
		}

		private static void RefreshConfigurationMetadata()
		{
			try
			{
				Configuration.RefreshAllLocalizedMetadata();
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to refresh localized config metadata: {arg}");
			}
		}

		private static void RefreshDefaultDrawerTranslations()
		{
			try
			{
				ConfigurationCustomDrawer.RefreshDefaultTranslations();
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to refresh custom drawer translations: {arg}");
			}
		}

		private static void ReloadTranslations(string language)
		{
			TranslationCache.Clear();
			foreach (TranslationSource translationSource in _translationSources)
			{
				try
				{
					new TranslationsLoader(translationSource.Localization).LoadTranslations(translationSource.Directory, language);
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[ModUtils] Failed to reload translations from {translationSource.Directory}: {arg}");
				}
			}
			Localization localization = TryGetLocalization();
			foreach (KeyValuePair<string, string> runtimeWord in RuntimeWords)
			{
				TranslationCache[runtimeWord.Key] = runtimeWord.Value;
				AddWordToLocalization(localization, runtimeWord.Key, runtimeWord.Value);
			}
		}

		private static void FireLanguageChanged(string language)
		{
			Action<string> languageChanged = L10N.LanguageChanged;
			if (languageChanged == null)
			{
				return;
			}
			Delegate[] invocationList = languageChanged.GetInvocationList();
			foreach (Delegate @delegate in invocationList)
			{
				try
				{
					((Action<string>)@delegate)(language);
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[ModUtils] LanguageChanged handler error: {arg}");
				}
			}
		}

		public void AddTranslationDirectory(string directory)
		{
			EnsurePatched();
			_translationSources.Add(new TranslationSource
			{
				Localization = this,
				Directory = directory
			});
			new TranslationsLoader(this).LoadTranslations(directory, DetectCurrentLanguage());
			Localization localization = TryGetLocalization();
			foreach (KeyValuePair<string, string> runtimeWord in RuntimeWords)
			{
				TranslationCache[runtimeWord.Key] = runtimeWord.Value;
				AddWordToLocalization(localization, runtimeWord.Key, runtimeWord.Value);
			}
		}

		private static string DetectCurrentLanguage()
		{
			if (_currentLanguage != null)
			{
				return _currentLanguage;
			}
			try
			{
				Localization instance = Localization.instance;
				string text = ((instance != null) ? instance.GetSelectedLanguage() : null);
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch (Exception)
			{
			}
			return "English";
		}

		internal static Localization TryGetLocalization()
		{
			try
			{
				Localization instance = Localization.instance;
				if (instance == null)
				{
					return null;
				}
				return string.IsNullOrEmpty(instance.GetSelectedLanguage()) ? null : instance;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static string InvokeTranslate(string word)
		{
			Localization val = TryGetLocalization();
			TranslationCache.TryGetValue(word, out var value);
			if (val == null)
			{
				return value ?? word;
			}
			string text = Reflections.InvokeMethod<string>(val, "Translate", new object[1] { word });
			if (text == null || IsMissingTranslation(word, text))
			{
				return value ?? word;
			}
			return text;
		}

		private static bool IsMissingTranslation(string word, string localized)
		{
			if (!string.Equals(localized, word, StringComparison.Ordinal))
			{
				return string.Equals(localized, "[" + word + "]", StringComparison.Ordinal);
			}
			return true;
		}

		private static string InvokeInsertWordsFallback(string text, IReadOnlyList<string> words)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			string text2 = text;
			for (int i = 0; i < words.Count; i++)
			{
				text2 = text2.Replace($"${i + 1}", words[i] ?? "");
			}
			return text2;
		}

		private static string InvokeInsertWords(string text, string[] words)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			Localization val = TryGetLocalization();
			if (val == null)
			{
				return InvokeInsertWordsFallback(text, words);
			}
			return Reflections.InvokeMethod<string>(val, "InsertWords", new object[2] { text, words });
		}

		private static void InvokeAddWord(string key, string word)
		{
			TranslationCache[key] = word;
			AddWordToLocalization(TryGetLocalization(), key, word);
		}

		private static void InvokeAddRuntimeWord(string key, string word)
		{
			RuntimeWords[key] = word;
			TranslationCache[key] = word;
			AddWordToLocalization(TryGetLocalization(), key, word);
		}

		private static void AddWordToLocalization(Localization localization, string key, string word)
		{
			if (localization != null)
			{
				Reflections.InvokeMethod(localization, "AddWord", key, word);
				EvictLocalizationCache(localization);
			}
		}

		private static void EvictLocalizationCache(Localization localization)
		{
			try
			{
				object field = Reflections.GetField<object>(localization, "m_cache");
				if (field != null)
				{
					Reflections.InvokeMethod(field, "EvictAll");
				}
			}
			catch (Exception arg)
			{
				if (!_localizationCacheWarningLogged)
				{
					Debug.LogWarning((object)$"[ModUtils] Failed to evict Localization cache after adding a word. Game-localized text may stay stale until the next language reload. {arg}");
					_localizationCacheWarningLogged = true;
				}
			}
		}

		internal static string GetTranslationKey(string prefix, string internalName)
		{
			if (string.IsNullOrEmpty(internalName))
			{
				return "";
			}
			return internalName[0] switch
			{
				'$' => internalName.Substring(1), 
				'@' => prefix + "_" + internalName.Substring(1), 
				_ => internalName, 
			};
		}

		internal static string Translate(string prefix, string word)
		{
			return InvokeTranslate(GetTranslationKey(prefix, word));
		}

		public static bool IsInternalName(string text)
		{
			if (!string.IsNullOrEmpty(text))
			{
				return InternalNamePattern.IsMatch(text);
			}
			return false;
		}

		private string GetTranslationKey(string internalName)
		{
			return GetTranslationKey(_prefix, internalName);
		}

		public void AddWord(string key, string word)
		{
			InvokeAddRuntimeWord(GetTranslationKey(key), word);
		}

		internal void AddFileWord(string key, string word)
		{
			InvokeAddWord(GetTranslationKey(key), word);
		}

		public string Translate(string word)
		{
			return InvokeTranslate(GetTranslationKey(word));
		}

		public string TranslateInternalName(string internalName)
		{
			if (IsInternalName(internalName))
			{
				return InvokeTranslate(GetTranslationKey(internalName));
			}
			return internalName;
		}

		public string Localize(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			StringBuilder stringBuilder = new StringBuilder();
			int num = 0;
			foreach (Match item in WordPattern.Matches(text))
			{
				GroupCollection groups = item.Groups;
				string word = ((groups[1].Value == "@") ? (_prefix + "_" + groups[2].Value) : groups[2].Value);
				stringBuilder.Append(text.Substring(num, groups[0].Index - num));
				stringBuilder.Append(InvokeTranslate(word));
				num = groups[0].Index + groups[0].Value.Length;
			}
			stringBuilder.Append(text.Substring(num));
			return stringBuilder.ToString();
		}

		public string Localize(string text, params object[] args)
		{
			object[] array = args ?? new object[0];
			return InvokeInsertWords(Localize(text), Array.ConvertAll(array, (object arg) => (arg != null) ? ((!(arg is string internalName)) ? arg.ToString() : TranslateInternalName(internalName)) : ""));
		}

		public string LocalizeTextOnly(string text, params object[] args)
		{
			object[] array = args ?? new object[0];
			return InvokeInsertWords(Localize(text), Array.ConvertAll(array, delegate(object arg)
			{
				object obj;
				if (arg != null)
				{
					obj = arg as string;
					if (obj == null)
					{
						return arg.ToString();
					}
				}
				else
				{
					obj = "";
				}
				return (string)obj;
			}));
		}
	}
	public class TranslationsLoader
	{
		private static readonly string DefaultLanguage;

		private static readonly string JsonFilePattern;

		private readonly L10N _localization;

		private Dictionary<string, TranslationsFile> _cache;

		private Logger _logger;

		static TranslationsLoader()
		{
			DefaultLanguage = "English";
			JsonFilePattern = "*.json";
		}

		public TranslationsLoader(L10N localization)
		{
			_localization = localization;
		}

		public void SetDebugLogger(Logger logger)
		{
			_logger = logger;
		}

		private bool LoadAllFile(string directory, string filePattern, string language, Func<string, string, bool> loading)
		{
			_logger?.Debug("Load translation files for " + language + " from directory: [directory: " + directory + ", file pattern: " + filePattern + "]");
			return Directory.EnumerateFiles(directory, filePattern, SearchOption.AllDirectories).Count((string path) => loading(path, language)) > 0;
		}

		public void LoadTranslations(string languagesDir, string language)
		{
			_cache = new Dictionary<string, TranslationsFile>();
			if (!Directory.Exists(languagesDir))
			{
				_logger?.Error("Directory does not exist: " + languagesDir);
				return;
			}
			if (language != DefaultLanguage && !LoadAllFile(languagesDir, JsonFilePattern, DefaultLanguage, ReadJsonFile))
			{
				_logger?.Warning("Directory does not contain a translation file for the default language: " + languagesDir);
			}
			if (!LoadAllFile(languagesDir, JsonFilePattern, language, ReadJsonFile))
			{
				_logger?.Warning("Directory does not contain a translation file for the " + language + ": " + languagesDir);
			}
			_cache = null;
		}

		public void LoadTranslations(string languagesDir)
		{
			string text;
			try
			{
				Localization instance = Localization.instance;
				text = ((instance != null) ? instance.GetSelectedLanguage() : null);
			}
			catch (Exception)
			{
				text = null;
			}
			LoadTranslations(languagesDir, string.IsNullOrEmpty(text) ? DefaultLanguage : text);
		}

		private bool ReadJsonFile(string path, string language)
		{
			if (!_cache.TryGetValue(path, out var value))
			{
				try
				{
					value = Json.Parse<TranslationsFile>(File.ReadAllText(path));
					_cache.Add(path, value);
				}
				catch (Exception arg)
				{
					_logger?.Error($"Failed to read Json file\n{arg}");
					_cache.Add(path, default(TranslationsFile));
					return false;
				}
			}
			if (!string.Equals(value.language, language, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			_logger?.Debug("Load translations: " + path);
			if (value.translations == null)
			{
				_logger?.Warning("Translation file does not contain translations: " + path);
				return true;
			}
			foreach (KeyValuePair<string, string> translation in value.translations)
			{
				_localization.AddFileWord(translation.Key, translation.Value);
			}
			return true;
		}
	}
	[Serializable]
	public struct TranslationsFile
	{
		public string language;

		public Dictionary<string, string> translations;
	}
	public class Logger
	{
		private readonly Func<LogLevel, bool> _isEnabled;

		private readonly ManualLogSource _logger;

		public Logger(ManualLogSource logger, Func<LogLevel, bool> isEnabled)
		{
			_logger = logger;
			_isEnabled = isEnabled;
		}

		private void Log(LogLevel level, string message)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (_isEnabled(level))
			{
				_logger.Log(level, (object)message);
			}
		}

		private void Log(LogLevel level, Func<string> message)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (_isEnabled(level))
			{
				_logger.Log(level, (object)message());
			}
		}

		public void Fatal(Func<string> message)
		{
			Log((LogLevel)1, message);
		}

		public void Fatal(string message)
		{
			Log((LogLevel)1, message);
		}

		public void Error(Func<string> message)
		{
			Log((LogLevel)2, message);
		}

		public void Error(string message)
		{
			Log((LogLevel)2, message);
		}

		public void Warning(Func<string> message)
		{
			Log((LogLevel)4, message);
		}

		public void Warning(string message)
		{
			Log((LogLevel)4, message);
		}

		public void Info(Func<string> message)
		{
			Log((LogLevel)16, message);
		}

		public void Info(string message)
		{
			Log((LogLevel)16, message);
		}

		public void Message(Func<string> message)
		{
			Log((LogLevel)8, message);
		}

		public void Message(string message)
		{
			Log((LogLevel)8, message);
		}

		public void Debug(Func<string> message)
		{
			Log((LogLevel)32, message);
		}

		public void Debug(string message)
		{
			Log((LogLevel)32, message);
		}
	}
	public abstract class ObjectNode<TNode, TNetwork> : MonoBehaviour where TNode : ObjectNode<TNode, TNetwork> where TNetwork : ObjectNetwork<TNode, TNetwork>
	{
		protected static readonly HashSet<TNode> ObjectNodes;

		private TNode This => (TNode)this;

		public TNetwork Network { get; set; }

		static ObjectNode()
		{
			ObjectNodes = new HashSet<TNode>();
		}

		protected virtual void Awake()
		{
			ObjectNodes.Add(This);
			((MonoBehaviour)this).Invoke("NetworkConstruction", Random.Range(1f, 2f));
		}

		protected virtual void OnDestroy()
		{
			ObjectNodes.Remove(This);
			Network?.RemoveNode(This);
			Network = null;
		}

		protected abstract TNetwork CreateNetwork();

		protected abstract bool IsConnectable(TNode other);

		private void NetworkConstruction()
		{
			foreach (TNode item in ObjectNodes.Where(IsConnectable))
			{
				if (Network == item.Network)
				{
					continue;
				}
				if (Network == null)
				{
					Network = item.Network;
					Network.AddNode(This);
					continue;
				}
				if (item.Network == null)
				{
					item.Network = Network;
					item.Network.AddNode(item);
					continue;
				}
				TNetwork obj = ((Network.NodeCount >= item.Network.NodeCount) ? item.Network : Network);
				TNetwork network = ((Network.NodeCount >= item.Network.NodeCount) ? Network : item.Network);
				foreach (TNode allNode in obj.GetAllNodes())
				{
					allNode.Network.RemoveNode(allNode);
					allNode.Network = network;
					allNode.Network.AddNode(allNode);
				}
			}
			if (Network == null)
			{
				Network = CreateNetwork();
				Network.AddNode(This);
			}
		}
	}
	public class ObjectNetwork<TNode, TNetwork> where TNode : ObjectNode<TNode, TNetwork> where TNetwork : ObjectNetwork<TNode, TNetwork>
	{
		private readonly HashSet<TNode> _nodes;

		protected Action<IEnumerable<TNode>> OnNodeChanged { get; set; }

		public bool IsDirty { get; private set; }

		public int NodeCount => _nodes.Count;

		protected ObjectNetwork()
		{
			_nodes = new HashSet<TNode>();
		}

		public IEnumerable<TNode> EnumerateNodes()
		{
			return _nodes;
		}

		public IEnumerable<TNode> GetAllNodes()
		{
			return _nodes.ToList();
		}

		public void AddNode(TNode node)
		{
			if (_nodes.Add(node))
			{
				IsDirty = true;
			}
		}

		public void RemoveNode(TNode node)
		{
			if (_nodes.Remove(node))
			{
				IsDirty = true;
			}
		}

		public void Update()
		{
			if (IsDirty)
			{
				OnNodeChanged?.Invoke(GetAllNodes());
				IsDirty = false;
			}
		}
	}
	public static class Objects
	{
		private static readonly ConditionalWeakTable<Component, ZNetView> ZNetViewCache;

		private static readonly ConditionalWeakTable<Component, string> NameCache;

		private const string HoverableMarker = "\u0001HOVERABLE";

		static Objects()
		{
			ZNetViewCache = new ConditionalWeakTable<Component, ZNetView>();
			NameCache = new ConditionalWeakTable<Component, string>();
		}

		public static string GetPrefabName(GameObject gameObject)
		{
			return Utils.GetPrefabName(gameObject);
		}

		public static string GetName(Component component)
		{
			if (!Object.op_Implicit((Object)(object)component))
			{
				return "";
			}
			if (NameCache.TryGetValue(component, out var value))
			{
				if ((object)value == "\u0001HOVERABLE")
				{
					Hoverable component2 = component.GetComponent<Hoverable>();
					string text = ((component2 != null) ? component2.GetHoverName() : null);
					if (string.IsNullOrEmpty(text))
					{
						return Utils.GetPrefabName(component.gameObject);
					}
					return text;
				}
				return value;
			}
			string text2 = (from x in ((object)component).GetType().GetFields(AccessTools.all)
				where x.Name == "m_name" && x.FieldType == typeof(string)
				select x.GetValue(component) as string).FirstOrDefault();
			if (!string.IsNullOrEmpty(text2))
			{
				NameCache.Add(component, text2);
				return text2;
			}
			Hoverable component3 = component.GetComponent<Hoverable>();
			if (component3 != null)
			{
				HoverText val = (HoverText)(object)((component3 is HoverText) ? component3 : null);
				if (val != null)
				{
					text2 = val.m_text;
					if (!string.IsNullOrEmpty(text2))
					{
						NameCache.Add(component, text2);
						return text2;
					}
				}
				else
				{
					text2 = component3.GetHoverName();
					if (!string.IsNullOrEmpty(text2))
					{
						NameCache.Add(component, "\u0001HOVERABLE");
						return text2;
					}
				}
			}
			text2 = Utils.GetPrefabName(component.gameObject);
			NameCache.Add(component, text2);
			return text2;
		}

		public static bool GetZNetView(Component component, out ZNetView zNetView)
		{
			if (!Object.op_Implicit((Object)(object)component))
			{
				zNetView = null;
				return false;
			}
			if (ZNetViewCache.TryGetValue(component, out zNetView))
			{
				return Object.op_Implicit((Object)(object)zNetView);
			}
			zNetView = (from x in ((object)component).GetType().GetFields(AccessTools.all)
				where x.Name == "m_nview" && x.FieldType == typeof(ZNetView)
				select x).Select(delegate(FieldInfo x)
			{
				object? value = x.GetValue(component);
				return (ZNetView)((value is ZNetView) ? value : null);
			}).FirstOrDefault() ?? component.GetComponent<ZNetView>();
			if ((Object)(object)zNetView == (Object)null)
			{
				return false;
			}
			ZNetViewCache.Add(component, zNetView);
			return true;
		}

		public static bool GetZdoid(Component component, out ZDOID id)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			id = (GetZNetView(component, out var zNetView) ? zNetView.GetZDO() : null)?.m_uid ?? ZDOID.None;
			return id != ZDOID.None;
		}

		public static bool HasValidOwnership(ZNetView zNetView)
		{
			if ((Object)(object)zNetView != (Object)null && zNetView.GetZDO() != null && zNetView.IsValid())
			{
				return zNetView.IsOwner();
			}
			return false;
		}

		public static bool HasValidOwnership(Component component)
		{
			ZNetView zNetView;
			return HasValidOwnership(component, out zNetView);
		}

		public static bool HasValidOwnership(Component component, out ZNetView zNetView)
		{
			if (GetZNetView(component, out zNetView))
			{
				return HasValidOwnership(zNetView);
			}
			return false;
		}

		public static float Distance(Component obj1, Component obj2)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Vector3.Distance(obj1.transform.position, obj2.transform.position);
		}

		public static List<(Collider collider, T obj, float distance)> GetInsideSphere<T>(Vector3 origin, float radius, Func<Collider, T> convertor, Collider[] buffer, int layerMask = -1)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			List<(Collider, T, float)> list = new List<(Collider, T, float)>();
			int num = Physics.OverlapSphereNonAlloc(origin, radius, buffer, layerMask);
			for (int i = 0; i < num; i++)
			{
				Collider val = buffer[i];
				T val2 = convertor(val);
				if (val2 != null)
				{
					list.Add((val, val2, Vector3.Distance(origin, ((Component)val).transform.position)));
				}
			}
			return list;
		}

		public static List<(Collider collider, T obj, float distance)> GetInsideSphere<T>(Vector3 origin, float radius, Func<Collider, T> convertor, int bufferSize = 128, int layerMask = -1)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return GetInsideSphere(origin, radius, convertor, (Collider[])(object)new Collider[bufferSize], layerMask);
		}
	}
	public static class Reflections
	{
		public static TR InvokeStaticMethod<T, TR>(string methodName, params object[] args)
		{
			return Traverse.Create<T>().Method(methodName, args).GetValue<TR>(args);
		}

		public static void InvokeStaticMethod<T>(string methodName, params object[] args)
		{
			Traverse.Create<T>().Method(methodName, args).GetValue(args);
		}

		public static TR InvokeStaticMethod<T, TR>(string methodName)
		{
			return Traverse.Create<T>().Method(methodName, Array.Empty<object>()).GetValue<TR>();
		}

		public static void InvokeStaticMethod<T>(string methodName)
		{
			Traverse.Create<T>().Method(methodName, Array.Empty<object>()).GetValue();
		}

		public static T InvokeMethod<T>(object instance, string methodName, params object[] args)
		{
			return Traverse.Create(instance).Method(methodName, args).GetValue<T>(args);
		}

		public static void InvokeMethod(object instance, string methodName, params object[] args)
		{
			Traverse.Create(instance).Method(methodName, args).GetValue(args);
		}

		public static T InvokeMethod<T>(object instance, string methodName)
		{
			return Traverse.Create(instance).Method(methodName, Array.Empty<object>()).GetValue<T>();
		}

		public static void InvokeMethod(object instance, string methodName)
		{
			Traverse.Create(instance).Method(methodName, Array.Empty<object>()).GetValue();
		}

		public static TType GetStaticField<TClass, TType>(string fieldName)
		{
			return Traverse.Create<TClass>().Field<TType>(fieldName).Value;
		}

		public static TType SetStaticField<TClass, TType>(string fieldName, TType value)
		{
			return Traverse.Create<TClass>().Field<TType>(fieldName).Value = value;
		}

		public static T GetField<T>(object instance, string fieldName)
		{
			return Traverse.Create(instance).Field<T>(fieldName).Value;
		}

		public static void SetField<T>(object instance, string fieldName, T value)
		{
			Traverse.Create(instance).Field<T>(fieldName).Value = value;
		}
	}
	public class SpriteLoader
	{
		private static readonly Dictionary<string, Texture2D> TextureCache;

		private Logger _logger;

		static SpriteLoader()
		{
			TextureCache = new Dictionary<string, Texture2D>();
		}

		private static Sprite CreateSprite(Texture2D texture, int width, int height)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return Sprite.Create(texture, new Rect(0f, 0f, (float)width, (float)height), Vector2.zero);
		}

		public static string GetTextureFileName(Sprite sprite)
		{
			using (IEnumerator<KeyValuePair<string, Texture2D>> enumerator = TextureCache.Where((KeyValuePair<string, Texture2D> pair) => (Object)(object)pair.Value == (Object)(object)sprite.texture).GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					return Path.GetFileName(enumerator.Current.Key);
				}
			}
			return "";
		}

		public void SetDebugLogger(Logger logger)
		{
			_logger = logger;
		}

		public Sprite Load(string texturePath, int width, int height)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			if (!File.Exists(texturePath))
			{
				return null;
			}
			if (TextureCache.TryGetValue(texturePath, out var value))
			{
				if (!((Object)(object)value != (Object)null))
				{
					return null;
				}
				return CreateSprite(value, width, height);
			}
			try
			{
				_logger?.Info("Try to create sprite: " + texturePath);
				Texture2D val = new Texture2D(0, 0);
				ImageConversion.LoadImage(val, File.ReadAllBytes(texturePath));
				TextureCache.Add(texturePath, val);
				return CreateSprite(val, width, height);
			}
			catch (Exception arg)
			{
				_logger?.Error($"Failed to create sprite: {texturePath}\n{arg}");
				TextureCache.Add(texturePath, null);
				return null;
			}
		}
	}
}
namespace BetterPortal
{
	[BepInPlugin("net.eidee.valheim.better_portal", "Better Portal", "1.0.7")]
	public class UnityPlugin : BaseUnityPlugin
	{
		private const string ModId = "net.eidee.valheim.better_portal";

		private const string ModName = "Better Portal";

		private const string ModVersion = "1.0.7";

		private void Awake()
		{
			BetterPortal.Initialize(((BaseUnityPlugin)this).Info, ((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config);
		}
	}
	internal static class BetterPortal
	{
		public static string ModLocation { get; private set; }

		public static Logger Logger { get; private set; }

		public static L10N L10N { get; private set; }

		public static ConfigEntry<KeyCode> ModifierKey { get; private set; }

		public static void Initialize(PluginInfo info, ManualLogSource logger, ConfigFile config)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			ModLocation = Path.GetDirectoryName(info.Location) ?? "";
			Logger = new Logger(logger, (LogLevel level) => (int)level != 32 && (int)level != 8);
			L10N = new L10N("better_portal");
			L10N.AddTranslationDirectory(Path.Combine(ModLocation, "Languages"));
			ModifierKey = new Configuration(config, L10N).Bind<KeyCode>("general", "ModifierKey", (KeyCode)304);
			ValidateModifierKey();
			UpdateModifierKeyDisplay(ModifierKey.Value);
			ModifierKey.SettingChanged += delegate
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				ValidateModifierKey();
				UpdateModifierKeyDisplay(ModifierKey.Value);
			};
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), info.Metadata.GUID);
		}

		public static bool IsModifierKeyPressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			KeyCode value = ModifierKey.Value;
			KeyCode pairedKey = GetPairedKey(value);
			if (!Input.GetKey(value))
			{
				if ((int)pairedKey != 0)
				{
					return Input.GetKey(pairedKey);
				}
				return false;
			}
			return true;
		}

		private static void ValidateModifierKey()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)ModifierKey.Value == 0)
			{
				ModifierKey.Value = (KeyCode)((ConfigEntryBase)ModifierKey).DefaultValue;
			}
		}

		private static void UpdateModifierKeyDisplay(KeyCode keyCode)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			L10N.AddWord("@modifier_key", GetKeyDisplayName(keyCode));
		}

		private static KeyCode GetPairedKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			return (KeyCode)((key - 303) switch
			{
				1 => 303, 
				0 => 304, 
				3 => 305, 
				2 => 306, 
				5 => 307, 
				4 => 308, 
				_ => 0, 
			});
		}

		private static string GetKeyDisplayName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			switch (key - 303)
			{
			case 0:
			case 1:
				return "Shift";
			case 2:
			case 3:
				return "Ctrl";
			case 4:
			case 5:
				return "Alt";
			default:
				return ((object)(KeyCode)(ref key)).ToString();
			}
		}
	}
	[HarmonyPatch]
	internal static class Patches
	{
		private static bool _transpilerApplied;

		private static bool _findRandomOverrideLogged;

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Game), "ConnectPortals")]
		private static IEnumerable<CodeInstruction> Game_ConnectPortals_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			List<CodeInstruction> list2 = ((IEnumerable<CodeInstruction>)list).Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction instruction) => new CodeInstruction(instruction))).ToList();
			FieldInfo sourceTagField = AccessTools.Field(typeof(ZDOVars), "s_tag");
			FieldInfo operand = AccessTools.Field(typeof(ZdoTags), "DestTag");
			MethodInfo getStringWithDefault = AccessTools.Method(typeof(ZDO), "GetString", new Type[2]
			{
				typeof(int),
				typeof(string)
			}, (Type[])null);
			MethodInfo addToCurrentlyConnectingPortals = AccessTools.Method(typeof(Game), "AddToCurrentlyConnectingPortals", (Type[])null, (Type[])null);
			MethodInfo setConnection = AccessTools.Method(typeof(Game), "SetConnection", new Type[3]
			{
				typeof(ZDO),
				typeof(ZDOID),
				typeof(bool)
			}, (Type[])null);
			FieldInfo uidField = AccessTools.Field(typeof(ZDO), "m_uid");
			int num = 0;
			for (int i = 0; i <= list2.Count - 4; i++)
			{
				if (IsDestTagReadStore(list2, i, sourceTagField, getStringWithDefault))
				{
					list2[i].operand = operand;
					num++;
				}
			}
			int num2 = FindAddToCurrentlyConnectingPortalsIndex(list2, addToCurrentlyConnectingPortals);
			if (num2 >= 3)
			{
				NopInstructions(list2, num2 - 3, 4);
			}
			int num3 = ((num2 >= 3) ? FindReverseSetConnectionIndex(list2, num2, setConnection, uidField) : (-1));
			if (num3 >= 5)
			{
				NopInstructions(list2, num3 - 5, 6);
			}
			if (num != 2 || num2 < 3 || num3 < 5)
			{
				BetterPortal.Logger.Error("Valheim 0.221.12 compatibility patch not applied completely. " + $"DestTag replacements={num}/2, " + "AddToCurrentlyConnectingPortals=" + ((num2 >= 0) ? "ok" : "missing") + ", Reverse SetConnection=" + ((num3 >= 0) ? "ok" : "missing") + ".");
				return list;
			}
			_transpilerApplied = true;
			BetterPortal.Logger.Info("Applied Valheim 0.221.12 compatibility patch: DestTag replacements=2, AddToCurrentlyConnectingPortals disabled=1, reverse SetConnection disabled=1.");
			return list2;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Game), "FindRandomUnconnectedPortal")]
		private static bool Game_FindRandomUnconnectedPortal_Prefix(ref ZDO __result, List<ZDO> portals, ZDO skip, string tag)
		{
			if (!_transpilerApplied)
			{
				return true;
			}
			if (!_findRandomOverrideLogged)
			{
				BetterPortal.Logger.Info("Applied BetterPortal FindRandomUnconnectedPortal override.");
				_findRandomOverrideLogged = true;
			}
			List<ZDO> list = portals.Where((ZDO portal) => portal != skip && portal.GetString(ZDOVars.s_tag, "") == tag).ToList();
			__result = ((list.Count == 0) ? null : list[Random.Range(0, list.Count)]);
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TeleportWorld), "Awake")]
		private static void TeleportWorld_Awake_Postfix(TeleportWorld __instance, ZNetView ___m_nview)
		{
			if (___m_nview.GetZDO() != null)
			{
				((Component)__instance).gameObject.AddComponent<TeleportWorldExtension>();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TeleportWorld), "GetHoverText")]
		private static bool TeleportWorld_GetHoverText_Prefix(TeleportWorld __instance, ZNetView ___m_nview, ref string __result)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ___m_nview.GetZDO();
			if (zDO == null)
			{
				return true;
			}
			string text = __instance.GetText();
			if (string.IsNullOrEmpty(text))
			{
				text = BetterPortal.L10N.Translate("@empty_tag");
			}
			string text2 = zDO.GetString(ZdoTags.DestTag, "");
			if (string.IsNullOrEmpty(text2))
			{
				text2 = BetterPortal.L10N.Translate("@empty_tag");
			}
			ZDOID connectionZDOID = zDO.GetConnectionZDOID((ConnectionType)1);
			string text3 = (((ZDOID)(ref connectionZDOID)).IsNone() ? "$piece_portal_unconnected" : "$piece_portal_connected");
			__result = BetterPortal.L10N.Localize("$piece_portal_tag:\"" + text + "\"  @piece_portal_dest:\"" + text2 + "\"  [" + text3 + "]\n[<color=yellow><b>$KEY_Use</b></color>] $piece_portal_settag\n[<color=yellow><b>@modifier_key + $KEY_Use</b></color>] @piece_portal_setdesttag");
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TeleportWorld), "Interact")]
		private static bool TeleportWorld_Interact_Prefix(TeleportWorld __instance, ZNetView ___m_nview, ref bool __result, Humanoid human, bool hold, bool alt)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (hold)
			{
				__result = false;
				return false;
			}
			if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false))
			{
				((Character)human).Message((MessageType)2, "$piece_noaccess", 0, (Sprite)null);
				__result = true;
				return false;
			}
			if (BetterPortal.IsModifierKeyPressed())
			{
				TextInput.instance.RequestText((TextReceiver)(object)((Component)__instance).GetComponent<TeleportWorldExtension>(), BetterPortal.L10N.Translate("@piece_portal_dest"), 10);
			}
			else
			{
				TextInput.instance.RequestText((TextReceiver)(object)__instance, "$piece_portal_tag", 10);
			}
			__result = true;
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TextInput), "Update")]
		private static void TextInput_Update_Postfix(TextInput __instance, TextReceiver ___m_queuedSign, bool ___m_visibleFrame)
		{
			if (___m_visibleFrame && !Console.IsVisible() && !Chat.instance.HasFocus() && Object.op_Implicit((Object)(object)__instance.m_inputField) && ((TMP_InputField)__instance.m_inputField).isFocused && TeleportWorldExtension.GetAllInstance().Any((TeleportWorldExtension x) => x == ___m_queuedSign))
			{
				TextInputExtension.Update(__instance);
			}
		}

		private static bool IsDestTagReadStore(IReadOnlyList<CodeInstruction> instructions, int start, FieldInfo sourceTagField, MethodInfo getStringWithDefault)
		{
			if (start + 3 < instructions.Count && instructions[start].opcode == OpCodes.Ldsfld && object.Equals(instructions[start].operand, sourceTagField) && instructions[start + 1].opcode == OpCodes.Ldstr && object.Equals(instructions[start + 1].operand, "") && instructions[start + 2].opcode == OpCodes.Callvirt && object.Equals(instructions[start + 2].operand, getStringWithDefault))
			{
				return IsStoreLocal(instructions[start + 3].opcode);
			}
			return false;
		}

		private static int FindAddToCurrentlyConnectingPortalsIndex(IReadOnlyList<CodeInstruction> instructions, MethodInfo addToCurrentlyConnectingPortals)
		{
			for (int i = 3; i < instructions.Count; i++)
			{
				if (!(instructions[i].opcode != OpCodes.Call) && object.Equals(instructions[i].operand, addToCurrentlyConnectingPortals) && !(instructions[i - 3].opcode != OpCodes.Ldarg_0) && IsLoadLocal(instructions[i - 2].opcode) && IsLoadLocal(instructions[i - 1].opcode))
				{
					return i;
				}
			}
			return -1;
		}

		private static int FindReverseSetConnectionIndex(IReadOnlyList<CodeInstruction> instructions, int addToCurrentlyConnectingIndex, MethodInfo setConnection, FieldInfo uidField)
		{
			int num = 0;
			for (int i = addToCurrentlyConnectingIndex + 1; i < instructions.Count; i++)
			{
				if (i >= 5 && !(instructions[i].opcode != OpCodes.Call) && object.Equals(instructions[i].operand, setConnection) && !(instructions[i - 5].opcode != OpCodes.Ldarg_0) && IsLoadLocal(instructions[i - 4].opcode) && IsLoadLocal(instructions[i - 3].opcode) && !(instructions[i - 2].opcode != OpCodes.Ldfld) && object.Equals(instructions[i - 2].operand, uidField) && !(instructions[i - 1].opcode != OpCodes.Ldc_I4_0))
				{
					num++;
					if (num == 2)
					{
						return i;
					}
				}
			}
			return -1;
		}

		private static void NopInstructions(IList<CodeInstruction> instructions, int start, int length)
		{
			for (int i = start; i < start + length; i++)
			{
				instructions[i] = Nop(instructions[i]);
			}
		}

		private static CodeInstruction Nop(CodeInstruction instruction)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			return new CodeInstruction(OpCodes.Nop, (object)null)
			{
				labels = instruction.labels,
				blocks = instruction.blocks
			};
		}

		private static bool IsLoadLocal(OpCode opcode)
		{
			if (!(opcode == OpCodes.Ldloc) && !(opcode == OpCodes.Ldloc_S) && !(opcode == OpCodes.Ldloc_0) && !(opcode == OpCodes.Ldloc_1) && !(opcode == OpCodes.Ldloc_2))
			{
				return opcode == OpCodes.Ldloc_3;
			}
			return true;
		}

		private static bool IsStoreLocal(OpCode opcode)
		{
			if (!(opcode == OpCodes.Stloc) && !(opcode == OpCodes.Stloc_S) && !(opcode == OpCodes.Stloc_0) && !(opcode == OpCodes.Stloc_1) && !(opcode == OpCodes.Stloc_2))
			{
				return opcode == OpCodes.Stloc_3;
			}
			return true;
		}
	}
	[DisallowMultipleComponent]
	internal class TeleportWorldExtension : MonoBehaviour, TextReceiver
	{
		private static readonly List<TeleportWorldExtension> AllInstance;

		private ZNetView _zNetView;

		static TeleportWorldExtension()
		{
			AllInstance = new List<TeleportWorldExtension>();
		}

		public static IEnumerable<TeleportWorldExtension> GetAllInstance()
		{
			return AllInstance;
		}

		private void Awake()
		{
			_zNetView = ((Component)this).GetComponent<ZNetView>();
			_zNetView.Register<string>("SetTagDest", (Action<long, string>)RPC_SetTagDest);
			AllInstance.Add(this);
		}

		private void OnDestroy()
		{
			AllInstance.Remove(this);
			_zNetView = null;
		}

		private IEnumerator UpdateConnection()
		{
			ZDO zdo = _zNetView.GetZDO();
			string dest = zdo.GetString(ZdoTags.DestTag, "");
			ZDOID connectionZDOID = zdo.GetConnectionZDOID((ConnectionType)1);
			if (!((ZDOID)(ref connectionZDOID)).IsNone())
			{
				ZDO zDO = ZDOMan.instance.GetZDO(connectionZDOID);
				if (zDO == null || zDO.GetString(ZDOVars.s_tag, "") != dest)
				{
					zdo.SetOwner(ZDOMan.GetSessionID());
					zdo.UpdateConnection((ConnectionType)1, ZDOID.None);
					ZDOMan.instance.ForceSendZDO(zdo.m_uid);
				}
			}
			ZDOID connectionZDOID2 = zdo.GetConnectionZDOID((ConnectionType)1);
			if (!((ZDOID)(ref connectionZDOID2)).IsNone())
			{
				((MonoBehaviour)this).StopCoroutine("UpdateConnection");
				yield return null;
			}
			List<ZDO> list = (from x in ZDOMan.instance.GetPortals()
				where x != zdo && x.GetString(ZDOVars.s_tag, "") == dest
				select x).ToList();
			ZDO val = ((list.Count == 0) ? null : list[Random.Range(0, list.Count)]);
			if (val != null)
			{
				zdo.SetOwner(ZDOMan.GetSessionID());
				zdo.UpdateConnection((ConnectionType)1, val.m_uid);
				ZDOMan.instance.ForceSendZDO(zdo.m_uid);
			}
			((MonoBehaviour)this).StopCoroutine("UpdateConnection");
			yield return null;
		}

		public string GetText()
		{
			return _zNetView.GetZDO().GetString(ZdoTags.DestTag, "");
		}

		public void SetText(string text)
		{
			if (_zNetView.IsValid())
			{
				_zNetView.InvokeRPC("SetTagDest", new object[1] { text });
			}
		}

		private void RPC_SetTagDest(long sender, string tagDest)
		{
			if (_zNetView.IsValid() && _zNetView.IsOwner() && !(GetText() == tagDest))
			{
				_zNetView.GetZDO().Set(ZdoTags.DestTag, tagDest);
				((MonoBehaviour)this).StartCoroutine("UpdateConnection");
			}
		}
	}
	internal static class TextInputExtension
	{
		private static bool _keyPressed;

		private static bool _keyHold;

		private static KeyCode _pressedKey;

		private static string _originalWord;

		private static string _previousResult;

		private static List<string> GetPortalTags()
		{
			return (from x in ZDOMan.instance.GetPortals()
				select x.GetString(ZDOVars.s_tag, "") into x
				orderby x
				select x).Distinct().ToList();
		}

		private static void UpdateTextInput(TextInput input, string text)
		{
			if (Object.op_Implicit((Object)(object)input.m_inputField))
			{
				GuiInputField inputField = input.m_inputField;
				if (!(text == ((TMP_InputField)inputField).text))
				{
					((TMP_InputField)inputField).text = (string.IsNullOrEmpty(text) ? "" : text);
					((TMP_InputField)inputField).MoveTextEnd(false);
				}
			}
		}

		private static void InputUpdate()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!_keyPressed)
			{
				if (Input.GetKeyDown((KeyCode)277))
				{
					_pressedKey = (KeyCode)277;
				}
				else if (Input.GetKeyDown((KeyCode)273))
				{
					_pressedKey = (KeyCode)273;
				}
				else if (Input.GetKeyDown((KeyCode)274))
				{
					_pressedKey = (KeyCode)274;
				}
				else
				{
					_pressedKey = (KeyCode)0;
				}
				_keyPressed = (int)_pressedKey > 0;
			}
			else if (!Input.GetKeyUp(_pressedKey))
			{
				_keyHold = true;
			}
			else
			{
				_keyPressed = false;
				_keyHold = false;
				_pressedKey = (KeyCode)0;
			}
		}

		public static void Update(TextInput input)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			InputUpdate();
			if (_keyPressed && !_keyHold)
			{
				string text = (Object.op_Implicit((Object)(object)input.m_inputField) ? ((TMP_InputField)input.m_inputField).text : "");
				if ((int)_pressedKey == 277)
				{
					UpdateTextInput(input, AutoComplete(text));
				}
				else if ((int)_pressedKey == 273 || (int)_pressedKey == 274)
				{
					UpdateTextInput(input, Rotate(text, (int)_pressedKey == 274));
				}
			}
		}

		private static string AutoComplete(string word)
		{
			List<string> portalTags = GetPortalTags();
			if (word == _previousResult)
			{
				for (int i = portalTags.IndexOf(_previousResult) + 1; i < portalTags.Count; i++)
				{
					if (portalTags[i].StartsWith(_originalWord, StringComparison.OrdinalIgnoreCase))
					{
						_previousResult = portalTags[i];
						return _previousResult;
					}
				}
				_previousResult = null;
				return _originalWord;
			}
			_originalWord = null;
			_previousResult = null;
			using (IEnumerator<string> enumerator = portalTags.Where((string tag) => tag.StartsWith(word, StringComparison.OrdinalIgnoreCase)).GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					string current = enumerator.Current;
					_originalWord = word;
					_previousResult = current;
					return _previousResult;
				}
			}
			return word;
		}

		private static string Rotate(string current, bool ascending)
		{
			List<string> portalTags = GetPortalTags();
			if (string.IsNullOrEmpty(current))
			{
				if (!ascending)
				{
					return portalTags.LastOrDefault((string x) => !string.IsNullOrEmpty(x));
				}
				return portalTags.FirstOrDefault((string x) => !string.IsNullOrEmpty(x));
			}
			int num = portalTags.FindIndex((string x) => x.Equals(current, StringComparison.OrdinalIgnoreCase));
			if (num == -1)
			{
				num = portalTags.FindIndex((string x) => x.StartsWith(current, StringComparison.OrdinalIgnoreCase));
			}
			if (num == -1)
			{
				if (!ascending)
				{
					return portalTags.LastOrDefault();
				}
				return portalTags.FirstOrDefault();
			}
			num += (ascending ? 1 : (-1));
			if (num < 0)
			{
				return portalTags.LastOrDefault();
			}
			if (num >= portalTags.Count)
			{
				return portalTags.FirstOrDefault();
			}
			return portalTags[num];
		}
	}
	public static class ZdoTags
	{
		public static readonly int DestTag = StringExtensionMethods.GetStableHashCode("desttag");
	}
}
[CompilerGenerated]
internal sealed class <7cda94bd-7874-4e2c-8bfa-88f10cd02752><PrivateImplementationDetails>
{
	internal static readonly long 52E5A2D9F0BC9DF8C1DC20A1983BE35AD3490120BF21F6328E54E10A37E9FE4C/* Not supported: data(22 00 2C 00 0D 00 0A 00) */;
}
namespace LitJson
{
	internal enum JsonType
	{
		None,
		Object,
		Array,
		String,
		Int,
		Long,
		Double,
		Boolean
	}
	internal interface IJsonWrapper : IList, ICollection, IEnumerable, IOrderedDictionary, IDictionary
	{
		bool IsArray { get; }

		bool IsBoolean { get; }

		bool IsDouble { get; }

		bool IsInt { get; }

		bool IsLong { get; }

		bool IsObject { get; }

		bool IsString { get; }

		bool GetBoolean();

		double GetDouble();

		int GetInt();

		JsonType GetJsonType();

		long GetLong();

		string GetString();

		void SetBoolean(bool val);

		void SetDouble(double val);

		void SetInt(int val);

		void SetJsonType(JsonType type);

		void SetLong(long val);

		void SetString(string val);

		string ToJson();

		void ToJson(JsonWriter writer);
	}
	internal class JsonData : IJsonWrapper, IList, ICollection, IEnumerable, IOrderedDictionary, IDictionary, IEquatable<JsonData>
	{
		private IList<JsonData> inst_array;

		private bool inst_boolean;

		private double inst_double;

		private int inst_int;

		private long inst_long;

		private IDictionary<string, JsonData> inst_object;

		private string inst_string;

		private string json;

		private JsonType type;

		private IList<KeyValuePair<string, JsonData>> object_list;

		public int Count => EnsureCollection().Count;

		public bool IsArray => type == JsonType.Array;

		public bool IsBoolean => type == JsonType.Boolean;

		public bool IsDouble => type == JsonType.Double;

		public bool IsInt => type == JsonType.Int;

		public bool IsLong => type == JsonType.Long;

		public bool IsObject => type == JsonType.Object;

		public bool IsString => type == JsonType.String;

		public ICollection<string> Keys
		{
			get
			{
				EnsureDictionary();
				return inst_object.Keys;
			}
		}

		int ICollection.Count => Count;

		bool ICollection.IsSynchronized => EnsureCollection().IsSynchronized;

		object ICollection.SyncRoot => EnsureCollection().SyncRoot;

		bool IDictionary.IsFixedSize => EnsureDictionary().IsFixedSize;

		bool IDictionary.IsReadOnly => EnsureDictionary().IsReadOnly;

		ICollection IDictionary.Keys
		{
			get
			{
				EnsureDictionary();
				IList<string> list = new List<string>();
				foreach (KeyValuePair<string, JsonData> item in object_list)
				{
					list.Add(item.Key);
				}
				return (ICollection)list;
			}
		}

		ICollection IDictionary.Values
		{
			get
			{
				EnsureDictionary();
				IList<JsonData> list = new List<JsonData>();
				foreach (KeyValuePair<string, JsonData> item in object_list)
				{
					list.Add(item.Value);
				}
				return (ICollection)list;
			}
		}

		bool IJsonWrapper.IsArray => IsArray;

		bool IJsonWrapper.IsBoolean => IsBoolean;

		bool IJsonWrapper.IsDouble => IsDouble;

		bool IJsonWrapper.IsInt => IsInt;

		bool IJsonWrapper.IsLong => IsLong;

		bool IJsonWrapper.IsObject => IsObject;

		bool IJsonWrapper.IsString => IsString;

		bool IList.IsFixedSize => EnsureList().IsFixedSize;

		bool IList.IsReadOnly => EnsureList().IsReadOnly;

		object IDictionary.this[object key]
		{
			get
			{
				return EnsureDictionary()[key];
			}
			set
			{
				if (!(key is string))
				{
					throw new ArgumentException("The key has to be a string");
				}
				JsonData value2 = ToJsonData(value);
				this[(string)key] =