Decompiled source of MutagenicWilds v0.9.3

MutagenicWilds.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MutagenicWilds
{
	public static class AllblackItems
	{
		private class Def
		{
			public string name;

			public string title;

			public string description;

			public string[] donors;

			public int craftAmount;

			public Func<string> ingredients;

			public GameObject go;

			public Recipe recipe;
		}

		public const string BloodName = "pm_AllblackBlood";

		public const string BarName = "pm_Allblack";

		public const string ArrowName = "pm_ArrowAllblack";

		public const string BoltName = "pm_BoltAllblack";

		public const string SwordName = "pm_SwordAllblack";

		public const string SpearName = "pm_SpearAllblack";

		public static readonly string BloodTitle = Loc.Token("item_allblack_blood");

		public static readonly string BarTitle = Loc.Token("item_allblack");

		public static readonly string ArrowTitle = Loc.Token("item_allblack_arrow");

		public static readonly string BoltTitle = Loc.Token("item_allblack_bolt");

		public static readonly string SwordTitle = Loc.Token("item_allblack_sword");

		public static readonly string SpearTitle = Loc.Token("item_allblack_spear");

		private static readonly Color Black = new Color(0.16f, 0.16f, 0.2f);

		private static readonly List<Def> Defs = new List<Def>
		{
			new Def
			{
				name = "pm_AllblackBlood",
				title = BloodTitle,
				donors = new string[1] { "SilverOre" },
				description = Loc.Token("item_allblack_blood_desc")
			},
			new Def
			{
				name = "pm_Allblack",
				title = BarTitle,
				donors = new string[1] { "Silver" },
				description = Loc.Token("item_allblack_desc")
			},
			new Def
			{
				name = "pm_ArrowAllblack",
				title = ArrowTitle,
				donors = new string[3] { "ArrowSilver", "ArrowFrost", "ArrowObsidian" },
				craftAmount = 10,
				ingredients = () => Cfg(Plugin.AllblackArrowIngredients, "Allblack:1,Coins:50,Feathers:6"),
				description = Loc.Token("item_allblack_weapon_desc")
			},
			new Def
			{
				name = "pm_BoltAllblack",
				title = BoltTitle,
				donors = new string[4] { "BoltBlackmetal", "BoltCarapace", "BoltIron", "BoltBone" },
				craftAmount = 10,
				ingredients = () => Cfg(Plugin.AllblackBoltIngredients, "Allblack:1,Coins:50,Feathers:6"),
				description = Loc.Token("item_allblack_weapon_desc")
			},
			new Def
			{
				name = "pm_SwordAllblack",
				title = SwordTitle,
				donors = new string[1] { "SwordSilver" },
				craftAmount = 1,
				ingredients = () => Cfg(Plugin.AllblackSwordIngredients, "Allblack:20,Coins:300,ElderBark:20"),
				description = Loc.Token("item_allblack_weapon_desc")
			},
			new Def
			{
				name = "pm_SpearAllblack",
				title = SpearTitle,
				donors = new string[2] { "SpearWolfFang", "SpearCarapace" },
				craftAmount = 1,
				ingredients = () => Cfg(Plugin.AllblackSpearIngredients, "Allblack:15,Coins:250,ElderBark:15"),
				description = Loc.Token("item_allblack_spear_desc")
			}
		};

		private static bool _warned;

		public static GameObject Blood => Get("pm_AllblackBlood");

		private static string Cfg(ConfigEntry<string> e, string fallback)
		{
			if (e == null)
			{
				return fallback;
			}
			return e.Value;
		}

		private static GameObject Get(string name)
		{
			return Defs.FirstOrDefault((Def x) => x.name == name)?.go;
		}

		public static bool IsAllblackWeapon(string sharedName)
		{
			if (!(sharedName == ArrowTitle) && !(sharedName == BoltTitle) && !(sharedName == SwordTitle))
			{
				return sharedName == SpearTitle;
			}
			return true;
		}

		public static void Ensure(ObjectDB db)
		{
			if ((Object)(object)db == (Object)null || db.m_items == null || db.m_items.Count == 0)
			{
				return;
			}
			try
			{
				foreach (Def def in Defs)
				{
					if ((Object)(object)def.go == (Object)null)
					{
						Build(db, def);
					}
				}
				foreach (Def def2 in Defs)
				{
					if (!((Object)(object)def2.go == (Object)null))
					{
						if (!db.m_items.Contains(def2.go))
						{
							db.m_items.Add(def2.go);
						}
						EnsureRecipe(db, def2);
					}
				}
				MethodInfo methodInfo = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(db, null);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Allblack items could not be set up: " + ex));
			}
		}

		private static void Build(ObjectDB db, Def d)
		{
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			string[] donors = d.donors;
			foreach (string name in donors)
			{
				val = PregnancyItems.Find(db, name);
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				if (!_warned)
				{
					_warned = true;
					Plugin.Log.LogWarning((object)("Allblack: the vanilla item to copy for " + Loc.Plain(d.title) + " (" + string.Join("/", d.donors) + ") was not found, so it is not added"));
				}
				return;
			}
			GameObject val2 = PregnancyItems.Clone(val, d.name);
			ItemDrop component = val2.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return;
			}
			component.m_itemData.m_shared.m_name = d.title;
			component.m_itemData.m_shared.m_description = d.description;
			SharedData shared = component.m_itemData.m_shared;
			if (shared.m_icons != null && shared.m_icons.Length != 0 && (Object)(object)shared.m_icons[0] != (Object)null)
			{
				try
				{
					Sprite[] array = (Sprite[])(object)new Sprite[shared.m_icons.Length];
					for (int j = 0; j < array.Length; j++)
					{
						array[j] = (((Object)(object)shared.m_icons[j] != (Object)null) ? PregnancyItems.Tinted(shared.m_icons[j], Black, silverEdge: true) : null);
					}
					shared.m_icons = array;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogInfo((object)("Allblack icon recolour skipped (" + ex.Message + "), the copied icon is used"));
				}
			}
			if (IsAllblackWeapon(d.title))
			{
				ToAllblackDamage(shared);
			}
			Blacken(val2);
			d.go = val2;
		}

		private static void ToAllblackDamage(SharedData sh)
		{
			//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)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DamageTypes damages = sh.m_damages;
				damages.m_damage += AllblackRules.FromDonor(damages.m_spirit, ((DamageTypes)(ref damages)).GetTotalDamage() - damages.m_spirit - damages.m_damage);
				damages.m_spirit = 0f;
				sh.m_damages = damages;
				DamageTypes damagesPerLevel = sh.m_damagesPerLevel;
				damagesPerLevel.m_damage += AllblackRules.FromDonor(damagesPerLevel.m_spirit, ((DamageTypes)(ref damagesPerLevel)).GetTotalDamage() - damagesPerLevel.m_spirit - damagesPerLevel.m_damage);
				damagesPerLevel.m_spirit = 0f;
				sh.m_damagesPerLevel = damagesPerLevel;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("Allblack damage type skipped (" + ex.Message + ")"));
			}
		}

		internal static void Blacken(GameObject go, float amount = 0.85f)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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)
			try
			{
				Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					Material[] sharedMaterials = val.sharedMaterials;
					for (int j = 0; j < sharedMaterials.Length; j++)
					{
						if (!((Object)(object)sharedMaterials[j] == (Object)null))
						{
							Material val2 = new Material(sharedMaterials[j]);
							if (val2.HasProperty("_Color"))
							{
								val2.SetColor("_Color", Color.Lerp(val2.GetColor("_Color"), Black, amount));
							}
							if (amount > 0.5f && val2.HasProperty("_EmissionColor"))
							{
								val2.SetColor("_EmissionColor", Color.black);
							}
							if (amount > 0.5f && val2.HasProperty("_MetalGlossColor"))
							{
								val2.SetColor("_MetalGlossColor", Black);
							}
							sharedMaterials[j] = val2;
						}
					}
					val.sharedMaterials = sharedMaterials;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("Allblack model recolour skipped (" + ex.Message + ")"));
			}
		}

		private static void EnsureRecipe(ObjectDB db, Def d)
		{
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			if (db.m_recipes == null || d.ingredients == null)
			{
				return;
			}
			if ((Object)(object)d.recipe == (Object)null)
			{
				ItemDrop component = d.go.GetComponent<ItemDrop>();
				string donorName = null;
				string[] donors = d.donors;
				foreach (string text in donors)
				{
					if ((Object)(object)PregnancyItems.Find(db, text) != (Object)null)
					{
						donorName = text;
						break;
					}
				}
				Recipe val = ((IEnumerable<Recipe>)db.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => (Object)(object)r != (Object)null && (Object)(object)r.m_item != (Object)null && ((Object)r.m_item).name == donorName));
				if ((Object)(object)val == (Object)null || (Object)(object)val.m_craftingStation == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Allblack: no recipe to copy the crafting station from for " + Loc.Plain(d.title) + ", so it can't be crafted"));
					return;
				}
				List<Requirement> list = new List<Requirement>();
				donors = d.ingredients().Split(',');
				for (int i = 0; i < donors.Length; i++)
				{
					string[] array = donors[i].Split(':');
					string text2 = array[0].Trim();
					if (text2.Length != 0)
					{
						if (array.Length < 2 || !int.TryParse(array[1].Trim(), out var result) || result <= 0)
						{
							result = 1;
						}
						GameObject val2 = ((text2 == "pm_Allblack" || text2 == "Allblack") ? Get("pm_Allblack") : PregnancyItems.Find(db, text2));
						ItemDrop val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<ItemDrop>() : null);
						if ((Object)(object)val3 == (Object)null)
						{
							Plugin.Log.LogWarning((object)(Loc.Plain(d.title) + ": ingredient '" + text2 + "' is not an item in this game, skipped"));
							continue;
						}
						list.Add(new Requirement
						{
							m_resItem = val3,
							m_amount = result,
							m_recover = true
						});
					}
				}
				if (list.Count == 0)
				{
					Plugin.Log.LogWarning((object)(Loc.Plain(d.title) + ": no valid ingredients, so it can't be crafted"));
					return;
				}
				Recipe val4 = ScriptableObject.CreateInstance<Recipe>();
				((Object)val4).name = "Recipe_" + d.name;
				val4.m_item = component;
				val4.m_amount = d.craftAmount;
				val4.m_enabled = true;
				val4.m_craftingStation = val.m_craftingStation;
				val4.m_minStationLevel = val.m_minStationLevel;
				val4.m_resources = list.ToArray();
				d.recipe = val4;
			}
			if (!db.m_recipes.Contains(d.recipe))
			{
				db.m_recipes.Add(d.recipe);
			}
		}

		public static void RegisterPrefabs(ZNetScene scene)
		{
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Expected O, but got Unknown
			if (Defs.Any((Def d) => (Object)(object)d.go == (Object)null) && (Object)(object)ObjectDB.instance != (Object)null)
			{
				Ensure(ObjectDB.instance);
			}
			Dictionary<int, GameObject> dictionary = ((AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs") != null) ? (AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene) as Dictionary<int, GameObject>) : null);
			foreach (Def def in Defs)
			{
				if ((Object)(object)def.go == (Object)null)
				{
					continue;
				}
				if (!scene.m_prefabs.Contains(def.go))
				{
					scene.m_prefabs.Add(def.go);
				}
				if (dictionary != null && dictionary.Count > 0)
				{
					int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)def.go).name);
					if (!dictionary.ContainsKey(stableHashCode))
					{
						dictionary[stableHashCode] = def.go;
					}
				}
			}
			GameObject val = Get("pm_AllblackBlood");
			GameObject val2 = Get("pm_Allblack");
			ItemDrop from = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			ItemDrop val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<ItemDrop>() : null);
			if ((Object)(object)from == (Object)null || (Object)(object)val3 == (Object)null)
			{
				return;
			}
			int num = 0;
			foreach (GameObject prefab in scene.m_prefabs)
			{
				Smelter val4 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Smelter>() : null);
				if (!((Object)(object)val4 == (Object)null) && val4.m_conversion != null && !val4.m_conversion.Any((ItemConversion c) => c != null && (Object)(object)c.m_from == (Object)(object)from) && val4.m_conversion.Any((ItemConversion c) => c != null && (Object)(object)c.m_from != (Object)null && ((Object)c.m_from).name == "SilverOre"))
				{
					val4.m_conversion.Add(new ItemConversion
					{
						m_from = from,
						m_to = val3
					});
					num++;
				}
			}
			Plugin.Log.LogInfo((object)("Allblack: items registered, " + num + " smelter(s) taught Allblack Blood -> Allblack"));
		}

		public static void AddDrop(List<KeyValuePair<GameObject, int>> drops)
		{
			GameObject blood = Blood;
			AllblackCfg allblack = Plugin.Cfg.allblack;
			if (!((Object)(object)blood == (Object)null) && allblack.dropAmount > 0 && !(Random.value >= allblack.dropChance))
			{
				drops.Add(new KeyValuePair<GameObject, int>(blood, allblack.dropAmount));
			}
		}
	}
	[HarmonyPatch]
	internal static class AllblackTooltipPatch
	{
		private static MethodBase TargetMethod()
		{
			return PatchUtil.Overload(typeof(ItemData), "GetTooltip", 6, isStatic: true);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix(ItemData __0, ref string __result)
		{
			try
			{
				if (__0 != null && __0.m_shared != null && __result != null && AllblackItems.IsAllblackWeapon(__0.m_shared.m_name))
				{
					__result = __result.Replace("$inventory_damage:", Loc.T("allblack_damage"));
				}
			}
			catch (Exception e)
			{
				Safe.Err("AllblackItems:261", e);
			}
		}
	}
	public static class ConfigBinder
	{
		private sealed class Binder
		{
			private readonly ConfigFile _f;

			public readonly List<Action<MutationConfig>> Apply = new List<Action<MutationConfig>>();

			private readonly Dictionary<ConfigDefinition, string> _orphans;

			public Binder(ConfigFile f)
			{
				_f = f;
				try
				{
					PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_orphans = ((property != null) ? (property.GetValue(f, null) as Dictionary<ConfigDefinition, string>) : null);
				}
				catch (Exception)
				{
					_orphans = null;
				}
			}

			public void Add<T>(string section, string key, T def, ConfigDescription desc, Action<MutationConfig, T> set)
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Expected O, but got Unknown
				if (typeof(T) == typeof(bool) && _orphans != null)
				{
					ConfigDefinition key2 = new ConfigDefinition(section, key);
					string value2;
					if (_orphans.TryGetValue(key2, out var value) && (value2 = ConfigRules.TolerantBool(value)) != value)
					{
						_orphans[key2] = value2;
					}
				}
				ConfigEntry<T> e = _f.Bind<T>(section, key, def, Wrapped(desc));
				Apply.Add(delegate(MutationConfig m)
				{
					set(m, e.Value);
				});
			}
		}

		private static readonly Dictionary<string, string[]> Tunable = new Dictionary<string, string[]>
		{
			{
				"giant",
				new string[5] { "scale", "health", "damage", "moveSpeed", "attackSpeed" }
			},
			{
				"tiny",
				new string[5] { "scale", "health", "damage", "moveSpeed", "attackSpeed" }
			},
			{
				"small",
				new string[5] { "scale", "health", "damage", "moveSpeed", "attackSpeed" }
			},
			{
				"large",
				new string[5] { "scale", "health", "damage", "moveSpeed", "attackSpeed" }
			},
			{
				"diplomat",
				new string[1] { "noticeRadius" }
			},
			{
				"mannequin",
				new string[2] { "comfort", "allowSleep" }
			},
			{
				"immortal",
				new string[6] { "scale", "health", "damage", "moveSpeed", "ambientLook", "ambientColour" }
			},
			{
				"vampiric",
				new string[9] { "lifesteal", "elderLifesteal", "ancientLifesteal", "daylightBurnPctMaxHpPerSec", "seekShelter", "shelterRadius", "elderChance", "ambientLook", "ambientColour" }
			},
			{
				"friendly",
				new string[2] { "ambientLook", "ambientColour" }
			},
			{
				"relentless",
				new string[3] { "moveSpeed", "ambientLook", "ambientColour" }
			},
			{
				"undying",
				new string[10] { "oozerHpPctOfBase", "oozerStartHpPct", "oozerMinHp", "oozerGraceSec", "oozerSizeFit", "regenPctPerSec", "regenDelaySec", "tint", "ambientLook", "ambientColour" }
			},
			{
				"moronic",
				new string[4] { "searchRadius", "excludeTamed", "ambientLook", "ambientColour" }
			},
			{
				"all_consuming",
				new string[10] { "maxConsumed", "lootPerMeal", "gainHpRatio", "gainDamageRatio", "mealCap", "excludeTamed", "eatOwnFaction", "digestSeconds", "preyRadius", "maxPursuitDistance" }
			},
			{
				"impregnator",
				new string[7] { "gestationSec", "maxStacks", "friendlyOffspringChance", "sicknessAtStacks", "sicknessChance", "childfreeDurationSec", "frenzyDurationSec" }
			},
			{
				"mother",
				new string[8] { "calves", "twinChance", "pregnancyChance", "maxCalves", "maxNearby", "ambientLook", "ambientColour", "exodiaColour" }
			},
			{
				"golden",
				new string[28]
				{
					"coins", "coinsMeadows", "coinsBlackForest", "coinsSwamp", "coinsMountain", "coinsPlains", "coinsMistlands", "coinsAshLands", "coinsDeepNorth", "gemsMeadows",
					"gemsBlackForest", "gemsSwamp", "gemsMountain", "gemsPlains", "gemsMistlands", "gemsAshLands", "gemsDeepNorth", "gemMin", "gemMax", "vanishSeconds",
					"spotDistance", "spotConeDegrees", "wallsBlock", "startleSeconds", "driftAfterSeconds", "revealDistance", "vanishMessage", "bodyGlow"
				}
			},
			{
				"shedding",
				new string[3] { "intervalSec", "amount", "drops" }
			},
			{
				"alpha",
				new string[8] { "herdRadius", "herdMax", "callCooldown", "rallySeconds", "leash", "rallyBiteBonus", "ambientLook", "ambientColour" }
			},
			{
				"drenching",
				new string[8] { "auraRadius", "sizeScaling", "wetSeconds", "poisonDamage", "auraVisual", "auraOpacity", "tint", "ambientLook" }
			},
			{
				"elemental",
				new string[9] { "fireScale", "fireScares", "fireWarms", "fireSound", "healShare", "freezeSeconds", "slowHoldSeconds", "debuffSeconds", "burnDamage" }
			},
			{
				"radiating",
				new string[8] { "auraRadius", "sizeScaling", "attackScalingMultiplier", "edgeDamage", "tickSeconds", "auraVisual", "auraBrightness", "tint" }
			},
			{
				"volatile",
				new string[13]
				{
					"periodSec", "chargeSparks", "chargeSound", "blastSound", "damageRatio", "maxHealthShare", "blastRadius", "sizeScaling", "vfxScale", "vfxOpacity",
					"tint", "ambientLook", "chargeColour"
				}
			},
			{
				"glass_cannon",
				new string[8] { "health", "oneShotBosses", "spareFullHealth", "blowMeadows", "blowBlackForest", "blowSwamp", "glowIntensity", "tint" }
			},
			{
				"rabid",
				new string[10] { "chaseRadius", "windupSeconds", "parryStunSeconds", "chargeSeconds", "restSeconds", "loseSeconds", "biteHealthShare", "biteMin", "biteMax", "companionAggroRange" }
			}
		};

		private static readonly Dictionary<string, string> Help = new Dictionary<string, string>
		{
			{ "scale", "Size multiplier (2 = twice as big)." },
			{ "health", "Health multiplier. For Glass Cannon this is its absolute hit points instead." },
			{ "damage", "Damage multiplier." },
			{ "moveSpeed", "Walk/run/swim speed multiplier (0.6 = 40% slower)." },
			{ "attackSpeed", "Animation speed multiplier, so also attack speed (0.6 = 40% slower)." },
			{ "lifesteal", "Fraction of damage dealt that a plain Vampiric heals back (0.75 = 75%). Healing never goes over max health." },
			{ "elderLifesteal", "The same for an Elder Vampiric (immune to the sun). Should be higher than the plain one." },
			{ "ancientLifesteal", "The same for an Ancient Vampire. The highest of the three." },
			{ "seekShelter", "A plain Vampiric mob that the sun burns looks for shade by day: it walks to the nearest roof, cave or overhang (what counts as shelter for the burn), fights what comes near it, and rests there until dusk. Elders and Ancient Vampires never do. Only creatures with a fighting AI (not a vampiric deer); a tame one is left alone." },
			{ "shelterRadius", "How far (metres, 4 to 34) a plain Vampiric mob looks for shade." },
			{ "daylightBurnPctMaxHpPerSec", "Fraction of max health lost per second in daylight when not sheltered (0.01 = 1%, so about 100 s to die in full sun). Elders and Ancient Vampires are immune." },
			{ "oozerSizeFit", "How much of the dead mob's hitbox its Oozer may fill (0.9 = 90%, at most 1): the Oozer is scaled to fit inside the creature it came from, small for a hen and larger for a Troll. 0 = the Oozer is always the same size." },
			{ "oozerHpPctOfBase", "Oozer form's max health as a fraction of the mob's normal max health (its level counted, mutations not)." },
			{ "oozerStartHpPct", "How much of that the Oozer starts with (0.4 = 40%). It must regrow the rest to bring the mob back." },
			{ "oozerMinHp", "The least max health an Oozer has, so a small creature's Oozer is not gone at the first touch." },
			{ "oozerGraceSec", "For this many seconds after it appears the Oozer takes no damage, so the blow, the burning or the crowd that killed the mob can't finish the Oozer in the same moment. 0 = none." },
			{ "regenPctPerSec", "Fraction of the Oozer's max health it regains per second once regeneration starts." },
			{ "regenDelaySec", "Seconds without being hit before the Oozer starts regenerating." },
			{ "poisonDamage", "A Poison Drenching aura drips poison instead of leaving you Wet: this much poison damage in total, renewed while you stand in it." },
			{ "wetSeconds", "How many seconds the Wet status lasts after the aura last touched you (the game's own lasts minutes). 0 = the game's duration." },
			{ "debuffSeconds", "How long an element's damage over time or debuff lasts, from its hits, auras and blasts: Burning (fire), Poison (poison), Shock (lightning), Frost, and spirit's Cold. Each pays out the damage the game itself would have dealt, spread over exactly this many seconds. Never more than 5." },
			{ "tint", "The colour of this mutation's look, as hex (#RRGGBB). Elemental mobs use their element's colour instead." },
			{ "ambientLook", "On: this mutation has a small ambient look on every player's screen (see \"Ambient looks\" in the Display settings, which switches all of them). Off: this one is not drawn. Looks only: nothing about how the mob behaves changes." },
			{ "ambientColour", "The colour of this mutation's ambient look, as hex (#RRGGBB). The default was chosen to differ from every element's colour and from the other mutations' looks, so a mutation can be told apart by its colour as well as its shape." },
			{ "chargeColour", "The colour of a plain Volatile mob: its glow, embers, pulses and blast. Hot magenta by default: the one colour no element and no other mutation uses. An Elemental Volatile mob uses its element's colour instead, and the pulses of a blast that would kill you still turn red." },
			{ "exodiaColour", "The colour of the glow when a Mother that is an Exodia (five mutations) is about to give birth. Red by default; a plain Mother's glow is pink (Look colour)." },
			{ "fireScares", "1 = other creatures keep away from a fire Elemental the way they do from any fire (a Greydwarf from a campfire); a fire Elemental itself is never afraid of fire. 0 = it is not a fire to them." },
			{ "fireWarms", "1 = a player standing near a fire Elemental is warmed by it, as by a campfire: the game's Warm status, and the cold of the weather goes. It cancels with an Elemental's own Frost or Cold: the two take each other away. 0 = off." },
			{ "fireSound", "How loud the burning sound of a fire Elemental is (a campfire, a hearth or a bonfire by the creature's size), as a share of the game's own. 0 = silent." },
			{ "healShare", "An Elemental is not hurt by its own element: that part of a hit is taken out and it is healed for this share of it (0.5 = half), however it was dealt. It is weak to the opposing element (fire to frost, lightning to frost, poison to fire, spirit to lightning). Only mobs that are Elementals by mutation. 0 = it just takes no damage from its own element." },
			{ "fireScale", "Size of a fire Elemental's flames compared with the game's own Burning effect on a creature of its size (1 = as the game shows it)." },
			{ "burnDamage", "The fire damage a Fire Drenching aura's smoke (the game's Smoked status, kept for its full time) deals in all while it lasts, renewed each time it touches you. Radiating and Volatile don't use it: they burn with their own damage." },
			{ "freezeSeconds", "How many seconds the Frost debuff from a frost Elemental lasts (every frost debuff of this mod: hits, auras, Drenching). Every hit or aura tick renews it, so it wears off quickly once you are clear. 0 = no Frost at all, just the frost damage." },
			{ "slowHoldSeconds", "How many of those seconds the Frost slows at full strength. After that the slow eases off in a straight line to nothing at the end of the Frost. 2 of 5 by default." },
			{ "sizeScaling", "How much the aura or blast follows the creature's actual body size (the same rule for Drenching, Radiating and Volatile): 1 = in proportion, 0 = every creature has the same reach. At 0.6 a creature three times a Boar's size reaches about 2x as far (never less than half or more than 3x). The log lists each kind's size and reach the first time it is seen." },
			{ "edgeDamage", "How much of the damage is left at the very rim of the aura, as a fraction (0.3 = 30%). It falls off in a straight line from the full amount at the centre." },
			{ "tickSeconds", "Seconds between the aura's damage ticks." },
			{ "attackScalingMultiplier", "Multiplier on the aura's centre damage, which follows the creature's own attack damage (flattened, so a strong creature does more but not proportionally more: an attack of 5 gives about 2.6, 20 about 6, 60 about 11.7). 1 = as designed. Anything of another faction inside the aura takes it: half piercing, half blunt (the blunt half is the element for an Elemental one)." },
			{ "vfxScale", "Size of the explosion picture (not the damage area) for an average-sized creature. It grows and shrinks in proportion to the creature's own size, so a Giant's is bigger and a calf's smaller. 1 = the effect at full size." },
			{ "chargeSound", "How loud the crackle of a charging Volatile mob is at its loudest, as a share of full volume. One crackle with each pulse, louder each time (and louder the more of your health the blast would take). 0 = silent; the pulses still show." },
			{ "blastSound", "How loud a Volatile mob's blast is, as a share of full volume (a Giant's a little louder, a Tiny's a little quieter). 0 = silent." },
			{ "chargeSparks", "Show the countdown of a Volatile mob: from its first hit, once a second, a smaller copy of its blast plays at the middle of its body, bigger each time, and the last beat is the blast itself at full size and in the same colour. The pulses turn red once the blast would kill you. 0 = no pulses (the crackle and the blast still happen)." },
			{ "vfxOpacity", "How solid the explosion picture is, 0 (invisible) to 1 (full). The damage is unchanged." },
			{ "searchRadius", "How far (metres) it looks for another creature of its own faction to fight." },
			{ "excludeTamed", "Leave tamed creatures alone (a tamed creature is not attacked or eaten)." },
			{ "maxConsumed", "How many creatures it can eat." },
			{ "lootPerMeal", "Extra loot for each creature it has eaten, added to its loot multiplier (0.3 = +30% a meal, so three meals add 90%): the more it ate, the stronger it is, and the more it drops." },
			{ "eatOwnFaction", "On: meadow and Black Forest creatures (the ForestMonsters faction: Boars, Greylings, Greydwarfs...) also hunt each other. Every other faction only hunts creatures of other factions." },
			{ "gainHpRatio", "How much of an eaten creature's health it keeps. 0.5 = half of it, 1 = all of it." },
			{ "gainDamageRatio", "How much of an eaten creature's damage it keeps. 0.5 = half of it, 1 = all of it. Both are held back by the meal cap below." },
			{ "spareFullHealth", "On: a Glass Cannon can't kill a player on full health in one hit; it leaves them on 1 hp, and then burning, poison, cold, auras and blasts ignore them until they heal. Only a real hit can finish them. Off: its hits are always lethal." },
			{ "blowMeadows", "How much of a player's max health one Glass Cannon blow takes in the Meadows, so a new player can learn to dodge it (0.5 = half: two blows kill). 1 = the usual lethal blow. Counted before armour, where the player is standing." },
			{ "blowBlackForest", "The same for the Black Forest (0.75 = three quarters). 1 = the usual lethal blow." },
			{ "glowIntensity", "How strong the faint crimson glow around a Glass Cannon is (1 = the default, a small dim light, a fraction of a Golden's). 0 = no glow. Looks only." },
			{ "blowSwamp", "The same for the Swamp (1 = the usual lethal blow, the default). Every later biome is always lethal." },
			{ "digestSeconds", "How long (seconds) it digests after a meal: it does not hunt and its blows are ordinary until that has passed, so a crowd cannot fill it in a moment. 0 = it can eat again at once." },
			{ "mealCap", "Stops one meal from making it too strong: a single meal can never add more than this share of the eater's own normal health or damage. 1 = at most double its own (3 meals = 4x at most). 0 = no cap." },
			{ "preyRadius", "How far (metres) it looks for something to eat when it has no target. Once it has picked a meal it keeps chasing it, up to the pursuit distance below." },
			{ "maxPursuitDistance", "How far (metres) its meal can get from it before it gives up the chase and goes back to what it was doing. 0 = it never gives up." },
			{ "gestationSec", "Seconds per pregnancy cycle (one offspring is born each cycle)." },
			{ "maxStacks", "Most pregnancies that can stack on one victim." },
			{ "friendlyOffspringChance", "Chance (0 to 1) that an offspring is born Friendly (hostile mobs only)." },
			{ "companionAggroRange", "Hostile creatures within this distance (metres) of a Loyal companion turn on it at once when it is closer to them than whatever they are targeting now (or they have no target). A creature that hits a Loyal also switches to it. 0 = leave it to the game." },
			{ "sicknessAtStacks", "Pregnancy stacks at which Nausea starts (it ends when stacks drop below this). Max stacks is a separate setting, so set this at or below it." },
			{ "sicknessChance", "Chance (0 to 1) on each roll of Nausea that the victim throws up one of the foods they are eating (picked at random)." },
			{ "childfreeDurationSec", "How long a Childfree Potion lasts, in seconds." },
			{ "frenzyDurationSec", "How long Freyja's Frenzy (the aphrodisiac mead) lasts, in seconds." },
			{ "comfort", "Comfort a Mannequin adds to a player resting (sheltered) within its range, like a piece of furniture: counted once however many there are. 0 turns it off." },
			{ "allowSleep", "On: you can sleep in a bed even when enemies are nearby, as long as a Mannequin is within the comfort distance of you. Off: the usual \"can't sleep with enemies nearby\" rule applies." },
			{ "calves", "How many calves a Mother spawns with, every time (each is a copy of the Mother's other mutations)." },
			{ "twinChance", "Chance (0 to 1) that a Mother spawns with one extra Young mob." },
			{ "pregnancyChance", "Chance (0 to 1), rolled once per check, that a Mother becomes pregnant (gains a stack)." },
			{ "maxNearby", "A pregnancy waits while this many of her calves are already close by. 0 = no limit. The calves she spawns with don't wait." },
			{ "maxCalves", "The most calves one Mother can ever have, counting the ones she spawned with. 0 = no limit." },
			{ "windupSeconds", "How long (seconds) a Rabid or called animal stops and faces you before a bite lands. If you have moved out of its reach (or rolled) by then, the bite misses. 0 = bites at once." },
			{ "chargeSeconds", "How long (seconds) it can run at you before it is winded and can only walk. 0 = it never tires." },
			{ "restSeconds", "How long (seconds) it is winded (walking pace) once its charge runs out." },
			{ "parryStunSeconds", "How long (seconds) a Rabid or called animal is stunned when you parry its bite (a shield or buckler raised just before the bite lands): it stops, cannot bite, and is pushed back a step. 0 = a parry does nothing to it." },
			{ "loseSeconds", "Seconds without a clear line to you (behind a wall, a rock, a building) before it gives up the hunt. A Relentless animal never gives up. 0 = it never does." },
			{ "herdRadius", "How far (metres) around a hurt Alpha its herd (animals of the same kind) can hear the call. Only the nearest few inside it answer (see Herd max)." },
			{ "herdMax", "Most herd mates that answer one call (the nearest ones). The rest of the herd carries on as normal." },
			{ "callCooldown", "Seconds before the same Alpha can call its herd again. 0 = it calls on every hit. A killing blow never calls the herd." },
			{ "rallySeconds", "Longest (seconds) a called animal hunts you. It stops sooner if its Alpha dies or you get out of reach (see Leash)." },
			{ "leash", "A called animal gives up the hunt when you are further than this (metres) from it. 0 = it never gives up while the call lasts." },
			{ "rallyBiteBonus", "Extra bite damage for the enraged herd (0.5 = 50% harder)." },
			{ "coins", "Coins a Golden creature drops in a biome with no entry of its own (the ocean), on top of its normal loot." },
			{ "gemMin", "A Golden creature drops at least this many gems or treasures from the list of the biome it spawned in." },
			{ "gemMax", "...and at most this many." },
			{ "coinsMeadows", "Coins a Golden creature spawned in the Meadows drops." },
			{ "gemsMeadows", "Gems and treasures a Golden creature spawned in the Meadows can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsBlackForest", "Coins a Golden creature spawned in the BlackForest drops." },
			{ "gemsBlackForest", "Gems and treasures a Golden creature spawned in the BlackForest can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsSwamp", "Coins a Golden creature spawned in the Swamp drops." },
			{ "gemsSwamp", "Gems and treasures a Golden creature spawned in the Swamp can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsMountain", "Coins a Golden creature spawned in the Mountain drops." },
			{ "gemsMountain", "Gems and treasures a Golden creature spawned in the Mountain can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsPlains", "Coins a Golden creature spawned in the Plains drops." },
			{ "gemsPlains", "Gems and treasures a Golden creature spawned in the Plains can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsMistlands", "Coins a Golden creature spawned in the Mistlands drops." },
			{ "gemsMistlands", "Gems and treasures a Golden creature spawned in the Mistlands can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsAshLands", "Coins a Golden creature spawned in the AshLands drops." },
			{ "gemsAshLands", "Gems and treasures a Golden creature spawned in the AshLands can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "coinsDeepNorth", "Coins a Golden creature spawned in the DeepNorth drops." },
			{ "gemsDeepNorth", "Gems and treasures a Golden creature spawned in the DeepNorth can drop, separated by | (game item names). They are the kind found in that biome's dungeon and structure chests." },
			{ "vanishSeconds", "A Golden creature vanishes (no drops) this many seconds after a player first comes near. 0 = never." },
			{ "spotDistance", "A Golden creature counts as seen when a player is within this many metres of it (and looking its way, see Spot cone degrees). Until then it behaves like any creature of its kind and never fights." },
			{ "spotConeDegrees", "How far to either side of where a player is looking a Golden creature counts as seen (45 = a 90 degree view in front of them)." },
			{ "wallsBlock", "A wall, rock or tree between the player and the Golden creature means it is not seen." },
			{ "startleSeconds", "When it is seen, a Golden creature gives a startled cry and holds still this many seconds before it runs. 0 = it runs at once." },
			{ "driftAfterSeconds", "If a player has been within Spot distance of a Golden creature for this many seconds without seeing it, it slowly walks towards them (not closer than Reveal distance) until they notice it. 0 = it never does, so a Golden can be missed." },
			{ "revealDistance", "The closest (metres) an unnoticed Golden creature walks to a player while it drifts towards them (see Drift after seconds)." },
			{ "vanishMessage", "Show \"<name> Vanished\" in the middle of the screen when a Golden creature near you vanishes." },
			{ "bodyGlow", "How much a Golden creature's body shines from inside, on top of its gold colour. 0 = none: the body shows its normal texture and shading in gold, like an Elemental. Higher is brighter in the dark but flattens the texture (at 1 the body is a plain gold shape). Looks only." },
			{ "intervalSec", "A Shedding animal drops an item about this often (seconds)." },
			{ "amount", "How many of the item it drops each time." },
			{ "drops", "What each animal sheds, as Animal=Item pairs separated by commas. \"default\" is used for any animal not listed. Use the game's item names, e.g. Hen=ChickenEgg,Deer=DeerHide,default=LeatherScraps." },
			{ "auraRadius", "How close (metres) a player has to be to be soaked (Wet, or the element's debuff) or hurt, for a creature about the size of a Boar. Bigger creatures reach a little further and smaller ones a little less (see Size scaling)." },
			{ "auraOpacity", "How see-through the mist is (0 = invisible, 1 = solid). Lower it if several Drenching mobs make the screen too busy." },
			{ "auraBrightness", "How bright the Radiating ring and wave are (0 = black, 1 = the element's full colour). Lower it for a dimmer ring." },
			{ "auraVisual", "Show the effect's picture (the look only; the gameplay works either way)." },
			{ "periodSec", "A Volatile mob explodes this many seconds after it was first hit. If it is killed first, nothing happens." },
			{ "damageRatio", "Fraction of the damage stored since the first hit that the blast deals (0.5 = half)." },
			{ "maxHealthShare", "The most one blast can take from one creature, as a share of that creature's FULL health, armour counted (0.5 = half). So a blast is never a one-hit kill on someone at full health. 0 turns the limit off." },
			{ "blastRadius", "Reach (metres) of the blast at full effect size. The real reach is this times the explosion picture's scale (Vfx scale x the creature's size), so the damage area always matches what is drawn. It hurts anything of another faction, never the mob or its own faction." },
			{ "noticeRadius", "How far (metres) from a creature that takes damage a Diplomat notices it." },
			{ "elderChance", "Chance (0 to 1) that a Vampiric mob is an Elder, which is immune to sunlight." },
			{ "oneShotBosses", "Let Glass Cannon one-shot bosses too (off by default)." },
			{ "chaseRadius", "How far (metres) it notices a player to chase." },
			{ "biteHealthShare", "How hard a bite hits, as a share of the animal's own health. 0.25 = a quarter, so a 20 hp boar bites for 5 and a big animal bites harder." },
			{ "biteMin", "A bite never hits softer than this." },
			{ "biteMax", "A bite never hits harder than this. 0 = no limit." }
		};

		private static readonly Dictionary<string, string> HelpFor = new Dictionary<string, string>
		{
			{ "drenching.auraRadius", "How close (metres) a player has to be to be soaked by the mist (Wet, or the element's debuff, or poison for a Poison Drenching), for a creature about the size of a Boar. Bigger creatures reach a little further and smaller ones a little less (see Size scaling)." },
			{ "radiating.auraRadius", "How far out (metres) the damaging wave reaches from the creature, for a creature about the size of a Boar. Bigger creatures reach a little further and smaller ones a little less (see Size scaling). Anything of another faction inside it is hurt." },
			{ "drenching.auraVisual", "On: show the blue mist around a Drenching mob. Off: no mist is drawn (the look only; the soaking works either way)." },
			{ "radiating.auraVisual", "On: draw the ring and wave of a Radiating mob. Off: nothing is drawn (the look only; the damage works either way, so players cannot see its reach)." },
			{ "moronic.excludeTamed", "On: a Moronic creature never attacks tamed creatures (it keeps to wild ones and players)." },
			{ "all_consuming.excludeTamed", "On: an All-consuming creature never eats tamed creatures." },
			{ "glass_cannon.health", "Its absolute hit points (not a multiplier): 1 by default, so almost anything kills it." },
			{ "friendly.ambientLook", "On: a few soft hearts rise from a Friendly mob when you are within about 14 m (see \"Ambient looks\" in the Display settings). Looks only." },
			{ "vampiric.ambientLook", "On: when a Vampiric mob heals from a bite, a short stream of dark-red motes runs from the victim to it. Nothing is drawn while it is idle. Looks only." },
			{ "relentless.ambientLook", "On: a Relentless mob kicks up a little dust behind it while it runs. Looks only." },
			{ "immortal.ambientLook", "On: a low, thin violet mist round an Ancient Vampire's feet. Looks only." },
			{ "volatile.ambientLook", "On: a Volatile mob has a few embers and a faint glow before it is hit, brightening as the charge runs down (the wind-up itself is \"Charging sparks\"). Looks only." },
			{ "drenching.ambientLook", "On: water drips from a Drenching mob (the mist round it is \"Aura visual\"). Looks only." },
			{ "undying.ambientLook", "On: a faint pale wisp drifts off an Undying mob. Looks only." },
			{ "moronic.ambientLook", "On: a few small stars circle over a Moronic mob's head. Looks only." },
			{ "alpha.ambientLook", "On: a ring spreads over the ground out to the herd's reach when an Alpha calls its herd. Nothing is drawn otherwise. Looks only." },
			{ "mother.ambientLook", "On: a Mother glows for the last 5 seconds before a calf is born (a warning you can act on), and hearts rise when one is. Looks only." },
			{ "immortal.health", "Health multiplier for an Ancient Vampire (the Immortal mutation)." }
		};

		private static readonly Dictionary<string, float[]> FloatRanges = new Dictionary<string, float[]>
		{
			{
				"vfxScale",
				new float[2] { 0.05f, 5f }
			},
			{
				"sizeScaling",
				new float[2] { 0f, 1f }
			},
			{
				"vfxOpacity",
				new float[2] { 0f, 1f }
			},
			{
				"elderChance",
				new float[2] { 0f, 1f }
			},
			{
				"shelterRadius",
				new float[2] { 4f, 34f }
			},
			{
				"oozerStartHpPct",
				new float[2] { 0.01f, 0.95f }
			},
			{
				"oozerMinHp",
				new float[2] { 1f, 1000f }
			},
			{
				"oozerGraceSec",
				new float[2] { 0f, 5f }
			},
			{
				"lootPerMeal",
				new float[2] { 0f, 2f }
			},
			{
				"wetSeconds",
				new float[2] { 0f, 3600f }
			},
			{
				"fireScale",
				new float[2] { 0.1f, 3f }
			},
			{
				"healShare",
				new float[2] { 0f, 1f }
			},
			{
				"fireScares",
				new float[2] { 0f, 1f }
			},
			{
				"fireWarms",
				new float[2] { 0f, 1f }
			},
			{
				"fireSound",
				new float[2] { 0f, 1f }
			},
			{
				"chargeSound",
				new float[2] { 0f, 1f }
			},
			{
				"blastSound",
				new float[2] { 0f, 1f }
			},
			{
				"auraOpacity",
				new float[2] { 0f, 1f }
			},
			{
				"auraBrightness",
				new float[2] { 0f, 1f }
			},
			{
				"freezeSeconds",
				new float[2] { 0f, 5f }
			},
			{
				"slowHoldSeconds",
				new float[2] { 0f, 5f }
			},
			{
				"debuffSeconds",
				new float[2] { 0.5f, 5f }
			},
			{
				"parryStunSeconds",
				new float[2] { 0f, 5f }
			},
			{
				"vanishSeconds",
				new float[2] { 0f, 3600f }
			},
			{
				"daylightBurnPctMaxHpPerSec",
				new float[2] { 0f, 1f }
			},
			{
				"mealCap",
				new float[2] { 0f, 10f }
			},
			{
				"biteHealthShare",
				new float[2] { 0f, 5f }
			},
			{
				"biteMin",
				new float[2] { 0f, 100f }
			},
			{
				"biteMax",
				new float[2] { 0f, 1000f }
			},
			{
				"sicknessChance",
				new float[2] { 0f, 1f }
			},
			{
				"friendlyOffspringChance",
				new float[2] { 0f, 1f }
			},
			{
				"blowMeadows",
				new float[2] { 0.05f, 1f }
			},
			{
				"blowBlackForest",
				new float[2] { 0.05f, 1f }
			},
			{
				"blowSwamp",
				new float[2] { 0.05f, 1f }
			},
			{
				"glowIntensity",
				new float[2] { 0f, 3f }
			},
			{
				"twinChance",
				new float[2] { 0f, 1f }
			},
			{
				"damageRatio",
				new float[2] { 0f, 20f }
			},
			{
				"maxHealthShare",
				new float[2] { 0f, 1f }
			},
			{
				"spotDistance",
				new float[2] { 1f, 100f }
			},
			{
				"oozerSizeFit",
				new float[2] { 0f, 1f }
			},
			{
				"bodyGlow",
				new float[2] { 0f, 1f }
			},
			{
				"spotConeDegrees",
				new float[2] { 5f, 180f }
			},
			{
				"startleSeconds",
				new float[2] { 0f, 3f }
			},
			{
				"driftAfterSeconds",
				new float[2] { 0f, 600f }
			},
			{
				"pregnancyChance",
				new float[2] { 0f, 1f }
			},
			{
				"regenPctPerSec",
				new float[2] { 0f, 1f }
			},
			{
				"scale",
				new float[2] { 0.1f, 10f }
			},
			{
				"moveSpeed",
				new float[2] { 0.1f, 10f }
			},
			{
				"attackSpeed",
				new float[2] { 0.1f, 10f }
			},
			{
				"health",
				new float[2] { 0.05f, 100f }
			},
			{
				"damage",
				new float[2] { 0.05f, 100f }
			}
		};

		private static string HelpText(string mid, string key)
		{
			if (HelpFor.TryGetValue(mid + "." + key, out var value))
			{
				return value;
			}
			if (Help.TryGetValue(key, out value))
			{
				return value;
			}
			return "Tuning value.";
		}

		private static ConfigDescription D(string text)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			return new ConfigDescription(text, (AcceptableValueBase)null, Array.Empty<object>());
		}

		private static ConfigDescription FloatDesc(string key, string help)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			if (FloatRanges.TryGetValue(key, out var value))
			{
				return new ConfigDescription(help, (AcceptableValueBase)(object)new AcceptableValueRange<float>(value[0], value[1]), Array.Empty<object>());
			}
			string text = key.ToLowerInvariant();
			if (text.EndsWith("sec") || text.EndsWith("seconds"))
			{
				return new ConfigDescription(help, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3600f), Array.Empty<object>());
			}
			if (text.EndsWith("radius") || text.EndsWith("range") || text.EndsWith("distance"))
			{
				return new ConfigDescription(help, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 500f), Array.Empty<object>());
			}
			return D(help);
		}

		private static string BiomeLabel(string biome)
		{
			return biome switch
			{
				"DeepNorth" => "Deep North", 
				"AshLands" => "Ash Lands", 
				"BlackForest" => "Black Forest", 
				_ => biome, 
			};
		}

		public static string Wrap(string text, int width = 100)
		{
			if (string.IsNullOrEmpty(text) || text.Length <= width)
			{
				return text;
			}
			StringBuilder stringBuilder = new StringBuilder();
			string[] array = text.Split('\n');
			foreach (string obj in array)
			{
				int num = 0;
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				string[] array2 = obj.Split(' ');
				foreach (string text2 in array2)
				{
					if (num > 0 && num + 1 + text2.Length > width)
					{
						stringBuilder.Append('\n');
						num = 0;
					}
					else if (num > 0)
					{
						stringBuilder.Append(' ');
						num++;
					}
					stringBuilder.Append(text2);
					num += text2.Length;
				}
			}
			return stringBuilder.ToString();
		}

		public static ConfigDescription Wrapped(ConfigDescription d)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if (d != null)
			{
				return new ConfigDescription(Wrap(d.Description), d.AcceptableValues, d.Tags);
			}
			return null;
		}

		private static ConfigDescription Adv(string text)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			return new ConfigDescription(text, (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					IsAdvanced = true
				}
			});
		}

		private static ConfigDescription Range01(string text)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return new ConfigDescription(text, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>());
		}

		public static List<Action<MutationConfig>> Bind(ConfigFile f, MutationConfig d)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Expected O, but got Unknown
			//IL_0679: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Expected O, but got Unknown
			//IL_06a2: Expected O, but got Unknown
			//IL_0af4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b1d: Expected O, but got Unknown
			//IL_0b51: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b7a: Expected O, but got Unknown
			//IL_0def: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e18: Expected O, but got Unknown
			//IL_0ede: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f07: Expected O, but got Unknown
			//IL_0f84: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fad: Expected O, but got Unknown
			//IL_0fe1: Unknown result type (might be due to invalid IL or missing references)
			//IL_100a: Expected O, but got Unknown
			//IL_103e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1067: Expected O, but got Unknown
			//IL_1094: Unknown result type (might be due to invalid IL or missing references)
			//IL_10bd: Expected O, but got Unknown
			//IL_10f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_111a: Expected O, but got Unknown
			//IL_126b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1294: Expected O, but got Unknown
			//IL_1473: Unknown result type (might be due to invalid IL or missing references)
			//IL_148a: Expected O, but got Unknown
			//IL_13e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_13fa: Expected O, but got Unknown
			Binder binder = new Binder(f);
			binder.Add("01 - Spawn chance", "Chance multiplier", d.spawnChance.chanceMultiplier, new ConfigDescription("A big dial for how many mobs mutate. 1 = normal, 0.5 = half as many, 2 = twice as many. It only changes the first mutation, not extra mutations or Ancient Vampires.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.spawnChance.chanceMultiplier = v;
			});
			binder.Add("01 - Spawn chance", "Immortal chance", d.spawnChance.immortalChance, Range01("How likely any mob is to be an Ancient Vampire. 0.001 = 1 in 1000, 0 = never. It can still pick up other mutations after."), delegate(MutationConfig m, float v)
			{
				m.spawnChance.immortalChance = v;
			});
			binder.Add("01 - Spawn chance", "Golden chance", d.spawnChance.goldenChance, Range01("How likely any normal mob is to be Golden (a rare gold creature that runs away and drops coins). 0.002 = 1 in 500, 0 = never. It never counts toward the mutation limit and is not rolled for raid or summoned mobs."), delegate(MutationConfig m, float v)
			{
				m.spawnChance.goldenChance = v;
			});
			binder.Add("01 - Spawn chance", "Size chance", d.spawnChance.sizeChance, Range01("When a mob's first mutation is not a size, how likely it is to also get a size (Giant, Large, Small or Tiny) on top. 0.5 = half the time. A size can also be the first mutation itself. A size counts as a mutation toward the limit."), delegate(MutationConfig m, float v)
			{
				m.spawnChance.sizeChance = v;
			});
			binder.Add("01 - Spawn chance", "Ancient Vampire - appears after", d.spawnChance.immortalAfterKey, D("Ancient Vampires wait until this world event has happened. defeated_bonemass = after Bonemass is beaten (when you can make Allblack). Leave empty to let them appear from the start."), delegate(MutationConfig m, string v)
			{
				m.spawnChance.immortalAfterKey = v;
			});
			ExtraCfg ex = d.spawnChance.extraMutation;
			binder.Add("01 - Spawn chance", "Extra mutations - max total", ex.maxTotal, new ConfigDescription("The most mutations one mob can ever have, sizes (Giant, Large, Small, Tiny) included: a size takes one of these slots. Each biome's own \"Most mutations\" does not count sizes, so a size comes on top of that limit but never past this total. Bigger = more chances of wild stacks.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()), delegate(MutationConfig m, int v)
			{
				m.spawnChance.extraMutation.maxTotal = v;
			});
			CapCfg mutationCap = d.spawnChance.mutationCap;
			binder.Add("01 - Spawn chance", "Mutation limit - by biome", mutationCap.byBiome, D("On: a natural roll can give at most the number set under each biome's \"Most mutations\" (1 in the Meadows, one more per biome up, 5 from the Plains). A size (Giant, Large, Small, Tiny) does not count toward this limit, so a Meadows mob can still be a Giant Vampiric. Off: only \"Extra mutations - max total\" limits. Creatures that already have more (bred, spawned with mm_spawn) keep them."), delegate(MutationConfig m, bool v)
			{
				m.spawnChance.mutationCap.byBiome = v;
			});
			binder.Add("01 - Spawn chance", "Mutation limit - follow boss progress", mutationCap.followProgress, D("On: a biome's limit only applies once the world has got that far: 1 mutation with no boss down, one more for each boss in the list below that has been defeated (by anyone in the world). So a Mountain mob stays at 3 until Bonemass is down. Off: the biome limit alone."), delegate(MutationConfig m, bool v)
			{
				m.spawnChance.mutationCap.followProgress = v;
			});
			binder.Add("01 - Spawn chance", "Mutation limit - boss keys", Csv(mutationCap.bossKeys), D("The world events that raise the progress limit by one each, in order. Comma separated. Default: Eikthyr, the Elder, Bonemass and Moder (defeated_eikthyr, defeated_gdking, defeated_bonemass, defeated_dragon)."), delegate(MutationConfig m, string v)
			{
				m.spawnChance.mutationCap.bossKeys = Split(v);
			});
			binder.Add("01 - Spawn chance", "Raid and summoned mobs - chance multiplier", d.spawnChance.eventChanceMultiplier, new ConfigDescription("Like the big dial above, but only for raid mobs and mobs that other creatures summon. 1 = same as everyone, 0 = never, 2 = twice as likely. Does nothing if they are switched off in 02 - Who can mutate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.spawnChance.eventChanceMultiplier = v;
			});
			string[] order = new string[9] { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands", "DeepNorth", "Ocean" };
			List<string> list = order.Where((string x) => d.spawnChance.biomeChance.ContainsKey(x) || ex.biomeChance.ContainsKey(x)).ToList();
			list.AddRange(from x in d.spawnChance.biomeChance.Keys.Concat(ex.biomeChance.Keys).Distinct()
				where !order.Contains(x)
				select x);
			for (int num = 0; num < list.Count; num++)
			{
				string name = list[num];
				string section = "01" + "bcdefghijklmnop"[num] + " - Biome: " + BiomeLabel(name);
				if (d.spawnChance.biomeChance.ContainsKey(name))
				{
					binder.Add(section, "Chance of a mutation", d.spawnChance.biomeChance[name], Range01("How likely a mob is to spawn mutated here. 0.3 = 3 in 10, 1 = always, 0 = never."), delegate(MutationConfig m, float v)
					{
						m.spawnChance.biomeChance[name] = v;
					});
				}
				if (ex.biomeChance.ContainsKey(name))
				{
					binder.Add(section, "Chance of extra mutations", ex.biomeChance[name], Range01("After a mob mutates, how likely it is to get another one (and another...). 0.1 = 1 in 10."), delegate(MutationConfig m, float v)
					{
						m.spawnChance.extraMutation.biomeChance[name] = v;
					});
				}
				if (mutationCap.maxByBiome.ContainsKey(name))
				{
					binder.Add(section, "Most mutations", mutationCap.maxByBiome[name], new ConfigDescription("The most mutations a natural roll can give here, sizes not counted (see \"Mutation limit\" in 01 - Spawn chance; a boss that is still alive can hold it lower).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()), delegate(MutationConfig m, int v)
					{
						m.spawnChance.mutationCap.maxByBiome[name] = v;
					});
				}
				if (!d.spawnChance.mobKillersAllowed.TryGetValue(name, out var value))
				{
					value = d.spawnChance.mobKillersAllowedElsewhere;
				}
				binder.Add(section, "Creature-killing mutations allowed", value, D("Off: the mutations that make mobs kill other creatures (All-consuming, Moronic; see \"Creature-killing mutations\" in 01 - Spawn chance) are never rolled here, so the animals you hunt are not thinned out. On: they roll like any other mutation. Off by default in the Meadows."), delegate(MutationConfig m, bool v)
				{
					m.spawnChance.mobKillersAllowed[name] = v;
				});
			}
			string section2 = "01" + "bcdefghijklmnop"[list.Count] + " - Biome: Any other";
			binder.Add(section2, "Chance of a mutation", d.spawnChance.defaultChance, Range01("How likely a mob is to spawn mutated in any biome not listed above. 0.3 = 3 in 10."), delegate(MutationConfig m, float v)
			{
				m.spawnChance.defaultChance = v;
			});
			binder.Add(section2, "Chance of extra mutations", ex.chance, Range01("How likely a mutated mob is to get another mutation in any biome not listed above."), delegate(MutationConfig m, float v)
			{
				m.spawnChance.extraMutation.chance = v;
			});
			binder.Add(section2, "Most mutations", mutationCap.maxElsewhere, new ConfigDescription("The most mutations a natural roll can give in any biome not listed above.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()), delegate(MutationConfig m, int v)
			{
				m.spawnChance.mutationCap.maxElsewhere = v;
			});
			binder.Add(section2, "Creature-killing mutations allowed", d.spawnChance.mobKillersAllowedElsewhere, D("Whether the mutations that make mobs kill other creatures (All-consuming, Moronic) can be rolled in any biome not listed above."), delegate(MutationConfig m, bool v)
			{
				m.spawnChance.mobKillersAllowedElsewhere = v;
			});
			binder.Add("02 - Who can mutate", "Exclude bosses", d.eligibility.excludeBosses, D("Bosses never mutate."), delegate(MutationConfig m, bool v)
			{
				m.eligibility.excludeBosses = v;
			});
			binder.Add("02 - Who can mutate", "Exclude tamed", d.eligibility.excludeTamed, D("Tamed creatures never mutate."), delegate(MutationConfig m, bool v)
			{
				m.eligibility.excludeTamed = v;
			});
			binder.Add("02 - Who can mutate", "Exclude raid and summoned mobs", d.eligibility.excludeSummonedAndEventMobs, D("On: mobs from raids/events and mobs summoned by other creatures never mutate. Off: they roll like any other mob, or at their own rate (see \"Raid and summoned mobs\" in 01 - Spawn chance)."), delegate(MutationConfig m, bool v)
			{
				m.eligibility.excludeSummonedAndEventMobs = v;
			});
			binder.Add("02 - Who can mutate", "Exclude passive creatures", d.eligibility.excludePassive, D("On: passive animals (deer, hens, boars... see \"Passive creatures\" below) never mutate. Off: they roll like any other mob. Rabid only rolls on passive animals, so with this on it can only come from breeding."), delegate(MutationConfig m, bool v)
			{
				m.eligibility.excludePassive = v;
			});
			binder.Add("02 - Who can mutate", "Exclude minibosses", d.eligibility.excludeMinibosses, D("On (default): the creatures listed under \"Minibosses\" below never mutate. Off: they roll like any other mob."), delegate(MutationConfig m, bool v)
			{
				m.eligibility.excludeMinibosses = v;
			});
			binder.Add("02 - Who can mutate", "Exclude Epic Loot bounty creatures", d.eligibility.excludeEpicLootBounties, D("On (default): the targets and escorts of Epic Loot bounties never mutate, so a bounty is the fight Epic Loot designed. Off: they roll like any other mob. Does nothing without Epic Loot."), delegate(MutationConfig m, bool v)
			{
				m.eligibility.excludeEpicLootBounties = v;
			});
			binder.Add("02 - Who can mutate", "Minibosses", Csv(d.mobOverrides.miniboss), D("Prefab names counted as minibosses (Hildir's and Bogwitch's challenge creatures...). They never mutate while \"Exclude minibosses\" is on. Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.miniboss = Split(v);
			});
			binder.Add("02 - Who can mutate", "Creatures that split on death", Csv(d.mobOverrides.splitsInto), D("Parent:Piece prefab pairs (BlobElite:Blob). The pieces a creature splits into keep its mutations, except Mimic, Mother, Friendly, Rabid, Undying, Impregnator and the Ancient Vampire. Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.splitsInto = Split(v);
			});
			binder.Add("02 - Who can mutate", "Passive creatures", Csv(d.mobOverrides.passive), D("Prefab names treated as passive (can roll Rabid). Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.passive = Split(v);
			});
			binder.Add("02 - Who can mutate", "Hostile creatures", Csv(d.mobOverrides.hostile), D("Prefab names forced to count as hostile. Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.hostile = Split(v);
			});
			binder.Add("02 - Who can mutate", "Creatures with a base element", Csv(d.mobOverrides.elemental), D("Prefab:element pairs for creatures that already have an element (Surtling:fire, Hatchling:frost, Ghost:spirit...). With the Elemental mutation they take one of the other four elements; any other creature takes any of the five. Elements: fire, frost, lightning, poison, spirit. Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.elemental = Split(v);
			});
			binder.Add("02 - Who can mutate", "Ranged creatures", Csv(d.mobOverrides.ranged), D("Prefab names forced to count as ranged (can't roll Glass Cannon). Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.ranged = Split(v);
			});
			binder.Add("02 - Who can mutate", "Never mutate", Csv(d.mobOverrides.neverMutate), D("Prefab names that never mutate. Comma separated."), delegate(MutationConfig m, string v)
			{
				m.mobOverrides.neverMutate = Split(v);
			});
			binder.Add("03 - Loot", "Passive variant multiplier", d.loot.passiveVariantMultiplier, new ConfigDescription("A Friendly or Mannequin mob (the passive variants) drops this fraction of its loot (0.5 = half; applies once). Each mutation's own loot multiplier is in its \"Mutation - ...\" section.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.loot.passiveVariantMultiplier = v;
			});
			binder.Add("03 - Loot", "Young loot multiplier", d.loot.youngMultiplier, new ConfigDescription("How much loot young creatures drop (calves from Mothers, Impregnator babies, Young group members). 0.5 = half, 1 = full, 0 = none.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.loot.youngMultiplier = v;
			});
			binder.Add("03 - Loot", "Scale trophies and fixed drops", d.loot.scaleFixedDrops, D("Off (default): like the game's own stars, the loot multipliers only scale the drops the game itself multiplies for a starred creature; trophies and other fixed drops stay as the game rolled them (a Giant drops more meat, not more trophies). On: every drop is scaled, trophies included."), delegate(MutationConfig m, bool v)
			{
				m.loot.scaleFixedDrops = v;
			});
			binder.Add("03 - Loot", "Apply loot multipliers to Epic Loot", d.loot.scaleEpicLoot, D("On (default): with Epic Loot installed, its drops follow the same multiplier as the vanilla drops: a mob that drops 2x loot gets an extra Epic Loot roll, 1.25x gives a 25% chance of one, and a Young or Friendly mob (below 1x) skips that share of its Epic Loot rolls. Off: Epic Loot's drops are not touched (an Undying mob's Oozer body still never rolls them)."), delegate(MutationConfig m, bool v)
			{
				m.loot.scaleEpicLoot = v;
			});
			binder.Add("04 - Offspring", "Pass on Ancient Vampire", d.offspring.passOnAncientVampire, D("Off (default): the Ancient Vampire is a rare title won at spawn and young are never born with it (they keep the other mutations), so a Mother or Impregnator can't breed a cluster of mobs that only Allblack can kill. On: it can be inherited."), delegate(MutationConfig m, bool v)
			{
				m.offspring.passOnAncientVampire = v;
			});
			binder.Add("04 - Offspring", "Pass on Elder", d.offspring.passOnElder, D("Off (default): young of an Elder Vampiric are Vampiric but roll Elder like any other mob, so breeding Elders (a Mother, an Impregnator, a tame pair) can't farm Allblack Blood. On: Elder parents give Elder young."), delegate(MutationConfig m, bool v)
			{
				m.offspring.passOnElder = v;
			});
			binder.Add("04 - Offspring", "Use vanilla calves", d.offspring.useVanillaCalves, D("Where the game has a young form of the mob (Boar piglet, Wolf cub, Lox calf), Impregnator births are born as that and grow up with the game's own timer. Off: every birth uses the newborn fraction above."), delegate(MutationConfig m, bool v)
			{
				m.offspring.useVanillaCalves = v;
			});
			binder.Add("04 - Offspring", "Grow-up time (seconds)", d.offspring.growUpSec, D("How long a Young mob takes to climb from Tiny to its grown-up size and stats, passing through every size step (Small, normal, Large...) on the way."), delegate(MutationConfig m, float v)
			{
				m.offspring.growUpSec = v;
			});
			binder.Add("04 - Offspring", "Bonus mutation roll", d.offspring.bonusMutationRoll, D("Offspring can roll extra mutations on top of the ones they inherit."), delegate(MutationConfig m, bool v)
			{
				m.offspring.bonusMutationRoll = v;
			});
			binder.Add("11 - Young and Aged", "Groups can have a calf or an Aged one", d.ageGroups.enabled, D("When this many creatures of one kind spawn close together (a camp, a herd), one of them can be Young (small and weak, grows up) or an Aged one (smaller and weaker)."), delegate(MutationConfig m, bool v)
			{
				m.ageGroups.enabled = v;
			});
			binder.Add("11 - Young and Aged", "Group size", d.ageGroups.groupSize, new ConfigDescription("How many of one kind close together make a group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 20), Array.Empty<object>()), delegate(MutationConfig m, int v)
			{
				m.ageGroups.groupSize = v;
			});
			binder.Add("11 - Young and Aged", "Calf chance", d.ageGroups.calfChance, Range01("Chance (0 to 1), per group, that one of them is Young. It grows up over the grow-up time (see 04 - Offspring)."), delegate(MutationConfig m, float v)
			{
				m.ageGroups.calfChance = v;
			});
			binder.Add("11 - Young and Aged", "Aged chance", d.ageGroups.ancientChance, Range01("Chance (0 to 1), per group, that one of them is Aged. A Vampiric is never Aged (it stays regular). Not the same as the Ancient Vampire mutation: see \"Immortal chance\" in 01 - Spawn chance."), delegate(MutationConfig m, float v)
			{
				m.ageGroups.ancientChance = v;
			});
			binder.Add("11 - Young and Aged", "Aged size, health and damage", d.ageGroups.ancientMultiplier, new ConfigDescription("An Aged mob's size, health and damage as a fraction of normal (0.8 = 80%).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.ageGroups.ancientMultiplier = v;
			});
			binder.Add("10 - Loyal breeding", "Loyal companions can breed", d.loyalBreeding.enabled, D("Feed a Loyal companion its breeding food (see the README) and two of the same kind that are both in the mood make a baby that is Loyal too."), delegate(MutationConfig m, bool v)
			{
				m.loyalBreeding.enabled = v;
			});
			binder.Add("10 - Loyal breeding", "In the mood for (seconds)", d.loyalBreeding.loveSeconds, new ConfigDescription("How long a fed companion waits for a partner.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 3600f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.loyalBreeding.loveSeconds = v;
			});
			binder.Add("10 - Loyal breeding", "Pregnancy time (seconds)", d.loyalBreeding.gestationSeconds, new ConfigDescription("From the two meeting to the baby being born.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 86400f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.loyalBreeding.gestationSeconds = v;
			});
			binder.Add("10 - Loyal breeding", "Cooldown (seconds)", d.loyalBreeding.cooldownSeconds, new ConfigDescription("After the birth, before either parent can breed again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 86400f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.loyalBreeding.cooldownSeconds = v;
			});
			binder.Add("10 - Loyal breeding", "Most companions of a kind nearby", d.loyalBreeding.maxNearby, new ConfigDescription("Breeding stops while this many of your companions of the same kind (young ones and ones expecting a baby included) are within the radius below, and starts again when there is room. Nothing is removed. 0 = no limit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()), delegate(MutationConfig m, int v)
			{
				m.loyalBreeding.maxNearby = v;
			});
			binder.Add("10 - Loyal breeding", "Population radius (metres)", d.loyalBreeding.populationRadius, new ConfigDescription("How far around a breeding companion the companions above are counted.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 500f), Array.Empty<object>()), delegate(MutationConfig m, float v)
			{
				m.loyalBreeding.populationRadius = v;
			});
			binder.Add("13 - First finds", "First finds", d.firstFinds.enabled, D("On: the server remembers who first met each mutation, combination and unique creature on this world, and every player's Compendium shows \"First found by ...\" beside it. Kept in a small file next to the server's settings (BepInEx/config/MutagenicWilds/firstfinds), one per world. Off: nothing is recorded or shown."), delegate(MutationConfig m, bool v)
			{
				m.firstFinds.enabled = v;
			});
			binder.Add("13 - First finds", "Announce first finds", d.firstFinds.announce, D("On: when someone meets a combination or a unique creature nobody on this world has met before, everyone online gets a short message (at most one every few seconds; several at once become \"... and 2 more\"). Each player can hide these messages for themselves in 12 - Compendium."), delegate(MutationConfig m, bool v)
			{
				m.firstFinds.announce = v;
			});
			binder.Add("13 - First finds", "Announce single mutations too", d.firstFinds.announceMutations, D("On: a single mutation met for the first time on the world is announced as well. Off (default): only combinations and unique creatures, since a new world turns up many single mutations in its first hours."), delegate(MutationConfig m, bool v)
			{
				m.firstFinds.announceMutations = v;
			});
			binder.Add("09 - Allblack", "Elder Vampiric drop chance", d.allblack.dropChance, Range01("Chance (0 to 1) that an Elder Vampiric drops Allblack Blood when it dies."), delegate(MutationConfig m, float v)
			{
				m.allblack.dropChance = v;
			});
			binder.Add("09 - Allblack", "Allblack Blood dropped", d.allblack.dropAmount, new ConfigDescription("How many Allblack Blood an Elder Vampiric drops.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), Array.Empty<object>()), delegate(MutationConfig m, int v)
			{
				m.allblack.dropAmount = v;
			});
			binder.Add("09 - Allblack", "Harmless Elders drop Blood", d.allblack.harmlessElderDrops, D("Off: a Friendly, Mannequin or Moronic Elder Vampiric drops no Allblack Blood, so the Blood has to be won from a dangerous Elder. On: any Elder drops it."), delegate(MutationConfig m, bool v)
			{
				m.allblack.harmlessElderDrops = v;
			});
			binder.Add("09 - Allblack", "Kin Slayer: owner only", d.allblack.kinSlayerOwnerOnly, D("On: only a Loyal companion's owner can kill it with the Kin Slayer. Off: anyone holding one can (in multiplayer, that includes other players' companions)."), delegate(MutationConfig m, bool v)
			{
				m.allblack.kinSlayerOwnerOnly = v;
			});
			string[] orderedIds = d.OrderedIds;
			foreach (string text in orderedIds)
			{
				string mid = text;
				MutationDef mutationDef = d.mutations[mid];
				string text2 = "Mutation - " + mutationDef.label;
				binder.Add(text2, "Enabled", mutationDef.enabled, D("Off: this mutation does not exist. It is never rolled, bred, or given by mm_spawn, and creatures that already have it lose its effects within a second or so (some looks, such as an aura already drawn, may last until the creature is seen again). Turn it back on and they get them back."), delegate(MutationConfig m, bool v)
				{
					m.mutations[mid].enabled = v;
				});
				if (mid != "immortal")
				{
					binder.Add(text2, "Weight", mutationDef.weight, new ConfigDescription("How often it is picked compared with the others. 0 turns it off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()), delegate(MutationConfig m, int v)
					{
						m.mutations[mid].weight = v;
					});
					if (mid == "friendly" || mid == "mannequin")
					{
						binder.Add(text2, "Passive variant (reduced loot)", mutationDef.passiveVariant, D("On: a mob with this mutation drops reduced loot (see 03 - Loot)."), delegate(MutationConfig m, bool v)
						{
							m.mutations[mid].passiveVariant = v;
						});
					}
				}
				binder.Add(text2, "Loot multiplier", mutationDef.lootMultiplier, new ConfigDescription("Loot from a mob with this mutation: 1 = vanilla, 1.5 = half as much again. A mob's mutations add up: each adds its multiplier minus 1 to a base of 1 (two at 1.5 give 2.0), so 0 means this mutation adds no loot of its own (a mob with only this one drops nothing).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()), delegate(MutationConfig m, float v)
				{
					m.mutations[mid].lootMultiplier = v;
				});
				if (mutationDef.wildLootOnly)
				{
					binder.Add(text2, "Loot bonus only when wild", def: true, D("On: the loot multiplier above only applies to wild creatures. A tamed or Loyal one drops without it, so a bonus that pays for a fight can't be farmed from animals a player keeps."), delegate(MutationConfig m, bool v)
					{
						m.mutations[mid].wildLootOnly = v;
					});
				}
				if (!Tunable.TryGetValue(mid, out var value2))
				{
					continue;
				}
				string[] array = value2;
				foreach (string text3 in array)
				{
					string k = text3;
					if (k == "tint" || k.EndsWith("Colour", StringComparison.Ordinal))
					{
						AddTint(binder, text2, mid, mutationDef, k);
					}
					else
					{
						if (!mutationDef.effects.TryGetValue(k, out var value3) || value3 == null)
						{
							continue;
						}
						string text4 = HelpText(mid, k);
						if (value3 is bool)
						{
							binder.Add(text2, Nice(k), (bool)value3, D(text4), delegate(MutationConfig m, bool v)
							{
								m.mutations[mid].effects[k] = v;
							});
						}
						else if (value3 is string)
						{
							binder.Add(text2, Nice(k), (string)value3, D(text4), delegate(MutationConfig m, string v)
							{
								m.mutations[mid].effects[k] = v;
							});
						}
						else if (value3 is long || value3 is int)
						{
							binder.Add(text2, Nice(k), Convert.ToInt32(value3), D(text4), delegate(MutationConfig m, int v)
							{
								m.mutations[mid].effects[k] = (long)v;
							});
						}
						else
						{
							binder.Add(text2, Nice(k), Convert.ToSingle(value3, CultureInfo.InvariantCulture), FloatDesc(k, text4), delegate(MutationConfig m, float v)
							{
								m.mutations[mid].effects[k] = (double)v;
							});
						}
					}
				}
			}
			foreach (KeyValuePair<string, object[]> item in d.pairs.OrderBy<KeyValuePair<string, object[]>, string>((KeyValuePair<string, object[]> p) => p.Key, StringComparer.Ordinal))
			{
				string key = item.Key;
				binder.Add("05 - Combo names", key, (string)item.Value[0], Adv("Name when a mob has exactly these two mutations (also used as part of the name for bigger combinations)."), delegate(MutationConfig m, string v)
				{
					m.pairs[key][0] = v;
				});
			}
			if (d.elementalPairs != null)
			{
				foreach (KeyValuePair<string, Dictionary<string, object[]>> item2 in d.elementalPairs.OrderBy<KeyValuePair<string, Dictionary<string, object[]>>, string>((KeyValuePair<string, Dictionary<string, object[]>> x) => x.Key, StringComparer.Ordinal))
				{
					foreach (KeyValuePair<string, object[]> item3 in item2.Value.OrderBy<KeyValuePair<string, object[]>, string>((KeyValuePair<string, object[]> x) => x.Key, StringComparer.Ordinal))
					{
						string element = item2.Key;
						string other = item3.Key;
						binder.Add("06 - Elemental combo names", element + "+" + other, (string)item3.Value[0], Adv("Name of an Elemental creature of this element with this one other mutation (also part of bigger combinations)."), delegate(MutationConfig m, string v)
						{
							m.elementalPairs[element][other][0] = v;
						});
					}
				}
			}
			return binder.Apply;
		}

		private static void AddTint(Binder b, string sec, string mid, MutationDef def, string key = "tint")
		{
			string prefix = ((key == "tint") ? "tint" : key.Substring(0, key.Length - "Colour".Length));
			string key2 = key switch
			{
				"exodiaColour" => "Exodia glow colour", 
				"chargeColour" => "Charge colour", 
				"ambientColour" => "Look colour", 
				"tint" => "Tint colour", 
				_ => "Colour", 
			};
			if (!def.effects.TryGetValue(prefix + "R", out var value) || !def.effects.TryGetValue(prefix + "G", out var value2) || !def.effects.TryGetValue(prefix + "B", out var value3))
			{
				return;
			}
			string defHex = ToHex(Convert.ToSingle(value, CultureInfo.InvariantCulture), Convert.ToSingle(value2, CultureInfo.InvariantCulture), Convert.ToSingle(value3, CultureInfo.InvariantCulture));
			b.Add(sec, key2, defHex, D(Help[key]), delegate(MutationConfig m, string v)
			{
				if (!string.Equals((v ?? "").Trim().TrimStart('#'), defHex.TrimStart('#'), StringComparison.OrdinalIgnoreCase) && FromHex(v, out var r, out var g, out var b2))
				{
					Dictionary<string, object> effects = m.mutations[mid].effects;
					effects[prefix + "R"] = (double)r;
					effects[prefix + "G"] = (double)g;
					effects[prefix + "B"] = (double)b2;
				}
			});
		}

		private static string ToHex(float r, float g, float b)
		{
			Func<float, int> func = (float x) => Math.Max(0, Math.Min(255, (int)Math.Round(x * 255f)));
			return "#" + func(r).ToString("X2") + func(g).ToString("X2") + func(b).ToString("X2");
		}

		private static bool FromHex(string v, out float r, out float g, out float b)
		{
			r = (g = (b = 0f));
			v = (v ?? "").Trim().TrimStart('#');
			if (v.Length != 6)
			{
				return false;
			}
			if (!int.TryParse(v, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			r = (float)((result >> 16) & 0xFF) / 255f;
			g = (float)((result >> 8) & 0xFF) / 255f;
			b = (float)(result & 0xFF) / 255f;
			return true;
		}

		public static MutationConfig Build(string defaultText, List<Action<MutationConfig>> apply)
		{
			MutationConfig mutationConfig = MutationConfig.FromText(defaultText);
			foreach (Action<MutationConfig> item in apply)
			{
				item(mutationConfig);
			}
			return mutationConfig.Rebuild();
		}

		private static string Nice(string key)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < key.Length; i++)
			{
				char c = key[i];
				if (i == 0)
				{
					stringBuilder.Append(char.ToUpperInvariant(c));
				}
				else if (char.IsUpper(c))
				{
					stringBuilder.Append(' ').Append(char.ToLowerInvariant(c));
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static string Csv(List<string> l)
		{
			if (l != null)
			{
				return string.Join(", ", l.ToArray());
			}
			return "";
		}

		private static List<string> Split(string s)
		{
			return (from x in (s ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select x.Trim() into x
				where x.Length > 0
				select x).ToList();
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? IsAdvanced;
	}
	public static class ConfigMigrate
	{
		private static readonly Regex NewName = new Regex("^0([1-9] - .+)$");

		public static void Run(ConfigFile f)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			try
			{
				PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				Dictionary<ConfigDefinition, string> dictionary = ((property != null) ? (property.GetValue(f, null) as Dictionary<ConfigDefinition, string>) : null);
				if (dictionary == null || dictionary.Count == 0)
				{
					return;
				}
				int num = 0;
				foreach (ConfigDefinition item in f.Keys.ToList())
				{
					Match match = NewName.Match(item.Section);
					if (!match.Success)
					{
						continue;
					}
					ConfigDefinition key = new ConfigDefinition(match.Groups[1].Value, item.Key);
					if (dictionary.TryGetValue(key, out var value))
					{
						ConfigEntryBase val = f[item];
						if (object.Equals(val.BoxedValue, val.DefaultValue))
						{
							val.SetSerializedValue(value);
							num++;
						}
						dictionary.Remove(key);
					}
				}
				if (num > 0)
				{
					f.Save();
					Plugin.Log.LogInfo((object)("Settings: moved " + num + " value(s) from the old section names to the new ones (01 - ... 09 - ...)"));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Settings from before the section rename could not be carried over: " + ex.Message));
			}
		}
	}
	public static class ConfigUpgrade
	{
		public static void Run(ConfigFile f, bool fileExisted)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			try
			{
				ConfigEntry<int> val = f.Bind<int>("00 - Mod", "Settings version", 0, new ConfigDescription("Used by the mod to carry your settings across updates. Leave it alone.", (AcceptableValueBase)null, Array.Empty<object>()));
				if (!fileExisted)
				{
					val.Value = 4;
					return;
				}
				int value = val.Value;
				if (value >= 4)
				{
					return;
				}
				List<ConfigVersionRules.Change> list = ConfigVersionRules.Plan(ConfigVersionRules.Steps, value, 4, delegate(string section, string key)
				{
					foreach (ConfigDefinition key in f.Keys)
					{
						if (key.Section == section && key.Key == key)
						{
							return f[key].GetSerializedValue();
						}
					}
					return (string)null;
				});
				if (ConfigVersionRules.AnyReplaced(list))
				{
					try
					{
						string text = f.ConfigFilePath + ".bak-v" + value;
						if (File.Exists(f.ConfigFilePath) && !File.Exists(text))
						{
							File.Copy(f.ConfigFilePath, text);
							Plugin.Log.LogInfo((object)("Settings: the old settings file was kept as " + Path.GetFileName(text)));
						}
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Settings: could not copy the old settings file (" + ex.Message + "); the update is not applied"));
						return;
					}
				}
				foreach (ConfigVersionRules.Change item in list)
				{
					string text2 = item.Step.Section + " / " + item.Step.Key;
					if (item.Outcome == ConfigVersionRules.Outcome.Replaced)
					{
						foreach (ConfigDefinition key2 in f.Keys)
						{
							if (key2.Section == item.Step.Section && key2.Key == item.Step.Key)
							{
								f[key2].SetSerializedValue(item.Step.NewDefault);
								break;
							}
						}
						Plugin.Log.LogInfo((object)("Settings: " + text2 + " " + item.Was + " -> " + item.Step.NewDefault + " (the new default; yours was the old one). " + item.Step.Note));
					}
					else if (item.Outcome == ConfigVersionRules.Outcome.KeptCustom)
					{
						Plugin.Log.LogInfo((object)("Settings: " + text2 + " stays " + item.Was + " (you changed it; the new default is " + item.Step.NewDefault + "). " + item.Step.Note));
					}
				}
				val.Value = ConfigVersionRules.After(value, 4);
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("Settings: the update of an older settings file did not run (" + ex2.Message + ")"));
			}
		}
	}
	public static class ConfigSync
	{
		public const string Rpc = "pm_config";

		public const string VersionRpc = "pm_version";

		public const string HelloRpc = "pm_hello";

		public const int Protocol = 1;

		private static string _mine;

		private static string _lastSent;

		public static bool Greeted;

		private static float _readySince = -1f;

		private static bool _missingHandled;

		public const float HandshakeWait = 12f;

		public const float ClientWait = 30f;

		private const float KickGrace = 1.5f;

		private static readonly Dictionary<long, string> _hellos = new Dictionary<long, string>();

		private static readonly Dictionary<long, float> _seen = new Dictionary<long, float>();

		private static readonly Dictionary<long, float> _closeAt = new Dictionary<long, float>();

		private static float _nextCheck;

		public static string Mine
		{
			get
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Expected O, but got Unknown
				if (_mine == null)
				{
					string text = "?";
					try
					{
						BepInPlugin val = (BepInPlugin)Attribute.GetCustomAttribute(typeof(Plugin), typeof(BepInPlugin));
						if (val != null)
						{
							text = val.Version.ToString();
						}
					}
					catch (Exception e)
					{
						Safe.Err("ConfigSync:29", e);
					}
					_mine = text + "/p" + 1;
				}
				return _mine;
			}
		}

		public static void OnVersion(ZRpc rpc, string server)
		{
			if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer())
			{
				Greeted = true;
				try
				{
					rpc.Invoke("pm_hello", new object[1] { Mine });
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Config sync could not answer the server: " + ex.Message));
				}
				if (!(server == Mine))
				{
					Reject(Loc.T("msg_version_mismatch", server, Mine));
				}
			}
		}

		public static HandshakeRules.State Handshake()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return HandshakeRules.State.NotApplicable;
			}
			bool flag = false;
			float seconds = 0f;
			if (!instance.IsServer())
			{
				ZNetPeer serverPeer = instance.GetServerPeer();
				flag = serverPeer != null && serverPeer.IsReady();
				if (flag)
				{
					if (_readySince < 0f)
					{
						_readySince = Time.realtimeSinceStartup;
					}
					seconds = Time.realtimeSinceStartup - _readySince;
				}
			}
			return HandshakeRules.Of(instance.IsServer(), flag, Greeted, seconds, 12f);
		}

		public static void ResetHandshake()
		{
			Greeted = false;
			_readySince = -1f;
			_missingHandled = false;
		}

		public static void ResetServer()
		{
			_hellos.Clear();
			_seen.Clear();
			_closeAt.Clear();
			_nextCheck = 0f;
		}

		public static bool MayRoll()
		{
			return HandshakeRules.MayRoll(Handshake());
		}

		public static void Watch()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance != (Object)null && instance.IsServer())
			{
				ServerWatch();
			}
			else if (!_missingHandled && Handshake() == HandshakeRules.State.Missing)
			{
				_missingHandled = true;
				Reject(Loc.T("msg_no_server_mod"));
			}
		}

		public static void OnHello(ZRpc rpc, string theirs)
		{
			try
			{
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance == (Object)null || !instance.IsServer())
				{
					return;
				}
				foreach (ZNetPeer peer in instance.GetPeers())
				{
					if (peer != null && peer.m_rpc == rpc)
					{
						_hellos[peer.m_uid] = theirs ?? "";
						break;
					}
				}
			}
			catch (Exception e)
			{
				Safe.Err("ConfigSync.OnHello", e);
			}
		}

		public static void ServerWatch()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || !instance.IsServer() || (Plugin.RequireClientMod != null && !Plugin.RequireClientMod.Value))
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < _nextCheck)
			{
				return;
			}
			_nextCheck = realtimeSinceStartup + 0.5f;
			HashSet<long> hashSet = new HashSet<long>();
			ZNetPeer[] array = instance.GetPeers().ToArray();
			foreach (ZNetPeer val in array)
			{
				if (val == null || val.m_rpc == null || !val.IsReady())
				{
					continue;
				}
				long uid = val.m_uid;
				hashSet.Add(uid);
				if (_closeAt.TryGetValue(uid, out var value))
				{
					if (realtimeSinceStartup >= value)
					{
						_closeAt.Remove(uid);
						Close(instance, val);
					}
					continue;
				}
				if (!_seen.TryGetValue(uid, out var value2))
				{
					value2 = realtimeSinceStartup;
					_seen[uid] = realtimeSinceStartup;
				}
				_hellos.TryGetValue(uid, out var value3);
				HandshakeRules.Verdict verdict = HandshakeRules.Client(value3, Mine, realtimeSinceStartup - value2, 30f);
				if (HandshakeRules.Kick(verdict))
				{
					Plugin.Log.LogWarning((object)(Loc.T("msg_prefix") + ((verdict == HandshakeRules.Verdict.KickMismatch) ? ("Turned away " + Describe(val) + ": it runs Mutagenic Wilds " + value3 + " and this server runs " + Mine + ".") : ("Turned away " + Describe(val) + ": it does not run Mutagenic Wilds (nothing answered in " + 30f + " s). Set \"Require Mutagenic Wilds on players\" off to let such players in."))));
					try
					{
						val.m_rpc.Invoke("Error", new object[1] { 3 });
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Could not tell " + Describe(val) + " why: " + ex.Message));
					}
					_closeAt[uid] = realtimeSinceStartup + 1.5f;
				}
			}
			Prune(_hellos, hashSet);
			Prune(_seen, hashSet);
			Prune(_closeAt, hashSet);
		}

		private static void Close(ZNet net, ZNetPeer peer)
		{
			try
			{
				net.Disconnect(peer);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not disconnect " + Describe(peer) + ": " + ex.Message));
			}
		}

		private static string Describe(ZNetPeer peer)
		{
			try
			{
				return string.IsNullOrEmpty(peer.m_playerName) ? "a player" : ("\"" + peer.m_playerName + "\"");
			}
			catch (Exception e)
			{
				Safe.Err("ConfigSync.Describe", e);
				return "a player";
			}
		}

		private static void Prune<T>(Dictionary<long, T> d, HashSet<long> live)
		{
			if (d.Count == 0)
			{
				return;
			}
			List<long> list = new List<long>();
			foreach (long key in d.Keys)
			{
				if (!live.Contains(key))
				{
					list.Add(key);
				}
			}
			foreach (long item in list)
			{
				d.Remove(item);
			}
		}

		public static void Reject(string why)
		{
			Plugin.Log.LogError((object)(Loc.T("msg_prefix") + why));
			try
			{
				if (Plugin.LeaveOnMismatch != null && !Plugin.LeaveOnMismatch.Value)
				{
					Plugin.Log.LogWarning((object)"Staying connected anyway (\"Leave on mismatch\" is off): creatures may behave differently for different players.");
					return;
				}
				ZNet instance = ZNet.instance;
				if (!((Object)(object)instance == (Object)null) && !instance.IsServer())
				{
					ZNetPeer serverPeer = instance.GetServerPeer();
					if (serverPeer != null)
					{
						instance.Disconnect(serverPeer);
					}
					if ((Object)(object)MessageHud.instance != (Object)null)
					{
						MessageHud.instance.ShowMessage((MessageType)2, "Mutagenic Wilds: " + why, 0, (Sprite)null, false, true);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not leave the server: " + ex.Message));
			}
		}

		public static void Broadcast()
		{
			try
			{
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance == (Object)null || !instance.IsServer() || Plugin.LocalCfg == null || Plugin.LocalCfg.Hash == _lastSent)
				{
					return;
				}
				_lastSent = Plugin.LocalCfg.Hash;
				foreach (ZNetPeer peer in instance.GetPeers())
				{
					if (peer != null && peer.m_rpc != null && peer.IsReady())
					{
						peer.m_rpc.Invoke("pm_config", new object[1] { Plugin.LocalCfg.RawText });
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Config sync could not broadcast the changed settings: " + ex.Message));
			}
		}

		public static void OnConfig(ZRpc rpc, string json)
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				MutationConfig mutationConfig = MutationConfig.FromText(json);
				Plugin.OnServerCfg = true;
				if (Plugin.Cfg == null || !(mutationConfig.Hash == Plugin.Cfg.Hash))
				{
					Plugin.Cfg = mutationConfig;
					Plugin.CfgEpoch++;
					Plugin.Log.LogInfo((object)("Using the server's mutation config (hash " + mutationConfig.Hash.Substring(0, 8) + ")"));
				}
			}
			catch (Exception ex)
			{
				Reject(Loc.T("msg_config_unreadable", ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ConfigSyncResetPatch
	{
		private static void Prefix()
		{
			Plugin.UseLocalConfig();
			ConfigSync.ResetHandshake();
			ConfigSync.ResetServer();
		}
	}
	[HarmonyPatch]
	internal static class ConfigSyncWatchPatch
	{
		private static MethodBase TargetMethod()
		{
			return PatchUtil.FirstMethod(typeof(ZNet), "Update");
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix()
		{
			try
			{
				ConfigSync.Watch();
			}
			catch (Exception e)
			{
				Safe.Err("ConfigSync.Watch", e);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class ConfigSyncListenPatch
	{
		private static void Postfix(ZNetPeer peer)
		{
			try
			{
				peer.m_rpc.Register<string>("pm_config", (Action<ZRpc, string>)ConfigSync.OnConfig);
				peer.m_rpc.Register<string>("pm_version", (Action<ZRpc, string>)ConfigSync.OnVersion);
				peer.m_rpc.Register<string>("pm_hello", (Action<ZRpc, string>)ConfigSync.OnHello);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Config sync could not listen: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	internal static class ConfigSyncSendPatch
	{
		private static void Postfix(ZNet __instance, ZRpc rpc)
		{
			if ((Object)(object)__instance == (Object)null || !__instance.IsServer() || rpc == null || Plugin.LocalCfg == null)
			{
				return;
			}
			try
			{
				rpc.Invoke("pm_version", new object[1] { ConfigSync.Mine });
				rpc.Invoke("pm_config", new object[1] { Plugin.LocalCfg.RawText });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Config sync could not send: " + ex.Message));
			}
		}
	}
	public class PairDef
	{
		public string key;

		public string name;

		public bool isTitle;

		public int priority;
	}
	public class MutationDef
	{
		public string label;

		public string adjective;

		public int weight;

		public bool enabled = true;

		public bool firstOnly;

		public string requiresBase;

		public string passiveNeeds;

		public bool passiveNeedsUnlessArmed;

		public string passiveBlockedBy;

		public bool passiveVariant;

		public float lootMultiplier = 1f;

		public bool wildLootOnly;

		public Dictionary<string, object> effects = new Dictionary<string, object>();
	}
	public class EligibilityCfg
	{
		public bool excludeBosses = true;

		public bool excludeTamed = true;

		public bool excludeSummonedAndEventMobs;

		public bool excludePassive;

		public bool excludeMinibosses = true;

		public bool excludeEpicLootBounties = true;
	}
	public class MobOverrides
	{
		public List<string> passive = new List<string>();

		public List<string> hostile = new List<string>();

		public List<string> ranged = new List<string>();

		public List<string> neverMutate = new List<string>();

		public List<string> splitsInto = new List<string>();

		public List<string> miniboss = new List<string>();

		public List<string> elemental = new List<string>();

		[JsonIgnore]
		public HashSet<string> PassiveSet;

		[JsonIgnore]
		pub

Newtonsoft.Json.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Schema, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
[assembly: CLSCompliant(true)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Newtonsoft")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
[assembly: AssemblyFileVersion("13.0.3.27908")]
[assembly: AssemblyInformationalVersion("13.0.3+0a2e291c0d9c0c7675d445703e51750363a549ef")]
[assembly: AssemblyProduct("Json.NET")]
[assembly: AssemblyTitle("Json.NET .NET 4.5")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JamesNK/Newtonsoft.Json")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("13.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class NotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public NotNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	internal sealed class MaybeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	internal sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	internal class DoesNotReturnIfAttribute : Attribute
	{
		public bool ParameterValue { get; }

		public DoesNotReturnIfAttribute(bool parameterValue)
		{
			ParameterValue = parameterValue;
		}
	}
}
namespace Newtonsoft.Json
{
	public enum ConstructorHandling
	{
		Default,
		AllowNonPublicDefaultConstructor
	}
	public enum DateFormatHandling
	{
		IsoDateFormat,
		MicrosoftDateFormat
	}
	public enum DateParseHandling
	{
		None,
		DateTime,
		DateTimeOffset
	}
	public enum DateTimeZoneHandling
	{
		Local,
		Utc,
		Unspecified,
		RoundtripKind
	}
	public class DefaultJsonNameTable : JsonNameTable
	{
		private class Entry
		{
			internal readonly string Value;

			internal readonly int HashCode;

			internal Entry Next;

			internal Entry(string value, int hashCode, Entry next)
			{
				Value = value;
				HashCode = hashCode;
				Next = next;
			}
		}

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

		static DefaultJsonNameTable()
		{
			HashCodeRandomizer = Environment.TickCount;
		}

		public DefaultJsonNameTable()
		{
			_entries = new Entry[_mask + 1];
		}

		public override string? Get(char[] key, int start, int length)
		{
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			num += (num << 7) ^ key[start];
			int num2 = start + length;
			for (int i = start + 1; i < num2; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			int num3 = Volatile.Read(ref _mask);
			int num4 = num & num3;
			for (Entry entry = _entries[num4]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && TextEquals(entry.Value, key, start, length))
				{
					return entry.Value;
				}
			}
			return null;
		}

		public string Add(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int length = key.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			for (int i = 0; i < key.Length; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal))
				{
					return entry.Value;
				}
			}
			return AddEntry(key, num);
		}

		private string AddEntry(string str, int hashCode)
		{
			int num = hashCode & _mask;
			Entry entry = new Entry(str, hashCode, _entries[num]);
			_entries[num] = entry;
			if (_count++ == _mask)
			{
				Grow();
			}
			return entry.Value;
		}

		private void Grow()
		{
			Entry[] entries = _entries;
			int num = _mask * 2 + 1;
			Entry[] array = new Entry[num + 1];
			for (int i = 0; i < entries.Length; i++)
			{
				Entry entry = entries[i];
				while (entry != null)
				{
					int num2 = entry.HashCode & num;
					Entry next = entry.Next;
					entry.Next = array[num2];
					array[num2] = entry;
					entry = next;
				}
			}
			_entries = array;
			Volatile.Write(ref _mask, num);
		}

		private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
		{
			if (str1.Length != str2Length)
			{
				return false;
			}
			for (int i = 0; i < str1.Length; i++)
			{
				if (str1[i] != str2[str2Start + i])
				{
					return false;
				}
			}
			return true;
		}
	}
	[Flags]
	public enum DefaultValueHandling
	{
		Include = 0,
		Ignore = 1,
		Populate = 2,
		IgnoreAndPopulate = 3
	}
	public enum FloatFormatHandling
	{
		String,
		Symbol,
		DefaultValue
	}
	public enum FloatParseHandling
	{
		Double,
		Decimal
	}
	public enum Formatting
	{
		None,
		Indented
	}
	public interface IArrayPool<T>
	{
		T[] Rent(int minimumLength);

		void Return(T[]? array);
	}
	public interface IJsonLineInfo
	{
		int LineNumber { get; }

		int LinePosition { get; }

		bool HasLineInfo();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonArrayAttribute : JsonContainerAttribute
	{
		private bool _allowNullItems;

		public bool AllowNullItems
		{
			get
			{
				return _allowNullItems;
			}
			set
			{
				_allowNullItems = value;
			}
		}

		public JsonArrayAttribute()
		{
		}

		public JsonArrayAttribute(bool allowNullItems)
		{
			_allowNullItems = allowNullItems;
		}

		public JsonArrayAttribute(string id)
			: base(id)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
	public sealed class JsonConstructorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public abstract class JsonContainerAttribute : Attribute
	{
		internal bool? _isReference;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType
		{
			get
			{
				return _namingStrategyType;
			}
			set
			{
				_namingStrategyType = value;
				NamingStrategyInstance = null;
			}
		}

		public object[]? NamingStrategyParameters
		{
			get
			{
				return _namingStrategyParameters;
			}
			set
			{
				_namingStrategyParameters = value;
				NamingStrategyInstance = null;
			}
		}

		internal NamingStrategy? NamingStrategyInstance { get; set; }

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		protected JsonContainerAttribute()
		{
		}

		protected JsonContainerAttribute(string id)
		{
			Id = id;
		}
	}
	public static class JsonConvert
	{
		public static readonly string True = "true";

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

		public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }

		public static string ToString(DateTime value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
		}

		public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
		{
			DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(DateTimeOffset value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat);
		}

		public static string ToString(DateTimeOffset value, DateFormatHandling format)
		{
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(bool value)
		{
			if (!value)
			{
				return False;
			}
			return True;
		}

		public static string ToString(char value)
		{
			return ToString(char.ToString(value));
		}

		public static string ToString(Enum value)
		{
			return value.ToString("D");
		}

		public static string ToString(int value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(short value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ushort value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(uint value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(long value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		private static string ToStringInternal(BigInteger value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ulong value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(float value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value)))
			{
				return text;
			}
			if (floatFormatHandling == FloatFormatHandling.DefaultValue)
			{
				if (nullable)
				{
					return Null;
				}
				return "0.0";
			}
			return quoteChar + text + quoteChar;
		}

		public static string ToString(double value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureDecimalPlace(double value, string text)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (StringUtils.IndexOf(text, '.') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		public static string ToString(byte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(sbyte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(decimal value)
		{
			return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
		}

		public static string ToString(Guid value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(Guid value, char quoteChar)
		{
			string text = value.ToString("D", CultureInfo.InvariantCulture);
			string text2 = quoteChar.ToString(CultureInfo.InvariantCulture);
			return text2 + text + text2;
		}

		public static string ToString(TimeSpan value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(TimeSpan value, char quoteChar)
		{
			return ToString(value.ToString(), quoteChar);
		}

		public static string ToString(Uri? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ToString(value, '"');
		}

		internal static string ToString(Uri value, char quoteChar)
		{
			return ToString(value.OriginalString, quoteChar);
		}

		public static string ToString(string? value)
		{
			return ToString(value, '"');
		}

		public static string ToString(string? value, char delimiter)
		{
			return ToString(value, delimiter, StringEscapeHandling.Default);
		}

		public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
		{
			if (delimiter != '"' && delimiter != '\'')
			{
				throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
			}
			return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling);
		}

		public static string ToString(object? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ConvertUtils.GetTypeCode(value.GetType()) switch
			{
				PrimitiveTypeCode.String => ToString((string)value), 
				PrimitiveTypeCode.Char => ToString((char)value), 
				PrimitiveTypeCode.Boolean => ToString((bool)value), 
				PrimitiveTypeCode.SByte => ToString((sbyte)value), 
				PrimitiveTypeCode.Int16 => ToString((short)value), 
				PrimitiveTypeCode.UInt16 => ToString((ushort)value), 
				PrimitiveTypeCode.Int32 => ToString((int)value), 
				PrimitiveTypeCode.Byte => ToString((byte)value), 
				PrimitiveTypeCode.UInt32 => ToString((uint)value), 
				PrimitiveTypeCode.Int64 => ToString((long)value), 
				PrimitiveTypeCode.UInt64 => ToString((ulong)value), 
				PrimitiveTypeCode.Single => ToString((float)value), 
				PrimitiveTypeCode.Double => ToString((double)value), 
				PrimitiveTypeCode.DateTime => ToString((DateTime)value), 
				PrimitiveTypeCode.Decimal => ToString((decimal)value), 
				PrimitiveTypeCode.DBNull => Null, 
				PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), 
				PrimitiveTypeCode.Guid => ToString((Guid)value), 
				PrimitiveTypeCode.Uri => ToString((Uri)value), 
				PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), 
				PrimitiveTypeCode.BigInteger => ToStringInternal((BigInteger)value), 
				_ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), 
			};
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value)
		{
			return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting)
		{
			return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			jsonSerializer.Formatting = formatting;
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
		{
			StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture);
			using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
			{
				jsonTextWriter.Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize(jsonTextWriter, value, type);
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value)
		{
			return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, JsonSerializerSettings settings)
		{
			return DeserializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
		{
			return DeserializeObject<T>(value);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings)
		{
			return DeserializeObject<T>(value, settings);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return DeserializeObject(value, type, settings);
		}

		public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
		{
			ValidationUtils.ArgumentNotNull(value, "value");
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			if (!jsonSerializer.IsCheckAdditionalContentSet())
			{
				jsonSerializer.CheckAdditionalContent = true;
			}
			using JsonTextReader reader = new JsonTextReader(new StringReader(value));
			return jsonSerializer.Deserialize(reader, type);
		}

		[DebuggerStepThrough]
		public static void PopulateObject(string value, object target)
		{
			PopulateObject(value, target, null);
		}

		public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			using JsonReader jsonReader = new JsonTextReader(new StringReader(value));
			jsonSerializer.Populate(jsonReader, target);
			if (settings == null || !settings.CheckAdditionalContent)
			{
				return;
			}
			while (jsonReader.Read())
			{
				if (jsonReader.TokenType != JsonToken.Comment)
				{
					throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
				}
			}
		}

		public static string SerializeXmlNode(XmlNode? node)
		{
			return SerializeXmlNode(node, Formatting.None);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XmlDocument? DeserializeXmlNode(string value)
		{
			return DeserializeXmlNode(value, null);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter);
		}

		public static string SerializeXNode(XObject? node)
		{
			return SerializeXNode(node, Formatting.None);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting)
		{
			return SerializeXNode(node, formatting, omitRootObject: false);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XDocument? DeserializeXNode(string value)
		{
			return DeserializeXNode(value, null);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter);
		}
	}
	public abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

		public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

		public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		public abstract bool CanConvert(Type objectType);
	}
	public abstract class JsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T))))
			{
				throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			WriteJson(writer, (T)value, serializer);
		}

		public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			bool flag = existingValue == null;
			if (!flag && !(existingValue is T))
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer);
		}

		public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonConverterAttribute : Attribute
	{
		private readonly Type _converterType;

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

		public JsonConverterAttribute(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			_converterType = converterType;
		}

		public JsonConverterAttribute(Type converterType, params object[] converterParameters)
			: this(converterType)
		{
			ConverterParameters = converterParameters;
		}
	}
	public class JsonConverterCollection : Collection<JsonConverter>
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonDictionaryAttribute : JsonContainerAttribute
	{
		public JsonDictionaryAttribute()
		{
		}

		public JsonDictionaryAttribute(string id)
			: base(id)
		{
		}
	}
	[Serializable]
	public class JsonException : Exception
	{
		public JsonException()
		{
		}

		public JsonException(string message)
			: base(message)
		{
		}

		public JsonException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		public JsonException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			return new JsonException(message);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public class JsonExtensionDataAttribute : Attribute
	{
		public bool WriteData { get; set; }

		public bool ReadData { get; set; }

		public JsonExtensionDataAttribute()
		{
			WriteData = true;
			ReadData = true;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonIgnoreAttribute : Attribute
	{
	}
	public abstract class JsonNameTable
	{
		public abstract string? Get(char[] key, int start, int length);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonObjectAttribute : JsonContainerAttribute
	{
		private MemberSerialization _memberSerialization;

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

		public MemberSerialization MemberSerialization
		{
			get
			{
				return _memberSerialization;
			}
			set
			{
				_memberSerialization = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public NullValueHandling ItemNullValueHandling
		{
			get
			{
				return _itemNullValueHandling.GetValueOrDefault();
			}
			set
			{
				_itemNullValueHandling = value;
			}
		}

		public Required ItemRequired
		{
			get
			{
				return _itemRequired.GetValueOrDefault();
			}
			set
			{
				_itemRequired = value;
			}
		}

		public JsonObjectAttribute()
		{
		}

		public JsonObjectAttribute(MemberSerialization memberSerialization)
		{
			MemberSerialization = memberSerialization;
		}

		public JsonObjectAttribute(string id)
			: base(id)
		{
		}
	}
	internal enum JsonContainerType
	{
		None,
		Object,
		Array,
		Constructor
	}
	internal struct JsonPosition
	{
		private static readonly char[] SpecialCharacters = new char[18]
		{
			'.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t',
			'\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029'
		};

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

		public JsonPosition(JsonContainerType type)
		{
			Type = type;
			HasIndex = TypeHasIndex(type);
			Position = -1;
			PropertyName = null;
		}

		internal int CalculateLength()
		{
			switch (Type)
			{
			case JsonContainerType.Object:
				return PropertyName.Length + 5;
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				return MathUtils.IntLength((ulong)Position) + 2;
			default:
				throw new ArgumentOutOfRangeException("Type");
			}
		}

		internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
		{
			switch (Type)
			{
			case JsonContainerType.Object:
			{
				string propertyName = PropertyName;
				if (propertyName.IndexOfAny(SpecialCharacters) != -1)
				{
					sb.Append("['");
					if (writer == null)
					{
						writer = new StringWriter(sb);
					}
					JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
					sb.Append("']");
				}
				else
				{
					if (sb.Length > 0)
					{
						sb.Append('.');
					}
					sb.Append(propertyName);
				}
				break;
			}
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				sb.Append('[');
				sb.Append(Position);
				sb.Append(']');
				break;
			}
		}

		internal static bool TypeHasIndex(JsonContainerType type)
		{
			if (type != JsonContainerType.Array)
			{
				return type == JsonContainerType.Constructor;
			}
			return true;
		}

		internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
		{
			int num = 0;
			if (positions != null)
			{
				for (int i = 0; i < positions.Count; i++)
				{
					num += positions[i].CalculateLength();
				}
			}
			if (currentPosition.HasValue)
			{
				num += currentPosition.GetValueOrDefault().CalculateLength();
			}
			StringBuilder stringBuilder = new StringBuilder(num);
			StringWriter writer = null;
			char[] buffer = null;
			if (positions != null)
			{
				foreach (JsonPosition position in positions)
				{
					position.WriteTo(stringBuilder, ref writer, ref buffer);
				}
			}
			currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer);
			return stringBuilder.ToString();
		}

		internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
		{
			if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
			{
				message = message.Trim();
				if (!StringUtils.EndsWith(message, '.'))
				{
					message += ".";
				}
				message += " ";
			}
			message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
			}
			message += ".";
			return message;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonPropertyAttribute : Attribute
	{
		internal NullValueHandling? _nullValueHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType { get; set; }

		public object[]? NamingStrategyParameters { get; set; }

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public int Order
		{
			get
			{
				return _order.GetValueOrDefault();
			}
			set
			{
				_order = value;
			}
		}

		public Required Required
		{
			get
			{
				return _required.GetValueOrDefault();
			}
			set
			{
				_required = value;
			}
		}

		public string? PropertyName { get; set; }

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public JsonPropertyAttribute()
		{
		}

		public JsonPropertyAttribute(string propertyName)
		{
			PropertyName = propertyName;
		}
	}
	public abstract class JsonReader : IDisposable
	{
		protected internal enum State
		{
			Start,
			Complete,
			Property,
			ObjectStart,
			Object,
			ArrayStart,
			Array,
			Closed,
			PostValue,
			ConstructorStart,
			Constructor,
			Error,
			Finished
		}

		private JsonToken _tokenType;

		private object? _value;

		internal char _quoteChar;

		internal State _currentState;

		private JsonPosition _currentPosition;

		private CultureInfo? _culture;

		private DateTimeZoneHandling _dateTimeZoneHandling;

		private int? _maxDepth;

		private bool _hasExceededMaxDepth;

		internal DateParseHandling _dateParseHandling;

		internal FloatParseHandling _floatParseHandling;

		private string? _dateFormatString;

		private List<JsonPosition>? _stack;

		protected State CurrentState => _currentState;

		public bool CloseInput { get; set; }

		public bool SupportMultipleContent { get; set; }

		public virtual char QuoteChar
		{
			get
			{
				return _quoteChar;
			}
			protected internal set
			{
				_quoteChar = value;
			}
		}

		public DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling;
			}
			set
			{
				if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateTimeZoneHandling = value;
			}
		}

		public DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling;
			}
			set
			{
				if (value < DateParseHandling.None || value > DateParseHandling.DateTimeOffset)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateParseHandling = value;
			}
		}

		public FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling;
			}
			set
			{
				if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_floatParseHandling = value;
			}
		}

		public string? DateFormatString
		{
			get
			{
				return _dateFormatString;
			}
			set
			{
				_dateFormatString = value;
			}
		}

		public int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
			}
		}

		public virtual JsonToken TokenType => _tokenType;

		public virtual object? Value => _value;

		public virtual Type? ValueType => _value?.GetType();

		public virtual int Depth
		{
			get
			{
				int num = _stack?.Count ?? 0;
				if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
				{
					return num;
				}
				return num + 1;
			}
		}

		public virtual string Path
		{
			get
			{
				if (_currentPosition.Type == JsonContainerType.None)
				{
					return string.Empty;
				}
				JsonPosition? currentPosition = ((_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart) ? new JsonPosition?(_currentPosition) : null);
				return JsonPosition.BuildPath(_stack, currentPosition);
			}
		}

		public CultureInfo Culture
		{
			get
			{
				return _culture ?? CultureInfo.InvariantCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync();
		}

		public async Task SkipAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TokenType == JsonToken.PropertyName)
			{
				await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false) && depth < Depth)
				{
				}
			}
		}

		internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken)
		{
			if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
			{
				throw CreateUnexpectedEndException();
			}
		}

		public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean());
		}

		public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<byte[]>() ?? Task.FromResult(ReadAsBytes());
		}

		internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
		{
			List<byte> buffer = new List<byte>();
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(buffer));
			byte[] array = buffer.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime());
		}

		public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset());
		}

		public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal());
		}

		public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return Task.FromResult(ReadAsDouble());
		}

		public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32());
		}

		public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<string>() ?? Task.FromResult(ReadAsString());
		}

		internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken)
		{
			bool flag = await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (flag)
			{
				flag = await MoveToContentAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			return flag;
		}

		internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType = TokenType;
			if (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				return MoveToContentFromNonContentAsync(cancellationToken);
			}
			return AsyncUtils.True;
		}

		private async Task<bool> MoveToContentFromNonContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType;
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					return false;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment);
			return true;
		}

		internal JsonPosition GetPosition(int depth)
		{
			if (_stack != null && depth < _stack.Count)
			{
				return _stack[depth];
			}
			return _currentPosition;
		}

		protected JsonReader()
		{
			_currentState = State.Start;
			_dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
			_dateParseHandling = DateParseHandling.DateTime;
			_floatParseHandling = FloatParseHandling.Double;
			_maxDepth = 64;
			CloseInput = true;
		}

		private void Push(JsonContainerType value)
		{
			UpdateScopeWithFinishedValue();
			if (_currentPosition.Type == JsonContainerType.None)
			{
				_currentPosition = new JsonPosition(value);
				return;
			}
			if (_stack == null)
			{
				_stack = new List<JsonPosition>();
			}
			_stack.Add(_currentPosition);
			_currentPosition = new JsonPosition(value);
			if (!_maxDepth.HasValue || !(Depth + 1 > _maxDepth) || _hasExceededMaxDepth)
			{
				return;
			}
			_hasExceededMaxDepth = true;
			throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
		}

		private JsonContainerType Pop()
		{
			JsonPosition currentPosition;
			if (_stack != null && _stack.Count > 0)
			{
				currentPosition = _currentPosition;
				_currentPosition = _stack[_stack.Count - 1];
				_stack.RemoveAt(_stack.Count - 1);
			}
			else
			{
				currentPosition = _currentPosition;
				_currentPosition = default(JsonPosition);
			}
			if (_maxDepth.HasValue && Depth <= _maxDepth)
			{
				_hasExceededMaxDepth = false;
			}
			return currentPosition.Type;
		}

		private JsonContainerType Peek()
		{
			return _currentPosition.Type;
		}

		public abstract bool Read();

		public virtual int? ReadAsInt32()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is int)
				{
					return (int)value;
				}
				int num;
				if (value is BigInteger bigInteger)
				{
					num = (int)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToInt32(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Integer, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadInt32String(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal int? ReadInt32String(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (int.TryParse(s, NumberStyles.Integer, Culture, out var result))
			{
				SetToken(JsonToken.Integer, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual string? ReadAsString()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.String:
				return (string)Value;
			default:
				if (JsonTokenUtils.IsPrimitiveToken(contentToken))
				{
					object value = Value;
					if (value != null)
					{
						string text = ((!(value is IFormattable formattable)) ? ((value is Uri uri) ? uri.OriginalString : value.ToString()) : formattable.ToString(null, Culture));
						SetToken(JsonToken.String, text, updateIndex: false);
						return text;
					}
				}
				throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		public virtual byte[]? ReadAsBytes()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.StartObject:
			{
				ReadIntoWrappedTypeObject();
				byte[] array2 = ReadAsBytes();
				ReaderReadAndAssert();
				if (TokenType != JsonToken.EndObject)
				{
					throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
				}
				SetToken(JsonToken.Bytes, array2, updateIndex: false);
				return array2;
			}
			case JsonToken.String:
			{
				string text = (string)Value;
				Guid g;
				byte[] array3 = ((text.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((!ConvertUtils.TryConvertGuid(text, out g)) ? Convert.FromBase64String(text) : g.ToByteArray()));
				SetToken(JsonToken.Bytes, array3, updateIndex: false);
				return array3;
			}
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Bytes:
				if (Value is Guid guid)
				{
					byte[] array = guid.ToByteArray();
					SetToken(JsonToken.Bytes, array, updateIndex: false);
					return array;
				}
				return (byte[])Value;
			case JsonToken.StartArray:
				return ReadArrayIntoByteArray();
			default:
				throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal byte[] ReadArrayIntoByteArray()
		{
			List<byte> list = new List<byte>();
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(list));
			byte[] array = list.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer)
		{
			switch (TokenType)
			{
			case JsonToken.None:
				throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
			case JsonToken.Integer:
				buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
				return false;
			case JsonToken.EndArray:
				return true;
			case JsonToken.Comment:
				return false;
			default:
				throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		public virtual double? ReadAsDouble()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is double)
				{
					return (double)value;
				}
				double num = ((!(value is BigInteger bigInteger)) ? Convert.ToDouble(value, CultureInfo.InvariantCulture) : ((double)bigInteger));
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDoubleString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal double? ReadDoubleString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual bool? ReadAsBoolean()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				bool flag = ((!(Value is BigInteger bigInteger)) ? Convert.ToBoolean(Value, CultureInfo.InvariantCulture) : (bigInteger != 0L));
				SetToken(JsonToken.Boolean, flag, updateIndex: false);
				return flag;
			}
			case JsonToken.String:
				return ReadBooleanString((string)Value);
			case JsonToken.Boolean:
				return (bool)Value;
			default:
				throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal bool? ReadBooleanString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (bool.TryParse(s, out var result))
			{
				SetToken(JsonToken.Boolean, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual decimal? ReadAsDecimal()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is decimal)
				{
					return (decimal)value;
				}
				decimal num;
				if (value is BigInteger bigInteger)
				{
					num = (decimal)bigInteger;
				}
				else
				{
					try
					{
						num = Convert.ToDecimal(value, CultureInfo.InvariantCulture);
					}
					catch (Exception ex)
					{
						throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
					}
				}
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDecimalString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal decimal? ReadDecimalString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (decimal.TryParse(s, NumberStyles.Number, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out result) == ParseResult.Success)
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTime? ReadAsDateTime()
		{
			switch (GetContentToken())
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTimeOffset dateTimeOffset)
				{
					SetToken(JsonToken.Date, dateTimeOffset.DateTime, updateIndex: false);
				}
				return (DateTime)Value;
			case JsonToken.String:
				return ReadDateTimeString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		internal DateTime? ReadDateTimeString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out var dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTimeOffset? ReadAsDateTimeOffset()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTime dateTime)
				{
					SetToken(JsonToken.Date, new DateTimeOffset(dateTime), updateIndex: false);
				}
				return (DateTimeOffset)Value;
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadDateTimeOffsetString(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal DateTimeOffset? ReadDateTimeOffsetString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out var dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		internal void ReaderReadAndAssert()
		{
			if (!Read())
			{
				throw CreateUnexpectedEndException();
			}
		}

		internal JsonReaderException CreateUnexpectedEndException()
		{
			return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
		}

		internal void ReadIntoWrappedTypeObject()
		{
			ReaderReadAndAssert();
			if (Value != null && Value.ToString() == "$type")
			{
				ReaderReadAndAssert();
				if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
				{
					ReaderReadAndAssert();
					if (Value.ToString() == "$value")
					{
						return;
					}
				}
			}
			throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
		}

		public void Skip()
		{
			if (TokenType == JsonToken.PropertyName)
			{
				Read();
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (Read() && depth < Depth)
				{
				}
			}
		}

		protected void SetToken(JsonToken newToken)
		{
			SetToken(newToken, null, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value)
		{
			SetToken(newToken, value, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value, bool updateIndex)
		{
			_tokenType = newToken;
			_value = value;
			switch (newToken)
			{
			case JsonToken.StartObject:
				_currentState = State.ObjectStart;
				Push(JsonContainerType.Object);
				break;
			case JsonToken.StartArray:
				_currentState = State.ArrayStart;
				Push(JsonContainerType.Array);
				break;
			case JsonToken.StartConstructor:
				_currentState = State.ConstructorStart;
				Push(JsonContainerType.Constructor);
				break;
			case JsonToken.EndObject:
				ValidateEnd(JsonToken.EndObject);
				break;
			case JsonToken.EndArray:
				ValidateEnd(JsonToken.EndArray);
				break;
			case JsonToken.EndConstructor:
				ValidateEnd(JsonToken.EndConstructor);
				break;
			case JsonToken.PropertyName:
				_currentState = State.Property;
				_currentPosition.PropertyName = (string)value;
				break;
			case JsonToken.Raw:
			case JsonToken.Integer:
			case JsonToken.Float:
			case JsonToken.String:
			case JsonToken.Boolean:
			case JsonToken.Null:
			case JsonToken.Undefined:
			case JsonToken.Date:
			case JsonToken.Bytes:
				SetPostValueState(updateIndex);
				break;
			case JsonToken.Comment:
				break;
			}
		}

		internal void SetPostValueState(bool updateIndex)
		{
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
			if (updateIndex)
			{
				UpdateScopeWithFinishedValue();
			}
		}

		private void UpdateScopeWithFinishedValue()
		{
			if (_currentPosition.HasIndex)
			{
				_currentPosition.Position++;
			}
		}

		private void ValidateEnd(JsonToken endToken)
		{
			JsonContainerType jsonContainerType = Pop();
			if (GetTypeForCloseToken(endToken) != jsonContainerType)
			{
				throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, jsonContainerType));
			}
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
		}

		protected void SetStateBasedOnCurrent()
		{
			JsonContainerType jsonContainerType = Peek();
			switch (jsonContainerType)
			{
			case JsonContainerType.Object:
				_currentState = State.Object;
				break;
			case JsonContainerType.Array:
				_currentState = State.Array;
				break;
			case JsonContainerType.Constructor:
				_currentState = State.Constructor;
				break;
			case JsonContainerType.None:
				SetFinished();
				break;
			default:
				throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContainerType));
			}
		}

		private void SetFinished()
		{
			_currentState = ((!SupportMultipleContent) ? State.Finished : State.Start);
		}

		private JsonContainerType GetTypeForCloseToken(JsonToken token)
		{
			return token switch
			{
				JsonToken.EndObject => JsonContainerType.Object, 
				JsonToken.EndArray => JsonContainerType.Array, 
				JsonToken.EndConstructor => JsonContainerType.Constructor, 
				_ => throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token)), 
			};
		}

		void IDisposable.Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (_currentState != State.Closed && disposing)
			{
				Close();
			}
		}

		public virtual void Close()
		{
			_currentState = State.Closed;
			_tokenType = JsonToken.None;
			_value = null;
		}

		internal void ReadAndAssert()
		{
			if (!Read())
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter)
		{
			if (!ReadForType(contract, hasConverter))
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal bool ReadForType(JsonContract? contract, bool hasConverter)
		{
			if (hasConverter)
			{
				return Read();
			}
			switch (contract?.InternalReadType ?? ReadType.Read)
			{
			case ReadType.Read:
				return ReadAndMoveToContent();
			case ReadType.ReadAsInt32:
				ReadAsInt32();
				break;
			case ReadType.ReadAsInt64:
			{
				bool result = ReadAndMoveToContent();
				if (TokenType == JsonToken.Undefined)
				{
					throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
				}
				return result;
			}
			case ReadType.ReadAsDecimal:
				ReadAsDecimal();
				break;
			case ReadType.ReadAsDouble:
				ReadAsDouble();
				break;
			case ReadType.ReadAsBytes:
				ReadAsBytes();
				break;
			case ReadType.ReadAsBoolean:
				ReadAsBoolean();
				break;
			case ReadType.ReadAsString:
				ReadAsString();
				break;
			case ReadType.ReadAsDateTime:
				ReadAsDateTime();
				break;
			case ReadType.ReadAsDateTimeOffset:
				ReadAsDateTimeOffset();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			return TokenType != JsonToken.None;
		}

		internal bool ReadAndMoveToContent()
		{
			if (Read())
			{
				return MoveToContent();
			}
			return false;
		}

		internal bool MoveToContent()
		{
			JsonToken tokenType = TokenType;
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				if (!Read())
				{
					return false;
				}
				tokenType = TokenType;
			}
			return true;
		}

		private JsonToken GetContentToken()
		{
			JsonToken tokenType;
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
					return JsonToken.None;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.Comment);
			return tokenType;
		}
	}
	[Serializable]
	public class JsonReaderException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonReaderException()
		{
		}

		public JsonReaderException(string message)
			: base(message)
		{
		}

		public JsonReaderException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonReaderException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonReaderException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonReaderException(message, path, lineNumber, linePosition, ex);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonRequiredAttribute : Attribute
	{
	}
	[Serializable]
	public class JsonSerializationException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonSerializationException()
		{
		}

		public JsonSerializationException(string message)
			: base(message)
		{
		}

		public JsonSerializationException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonSerializationException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonSerializationException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonSerializationException(message, path, lineNumber, linePosition, ex);
		}
	}
	public class JsonSerializer
	{
		internal TypeNameHandling _typeNameHandling;

		internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;

		internal PreserveReferencesHandling _preserveReferencesHandling;

		internal ReferenceLoopHandling _referenceLoopHandling;

		internal MissingMemberHandling _missingMemberHandling;

		internal ObjectCreationHandling _objectCreationHandling;

		internal NullValueHandling _nullValueHandling;

		internal DefaultValueHandling _defaultValueHandling;

		internal ConstructorHandling _constructorHandling;

		internal MetadataPropertyHandling _metadataPropertyHandling;

		internal JsonConverterCollection? _converters;

		internal IContractResolver _contractResolver;

		internal ITraceWriter? _traceWriter;

		internal IEqualityComparer? _equalityComparer;

		internal ISerializationBinder _serializationBinder;

		internal StreamingContext _context;

		private IReferenceResolver? _referenceResolver;

		private Formatting? _formatting;

		private DateFormatHandling? _dateFormatHandling;

		private DateTimeZoneHandling? _dateTimeZoneHandling;

		private DateParseHandling? _dateParseHandling;

		private FloatFormatHandling? _floatFormatHandling;

		private FloatParseHandling? _floatParseHandling;

		private StringEscapeHandling? _stringEscapeHandling;

		private CultureInfo _culture;

		private int? _maxDepth;

		private bool _maxDepthSet;

		private bool? _checkAdditionalContent;

		private string? _dateFormatString;

		private bool _dateFormatStringSet;

		public virtual IReferenceResolver? ReferenceResolver
		{
			get
			{
				return GetReferenceResolver();
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Reference resolver cannot be null.");
				}
				_referenceResolver = value;
			}
		}

		[Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
		public virtual SerializationBinder Binder
		{
			get
			{
				if (_serializationBinder is SerializationBinder result)
				{
					return result;
				}
				if (_serializationBinder is SerializationBinderAdapter serializationBinderAdapter)
				{
					return serializationBinderAdapter.SerializationBinder;
				}
				throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = (value as ISerializationBinder) ?? new SerializationBinderAdapter(value);
			}
		}

		public virtual ISerializationBinder SerializationBinder
		{
			get
			{
				return _serializationBinder;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = value;
			}
		}

		public virtual ITraceWriter? TraceWriter
		{
			get
			{
				return _traceWriter;
			}
			set
			{
				_traceWriter = value;
			}
		}

		public virtual IEqualityComparer? EqualityComparer
		{
			get
			{
				return _equalityComparer;
			}
			set
			{
				_equalityComparer = value;
			}
		}

		public virtual TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling;
			}
			set
			{
				if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameHandling = value;
			}
		}

		[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
		public virtual FormatterAssemblyStyle TypeNameAssemblyFormat
		{
			get
			{
				return (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
			}
		}

		public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
		{
			get
			{
				return _typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = value;
			}
		}

		public virtual PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling;
			}
			set
			{
				if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_preserveReferencesHandling = value;
			}
		}

		public virtual ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling;
			}
			set
			{
				if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_referenceLoopHandling = value;
			}
		}

		public virtual MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling;
			}
			set
			{
				if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_missingMemberHandling = value;
			}
		}

		public virtual NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling;
			}
			set
			{
				if (value < NullValueHandling.Include || value > NullValueHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_nullValueHandling = value;
			}
		}

		public virtual DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling;
			}
			set
			{
				if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_defaultValueHandling = value;
			}
		}

		public virtual ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling;
			}
			set
			{
				if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_objectCreationHandling = value;
			}
		}

		public virtual ConstructorHandling ConstructorHandling
		{
			get
			{
				return _constructorHandling;
			}
			set
			{
				if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_constructorHandling = value;
			}
		}

		public virtual MetadataPropertyHandling MetadataPropertyHandling
		{
			get
			{
				return _metadataPropertyHandling;
			}
			set
			{
				if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_metadataPropertyHandling = value;
			}
		}

		public virtual JsonConverterCollection Converters
		{
			get
			{
				if (_converters == null)
				{
					_converters = new JsonConverterCollection();
				}
				return _converters;
			}
		}

		public virtual IContractResolver ContractResolver
		{
			get
			{
				return _contractResolver;
			}
			set
			{
				_contractResolver = value ?? DefaultContractResolver.Instance;
			}
		}

		public virtual StreamingContext Context
		{
			get
			{
				return _context;
			}
			set
			{
				_context = value;
			}
		}

		public virtual Formatting Formatting
		{
			get
			{
				return _formatting.GetValueOrDefault();
			}
			set
			{
				_formatting = value;
			}
		}

		public virtual DateFormatHandling DateFormatHandling
		{
			get
			{
				return _dateFormatHandling.GetValueOrDefault();
			}
			set
			{
				_dateFormatHandling = value;
			}
		}

		public virtual DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind;
			}
			set
			{
				_dateTimeZoneHandling = value;
			}
		}

		public virtual DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling ?? DateParseHandling.DateTime;
			}
			set
			{
				_dateParseHandling = value;
			}
		}

		public virtual FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling.GetValueOrDefault();
			}
			set
			{
				_floatParseHandling = value;
			}
		}

		public virtual FloatFormatHandling FloatFormatHandling
		{
			get
			{
				return _floatFormatHandling.GetValueOrDefault();
			}
			set
			{
				_floatFormatHandling = value;
			}
		}

		public virtual StringEscapeHandling StringEscapeHandling
		{
			get
			{
				return _stringEscapeHandling.GetValueOrDefault();
			}
			set
			{
				_stringEscapeHandling = value;
			}
		}

		public virtual string DateFormatString
		{
			get
			{
				return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
			}
			set
			{
				_dateFormatString = value;
				_dateFormatStringSet = true;
			}
		}

		public virtual CultureInfo Culture
		{
			get
			{
				return _culture ?? JsonSerializerSettings.DefaultCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
				_maxDepthSet = true;
			}
		}

		public virtual bool CheckAdditionalContent
		{
			get
			{
				return _checkAdditionalContent.GetValueOrDefault();
			}
			set
			{
				_checkAdditionalContent = value;
			}
		}

		public virtual event EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error;

		internal bool IsCheckAdditionalContentSet()
		{
			return _checkAdditionalContent.HasValue;
		}

		public JsonSerializer()
		{
			_referenceLoopHandling = ReferenceLoopHandling.Error;
			_missingMemberHandling = MissingMemberHandling.Ignore;
			_nullValueHandling = NullValueHandling.Include;
			_defaultValueHandling = DefaultValueHandling.Include;
			_objectCreationHandling = ObjectCreationHandling.Auto;
			_preserveReferencesHandling = PreserveReferencesHandling.None;
			_constructorHandling = ConstructorHandling.Default;
			_typeNameHandling = TypeNameHandling.None;
			_metadataPropertyHandling = MetadataPropertyHandling.Default;
			_context = JsonSerializerSettings.DefaultContext;
			_serializationBinder = DefaultSerializationBinder.Instance;
			_culture = JsonSerializerSettings.DefaultCulture;
			_contractResolver = DefaultContractResolver.Instance;
		}

		public static JsonSerializer Create()
		{
			return new JsonSerializer();
		}

		public static JsonSerializer Create(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = Create();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		public static JsonSerializer CreateDefault()
		{
			return Create(JsonConvert.DefaultSettings?.Invoke());
		}

		public static JsonSerializer CreateDefault(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = CreateDefault();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
		{
			if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
			{
				for (int i = 0; i < settings.Converters.Count; i++)
				{
					serializer.Converters.Insert(i, settings.Converters[i]);
				}
			}
			if (settings._typeNameHandling.HasValue)
			{
				serializer.TypeNameHandling = settings.TypeNameHandling;
			}
			if (settings._metadataPropertyHandling.HasValue)
			{
				serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling;
			}
			if (settings._typeNameAssemblyFormatHandling.HasValue)
			{
				serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling;
			}
			if (settings._preserveReferencesHandling.HasValue)
			{
				serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
			}
			if (settings._referenceLoopHandling.HasValue)
			{
				serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
			}
			if (settings._missingMemberHandling.HasValue)
			{
				serializer.MissingMemberHandling = settings.MissingMemberHandling;
			}
			if (settings._objectCreationHandling.HasValue)
			{
				serializer.ObjectCreationHandling = settings.ObjectCreationHandling;
			}
			if (settings._nullValueHandling.HasValue)
			{
				serializer.NullValueHandling = settings.NullValueHandling;
			}
			if (settings._defaultValueHandling.HasValue)
			{
				serializer.DefaultValueHandling = settings.DefaultValueHandling;
			}
			if (settings._constructorHandling.HasValue)
			{
				serializer.ConstructorHandling = settings.ConstructorHandling;
			}
			if (settings._context.HasValue)
			{
				serializer.Context = settings.Context;
			}
			if (settings._checkAdditionalContent.HasValue)
			{
				serializer._checkAdditionalContent = settings._checkAdditionalContent;
			}
			if (settings.Error != null)
			{
				serializer.Error += settings.Error;
			}
			if (settings.ContractResolver != null)
			{
				serializer.ContractResolver = settings.ContractResolver;
			}
			if (settings.ReferenceResolverProvider != null)
			{
				serializer.ReferenceResolver = settings.ReferenceResolverProvider();
			}
			if (settings.TraceWriter != null)
			{
				serializer.TraceWriter = settings.TraceWriter;
			}
			if (settings.EqualityComparer != null)
			{
				serializer.EqualityComparer = settings.EqualityComparer;
			}
			if (settings.SerializationBinder != null)
			{
				serializer.SerializationBinder = settings.SerializationBinder;
			}
			if (settings._formatting.HasValue)
			{
				serializer._formatting = settings._formatting;
			}
			if (settings._dateFormatHandling.HasValue)
			{
				serializer._dateFormatHandling = settings._dateFormatHandling;
			}
			if (settings._dateTimeZoneHandling.HasValue)
			{
				serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
			}
			if (settings._dateParseHandling.HasValue)
			{
				serializer._dateParseHandling = settings._dateParseHandling;
			}
			if (settings._dateFormatStringSet)
			{
				serializer._dateFormatString = settings._dateFormatString;
				serializer._dateFormatStringSet = settings._dateFormatStringSet;
			}
			if (settings._floatFormatHandling.HasValue)
			{
				serializer._floatFormatHandling = settings._floatFormatHandling;
			}
			if (settings._floatParseHandling.HasValue)
			{
				serializer._floatParseHandling = settings._floatParseHandling;
			}
			if (settings._stringEscapeHandling.HasValue)
			{
				serializer._stringEscapeHandling = settings._stringEscapeHandling;
			}
			if (settings._culture != null)
			{
				serializer._culture = settings._culture;
			}
			if (settings._maxDepthSet)
			{
				serializer._maxDepth = settings._maxDepth;
				serializer._maxDepthSet = settings._maxDepthSet;
			}
		}

		[DebuggerStepThrough]
		public void Populate(TextReader reader, object target)
		{
			Populate(new JsonTextReader(reader), target);
		}

		[DebuggerStepThrough]
		public void Populate(JsonReader reader, object target)
		{
			PopulateInternal(reader, target);
		}

		internal virtual void PopulateInternal(JsonReader reader, object target)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			ValidationUtils.ArgumentNotNull(target, "target");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			new JsonSerializerInternalReader(this).Populate(traceJsonReader ?? reader, target);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader)
		{
			return Deserialize(reader, null);
		}

		[DebuggerStepThrough]
		public object? Deserialize(TextReader reader, Type objectType)
		{
			return Deserialize(new JsonTextReader(reader), objectType);
		}

		[DebuggerStepThrough]
		public T? Deserialize<T>(JsonReader reader)
		{
			return (T)Deserialize(reader, typeof(T));
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader, Type? objectType)
		{
			return DeserializeInternal(reader, objectType);
		}

		internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			object? result = new JsonSerializerInternalReader(this).Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
			return result;
		}

		internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
		{
			if (_culture != null && !_culture.Equals(reader.Culture))
			{
				previousCulture = reader.Culture;
				reader.Culture = _culture;
			}
			else
			{
				previousCulture = null;
			}
			if (_dateTimeZoneHandling.HasValue && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
				reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			else
			{
				previousDateTimeZoneHandling = null;
			}
			if (_dateParseHandling.HasValue && reader.DateParseHandling != _dateParseHandling)
			{
				previousDateParseHandling = reader.DateParseHandling;
				reader.DateParseHandling = _dateParseHandling.GetValueOrDefault();
			}
			else
			{
				previousDateParseHandling = null;
			}
			if (_floatParseHandling.HasValue && reader.FloatParseHandling != _floatParseHandling)
			{
				previousFloatParseHandling = reader.FloatParseHandling;
				reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault();
			}
			else
			{
				previousFloatParseHandling = null;
			}
			if (_maxDepthSet && reader.MaxDepth != _maxDepth)
			{
				previousMaxDepth = reader.MaxDepth;
				reader.MaxDepth = _maxDepth;
			}
			else
			{
				previousMaxDepth = null;
			}
			if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString)
			{
				previousDateFormatString = reader.DateFormatString;
				reader.DateFormatString = _dateFormatString;
			}
			else
			{
				previousDateFormatString = null;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver defaultContractResolver)
			{
				jsonTextReader.PropertyNameTable = defaultContractResolver.GetNameTable();
			}
		}

		private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString)
		{
			if (previousCulture != null)
			{
				reader.Culture = previousCulture;
			}
			if (previousDateTimeZoneHandling.HasValue)
			{
				reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
			}
			if (previousDateParseHandling.HasValue)
			{
				reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault();
			}
			if (previousFloatParseHandling.HasValue)
			{
				reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault();
			}
			if (_maxDepthSet)
			{
				reader.MaxDepth = previousMaxDepth;
			}
			if (_dateFormatStringSet)
			{
				reader.DateFormatString = previousDateFormatString;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable != null && _contractResolver is DefaultContractResolver defaultContractResolver && jsonTextReader.PropertyNameTable == defaultContractResolver.GetNameTable())
			{
				jsonTextReader.PropertyNameTable = null;
			}
		}

		public void Serialize(TextWriter textWriter, object? value)
		{
			Serialize(new JsonTextWriter(textWriter), value);
		}

		public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			SerializeInternal(jsonWriter, value, objectType);
		}

		public void Serialize(TextWriter textWriter, object? value, Type objectType)
		{
			Serialize(new JsonTextWriter(textWriter), value, objectType);
		}

		public void Serialize(JsonWriter jsonWriter, object? value)
		{
			SerializeInternal(jsonWriter, value, null);
		}

		private TraceJsonReader CreateTraceJsonReader(JsonReader reader)
		{
			TraceJsonReader traceJsonReader = new TraceJsonReader(reader);
			if (reader.TokenType != 0)
			{
				traceJsonReader.WriteCurrentToken();
			}
			return traceJsonReader;
		}

		internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
			Formatting? formatting = null;
			if (_formatting.HasValue && jsonWriter.Formatting != _formatting)
			{
				formatting = jsonWriter.Formatting;
				jsonWriter.Formatting = _formatting.GetValueOrDefault();
			}
			DateFormatHandling? dateFormatHandling = null;
			if (_dateFormatHandling.HasValue && jsonWriter.DateFormatHandling != _dateFormatHandling)
			{
				dateFormatHandling = jsonWriter.DateFormatHandling;
				jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault();
			}
			DateTimeZoneHandling? dateTimeZoneHandling = null;
			if (_dateTimeZoneHandling.HasValue && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				dateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
				jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			FloatFormatHandling? floatFormatHandling = null;
			if (_floatFormatHandling.HasValue && jsonWriter.FloatFormatHandling != _floatFormatHandling)
			{
				floatFormatHandling = jsonWriter.FloatFormatHandling;
				jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault();
			}
			StringEscapeHandling? stringEscapeHandling = null;
			if (_stringEscapeHandling.HasValue && jsonWriter.StringEscapeHandling != _stringEscapeHandling)
			{
				stringEscapeHandling = jsonWriter.StringEscapeHandling;
				jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault();
			}
			CultureInfo cultureInfo = null;
			if (_culture != null && !_culture.Equals(jsonWriter.Culture))
			{
				cultureInfo = jsonWriter.Culture;
				jsonWriter.Culture = _culture;
			}
			string dateFormatString = null;
			if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString)
			{
				dateFormatString = jsonWriter.DateFormatString;
				jsonWriter.DateFormatString = _dateFormatString;
			}
			TraceJsonWriter traceJsonWriter = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null);
			new JsonSerializerInternalWriter(this).Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
			if (traceJsonWriter != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
			}
			if (formatting.HasValue)
			{
				jsonWriter.Formatting = formatting.GetValueOrDefault();
			}
			if (dateFormatHandling.HasValue)
			{
				jsonWriter.DateFormatHandling = dateFormatHandling.GetValueOrDefault();
			}
			if (dateTimeZoneHandling.HasValue)
			{
				jsonWriter.DateTimeZoneHandling = dateTimeZoneHandling.GetValueOrDefault();
			}
			if (floatFormatHandling.HasValue)
			{
				jsonWriter.FloatFormatHandling = floatFormatHandling.GetValueOrDefault();
			}
			if (stringEscapeHandling.HasValue)
			{
				jsonWriter.StringEscapeHandling = stringEscapeHandling.GetValueOrDefault();
			}
			if (_dateFormatStringSet)
			{
				jsonWriter.DateFormatString = dateFormatString;
			}
			if (cultureInfo != null)
			{
				jsonWriter.Culture = cultureInfo;
			}
		}

		internal IReferenceResolver GetReferenceResolver()
		{
			if (_referenceResolver == null)
			{
				_referenceResolver = new DefaultReferenceResolver();
			}
			return _referenceResolver;
		}

		internal JsonConverter? GetMatchingConverter(Type type)
		{
			return GetMatchingConverter(_converters, type);
		}

		internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType)
		{
			if (converters != null)
			{
				for (int i = 0; i < converters.Count; i++)
				{
					JsonConverter jsonConverter = converters[i];
					if (jsonConverter.CanConvert(objectType))
					{
						return jsonConverter;
					}
				}
			}
			return null;
		}

		internal void OnError(Newtonsoft.Json.Serialization.ErrorEventArgs e)
		{
			this.Error?.Invoke(this, e);
		}
	}
	public class JsonSerializerSettings
	{
		internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;

		internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;

		internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;

		internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;

		internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;

		internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;

		internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;

		internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;

		internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default;

		internal static readonly StreamingContext DefaultContext;

		internal const Formatting DefaultFormatting = Formatting.None;

		internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;

		internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;

		internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;

		internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double;

		internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String;

		internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default;

		internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;

		internal static readonly CultureInfo DefaultCulture;

		internal const bool DefaultCheckAdditionalContent = false;

		internal const string DefaultDateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";

		internal const int DefaultMaxDepth = 64;

		internal Formatting? _formatting;

		internal DateFormatHandling? _dateFormatHandling;

		internal DateTimeZoneHandling? _dateTimeZoneHandling;

		internal DateParseHandling? _dateParseHandling;

		internal FloatFormatHandling? _floatFormatHandling;

		internal FloatParseHandling? _floatParseHandling;

		internal StringEscapeHandling? _stringEscapeHandling;

		internal CultureInfo? _culture;

		internal bool? _checkAdditionalContent;

		internal int? _maxDepth;

		internal bool _maxDepthSet;

		internal string? _dateFormatString;

		internal bool _dateFormatStringSet;

		internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal PreserveReferencesHandling? _preserveReferencesHandling;

		internal NullValueHandling? _nullValueHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal MissingMemberHandling? _missingMemberHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal StreamingContext? _context;

		internal ConstructorHandling? _constructorHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal MetadataPropertyHandling? _metadataPropertyHandling;

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public IList<JsonConverter> Converters { get; set; }

		public PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling.GetValueOrDef